Skip to content

Conversation

@cirospaciari
Copy link
Member

@cirospaciari cirospaciari commented Jan 8, 2026

Adds support for using https.globalAgent.options as default TLS settings across fetch, node:https, and WebSocket APIs. When applications set TLS properties on the global agent, those settings now automatically apply unless overridden per-request.

Features

  • TLS option fallback chain: Per-request options → agent-specific settings → https.globalAgent
  • Multiple agent sources: Supports agent.options, agent.connectOpts (https-proxy-agent), and agent.connect (undici.Agent)
  • Proxy fallback: WebSocket and fetch now fall back to https.globalAgent.proxy when no explicit proxy is set
  • Supported TLS properties: ca, cert, key, passphrase, rejectUnauthorized

Example Usage

import https from "https";

// Set global TLS defaults
https.globalAgent.options.rejectUnauthorized = false;
https.globalAgent.options.ca = myCustomCA;

// All APIs now use these defaults
await fetch("https://self-signed.example.com");  // Works!
new WebSocket("wss://self-signed.example.com");  // Works!
https.get("https://self-signed.example.com");    // Works!

// Per-request options still take precedence
await fetch(url, { tls: { rejectUnauthorized: true } });

Changes

Core implementation:

  • src/bun.js/webcore/fetch.zig - TLS fallback logic for fetch
  • src/bun.js/bindings/webcore/JSWebSocket.cpp - TLS and proxy fallback for WebSocket
  • src/js/node/_http_client.ts - TLS fallback for node:https

Infrastructure:

  • src/bun.js/bindings/JSGlobalObject.zig - Zig binding to access global agent
  • src/bun.js/bindings/bindings.cpp - C++ wrapper for agent retrieval
  • src/js/thirdparty/undici.js - Store dispatcher/agent TLS options

Tests:

  • test/js/node/tls/globalAgent-tls-options.test.ts - Integration tests for all APIs
  • test/js/web/websocket/websocket-proxy.test.ts - WebSocket globalAgent tests
  • test/js/first_party/undici/undici-properties.test.ts - Property storage validation

@robobun
Copy link
Collaborator

robobun commented Jan 8, 2026

Updated 11:44 AM PT - Jan 9th, 2026

@cirospaciari, your commit 3960596 has 4 failures in Build #34399 (All Failures):


🧪   To try this PR locally:

bunx bun-pr 25910

That installs a local version of the PR into your bun-25910 executable, so you can run:

bun-25910 --bun

@cirospaciari cirospaciari changed the title feat(tls): add https.globalAgent.options fallback for TLS options feat(tls): add https.globalAgent.options fallback for TLS options in fetch and node:https, add agent and dispatcher support for fetch and better agent support for node:https Jan 8, 2026
@cirospaciari cirospaciari changed the title feat(tls): add https.globalAgent.options fallback for TLS options in fetch and node:https, add agent and dispatcher support for fetch and better agent support for node:https feat(tls): add https.globalAgent.options fallback for TLS options in fetch and node:https, improve agent and dispatcher support for fetch and better agent support for node:https Jan 8, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 8, 2026

@cirospaciari: I'll review the changes in this PR. I notice there's a build failure on macOS aarch64 (build-zig) that you'll want to address - you can check the details in the Build #34298 logs.


🧠 Learnings used
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Run `bun run zig:check-all` to compile Zig code on all platforms when making platform-specific changes

Learnt from: fmguerreiro
Repo: oven-sh/bun PR: 23774
File: src/install/PackageManager/updatePackageJSONAndInstall.zig:548-548
Timestamp: 2025-10-24T10:43:09.398Z
Learning: In Bun's Zig codebase, the `as(usize, intCast(...))` cast pattern triggers a Zig compiler bug that causes compilation to hang indefinitely when used in complex control flow contexts (loops + short-circuit operators + optional unwrapping). Avoid this pattern and use simpler alternatives like just `intCast(...)` if type casting is necessary.

Learnt from: taylordotfish
Repo: oven-sh/bun PR: 0
File: :0-0
Timestamp: 2025-09-02T19:17:26.376Z
Learning: In Bun's Zig codebase, when handling error unions where the same cleanup operation (like `rawFree`) needs to be performed regardless of success or failure, prefer using boolean folding with `else |err| switch (err)` over duplicating the cleanup call in multiple switch branches. This approach avoids code duplication while maintaining compile-time error checking.

Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Applies to test/**/*.test.{ts,js,jsx,tsx,mjs,cjs} : Use `bun bd test <...test file>` to run tests with compiled code changes. Do not use `bun test` as it will not include your changes.

Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/test/v8/v8.test.ts : Add corresponding test cases to test/v8/v8.test.ts using checkSameOutput() function to compare Node.js and Bun output

Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/js/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:37:11.466Z
Learning: Write JS builtins for Bun's Node.js compatibility and APIs, and run `bun bd` after changes

Learnt from: RiskyMH
Repo: oven-sh/bun PR: 22606
File: src/glob/GlobWalker.zig:449-452
Timestamp: 2025-09-12T18:16:50.754Z
Learning: For Bun codebase: prefer using `std.fs.path.sep` over manual platform separator detection, and use `bun.strings.lastIndexOfChar` instead of `std.mem.lastIndexOfScalar` for string operations.
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 8, 2026

@cirospaciari: Understood! I'll proceed with reviewing the code changes and ignore the stale build failure. Let me review the current state of the PR.


🧠 Learnings used
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Run `bun run zig:check-all` to compile Zig code on all platforms when making platform-specific changes

Learnt from: fmguerreiro
Repo: oven-sh/bun PR: 23774
File: src/install/PackageManager/updatePackageJSONAndInstall.zig:548-548
Timestamp: 2025-10-24T10:43:09.398Z
Learning: In Bun's Zig codebase, the `as(usize, intCast(...))` cast pattern triggers a Zig compiler bug that causes compilation to hang indefinitely when used in complex control flow contexts (loops + short-circuit operators + optional unwrapping). Avoid this pattern and use simpler alternatives like just `intCast(...)` if type casting is necessary.

Learnt from: markovejnovic
Repo: oven-sh/bun PR: 23710
File: src/install/PackageManager/PackageManagerOptions.zig:187-193
Timestamp: 2025-10-16T17:32:03.074Z
Learning: In Bun's codebase (particularly in files like src/install/PackageManager/PackageManagerOptions.zig), mixing bun.EnvVar.*.get() and bun.EnvVar.*.platformGet() for environment variable lookups is intentional and safe. The code is protected by compile-time platform checks (Environment.isWindows, etc.), and compilation will fail if the wrong function is used on the wrong platform. This pattern should not be flagged as a consistency issue.

Learnt from: taylordotfish
Repo: oven-sh/bun PR: 0
File: :0-0
Timestamp: 2025-09-02T19:17:26.376Z
Learning: In Bun's Zig codebase, when handling error unions where the same cleanup operation (like `rawFree`) needs to be performed regardless of success or failure, prefer using boolean folding with `else |err| switch (err)` over duplicating the cleanup call in multiple switch branches. This approach avoids code duplication while maintaining compile-time error checking.

Learnt from: alii
Repo: oven-sh/bun PR: 25474
File: src/bun.js/event_loop/Sigusr1Handler.zig:0-0
Timestamp: 2026-01-05T16:32:15.175Z
Learning: In Bun's Zig codebase, std.posix.sigaction returns void (not an error union) and should be called without error handling. The Zig standard library treats sigaction failures as programmer errors (unreachable) since they only occur with invalid signals like SIGKILL/SIGSTOP. This pattern is used consistently across crash_handler.zig, main.zig, filter_run.zig, and process.zig.

Learnt from: taylordotfish
Repo: oven-sh/bun PR: 22227
File: src/allocators/allocation_scope.zig:79-85
Timestamp: 2025-09-02T18:09:21.647Z
Learning: In Bun's Zig codebase, prefer simple, direct error handling patterns. When an error type has only one variant (like FreeError with only NotAllocated), use a switch statement rather than generic catch blocks to leverage compile-time knowledge and avoid unnecessary complexity. Avoid duplicating function calls across error paths when a cleaner structure is possible.
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 8, 2026

Walkthrough

The PR adds support for falling back to Node.js https.globalAgent for TLS settings (rejectUnauthorized, CA, certificates) and proxy configuration in Bun's fetch, WebSocket, and HTTPS request implementations. New bindings expose globalAgent, helper functions extract TLS/proxy options from agents, and Undici classes are updated to store options for compatibility.

Changes

Cohort / File(s) Summary
Bindings & Globals Access
src/bun.js/bindings/JSGlobalObject.zig, src/bun.js/bindings/bindings.cpp
Adds extern C binding to retrieve https.globalAgent from the node:https module via JSGlobalObject, returning the globalAgent value or undefined if unavailable.
Fetch & WebSocket TLS Integration
src/bun.js/webcore/fetch.zig, src/bun.js/bindings/webcore/JSWebSocket.cpp
Implements TLS/proxy extraction helpers (hasTLSProperties, getAgentTLSOptions, findAgentOrDispatcher, findAgentWithProxy, extractTLSSettings) and integrates them into fetch and WebSocket construction to apply globalAgent fallback settings when not explicitly provided.
Node HTTP/HTTPS Client Updates
src/js/node/_http_client.ts
Adds getAgentTlsOption helper to fetch TLS options from agent via fallback chain (agent.options → agent.connectOpts → agent.connect); applies agent-derived TLS settings (rejectUnauthorized, ca, cert, key, etc.) when not in user options.
Undici Compatibility
src/js/thirdparty/undici.js
Extends Dispatcher, Agent, Pool, BalancedPool, Client, and related classes to accept and store options non-enumerably; adds fetch wrapper that routes through globalDispatcher; propagates options and connect properties across class hierarchy.
TLS Configuration
src/bun.js/api/server/SSLConfig.bindv2.ts, src/bun.js/api/server/SSLConfig.zig
Expands ALPN protocol handling to support array input type in addition to existing string/buffer/none cases; converts arrays to length-prefixed wire format.
Tests
test/js/first_party/undici/undici.test.ts, test/js/first_party/undici/undici-properties.test.ts, test/js/web/websocket/websocket-proxy.test.ts, test/js/node/tls/globalAgent-fetch.test.ts, test/js/node/tls/globalAgent-https-request.test.ts, test/js/node/tls/globalAgent-undici.test.ts, test/js/web/fetch/fetch-tls-abortsignal-timeout.test.ts
Adds comprehensive test coverage for globalAgent TLS/proxy fallback behavior in fetch, WebSocket, and HTTPS requests; verifies Undici dispatcher options storage and compatibility; adjusts timeout threshold in abort test.

Suggested reviewers

  • alii
  • nektro
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: adding https.globalAgent.options fallback support for fetch, node:https, and WebSocket APIs.
Description check ✅ Passed The description comprehensively covers features, implementation details, usage examples, and lists all modified files, though it references test files that differ from actual split test file names.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between f134729 and 3960596.

📒 Files selected for processing (3)
  • test/js/node/tls/globalAgent-fetch.test.ts
  • test/js/node/tls/globalAgent-https-request.test.ts
  • test/js/node/tls/globalAgent-undici.test.ts
🧰 Additional context used
📓 Path-based instructions (3)
**/*.test.ts?(x)

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.test.ts?(x): Never use bun test directly - always use bun bd test to run tests with debug build changes
For single-file tests, prefer -e flag over tempDir
For multi-file tests, prefer tempDir and Bun.spawn over single-file tests
Use normalizeBunSnapshot to normalize snapshot output of tests
Never write tests that check for 'panic', 'uncaught exception', or similar strings in test output
Use tempDir from harness to create temporary directories - do not use tmpdirSync or fs.mkdtempSync
When spawning processes in tests, expect stdout before expecting exit code for more useful error messages on test failure
Do not write flaky tests - do not use setTimeout in tests; instead await the condition to be met
Verify tests fail with USE_SYSTEM_BUN=1 bun test <file> and pass with bun bd test <file> - tests are invalid if they pass with USE_SYSTEM_BUN=1
Test files must end with .test.ts or .test.tsx
Avoid shell commands like find or grep in tests - use Bun's Glob and built-in tools instead

Files:

  • test/js/node/tls/globalAgent-fetch.test.ts
  • test/js/node/tls/globalAgent-undici.test.ts
  • test/js/node/tls/globalAgent-https-request.test.ts
test/**/*.test.ts?(x)

📄 CodeRabbit inference engine (CLAUDE.md)

Always use port: 0 in tests - do not hardcode ports or use custom random port number functions

Files:

  • test/js/node/tls/globalAgent-fetch.test.ts
  • test/js/node/tls/globalAgent-undici.test.ts
  • test/js/node/tls/globalAgent-https-request.test.ts
test/**/*.test.{ts,js,jsx,tsx,mjs,cjs}

📄 CodeRabbit inference engine (test/CLAUDE.md)

test/**/*.test.{ts,js,jsx,tsx,mjs,cjs}: Use bun bd test <...test file> to run tests with compiled code changes. Do not use bun test as it will not include your changes.
Use bun:test for files ending in *.test.{ts,js,jsx,tsx,mjs,cjs}. For test files without .test extension in test/js/node/test/{parallel,sequential}/*.js, use bun bd <file> instead of bun bd test <file> since they expect exit code 0.
Do not set a timeout on tests. Bun already has timeouts built-in.

Files:

  • test/js/node/tls/globalAgent-fetch.test.ts
  • test/js/node/tls/globalAgent-undici.test.ts
  • test/js/node/tls/globalAgent-https-request.test.ts
🧠 Learnings (21)
📓 Common learnings
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: packages/bun-otel/BunFetchInstrumentation.ts:126-131
Timestamp: 2025-10-20T01:38:02.660Z
Learning: In BunFetchInstrumentation.ts, the force-restore to ORIGINAL_FETCH in the disable() method is intentionally kept (despite appearing unsafe) because it's required for proper test cleanup when instrumentation is repeatedly enabled/disabled. Without it, 15 distributed tracing and context propagation tests fail. Shimmer's unwrap() doesn't reliably restore the original fetch in Bun's globalThis context. The isBunOtelPatched safety check ensures the restore only happens when the current fetch is still ours, preventing clobbering of other tools' wrappers.
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: test/js/bun/http/node-telemetry.test.ts:27-203
Timestamp: 2025-10-19T04:55:33.099Z
Learning: In test/js/bun/http/node-telemetry.test.ts and the Bun.telemetry._node_binding API, after the architecture refactor, the _node_binding interface only contains two methods: handleIncomingRequest(req, res) and handleWriteHead(res, statusCode). The handleRequestFinish hook and other lifecycle hooks were removed during simplification. Both current methods are fully tested.
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 22323
File: test/js/web/websocket/websocket-subprotocol.test.ts:74-75
Timestamp: 2025-09-02T05:33:37.517Z
Learning: In Bun's runtime, `await using` with Node.js APIs like `net.createServer()` is properly supported and should not be replaced with explicit cleanup. Bun has extended Node.js APIs with proper async dispose support.
📚 Learning: 2025-10-19T04:55:33.099Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: test/js/bun/http/node-telemetry.test.ts:27-203
Timestamp: 2025-10-19T04:55:33.099Z
Learning: In test/js/bun/http/node-telemetry.test.ts and the Bun.telemetry._node_binding API, after the architecture refactor, the _node_binding interface only contains two methods: handleIncomingRequest(req, res) and handleWriteHead(res, statusCode). The handleRequestFinish hook and other lifecycle hooks were removed during simplification. Both current methods are fully tested.

Applied to files:

  • test/js/node/tls/globalAgent-fetch.test.ts
  • test/js/node/tls/globalAgent-undici.test.ts
  • test/js/node/tls/globalAgent-https-request.test.ts
📚 Learning: 2025-10-18T05:23:24.403Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: test/js/bun/telemetry-server.test.ts:91-100
Timestamp: 2025-10-18T05:23:24.403Z
Learning: In the Bun codebase, telemetry tests (test/js/bun/telemetry-*.test.ts) should focus on telemetry API behavior: configure/disable/isEnabled, callback signatures and invocation, request ID correlation, and error handling. HTTP protocol behaviors like status code normalization (e.g., 200 with empty body → 204) should be tested in HTTP server tests (test/js/bun/http/), not in telemetry tests. Keep separation of concerns: telemetry tests verify the telemetry API contract; HTTP tests verify HTTP semantics.

Applied to files:

  • test/js/node/tls/globalAgent-fetch.test.ts
  • test/js/node/tls/globalAgent-undici.test.ts
  • test/js/node/tls/globalAgent-https-request.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to test/**/*.test.ts?(x) : Always use `port: 0` in tests - do not hardcode ports or use custom random port number functions

Applied to files:

  • test/js/node/tls/globalAgent-fetch.test.ts
  • test/js/node/tls/globalAgent-https-request.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to **/*.test.ts?(x) : For multi-file tests, prefer `tempDir` and `Bun.spawn` over single-file tests

Applied to files:

  • test/js/node/tls/globalAgent-fetch.test.ts
  • test/js/node/tls/globalAgent-undici.test.ts
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/test/v8/v8.test.ts : Add corresponding test cases to test/v8/v8.test.ts using checkSameOutput() function to compare Node.js and Bun output

Applied to files:

  • test/js/node/tls/globalAgent-fetch.test.ts
  • test/js/node/tls/globalAgent-undici.test.ts
📚 Learning: 2025-09-03T01:30:58.001Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 21728
File: test/js/valkey/valkey.test.ts:264-271
Timestamp: 2025-09-03T01:30:58.001Z
Learning: For test/js/valkey/valkey.test.ts PUB/SUB tests, avoid arbitrary sleeps and async-forEach. Instead, resolve a Promise from the subscriber callback when the expected number of messages is observed and await it with a bounded timeout (e.g., withTimeout + Promise.withResolvers) to account for Redis server→subscriber propagation.

Applied to files:

  • test/js/node/tls/globalAgent-fetch.test.ts
📚 Learning: 2025-09-20T00:57:56.685Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 22568
File: test/js/valkey/valkey.test.ts:268-276
Timestamp: 2025-09-20T00:57:56.685Z
Learning: For test/js/valkey/valkey.test.ts, do not comment on synchronous throw assertions for async Redis methods like ctx.redis.set() - the maintainer has explicitly requested to stop looking at this error pattern.

Applied to files:

  • test/js/node/tls/globalAgent-fetch.test.ts
📚 Learning: 2025-09-20T00:58:38.042Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 22568
File: test/js/valkey/valkey.test.ts:561-564
Timestamp: 2025-09-20T00:58:38.042Z
Learning: For test/js/valkey/valkey.test.ts, do not comment on synchronous throw assertions for async Redis methods (like ctx.redis.set(), ctx.redis.unsubscribe(), etc.) - Bun's Redis client implementation differs from Node.js and can throw synchronously even for async methods. The maintainer has explicitly requested to stop looking at this error pattern.

Applied to files:

  • test/js/node/tls/globalAgent-fetch.test.ts
  • test/js/node/tls/globalAgent-undici.test.ts
📚 Learning: 2025-10-20T01:38:02.660Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: packages/bun-otel/BunFetchInstrumentation.ts:126-131
Timestamp: 2025-10-20T01:38:02.660Z
Learning: In BunFetchInstrumentation.ts, the force-restore to ORIGINAL_FETCH in the disable() method is intentionally kept (despite appearing unsafe) because it's required for proper test cleanup when instrumentation is repeatedly enabled/disabled. Without it, 15 distributed tracing and context propagation tests fail. Shimmer's unwrap() doesn't reliably restore the original fetch in Bun's globalThis context. The isBunOtelPatched safety check ensures the restore only happens when the current fetch is still ours, preventing clobbering of other tools' wrappers.

Applied to files:

  • test/js/node/tls/globalAgent-fetch.test.ts
  • test/js/node/tls/globalAgent-undici.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to **/*.test.ts?(x) : Do not write flaky tests - do not use `setTimeout` in tests; instead await the condition to be met

Applied to files:

  • test/js/node/tls/globalAgent-fetch.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Prefer async/await over callbacks in tests. When callbacks must be used for a single callback, use `Promise.withResolvers` to create a promise that can be resolved or rejected from a callback.

Applied to files:

  • test/js/node/tls/globalAgent-fetch.test.ts
📚 Learning: 2025-10-19T02:44:46.354Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: packages/bun-otel/context-propagation.test.ts:1-1
Timestamp: 2025-10-19T02:44:46.354Z
Learning: In the Bun repository, standalone packages under packages/ (e.g., bun-vscode, bun-inspector-protocol, bun-plugin-yaml, bun-plugin-svelte, bun-debug-adapter-protocol, bun-otel) co-locate their tests with package source code using *.test.ts files. This follows standard npm/monorepo patterns. The test/ directory hierarchy (test/js/bun/, test/cli/, test/js/node/) is reserved for testing Bun's core runtime APIs and built-in functionality, not standalone packages.

Applied to files:

  • test/js/node/tls/globalAgent-undici.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Applies to test/**/*.test.{ts,js,jsx,tsx,mjs,cjs} : Use `bun bd test <...test file>` to run tests with compiled code changes. Do not use `bun test` as it will not include your changes.

Applied to files:

  • test/js/node/tls/globalAgent-undici.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Applies to test/**/*.test.{ts,js,jsx,tsx,mjs,cjs} : Use `bun:test` for files ending in `*.test.{ts,js,jsx,tsx,mjs,cjs}`. For test files without .test extension in test/js/node/test/{parallel,sequential}/*.js, use `bun bd <file>` instead of `bun bd test <file>` since they expect exit code 0.

Applied to files:

  • test/js/node/tls/globalAgent-undici.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Organize unit tests by module in directories like `/test/js/bun/` and `/test/js/node/`.

Applied to files:

  • test/js/node/tls/globalAgent-undici.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Applies to test/**/*.test.{ts,js,jsx,tsx,mjs,cjs} : Do not set a timeout on tests. Bun already has timeouts built-in.

Applied to files:

  • test/js/node/tls/globalAgent-undici.test.ts
📚 Learning: 2025-10-25T17:20:19.041Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 24063
File: test/js/bun/telemetry/server-header-injection.test.ts:5-20
Timestamp: 2025-10-25T17:20:19.041Z
Learning: In the Bun telemetry codebase, tests are organized into two distinct layers: (1) Internal API tests in test/js/bun/telemetry/ use numeric InstrumentKind enum values to test Zig↔JS injection points and low-level integration; (2) Public API tests in packages/bun-otel/test/ use string InstrumentKind values ("http", "fetch", etc.) to test the public-facing BunSDK and instrumentation APIs. This separation allows internal tests to use efficient numeric enums for refactoring flexibility while the public API maintains a developer-friendly string-based interface.

Applied to files:

  • test/js/node/tls/globalAgent-undici.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to **/*.test.ts?(x) : Verify tests fail with `USE_SYSTEM_BUN=1 bun test <file>` and pass with `bun bd test <file>` - tests are invalid if they pass with USE_SYSTEM_BUN=1

Applied to files:

  • test/js/node/tls/globalAgent-undici.test.ts
  • test/js/node/tls/globalAgent-https-request.test.ts
📚 Learning: 2025-10-30T03:48:10.513Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 24063
File: packages/bun-otel/test/context-propagation.test.ts:1-7
Timestamp: 2025-10-30T03:48:10.513Z
Learning: In Bun test files, `using` declarations at the describe block level execute during module load/parsing, not during test execution. This means they acquire and dispose resources before any tests run. For test-scoped resource management, use beforeAll/afterAll hooks instead. The pattern `beforeAll(beforeUsingEchoServer); afterAll(afterUsingEchoServer);` is correct for managing ref-counted test resources like the EchoServer in packages/bun-otel/test/ - the using block pattern should not be used at describe-block level for test resources.
<!-- [/add_learning]

Applied to files:

  • test/js/node/tls/globalAgent-undici.test.ts
📚 Learning: 2025-10-08T13:48:02.430Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 23373
File: test/js/bun/tarball/extract.test.ts:107-111
Timestamp: 2025-10-08T13:48:02.430Z
Learning: In Bun's test runner, use `expect(async () => { await ... }).toThrow()` to assert async rejections. Unlike Jest/Vitest, Bun does not require `await expect(...).rejects.toThrow()` - the async function wrapper with `.toThrow()` is the correct pattern for async error assertions in Bun tests.

Applied to files:

  • test/js/node/tls/globalAgent-https-request.test.ts
🧬 Code graph analysis (3)
test/js/node/tls/globalAgent-fetch.test.ts (1)
test/harness.ts (2)
  • tempDir (277-284)
  • bunRun (292-317)
test/js/node/tls/globalAgent-undici.test.ts (1)
test/harness.ts (2)
  • tempDir (277-284)
  • bunRun (292-317)
test/js/node/tls/globalAgent-https-request.test.ts (1)
test/harness.ts (2)
  • tempDir (277-284)
  • bunRun (292-317)
🔇 Additional comments (3)
test/js/node/tls/globalAgent-https-request.test.ts (1)

1-217: LGTM! Well-structured test suite.

The tests follow Bun's coding guidelines correctly:

  • Uses bunRun with subprocess spawning for multi-file tests
  • Uses tempDir for test isolation
  • Uses port: 0 for dynamic port assignment
  • Uses describe.concurrent for parallel execution
  • No flaky patterns (no setTimeout, proper async handling)

The test coverage is comprehensive for the HTTPS request scenarios with various TLS configuration fallback chains (per-request → agent-specific → globalAgent).

test/js/node/tls/globalAgent-fetch.test.ts (1)

1-357: LGTM! Comprehensive fetch TLS test coverage.

The tests correctly exercise fetch API with various TLS configurations and agent/dispatcher scenarios. The test structure follows Bun's guidelines and properly validates the TLS resolution order (per-request tls options → agent/dispatcher options → globalAgent.options).

The checkServerIdentity = () => {} pattern at line 83 is correct—returning undefined allows the connection to proceed, which is necessary for testing with self-signed certificates.

test/js/node/tls/globalAgent-undici.test.ts (1)

1-408: LGTM! Excellent undici integration test coverage.

The tests thoroughly exercise Bun's fetch integration with various undici dispatcher types (Agent, Pool, Client, ProxyAgent) and verify that TLS options are correctly propagated through different configuration paths:

  • Per-dispatcher connect options
  • Global dispatcher via setGlobalDispatcher
  • Fallback to https.globalAgent.options

The test structure is consistent with the other files in this PR and follows Bun's coding guidelines.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Fix all issues with AI agents
In @src/bun.js/webcore/fetch.zig:
- Around line 952-996: The TLS extraction block duplicates logic already
encapsulated by getAgentTLSOptions(); replace the manual connectOpts/connect
probing in the current_agent branch with a call to
getAgentTLSOptions(current_agent, vm, globalThis) (or the same signature used
earlier), then apply the returned values to reject_unauthorized,
check_server_identity, and ssl_config (allocating SSLConfig on success) and
preserve the existing error path (set is_error and return .zero on failure),
ensuring you reference current_agent, getAgentTLSOptions(), reject_unauthorized,
check_server_identity, and ssl_config so the behavior matches the earlier TLS
fallback block.

In @src/js/node/_http_client.ts:
- Around line 733-841: The TLS option fallback chain (agent.options →
agent.connectOpts → agent.connect) is duplicated across many blocks; extract a
helper like getAgentTlsOption(agent, key) and use it in each branch (e.g., when
resolving agentRejectUnauthorized, agentCa, agentCert, agentKey,
agentPassphrase, agentCiphers, agentServername, agentSecureOptions) so the
repeated three-step lookup is centralized, then keep the existing validations
(isValidTLSArray, typeof checks) and assign via this._ensureTls() as before;
update places referencing the inline fallback logic to call the new helper to
reduce duplication.

In @src/js/thirdparty/undici.js:
- Around line 340-344: The RetryAgent constructor currently ignores the
dispatcher parameter which should be the wrapped agent; update the constructor
in class RetryAgent to store the passed-in dispatcher (e.g., assign it to
this.dispatcher) so future methods can delegate to it, and optionally validate
its type (instanceof Dispatcher) or add a comment/docstring noting it's
intentionally stubbed if you don't want to use it yet; ensure references to
dispatcher in other RetryAgent methods use this.dispatcher.
- Around line 274-326: Dispatcher and DispatcherBase duplicate the same
constructor logic for storing options and options.connect; remove the
duplication by extracting that logic into a single reusable place—either create
a small helper function (e.g., storeConnectOptions(options)) and call it from
both Dispatcher and DispatcherBase constructors, or make one class the true base
(e.g., have Dispatcher extend DispatcherBase or vice versa) and keep the
constructor logic only in the base; update the constructors of Dispatcher,
DispatcherBase (and any subclasses like Agent, Pool, Client, BalancedPool if
needed) to call the shared helper or the single base constructor so the
duplicated block is eliminated.

In @test/js/node/tls/globalAgent-tls-options.test.ts:
- Around line 1121-1242: The property-storage assertions for undici classes
(Agent, Dispatcher, Pool, Client, ProxyAgent, EnvHttpProxyAgent, RetryAgent)
belong to a structural/unit test, not the TLS integration suite; move the test
"undici.Agent stores options and connect properties correctly" into its own
describe block or a separate test file (e.g., undici-agent-properties.test.ts),
keeping the same assertions and process spawning logic but removing it from the
TLS/globalAgent-tls-options.test.ts integration file so integration vs.
structural tests are clearly separated.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 65d006a and e75b7db.

📒 Files selected for processing (7)
  • src/bun.js/bindings/JSGlobalObject.zig
  • src/bun.js/bindings/bindings.cpp
  • src/bun.js/webcore/fetch.zig
  • src/js/node/_http_client.ts
  • src/js/thirdparty/undici.js
  • test/js/first_party/undici/undici.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
🧰 Additional context used
📓 Path-based instructions (8)
**/*.zig

📄 CodeRabbit inference engine (CLAUDE.md)

In Zig code, be careful with allocators and use defer for cleanup

Files:

  • src/bun.js/bindings/JSGlobalObject.zig
  • src/bun.js/webcore/fetch.zig
src/**/*.zig

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.zig: Use the # prefix for private fields in Zig structs, e.g., struct { #foo: u32 };
Use Decl literals in Zig, e.g., const decl: Decl = .{ .binding = 0, .value = 0 };
Place @import statements at the bottom of the file in Zig (auto formatter will handle positioning)
Never use @import() inline inside functions in Zig; always place imports at the bottom of the file or containing struct

Files:

  • src/bun.js/bindings/JSGlobalObject.zig
  • src/bun.js/webcore/fetch.zig
**/*.test.ts?(x)

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.test.ts?(x): Never use bun test directly - always use bun bd test to run tests with debug build changes
For single-file tests, prefer -e flag over tempDir
For multi-file tests, prefer tempDir and Bun.spawn over single-file tests
Use normalizeBunSnapshot to normalize snapshot output of tests
Never write tests that check for 'panic', 'uncaught exception', or similar strings in test output
Use tempDir from harness to create temporary directories - do not use tmpdirSync or fs.mkdtempSync
When spawning processes in tests, expect stdout before expecting exit code for more useful error messages on test failure
Do not write flaky tests - do not use setTimeout in tests; instead await the condition to be met
Verify tests fail with USE_SYSTEM_BUN=1 bun test <file> and pass with bun bd test <file> - tests are invalid if they pass with USE_SYSTEM_BUN=1
Test files must end with .test.ts or .test.tsx
Avoid shell commands like find or grep in tests - use Bun's Glob and built-in tools instead

Files:

  • test/js/first_party/undici/undici.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
test/**/*.test.ts?(x)

📄 CodeRabbit inference engine (CLAUDE.md)

Always use port: 0 in tests - do not hardcode ports or use custom random port number functions

Files:

  • test/js/first_party/undici/undici.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
test/**/*.test.{ts,js,jsx,tsx,mjs,cjs}

📄 CodeRabbit inference engine (test/CLAUDE.md)

test/**/*.test.{ts,js,jsx,tsx,mjs,cjs}: Use bun bd test <...test file> to run tests with compiled code changes. Do not use bun test as it will not include your changes.
Use bun:test for files ending in *.test.{ts,js,jsx,tsx,mjs,cjs}. For test files without .test extension in test/js/node/test/{parallel,sequential}/*.js, use bun bd <file> instead of bun bd test <file> since they expect exit code 0.
Do not set a timeout on tests. Bun already has timeouts built-in.

Files:

  • test/js/first_party/undici/undici.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
src/js/{builtins,node,bun,thirdparty,internal}/**/*.{ts,js}

📄 CodeRabbit inference engine (src/js/CLAUDE.md)

src/js/{builtins,node,bun,thirdparty,internal}/**/*.{ts,js}: Use .$call() and .$apply() instead of .call() and .apply() to prevent user tampering with function invocation
Use string literal require() statements only; dynamic requires are not permitted
Export modules using export default { ... } syntax; modules are NOT ES modules
Use JSC intrinsics (prefixed with $) such as $Array.from(), $isCallable(), and $newArrayWithSize() for performance-critical operations
Use private globals and methods with $ prefix (e.g., $Array, map.$set()) instead of public JavaScript globals
Use $debug() for debug logging and $assert() for assertions; both are stripped in release builds
Validate function arguments using validators from internal/validators and throw $ERR_* error codes for invalid arguments
Use process.platform and process.arch for platform detection; these values are inlined and dead-code eliminated at build time

Files:

  • src/js/node/_http_client.ts
  • src/js/thirdparty/undici.js
src/js/{builtins,node,bun,thirdparty,internal}/**/*.ts

📄 CodeRabbit inference engine (src/js/CLAUDE.md)

Builtin functions must include this parameter typing in TypeScript to enable direct method binding in C++

Files:

  • src/js/node/_http_client.ts
src/bun.js/bindings/**/*.cpp

📄 CodeRabbit inference engine (CLAUDE.md)

src/bun.js/bindings/**/*.cpp: Create classes in three parts in C++ when there is a public constructor: Foo (JSDestructibleObject), FooPrototype (JSNonFinalObject), and FooConstructor (InternalFunction)
Define properties using HashTableValue arrays in C++ JavaScript class bindings
Add iso subspaces for C++ classes with fields in JavaScript class bindings
Cache structures in ZigGlobalObject for JavaScript class bindings

Files:

  • src/bun.js/bindings/bindings.cpp
🧠 Learnings (36)
📓 Common learnings
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: packages/bun-otel/BunFetchInstrumentation.ts:126-131
Timestamp: 2025-10-20T01:38:02.660Z
Learning: In BunFetchInstrumentation.ts, the force-restore to ORIGINAL_FETCH in the disable() method is intentionally kept (despite appearing unsafe) because it's required for proper test cleanup when instrumentation is repeatedly enabled/disabled. Without it, 15 distributed tracing and context propagation tests fail. Shimmer's unwrap() doesn't reliably restore the original fetch in Bun's globalThis context. The isBunOtelPatched safety check ensures the restore only happens when the current fetch is still ours, preventing clobbering of other tools' wrappers.
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: test/js/bun/http/node-telemetry.test.ts:27-203
Timestamp: 2025-10-19T04:55:33.099Z
Learning: In test/js/bun/http/node-telemetry.test.ts and the Bun.telemetry._node_binding API, after the architecture refactor, the _node_binding interface only contains two methods: handleIncomingRequest(req, res) and handleWriteHead(res, statusCode). The handleRequestFinish hook and other lifecycle hooks were removed during simplification. Both current methods are fully tested.
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/src/napi/napi.zig : For each new V8 C++ method, add both GCC/Clang and MSVC mangled symbol names to the V8API struct in src/napi/napi.zig using extern fn declarations

Applied to files:

  • src/bun.js/bindings/JSGlobalObject.zig
  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to src/bun.js/bindings/**/*.cpp : Cache structures in ZigGlobalObject for JavaScript class bindings

Applied to files:

  • src/bun.js/bindings/JSGlobalObject.zig
  • src/js/thirdparty/undici.js
  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:37:47.899Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/AGENTS.md:0-0
Timestamp: 2025-11-24T18:37:47.899Z
Learning: Applies to src/bun.js/bindings/v8/**/<UNKNOWN> : <UNKNOWN>

Applied to files:

  • src/bun.js/bindings/JSGlobalObject.zig
  • src/js/thirdparty/undici.js
  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.h : Add BUN_EXPORT visibility attribute to all public V8 API functions to ensure proper symbol export across platforms

Applied to files:

  • src/bun.js/bindings/JSGlobalObject.zig
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/src/symbols.txt : Add symbol names without leading underscore to src/symbols.txt for each new V8 API method

Applied to files:

  • src/bun.js/bindings/JSGlobalObject.zig
  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/src/symbols.dyn : Add symbol names with leading underscore and semicolons in braces to src/symbols.dyn for each new V8 API method

Applied to files:

  • src/bun.js/bindings/JSGlobalObject.zig
  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-10-11T15:19:30.301Z
Learnt from: mastermakrela
Repo: oven-sh/bun PR: 19167
File: src/bun.js/api.zig:31-31
Timestamp: 2025-10-11T15:19:30.301Z
Learning: The learnings about `pub const js = JSC.Codegen.JS<ClassName>` and re-exporting toJS/fromJS/fromJSDirect apply to class-based Zig bindings with constructors and prototype methods (e.g., those with `new` constructors). They do NOT apply to simple namespace-style API objects like TOMLObject, YAMLObject, and CSVObject which expose static functions via a `create()` method that returns a plain JS object.

Applied to files:

  • src/bun.js/bindings/JSGlobalObject.zig
📚 Learning: 2025-11-24T18:37:11.466Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/js/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:37:11.466Z
Learning: Applies to src/js/{builtins,node,bun,thirdparty,internal}/**/*.{ts,js} : Use private globals and methods with `$` prefix (e.g., `$Array`, `map.$set()`) instead of public JavaScript globals

Applied to files:

  • src/bun.js/bindings/JSGlobalObject.zig
📚 Learning: 2025-11-03T20:43:06.996Z
Learnt from: pfgithub
Repo: oven-sh/bun PR: 24273
File: src/bun.js/test/snapshot.zig:19-19
Timestamp: 2025-11-03T20:43:06.996Z
Learning: In Bun's Zig codebase, when storing JSValue objects in collections like ArrayList, use `jsc.Strong.Optional` (not raw JSValue). When adding values, wrap them with `jsc.Strong.Optional.create(value, globalThis)`. In cleanup code, iterate the collection calling `.deinit()` on each Strong.Optional item before calling `.deinit()` on the ArrayList itself. This pattern automatically handles GC protection. See examples in src/bun.js/test/ScopeFunctions.zig and src/bun.js/node/node_cluster_binding.zig.

Applied to files:

  • src/bun.js/bindings/JSGlobalObject.zig
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/test/v8/v8-module/main.cpp : Register new V8 API test functions in the Init method using NODE_SET_METHOD with exports object

Applied to files:

  • src/bun.js/bindings/JSGlobalObject.zig
  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2026-01-05T16:32:07.551Z
Learnt from: alii
Repo: oven-sh/bun PR: 25474
File: src/bun.js/event_loop/Sigusr1Handler.zig:0-0
Timestamp: 2026-01-05T16:32:07.551Z
Learning: In Zig codebases (e.g., Bun), treat std.posix.sigaction as returning void and do not perform runtime error handling for its failure. The Zig standard library views sigaction failures as programmer errors (unreachable) because they only occur with invalid signals like SIGKILL/SIGSTOP. Apply this pattern across Zig files that call sigaction (e.g., crash_handler.zig, main.zig, filter_run.zig, process.zig) and ensure failures are not handled as recoverable errors; prefer reaching an explicit unreachable/compile-time assumption when such failures are detected.

Applied to files:

  • src/bun.js/bindings/JSGlobalObject.zig
  • src/bun.js/webcore/fetch.zig
📚 Learning: 2025-09-03T01:30:58.001Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 21728
File: test/js/valkey/valkey.test.ts:264-271
Timestamp: 2025-09-03T01:30:58.001Z
Learning: For test/js/valkey/valkey.test.ts PUB/SUB tests, avoid arbitrary sleeps and async-forEach. Instead, resolve a Promise from the subscriber callback when the expected number of messages is observed and await it with a bounded timeout (e.g., withTimeout + Promise.withResolvers) to account for Redis server→subscriber propagation.

Applied to files:

  • test/js/first_party/undici/undici.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to test/**/*.test.ts?(x) : Always use `port: 0` in tests - do not hardcode ports or use custom random port number functions

Applied to files:

  • test/js/first_party/undici/undici.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-10-18T05:23:24.403Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: test/js/bun/telemetry-server.test.ts:91-100
Timestamp: 2025-10-18T05:23:24.403Z
Learning: In the Bun codebase, telemetry tests (test/js/bun/telemetry-*.test.ts) should focus on telemetry API behavior: configure/disable/isEnabled, callback signatures and invocation, request ID correlation, and error handling. HTTP protocol behaviors like status code normalization (e.g., 200 with empty body → 204) should be tested in HTTP server tests (test/js/bun/http/), not in telemetry tests. Keep separation of concerns: telemetry tests verify the telemetry API contract; HTTP tests verify HTTP semantics.

Applied to files:

  • test/js/first_party/undici/undici.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-10-19T04:55:33.099Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: test/js/bun/http/node-telemetry.test.ts:27-203
Timestamp: 2025-10-19T04:55:33.099Z
Learning: In test/js/bun/http/node-telemetry.test.ts and the Bun.telemetry._node_binding API, after the architecture refactor, the _node_binding interface only contains two methods: handleIncomingRequest(req, res) and handleWriteHead(res, statusCode). The handleRequestFinish hook and other lifecycle hooks were removed during simplification. Both current methods are fully tested.

Applied to files:

  • test/js/first_party/undici/undici.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-10-20T01:38:02.660Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: packages/bun-otel/BunFetchInstrumentation.ts:126-131
Timestamp: 2025-10-20T01:38:02.660Z
Learning: In BunFetchInstrumentation.ts, the force-restore to ORIGINAL_FETCH in the disable() method is intentionally kept (despite appearing unsafe) because it's required for proper test cleanup when instrumentation is repeatedly enabled/disabled. Without it, 15 distributed tracing and context propagation tests fail. Shimmer's unwrap() doesn't reliably restore the original fetch in Bun's globalThis context. The isBunOtelPatched safety check ensures the restore only happens when the current fetch is still ours, preventing clobbering of other tools' wrappers.

Applied to files:

  • src/bun.js/webcore/fetch.zig
  • src/js/thirdparty/undici.js
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-10-17T20:50:58.644Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 23755
File: src/bun.js/api/bun/socket/Handlers.zig:154-159
Timestamp: 2025-10-17T20:50:58.644Z
Learning: In Bun socket configuration error messages (src/bun.js/api/bun/socket/Handlers.zig), use the user-facing JavaScript names "data" and "drain" instead of internal field names "onData" and "onWritable", as these are the names users see in the API according to SocketConfig.bindv2.ts.

Applied to files:

  • src/bun.js/webcore/fetch.zig
📚 Learning: 2025-11-24T18:37:11.466Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/js/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:37:11.466Z
Learning: Write JS builtins for Bun's Node.js compatibility and APIs, and run `bun bd` after changes

Applied to files:

  • src/js/thirdparty/undici.js
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to src/bun.js/bindings/**/*.cpp : Create classes in three parts in C++ when there is a public constructor: Foo (JSDestructibleObject), FooPrototype (JSNonFinalObject), and FooConstructor (InternalFunction)

Applied to files:

  • src/js/thirdparty/undici.js
📚 Learning: 2025-09-02T05:33:37.517Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 22323
File: test/js/web/websocket/websocket-subprotocol.test.ts:74-75
Timestamp: 2025-09-02T05:33:37.517Z
Learning: In Bun's runtime, `await using` with Node.js APIs like `net.createServer()` is properly supported and should not be replaced with explicit cleanup. Bun has extended Node.js APIs with proper async dispose support.

Applied to files:

  • src/js/thirdparty/undici.js
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to src/bun.js/bindings/**/*.cpp : Add iso subspaces for C++ classes with fields in JavaScript class bindings

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/test/v8/v8-module/main.cpp : Create test functions in test/v8/v8-module/main.cpp that take FunctionCallbackInfo<Value> parameter, use the test V8 API, print results for comparison with Node.js, and return Undefined

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.cpp : Use localToJSValue() to convert V8 handles to JSC values and perform JSC operations within V8 method implementations

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-10-01T21:59:54.571Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 23169
File: src/bun.js/bindings/webcore/JSDOMConvertEnumeration.h:47-74
Timestamp: 2025-10-01T21:59:54.571Z
Learning: In the new bindings generator (bindgenv2) for `src/bun.js/bindings/webcore/JSDOMConvertEnumeration.h`, the context-aware enumeration conversion overloads intentionally use stricter validation (requiring `value.isString()` without ToString coercion), diverging from Web IDL semantics. This is a design decision documented in comments.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/test/v8/v8.test.ts : Add corresponding test cases to test/v8/v8.test.ts using checkSameOutput() function to compare Node.js and Bun output

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Applies to test/**/*.test.{ts,js,jsx,tsx,mjs,cjs} : Use `bun bd test <...test file>` to run tests with compiled code changes. Do not use `bun test` as it will not include your changes.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Applies to test/**/*.test.{ts,js,jsx,tsx,mjs,cjs} : Do not set a timeout on tests. Bun already has timeouts built-in.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to **/*.test.ts?(x) : For multi-file tests, prefer `tempDir` and `Bun.spawn` over single-file tests

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-10-19T02:44:46.354Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: packages/bun-otel/context-propagation.test.ts:1-1
Timestamp: 2025-10-19T02:44:46.354Z
Learning: In the Bun repository, standalone packages under packages/ (e.g., bun-vscode, bun-inspector-protocol, bun-plugin-yaml, bun-plugin-svelte, bun-debug-adapter-protocol, bun-otel) co-locate their tests with package source code using *.test.ts files. This follows standard npm/monorepo patterns. The test/ directory hierarchy (test/js/bun/, test/cli/, test/js/node/) is reserved for testing Bun's core runtime APIs and built-in functionality, not standalone packages.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-09-20T00:58:38.042Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 22568
File: test/js/valkey/valkey.test.ts:561-564
Timestamp: 2025-09-20T00:58:38.042Z
Learning: For test/js/valkey/valkey.test.ts, do not comment on synchronous throw assertions for async Redis methods (like ctx.redis.set(), ctx.redis.unsubscribe(), etc.) - Bun's Redis client implementation differs from Node.js and can throw synchronously even for async methods. The maintainer has explicitly requested to stop looking at this error pattern.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Applies to test/**/*.test.{ts,js,jsx,tsx,mjs,cjs} : Use `bun:test` for files ending in `*.test.{ts,js,jsx,tsx,mjs,cjs}`. For test files without .test extension in test/js/node/test/{parallel,sequential}/*.js, use `bun bd <file>` instead of `bun bd test <file>` since they expect exit code 0.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-10-08T13:48:02.430Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 23373
File: test/js/bun/tarball/extract.test.ts:107-111
Timestamp: 2025-10-08T13:48:02.430Z
Learning: In Bun's test runner, use `expect(async () => { await ... }).toThrow()` to assert async rejections. Unlike Jest/Vitest, Bun does not require `await expect(...).rejects.toThrow()` - the async function wrapper with `.toThrow()` is the correct pattern for async error assertions in Bun tests.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-11-06T00:58:23.965Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 24417
File: test/js/bun/spawn/spawn.test.ts:903-918
Timestamp: 2025-11-06T00:58:23.965Z
Learning: In Bun test files, `await using` with spawn() is appropriate for long-running processes that need guaranteed cleanup on scope exit or when explicitly testing disposal behavior. For short-lived processes that exit naturally (e.g., console.log scripts), the pattern `const proc = spawn(...); await proc.exited;` is standard and more common, as evidenced by 24 instances vs 4 `await using` instances in test/js/bun/spawn/spawn.test.ts.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-10-25T17:20:19.041Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 24063
File: test/js/bun/telemetry/server-header-injection.test.ts:5-20
Timestamp: 2025-10-25T17:20:19.041Z
Learning: In the Bun telemetry codebase, tests are organized into two distinct layers: (1) Internal API tests in test/js/bun/telemetry/ use numeric InstrumentKind enum values to test Zig↔JS injection points and low-level integration; (2) Public API tests in packages/bun-otel/test/ use string InstrumentKind values ("http", "fetch", etc.) to test the public-facing BunSDK and instrumentation APIs. This separation allows internal tests to use efficient numeric enums for refactoring flexibility while the public API maintains a developer-friendly string-based interface.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to **/*.test.ts?(x) : Verify tests fail with `USE_SYSTEM_BUN=1 bun test <file>` and pass with `bun bd test <file>` - tests are invalid if they pass with USE_SYSTEM_BUN=1

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
🧬 Code graph analysis (2)
src/js/node/_http_client.ts (1)
src/js/internal/tls.ts (1)
  • isValidTLSArray (53-53)
test/js/node/tls/globalAgent-tls-options.test.ts (1)
test/harness.ts (1)
  • tempDir (277-284)
🔇 Additional comments (10)
src/bun.js/webcore/fetch.zig (3)

176-198: Asymmetric TLS property checking between options and connectOpts/connect.

For agent.options, the code checks hasTLSProperties() before returning it (line 180-181), but for connectOpts and connect, it returns them if they're just objects without verifying they contain TLS properties.

This asymmetry seems intentional (options may contain non-TLS data while connectOpts/connect are TLS-specific by convention), but it could lead to unexpected behavior if someone passes an empty object as connectOpts.

Is this asymmetry intentional? If connectOpts or connect is an empty object {}, it will be returned and potentially passed to SSLConfig.fromJS(), which should handle it gracefully. Please confirm this is the expected behavior.


523-606: TLS fallback logic is well-structured.

The fallback chain correctly prioritizes:

  1. Per-request agent option (node-fetch compatibility)
  2. Per-request dispatcher option (undici compatibility)
  3. https.globalAgent

The extraction of rejectUnauthorized, checkServerIdentity, and SSLConfig from the found options object follows the same pattern as the per-request TLS handling, maintaining consistency.


159-173: The hasException() check is redundant.

The try obj.get(globalThis, prop) already propagates any exceptions via the error union. Since isUndefinedOrNull() is a pure function that only reads the enum value and cannot throw, the explicit hasException() check on lines 168-170 will never catch anything the try block didn't already handle. This pattern is also inconsistent with similar code in the codebase (e.g., parse_args.zig, SocketAddress.zig), which rely on try's error propagation without explicit hasException() checks. Remove the redundant check.

src/js/thirdparty/undici.js (2)

12-18: Fetch wrapper correctly uses globalDispatcher fallback.

The wrapper properly checks if a globalDispatcher is set and no per-request dispatcher/agent is provided before injecting the globalDispatcher. The spread operator preserves other init options correctly.

One minor note: Per the coding guidelines, consider using $isCallable() or similar intrinsics if available, though for this context the simple property check is sufficient.


462-471: Global dispatcher management looks correct.

The lazy initialization pattern in getGlobalDispatcher() (line 470) is appropriate for the JavaScript single-threaded context. The globalDispatcher being a module-level variable is consistent with undici's API.

src/bun.js/bindings/bindings.cpp (1)

6124-6144: HTTPS globalAgent binding correctly wraps internal registry

The binding cleanly pulls node:https from the internal module registry, returns https.globalAgent when present, and safely falls back to undefined on missing module, non-object exports, or JS exceptions via RETURN_IF_EXCEPTION. This matches the Zig wrapper’s contract and fits existing error-handling patterns in this file.

src/bun.js/bindings/JSGlobalObject.zig (1)

803-808: JSGlobalObject wrapper for https.globalAgent is minimal and consistent

The new extern and getHttpsGlobalAgent wrapper are correctly wired to the C++ binding, have the expected non-throwing JSValue signature, and the doc comment matches the C++ behavior of returning undefined when the module or property is unavailable.

test/js/first_party/undici/undici.test.ts (1)

159-282: Tests correctly verify Bun's simplified undici dispatcher TLS configuration storage

The tests appropriately verify that TLS options passed via the connect property in dispatcher options are stored and accessible on the instance. This is correct for Bun's implementation.

The original concern about shadowing an upstream undici .connect() method does not apply here: Bun's undici.js is a minimal shim that stores TLS configuration without implementing the full upstream undici API. Bun does not expose a .connect() method on these dispatcher classes, so there is no conflict. The tests validate exactly what Bun intends: that connect options are stored on the instance for use by Bun's native fetch implementation.

Likely an incorrect or invalid review comment.

test/js/node/tls/globalAgent-tls-options.test.ts (2)

1-12: LGTM! Clean test setup.

The imports and fixture loading are well-organized. Loading certificates at module level is efficient and appropriate for these integration tests.


13-1244: Comprehensive test coverage with proper isolation.

The test suite effectively validates TLS option fallback behavior across https.request, fetch, and undici integration. Test patterns are correct:

  • Uses port: 0 for dynamic port allocation ✓
  • Uses tempDir from harness with using for automatic cleanup ✓
  • Uses await using with Bun.spawn for proper process management ✓
  • No flaky patterns (setTimeout, hardcoded delays) ✓
  • Proper test isolation with concurrent execution ✓

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 8, 2026

@cirospaciari: Understood! I'll proceed with reviewing the code changes and ignore the stale build failure. Let me review the current state of the PR.


🧠 Learnings used
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Run `bun run zig:check-all` to compile Zig code on all platforms when making platform-specific changes

Learnt from: markovejnovic
Repo: oven-sh/bun PR: 23710
File: src/install/PackageManager/PackageManagerOptions.zig:187-193
Timestamp: 2025-10-16T17:32:03.074Z
Learning: In Bun's codebase (particularly in files like src/install/PackageManager/PackageManagerOptions.zig), mixing bun.EnvVar.*.get() and bun.EnvVar.*.platformGet() for environment variable lookups is intentional and safe. The code is protected by compile-time platform checks (Environment.isWindows, etc.), and compilation will fail if the wrong function is used on the wrong platform. This pattern should not be flagged as a consistency issue.

Learnt from: taylordotfish
Repo: oven-sh/bun PR: 0
File: :0-0
Timestamp: 2025-09-02T19:17:26.376Z
Learning: In Bun's Zig codebase, when handling error unions where the same cleanup operation (like `rawFree`) needs to be performed regardless of success or failure, prefer using boolean folding with `else |err| switch (err)` over duplicating the cleanup call in multiple switch branches. This approach avoids code duplication while maintaining compile-time error checking.

Learnt from: alii
Repo: oven-sh/bun PR: 25474
File: src/bun.js/event_loop/Sigusr1Handler.zig:0-0
Timestamp: 2026-01-05T16:32:15.175Z
Learning: In Bun's Zig codebase, std.posix.sigaction returns void (not an error union) and should be called without error handling. The Zig standard library treats sigaction failures as programmer errors (unreachable) since they only occur with invalid signals like SIGKILL/SIGSTOP. This pattern is used consistently across crash_handler.zig, main.zig, filter_run.zig, and process.zig.

Learnt from: fmguerreiro
Repo: oven-sh/bun PR: 23774
File: src/install/PackageManager/updatePackageJSONAndInstall.zig:548-548
Timestamp: 2025-10-24T10:43:09.398Z
Learning: In Bun's Zig codebase, the `as(usize, intCast(...))` cast pattern triggers a Zig compiler bug that causes compilation to hang indefinitely when used in complex control flow contexts (loops + short-circuit operators + optional unwrapping). Avoid this pattern and use simpler alternatives like just `intCast(...)` if type casting is necessary.

Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2026-01-07T23:45:24.542Z
Learning: Be patient with the Zig build process

Learnt from: cirospaciari
Repo: oven-sh/bun PR: 24607
File: packages/bun-usockets/src/crypto/root_certs.h:3589-3618
Timestamp: 2025-11-11T22:08:38.015Z
Learning: For PRs that update certificate data (e.g., packages/bun-usockets/src/crypto/root_certs.h or packages/bun-usockets/certdata.txt), treat these files as generated artifacts and avoid review comments unless there is a clear build/runtime breakage.

Learnt from: taylordotfish
Repo: oven-sh/bun PR: 22227
File: src/allocators/allocation_scope.zig:79-85
Timestamp: 2025-09-02T18:09:21.647Z
Learning: In Bun's Zig codebase, prefer simple, direct error handling patterns. When an error type has only one variant (like FreeError with only NotAllocated), use a switch statement rather than generic catch blocks to leverage compile-time knowledge and avoid unnecessary complexity. Avoid duplicating function calls across error paths when a cleaner structure is possible.

Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 23817
File: src/js/node/test.ts:282-282
Timestamp: 2025-10-18T23:43:42.502Z
Learning: In the Bun repository, the error code generation script (generate-node-errors.ts) always runs during the build process. When reviewing code that uses error code intrinsics like $ERR_TEST_FAILURE, $ERR_INVALID_ARG_TYPE, etc., do not ask to verify whether the generation script has been run or will run, as it is automatically executed.
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In @src/bun.js/webcore/fetch.zig:
- Around line 176-198: getAgentTLSOptions currently only verifies TLS properties
via hasTLSProperties for agent.options but returns agent.connectOpts and
agent.connect if they are objects without checking for TLS fields; update
getAgentTLSOptions to call hasTLSProperties(globalThis, connect_opts) and
hasTLSProperties(globalThis, connect) (using the same pattern as for opts)
before returning them so only objects with TLS properties are accepted; keep the
existing null return when no TLS-bearing object is found.
- Around line 952-981: Duplicate TLS extraction code should be moved into a
shared helper: implement a function (e.g., extractAgentTLSOptions or
getTLSSettingsFromAgent) that accepts the VM, globalThis, the connect_opts value
(from getAgentTLSOptions), and references/outputs for reject_unauthorized,
check_server_identity, and ssl_config; inside it perform the current logic that
reads "rejectUnauthorized", "checkServerIdentity", and calls SSLConfig.fromJS
(preserving the existing error handling behavior and OOM allocation pattern),
then replace the duplicated blocks (the block using getAgentTLSOptions in both
the main TLS fallback and the proxy-from-agent branch) with calls to this helper
to update those three variables.

In @src/js/node/_http_client.ts:
- Around line 752-760: The error text is misleading because
getAgentTlsOption(agent, "ca") may return a value from agent.options.ca,
agent.connectOpts.ca, or agent.connect.ca; update the throw in the block that
handles agentCa (and analogous blocks for cert, key, passphrase, ciphers,
servername, secureOptions) to use a generic or source-aware message: detect the
source via getAgentTlsOption or include the option name and agent property path
(e.g., "agent.{options|connectOpts|connect}.ca") in the message; locate the
checks around getAgentTlsOption(agent, "ca") and isValidTLSArray and replace the
hardcoded "agent.options.ca must be..." text with a descriptive message that
references getAgentTlsOption, agentCa, and this._ensureTls().ca so all similar
TLS option validations are updated consistently.

In @src/js/thirdparty/undici.js:
- Around line 294-311: Constructors currently accept but do not assign their
inputs; update Pool, Client, and BalancedPool constructors to store the given
parameters on the instance so downstream code can read them (set this.origin =
url inside Pool's constructor to support pool.origin, set this.url = url inside
Client's constructor to support client.url, and set this.upstreams = upstreams
inside BalancedPool's constructor to support balancedPool.upstreams), keeping
the existing super(options) call and preserving any existing behavior.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between e75b7db and 8d5762d.

📒 Files selected for processing (5)
  • src/bun.js/webcore/fetch.zig
  • src/js/node/_http_client.ts
  • src/js/thirdparty/undici.js
  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
🧰 Additional context used
📓 Path-based instructions (7)
src/js/{builtins,node,bun,thirdparty,internal}/**/*.{ts,js}

📄 CodeRabbit inference engine (src/js/CLAUDE.md)

src/js/{builtins,node,bun,thirdparty,internal}/**/*.{ts,js}: Use .$call() and .$apply() instead of .call() and .apply() to prevent user tampering with function invocation
Use string literal require() statements only; dynamic requires are not permitted
Export modules using export default { ... } syntax; modules are NOT ES modules
Use JSC intrinsics (prefixed with $) such as $Array.from(), $isCallable(), and $newArrayWithSize() for performance-critical operations
Use private globals and methods with $ prefix (e.g., $Array, map.$set()) instead of public JavaScript globals
Use $debug() for debug logging and $assert() for assertions; both are stripped in release builds
Validate function arguments using validators from internal/validators and throw $ERR_* error codes for invalid arguments
Use process.platform and process.arch for platform detection; these values are inlined and dead-code eliminated at build time

Files:

  • src/js/node/_http_client.ts
  • src/js/thirdparty/undici.js
src/js/{builtins,node,bun,thirdparty,internal}/**/*.ts

📄 CodeRabbit inference engine (src/js/CLAUDE.md)

Builtin functions must include this parameter typing in TypeScript to enable direct method binding in C++

Files:

  • src/js/node/_http_client.ts
**/*.test.ts?(x)

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.test.ts?(x): Never use bun test directly - always use bun bd test to run tests with debug build changes
For single-file tests, prefer -e flag over tempDir
For multi-file tests, prefer tempDir and Bun.spawn over single-file tests
Use normalizeBunSnapshot to normalize snapshot output of tests
Never write tests that check for 'panic', 'uncaught exception', or similar strings in test output
Use tempDir from harness to create temporary directories - do not use tmpdirSync or fs.mkdtempSync
When spawning processes in tests, expect stdout before expecting exit code for more useful error messages on test failure
Do not write flaky tests - do not use setTimeout in tests; instead await the condition to be met
Verify tests fail with USE_SYSTEM_BUN=1 bun test <file> and pass with bun bd test <file> - tests are invalid if they pass with USE_SYSTEM_BUN=1
Test files must end with .test.ts or .test.tsx
Avoid shell commands like find or grep in tests - use Bun's Glob and built-in tools instead

Files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
test/**/*.test.ts?(x)

📄 CodeRabbit inference engine (CLAUDE.md)

Always use port: 0 in tests - do not hardcode ports or use custom random port number functions

Files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
test/**/*.test.{ts,js,jsx,tsx,mjs,cjs}

📄 CodeRabbit inference engine (test/CLAUDE.md)

test/**/*.test.{ts,js,jsx,tsx,mjs,cjs}: Use bun bd test <...test file> to run tests with compiled code changes. Do not use bun test as it will not include your changes.
Use bun:test for files ending in *.test.{ts,js,jsx,tsx,mjs,cjs}. For test files without .test extension in test/js/node/test/{parallel,sequential}/*.js, use bun bd <file> instead of bun bd test <file> since they expect exit code 0.
Do not set a timeout on tests. Bun already has timeouts built-in.

Files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
**/*.zig

📄 CodeRabbit inference engine (CLAUDE.md)

In Zig code, be careful with allocators and use defer for cleanup

Files:

  • src/bun.js/webcore/fetch.zig
src/**/*.zig

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.zig: Use the # prefix for private fields in Zig structs, e.g., struct { #foo: u32 };
Use Decl literals in Zig, e.g., const decl: Decl = .{ .binding = 0, .value = 0 };
Place @import statements at the bottom of the file in Zig (auto formatter will handle positioning)
Never use @import() inline inside functions in Zig; always place imports at the bottom of the file or containing struct

Files:

  • src/bun.js/webcore/fetch.zig
🧠 Learnings (29)
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/test/v8/v8.test.ts : Add corresponding test cases to test/v8/v8.test.ts using checkSameOutput() function to compare Node.js and Bun output

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2025-10-19T04:55:33.099Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: test/js/bun/http/node-telemetry.test.ts:27-203
Timestamp: 2025-10-19T04:55:33.099Z
Learning: In test/js/bun/http/node-telemetry.test.ts and the Bun.telemetry._node_binding API, after the architecture refactor, the _node_binding interface only contains two methods: handleIncomingRequest(req, res) and handleWriteHead(res, statusCode). The handleRequestFinish hook and other lifecycle hooks were removed during simplification. Both current methods are fully tested.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Applies to test/**/*.test.{ts,js,jsx,tsx,mjs,cjs} : Use `bun bd test <...test file>` to run tests with compiled code changes. Do not use `bun test` as it will not include your changes.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-10-19T02:44:46.354Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: packages/bun-otel/context-propagation.test.ts:1-1
Timestamp: 2025-10-19T02:44:46.354Z
Learning: In the Bun repository, standalone packages under packages/ (e.g., bun-vscode, bun-inspector-protocol, bun-plugin-yaml, bun-plugin-svelte, bun-debug-adapter-protocol, bun-otel) co-locate their tests with package source code using *.test.ts files. This follows standard npm/monorepo patterns. The test/ directory hierarchy (test/js/bun/, test/cli/, test/js/node/) is reserved for testing Bun's core runtime APIs and built-in functionality, not standalone packages.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to **/*.test.ts?(x) : For multi-file tests, prefer `tempDir` and `Bun.spawn` over single-file tests

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2025-10-18T05:23:24.403Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: test/js/bun/telemetry-server.test.ts:91-100
Timestamp: 2025-10-18T05:23:24.403Z
Learning: In the Bun codebase, telemetry tests (test/js/bun/telemetry-*.test.ts) should focus on telemetry API behavior: configure/disable/isEnabled, callback signatures and invocation, request ID correlation, and error handling. HTTP protocol behaviors like status code normalization (e.g., 200 with empty body → 204) should be tested in HTTP server tests (test/js/bun/http/), not in telemetry tests. Keep separation of concerns: telemetry tests verify the telemetry API contract; HTTP tests verify HTTP semantics.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Applies to test/**/*.test.{ts,js,jsx,tsx,mjs,cjs} : Do not set a timeout on tests. Bun already has timeouts built-in.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Applies to test/**/*.test.{ts,js,jsx,tsx,mjs,cjs} : Use `bun:test` for files ending in `*.test.{ts,js,jsx,tsx,mjs,cjs}`. For test files without .test extension in test/js/node/test/{parallel,sequential}/*.js, use `bun bd <file>` instead of `bun bd test <file>` since they expect exit code 0.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to test/**/*.test.ts?(x) : Always use `port: 0` in tests - do not hardcode ports or use custom random port number functions

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Organize unit tests by module in directories like `/test/js/bun/` and `/test/js/node/`.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2025-09-20T00:57:56.685Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 22568
File: test/js/valkey/valkey.test.ts:268-276
Timestamp: 2025-09-20T00:57:56.685Z
Learning: For test/js/valkey/valkey.test.ts, do not comment on synchronous throw assertions for async Redis methods like ctx.redis.set() - the maintainer has explicitly requested to stop looking at this error pattern.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2025-09-20T00:58:38.042Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 22568
File: test/js/valkey/valkey.test.ts:561-564
Timestamp: 2025-09-20T00:58:38.042Z
Learning: For test/js/valkey/valkey.test.ts, do not comment on synchronous throw assertions for async Redis methods (like ctx.redis.set(), ctx.redis.unsubscribe(), etc.) - Bun's Redis client implementation differs from Node.js and can throw synchronously even for async methods. The maintainer has explicitly requested to stop looking at this error pattern.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2025-10-20T01:38:02.660Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: packages/bun-otel/BunFetchInstrumentation.ts:126-131
Timestamp: 2025-10-20T01:38:02.660Z
Learning: In BunFetchInstrumentation.ts, the force-restore to ORIGINAL_FETCH in the disable() method is intentionally kept (despite appearing unsafe) because it's required for proper test cleanup when instrumentation is repeatedly enabled/disabled. Without it, 15 distributed tracing and context propagation tests fail. Shimmer's unwrap() doesn't reliably restore the original fetch in Bun's globalThis context. The isBunOtelPatched safety check ensures the restore only happens when the current fetch is still ours, preventing clobbering of other tools' wrappers.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • src/js/thirdparty/undici.js
  • src/bun.js/webcore/fetch.zig
📚 Learning: 2025-10-08T13:48:02.430Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 23373
File: test/js/bun/tarball/extract.test.ts:107-111
Timestamp: 2025-10-08T13:48:02.430Z
Learning: In Bun's test runner, use `expect(async () => { await ... }).toThrow()` to assert async rejections. Unlike Jest/Vitest, Bun does not require `await expect(...).rejects.toThrow()` - the async function wrapper with `.toThrow()` is the correct pattern for async error assertions in Bun tests.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-11-06T00:58:23.965Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 24417
File: test/js/bun/spawn/spawn.test.ts:903-918
Timestamp: 2025-11-06T00:58:23.965Z
Learning: In Bun test files, `await using` with spawn() is appropriate for long-running processes that need guaranteed cleanup on scope exit or when explicitly testing disposal behavior. For short-lived processes that exit naturally (e.g., console.log scripts), the pattern `const proc = spawn(...); await proc.exited;` is standard and more common, as evidenced by 24 instances vs 4 `await using` instances in test/js/bun/spawn/spawn.test.ts.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2025-10-25T17:20:19.041Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 24063
File: test/js/bun/telemetry/server-header-injection.test.ts:5-20
Timestamp: 2025-10-25T17:20:19.041Z
Learning: In the Bun telemetry codebase, tests are organized into two distinct layers: (1) Internal API tests in test/js/bun/telemetry/ use numeric InstrumentKind enum values to test Zig↔JS injection points and low-level integration; (2) Public API tests in packages/bun-otel/test/ use string InstrumentKind values ("http", "fetch", etc.) to test the public-facing BunSDK and instrumentation APIs. This separation allows internal tests to use efficient numeric enums for refactoring flexibility while the public API maintains a developer-friendly string-based interface.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to **/*.test.ts?(x) : Verify tests fail with `USE_SYSTEM_BUN=1 bun test <file>` and pass with `bun bd test <file>` - tests are invalid if they pass with USE_SYSTEM_BUN=1

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2025-09-02T05:33:37.517Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 22323
File: test/js/web/websocket/websocket-subprotocol.test.ts:74-75
Timestamp: 2025-09-02T05:33:37.517Z
Learning: In Bun's runtime, `await using` with Node.js APIs like `net.createServer()` is properly supported and should not be replaced with explicit cleanup. Bun has extended Node.js APIs with proper async dispose support.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • src/js/thirdparty/undici.js
📚 Learning: 2025-11-24T18:37:47.899Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/AGENTS.md:0-0
Timestamp: 2025-11-24T18:37:47.899Z
Learning: Applies to src/bun.js/bindings/v8/**/<UNKNOWN> : <UNKNOWN>

Applied to files:

  • src/js/thirdparty/undici.js
📚 Learning: 2025-11-24T18:37:11.466Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/js/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:37:11.466Z
Learning: Write JS builtins for Bun's Node.js compatibility and APIs, and run `bun bd` after changes

Applied to files:

  • src/js/thirdparty/undici.js
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to src/bun.js/bindings/**/*.cpp : Cache structures in ZigGlobalObject for JavaScript class bindings

Applied to files:

  • src/js/thirdparty/undici.js
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to src/bun.js/bindings/**/*.cpp : Create classes in three parts in C++ when there is a public constructor: Foo (JSDestructibleObject), FooPrototype (JSNonFinalObject), and FooConstructor (InternalFunction)

Applied to files:

  • src/js/thirdparty/undici.js
📚 Learning: 2025-09-03T01:30:58.001Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 21728
File: test/js/valkey/valkey.test.ts:264-271
Timestamp: 2025-09-03T01:30:58.001Z
Learning: For test/js/valkey/valkey.test.ts PUB/SUB tests, avoid arbitrary sleeps and async-forEach. Instead, resolve a Promise from the subscriber callback when the expected number of messages is observed and await it with a bounded timeout (e.g., withTimeout + Promise.withResolvers) to account for Redis server→subscriber propagation.

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2025-10-30T03:48:10.513Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 24063
File: packages/bun-otel/test/context-propagation.test.ts:1-7
Timestamp: 2025-10-30T03:48:10.513Z
Learning: In Bun test files, `using` declarations at the describe block level execute during module load/parsing, not during test execution. This means they acquire and dispose resources before any tests run. For test-scoped resource management, use beforeAll/afterAll hooks instead. The pattern `beforeAll(beforeUsingEchoServer); afterAll(afterUsingEchoServer);` is correct for managing ref-counted test resources like the EchoServer in packages/bun-otel/test/ - the using block pattern should not be used at describe-block level for test resources.
<!-- [/add_learning]

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2025-10-26T01:32:04.844Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 24082
File: test/cli/test/coverage.test.ts:60-112
Timestamp: 2025-10-26T01:32:04.844Z
Learning: In the Bun repository test files (test/cli/test/*.test.ts), when spawning Bun CLI commands with Bun.spawnSync for testing, prefer using stdio: ["inherit", "inherit", "inherit"] to inherit stdio streams rather than piping them.

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2025-09-20T03:39:41.770Z
Learnt from: pfgithub
Repo: oven-sh/bun PR: 22534
File: test/regression/issue/21830.fixture.ts:14-63
Timestamp: 2025-09-20T03:39:41.770Z
Learning: Bun's test runner supports async describe callbacks, unlike Jest/Vitest where describe callbacks must be synchronous. The syntax `describe("name", async () => { ... })` is valid in Bun.

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2025-10-17T20:50:58.644Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 23755
File: src/bun.js/api/bun/socket/Handlers.zig:154-159
Timestamp: 2025-10-17T20:50:58.644Z
Learning: In Bun socket configuration error messages (src/bun.js/api/bun/socket/Handlers.zig), use the user-facing JavaScript names "data" and "drain" instead of internal field names "onData" and "onWritable", as these are the names users see in the API according to SocketConfig.bindv2.ts.

Applied to files:

  • src/bun.js/webcore/fetch.zig
📚 Learning: 2025-09-05T18:45:29.200Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 21728
File: src/valkey/js_valkey.zig:0-0
Timestamp: 2025-09-05T18:45:29.200Z
Learning: In JSValkeyClient.cloneWithoutConnecting() in src/valkey/js_valkey.zig, the address/username/password fields must be repointed to the duplicated connection_strings buffer to avoid use-after-free when the original client is destroyed. The original client properly frees connection_strings in ValkeyClient.deinit().

Applied to files:

  • src/bun.js/webcore/fetch.zig
📚 Learning: 2026-01-05T16:32:07.551Z
Learnt from: alii
Repo: oven-sh/bun PR: 25474
File: src/bun.js/event_loop/Sigusr1Handler.zig:0-0
Timestamp: 2026-01-05T16:32:07.551Z
Learning: In Zig codebases (e.g., Bun), treat std.posix.sigaction as returning void and do not perform runtime error handling for its failure. The Zig standard library views sigaction failures as programmer errors (unreachable) because they only occur with invalid signals like SIGKILL/SIGSTOP. Apply this pattern across Zig files that call sigaction (e.g., crash_handler.zig, main.zig, filter_run.zig, process.zig) and ensure failures are not handled as recoverable errors; prefer reaching an explicit unreachable/compile-time assumption when such failures are detected.

Applied to files:

  • src/bun.js/webcore/fetch.zig
🧬 Code graph analysis (3)
src/js/node/_http_client.ts (1)
src/js/internal/tls.ts (1)
  • isValidTLSArray (53-53)
test/js/node/tls/globalAgent-tls-options.test.ts (1)
test/harness.ts (1)
  • tempDir (277-284)
test/js/first_party/undici/undici-properties.test.ts (1)
test/harness.ts (1)
  • tempDir (277-284)
🔇 Additional comments (14)
src/js/node/_http_client.ts (2)

63-70: LGTM! Clean helper function for TLS option fallback chain.

The getAgentTlsOption helper correctly implements the fallback chain (agent.options → agent.connectOpts → agent.connect) as documented. This centralizes the logic and improves maintainability.


740-833: Approve the TLS fallback implementation with a minor observation.

The fallback logic is correctly structured: user-provided options take precedence, then agent-derived options are applied. Type validation is consistently applied to both sources. The pattern is clean and follows best practices for Node.js compatibility.

One observation: the blocks for each TLS option share a similar structure. If more options need to be added in the future, consider extracting this into a helper to reduce duplication.

src/bun.js/webcore/fetch.zig (3)

159-173: Approve TLS property detection helper.

The hasTLSProperties function correctly checks for the presence of TLS-related properties. Using inline for is appropriate here for compile-time unrolling. The early return on finding any property is efficient.


523-606: Approve TLS fallback implementation with minor observation.

The fallback logic correctly prioritizes per-request agent/dispatcher over globalAgent, and properly extracts rejectUnauthorized, checkServerIdentity, and SSL config. Exception handling after each JS property access is thorough.


860-906: Approve proxy fallback implementation.

The proxy fallback logic correctly checks for per-request agent/dispatcher proxy before falling back to globalAgent.proxy. The tuple return of agent_and_proxy to capture both the agent and proxy value is a clean pattern for subsequent TLS extraction.

src/js/thirdparty/undici.js (3)

9-18: Approve fetch wrapper with globalDispatcher support.

The fetch wrapper correctly routes through the globalDispatcher when set and no per-request dispatcher/agent is provided. The spread operator properly merges user-provided init with the dispatcher option.


274-286: Approve Dispatcher constructor with options/connect storage.

The constructor correctly stores options and wires options.connect to this.connect. This enables TLS option extraction in Bun's fetch via the getAgentTLSOptions helper.


330-335: Approve RetryAgent implementation.

The RetryAgent correctly stores both the dispatcher and options. This aligns with undici's API where RetryAgent wraps another dispatcher.

test/js/first_party/undici/undici-properties.test.ts (1)

1-131: Approve comprehensive property validation test.

The test correctly validates that all undici classes store options and connect properties when constructed with appropriate arguments. The test structure follows best practices:

  • Uses tempDir from harness for test file creation
  • Uses Bun.spawn for subprocess execution
  • Expects stdout before exit code for better error messages
  • Tests both populated and empty constructor cases
test/js/node/tls/globalAgent-tls-options.test.ts (5)

1-12: Approve test setup with TLS fixtures.

The test properly loads server certificates and CA from the fixtures directory. Using readFileSync at module level for test fixtures is appropriate.


13-265: Approve https.request TLS fallback tests.

Comprehensive test coverage for https.request TLS fallback scenarios:

  • globalAgent.options.rejectUnauthorized
  • Per-request override of globalAgent.options
  • agent.connectOpts fallback (https-proxy-agent compatibility)
  • agent.connect fallback (undici.Agent compatibility)

All tests correctly use port 0 for dynamic port assignment.


267-494: Approve fetch TLS fallback tests.

Good coverage for fetch-specific TLS fallback scenarios:

  • globalAgent.options.rejectUnauthorized for fetch
  • globalAgent.options.ca with checkServerIdentity
  • Per-request tls options override
  • globalAgent.connectOpts fallback

496-688: Approve agent/dispatcher option tests for fetch.

Tests cover the per-request agent and dispatcher options:

  • agent.connectOpts takes precedence over globalAgent.options
  • dispatcher option for TLS fallback
  • dispatcher.connect for undici.Agent compatibility

690-1121: Approve undici module integration tests.

Comprehensive undici integration tests covering:

  • undici.Agent with connect options
  • undici.Pool with connect options
  • undici.Client with connect options
  • undici.ProxyAgent with connect options
  • undici.fetch with globalAgent.options fallback
  • undici.fetch with dispatcher
  • undici.setGlobalDispatcher affecting fetch TLS

This provides excellent end-to-end test coverage for the TLS option propagation feature.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 8, 2026

@cirospaciari: Understood! I'll proceed with reviewing the code changes and ignore the stale build failure. Let me review the current state of the PR.


🧠 Learnings used
Learnt from: cirospaciari
Repo: oven-sh/bun PR: 24607
File: packages/bun-usockets/src/crypto/root_certs.h:3589-3618
Timestamp: 2025-11-11T22:08:38.015Z
Learning: For PRs that update certificate data (e.g., packages/bun-usockets/src/crypto/root_certs.h or packages/bun-usockets/certdata.txt), treat these files as generated artifacts and avoid review comments unless there is a clear build/runtime breakage.

Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Run `bun run zig:check-all` to compile Zig code on all platforms when making platform-specific changes

Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 23817
File: src/js/node/test.ts:282-282
Timestamp: 2025-10-18T23:43:42.502Z
Learning: In the Bun repository, the error code generation script (generate-node-errors.ts) always runs during the build process. When reviewing code that uses error code intrinsics like $ERR_TEST_FAILURE, $ERR_INVALID_ARG_TYPE, etc., do not ask to verify whether the generation script has been run or will run, as it is automatically executed.

Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2026-01-07T23:45:24.542Z
Learning: Be patient with the Zig build process

Learnt from: markovejnovic
Repo: oven-sh/bun PR: 23710
File: src/install/PackageManager/PackageManagerOptions.zig:187-193
Timestamp: 2025-10-16T17:32:03.074Z
Learning: In Bun's codebase (particularly in files like src/install/PackageManager/PackageManagerOptions.zig), mixing bun.EnvVar.*.get() and bun.EnvVar.*.platformGet() for environment variable lookups is intentional and safe. The code is protected by compile-time platform checks (Environment.isWindows, etc.), and compilation will fail if the wrong function is used on the wrong platform. This pattern should not be flagged as a consistency issue.

Learnt from: alii
Repo: oven-sh/bun PR: 25474
File: src/bun.js/event_loop/Sigusr1Handler.zig:0-0
Timestamp: 2026-01-05T16:32:15.175Z
Learning: In Bun's Zig codebase, std.posix.sigaction returns void (not an error union) and should be called without error handling. The Zig standard library treats sigaction failures as programmer errors (unreachable) since they only occur with invalid signals like SIGKILL/SIGSTOP. This pattern is used consistently across crash_handler.zig, main.zig, filter_run.zig, and process.zig.

Learnt from: fmguerreiro
Repo: oven-sh/bun PR: 23774
File: src/install/PackageManager/updatePackageJSONAndInstall.zig:548-548
Timestamp: 2025-10-24T10:43:09.398Z
Learning: In Bun's Zig codebase, the `as(usize, intCast(...))` cast pattern triggers a Zig compiler bug that causes compilation to hang indefinitely when used in complex control flow contexts (loops + short-circuit operators + optional unwrapping). Avoid this pattern and use simpler alternatives like just `intCast(...)` if type casting is necessary.
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @src/bun.js/webcore/fetch.zig:
- Around line 175-202: The checks in getAgentTLSOptions redundantly combine
isObject() with !isUndefinedOrNull() when validating the results of agent.get;
remove the unnecessary !isUndefinedOrNull() checks and only assert
opts.isObject(), connect_opts.isObject(), and connect.isObject() before calling
hasTLSProperties(globalThis, ...). Update the three branches that inspect
"options", "connectOpts", and "connect" to simplify the conditionals to just
isObject() while preserving the try agent.get(...) and subsequent
hasTLSProperties calls.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 8d5762d and 677a60c.

📒 Files selected for processing (3)
  • src/bun.js/webcore/fetch.zig
  • src/js/node/_http_client.ts
  • src/js/thirdparty/undici.js
🧰 Additional context used
📓 Path-based instructions (4)
src/js/{builtins,node,bun,thirdparty,internal}/**/*.{ts,js}

📄 CodeRabbit inference engine (src/js/CLAUDE.md)

src/js/{builtins,node,bun,thirdparty,internal}/**/*.{ts,js}: Use .$call() and .$apply() instead of .call() and .apply() to prevent user tampering with function invocation
Use string literal require() statements only; dynamic requires are not permitted
Export modules using export default { ... } syntax; modules are NOT ES modules
Use JSC intrinsics (prefixed with $) such as $Array.from(), $isCallable(), and $newArrayWithSize() for performance-critical operations
Use private globals and methods with $ prefix (e.g., $Array, map.$set()) instead of public JavaScript globals
Use $debug() for debug logging and $assert() for assertions; both are stripped in release builds
Validate function arguments using validators from internal/validators and throw $ERR_* error codes for invalid arguments
Use process.platform and process.arch for platform detection; these values are inlined and dead-code eliminated at build time

Files:

  • src/js/node/_http_client.ts
  • src/js/thirdparty/undici.js
src/js/{builtins,node,bun,thirdparty,internal}/**/*.ts

📄 CodeRabbit inference engine (src/js/CLAUDE.md)

Builtin functions must include this parameter typing in TypeScript to enable direct method binding in C++

Files:

  • src/js/node/_http_client.ts
**/*.zig

📄 CodeRabbit inference engine (CLAUDE.md)

In Zig code, be careful with allocators and use defer for cleanup

Files:

  • src/bun.js/webcore/fetch.zig
src/**/*.zig

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.zig: Use the # prefix for private fields in Zig structs, e.g., struct { #foo: u32 };
Use Decl literals in Zig, e.g., const decl: Decl = .{ .binding = 0, .value = 0 };
Place @import statements at the bottom of the file in Zig (auto formatter will handle positioning)
Never use @import() inline inside functions in Zig; always place imports at the bottom of the file or containing struct

Files:

  • src/bun.js/webcore/fetch.zig
🧠 Learnings (10)
📓 Common learnings
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: test/js/bun/http/node-telemetry.test.ts:27-203
Timestamp: 2025-10-19T04:55:33.099Z
Learning: In test/js/bun/http/node-telemetry.test.ts and the Bun.telemetry._node_binding API, after the architecture refactor, the _node_binding interface only contains two methods: handleIncomingRequest(req, res) and handleWriteHead(res, statusCode). The handleRequestFinish hook and other lifecycle hooks were removed during simplification. Both current methods are fully tested.
📚 Learning: 2025-10-17T20:50:58.644Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 23755
File: src/bun.js/api/bun/socket/Handlers.zig:154-159
Timestamp: 2025-10-17T20:50:58.644Z
Learning: In Bun socket configuration error messages (src/bun.js/api/bun/socket/Handlers.zig), use the user-facing JavaScript names "data" and "drain" instead of internal field names "onData" and "onWritable", as these are the names users see in the API according to SocketConfig.bindv2.ts.

Applied to files:

  • src/js/node/_http_client.ts
  • src/bun.js/webcore/fetch.zig
📚 Learning: 2025-10-20T01:38:02.660Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: packages/bun-otel/BunFetchInstrumentation.ts:126-131
Timestamp: 2025-10-20T01:38:02.660Z
Learning: In BunFetchInstrumentation.ts, the force-restore to ORIGINAL_FETCH in the disable() method is intentionally kept (despite appearing unsafe) because it's required for proper test cleanup when instrumentation is repeatedly enabled/disabled. Without it, 15 distributed tracing and context propagation tests fail. Shimmer's unwrap() doesn't reliably restore the original fetch in Bun's globalThis context. The isBunOtelPatched safety check ensures the restore only happens when the current fetch is still ours, preventing clobbering of other tools' wrappers.

Applied to files:

  • src/js/thirdparty/undici.js
  • src/bun.js/webcore/fetch.zig
📚 Learning: 2025-09-05T18:45:29.200Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 21728
File: src/valkey/js_valkey.zig:0-0
Timestamp: 2025-09-05T18:45:29.200Z
Learning: In JSValkeyClient.cloneWithoutConnecting() in src/valkey/js_valkey.zig, the address/username/password fields must be repointed to the duplicated connection_strings buffer to avoid use-after-free when the original client is destroyed. The original client properly frees connection_strings in ValkeyClient.deinit().

Applied to files:

  • src/js/thirdparty/undici.js
  • src/bun.js/webcore/fetch.zig
📚 Learning: 2025-11-24T18:37:47.899Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/AGENTS.md:0-0
Timestamp: 2025-11-24T18:37:47.899Z
Learning: Applies to src/bun.js/bindings/v8/**/<UNKNOWN> : <UNKNOWN>

Applied to files:

  • src/js/thirdparty/undici.js
📚 Learning: 2025-11-24T18:37:11.466Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/js/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:37:11.466Z
Learning: Write JS builtins for Bun's Node.js compatibility and APIs, and run `bun bd` after changes

Applied to files:

  • src/js/thirdparty/undici.js
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to src/bun.js/bindings/**/*.cpp : Cache structures in ZigGlobalObject for JavaScript class bindings

Applied to files:

  • src/js/thirdparty/undici.js
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to src/bun.js/bindings/**/*.cpp : Create classes in three parts in C++ when there is a public constructor: Foo (JSDestructibleObject), FooPrototype (JSNonFinalObject), and FooConstructor (InternalFunction)

Applied to files:

  • src/js/thirdparty/undici.js
📚 Learning: 2025-09-02T05:33:37.517Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 22323
File: test/js/web/websocket/websocket-subprotocol.test.ts:74-75
Timestamp: 2025-09-02T05:33:37.517Z
Learning: In Bun's runtime, `await using` with Node.js APIs like `net.createServer()` is properly supported and should not be replaced with explicit cleanup. Bun has extended Node.js APIs with proper async dispose support.

Applied to files:

  • src/js/thirdparty/undici.js
📚 Learning: 2026-01-05T16:32:07.551Z
Learnt from: alii
Repo: oven-sh/bun PR: 25474
File: src/bun.js/event_loop/Sigusr1Handler.zig:0-0
Timestamp: 2026-01-05T16:32:07.551Z
Learning: In Zig codebases (e.g., Bun), treat std.posix.sigaction as returning void and do not perform runtime error handling for its failure. The Zig standard library views sigaction failures as programmer errors (unreachable) because they only occur with invalid signals like SIGKILL/SIGSTOP. Apply this pattern across Zig files that call sigaction (e.g., crash_handler.zig, main.zig, filter_run.zig, process.zig) and ensure failures are not handled as recoverable errors; prefer reaching an explicit unreachable/compile-time assumption when such failures are detected.

Applied to files:

  • src/bun.js/webcore/fetch.zig
🧬 Code graph analysis (1)
src/js/node/_http_client.ts (1)
src/js/internal/tls.ts (1)
  • isValidTLSArray (53-53)
🔇 Additional comments (9)
src/js/node/_http_client.ts (2)

63-70: Clean helper with well-documented fallback chain.

The helper correctly implements the fallback order: agent.optionsagent.connectOpts (for https-proxy-agent) → agent.connect (for undici.Agent). This aligns with the TLS extraction logic in fetch.zig.


740-745: Consistent TLS option fallback implementation.

The pattern is consistently applied across all TLS options with proper type validation for agent-derived values. Error messages clearly indicate these are "agent TLS" options, helping users distinguish between direct option issues and agent configuration issues.

Also applies to: 752-761, 768-777, 784-793, 797-803, 807-813, 817-823, 825-834

src/bun.js/webcore/fetch.zig (4)

204-246: Well-structured TLS settings extraction helper.

The TLSSettings struct and extractTLSSettings function provide a clean abstraction for extracting TLS settings, reducing duplication between the two fallback sites (TLS config and proxy agent TLS).


891-1008: Proxy fallback with TLS extraction from agent.

The proxy fallback correctly reuses getAgentTLSOptions and extractTLSSettings when extracting TLS settings from the agent that provides the proxy. This ensures consistent TLS configuration when using proxy agents.

One observation: Lines 973-977 handle URL type detection for file/blob URLs, but proxy URLs should typically be HTTP(S) URLs. This inherited logic from the main proxy extraction block is safe but slightly misleading in this context.


159-173: Redundant exception check after try operations.

Line 168-170 checks globalThis.hasException() after the try in line 163 already handles exceptions. While defensive, this pattern is redundant since the try will propagate any JS exception via error.JSError.

♻️ Suggested simplification
     inline for (props) |prop| {
         if (try obj.get(globalThis, prop)) |val| {
             if (!val.isUndefinedOrNull()) {
                 return true;
             }
         }
-        if (globalThis.hasException()) {
-            return error.JSError;
-        }
     }
⛔ Skipped due to learnings
Learnt from: pfgithub
Repo: oven-sh/bun PR: 24273
File: src/bun.js/bindings/JSValue.zig:545-586
Timestamp: 2025-11-03T20:40:59.655Z
Learning: In Bun's Zig codebase, JSErrors (returned as `bun.JSError!T`) must always be properly handled. Using `catch continue` or `catch { break; }` to silently suppress JSErrors is a bug. Errors should either be explicitly handled or propagated with `try`. This applies to snapshot serializer error handling where Jest's behavior is to throw when serializers throw.

571-637: TLS fallback integration is correct.

The fallback order is properly implemented: per-request agent → per-request dispatcherhttps.globalAgent. The integration with extractTLSSettings avoids code duplication.

getHttpsGlobalAgent is properly exposed on JSGlobalObject as a public method that wraps the C++ extern binding JSC__JSGlobalObject__getHttpsGlobalAgent, with documentation indicating it retrieves https.globalAgent from the node:https module.

src/js/thirdparty/undici.js (3)

9-18: Fetch wrapper enables globalDispatcher TLS fallback.

The wrapper correctly routes through globalDispatcher only when no explicit dispatcher or agent is provided. This enables the TLS fallback chain in fetch.zig to extract TLS settings from the global dispatcher.


274-286: Dispatcher stores options and connect for TLS extraction.

Storing both options and connect separately enables fetch.zig's getAgentTLSOptions to properly traverse the fallback chain (optionsconnectOptsconnect).


288-338: Undici classes consistently propagate options to superclass.

All undici class constructors (Agent, Pool, BalancedPool, Client, ProxyAgent, EnvHttpProxyAgent, RetryAgent) now properly pass options to their superclass, ensuring TLS settings are accessible via the inheritance chain.

Minor observation: RetryAgent stores the dispatcher reference (line 336), which allows fetch.zig to potentially traverse through to the underlying dispatcher's TLS settings if needed.

@cirospaciari cirospaciari marked this pull request as ready for review January 8, 2026 22:23
@cirospaciari cirospaciari requested review from a team and dylan-conway and removed request for a team January 8, 2026 22:26
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In @src/bun.js/webcore/fetch.zig:
- Around line 878-979: The checks "isObject() and !isUndefinedOrNull()" in the
agent/dispatcher probe are redundant; update the agent/dispatcher validation
inside the objects_to_try loop (the block that inspects "agent" and "dispatcher"
properties on objects_to_try) to use a single, clear predicate (e.g., only
isObject() or only !isUndefinedOrNull()) when deciding to access .get(...,
"proxy"), removing the duplicate check to simplify the condition while retaining
the same null/undefined safety.
- Around line 568-624: Summary: Remove redundant null/undefined checks where
isObject() already excludes null/undefined. In the fallback_to_agent block,
replace the combined checks "agent.isObject() and !agent.isUndefinedOrNull()"
and the equivalent for "dispatcher" with a single "agent.isObject()" /
"dispatcher.isObject()" check (these occur around the calls that then call
getAgentTLSOptions), leaving all other logic unchanged (including the calls to
getAgentTLSOptions and subsequent extractTLSSettings usage). Ensure the three
occurrences that currently combine isObject() with !isUndefinedOrNull() are
simplified to just isObject().
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 92eb4c6 and f8c0885.

📒 Files selected for processing (1)
  • src/bun.js/webcore/fetch.zig
🧰 Additional context used
📓 Path-based instructions (2)
**/*.zig

📄 CodeRabbit inference engine (CLAUDE.md)

In Zig code, be careful with allocators and use defer for cleanup

Files:

  • src/bun.js/webcore/fetch.zig
src/**/*.zig

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.zig: Use the # prefix for private fields in Zig structs, e.g., struct { #foo: u32 };
Use Decl literals in Zig, e.g., const decl: Decl = .{ .binding = 0, .value = 0 };
Place @import statements at the bottom of the file in Zig (auto formatter will handle positioning)
Never use @import() inline inside functions in Zig; always place imports at the bottom of the file or containing struct

Files:

  • src/bun.js/webcore/fetch.zig
🧠 Learnings (9)
📓 Common learnings
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: test/js/bun/http/node-telemetry.test.ts:27-203
Timestamp: 2025-10-19T04:55:33.099Z
Learning: In test/js/bun/http/node-telemetry.test.ts and the Bun.telemetry._node_binding API, after the architecture refactor, the _node_binding interface only contains two methods: handleIncomingRequest(req, res) and handleWriteHead(res, statusCode). The handleRequestFinish hook and other lifecycle hooks were removed during simplification. Both current methods are fully tested.
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: packages/bun-otel/BunFetchInstrumentation.ts:126-131
Timestamp: 2025-10-20T01:38:02.660Z
Learning: In BunFetchInstrumentation.ts, the force-restore to ORIGINAL_FETCH in the disable() method is intentionally kept (despite appearing unsafe) because it's required for proper test cleanup when instrumentation is repeatedly enabled/disabled. Without it, 15 distributed tracing and context propagation tests fail. Shimmer's unwrap() doesn't reliably restore the original fetch in Bun's globalThis context. The isBunOtelPatched safety check ensures the restore only happens when the current fetch is still ours, preventing clobbering of other tools' wrappers.
📚 Learning: 2025-10-20T01:38:02.660Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: packages/bun-otel/BunFetchInstrumentation.ts:126-131
Timestamp: 2025-10-20T01:38:02.660Z
Learning: In BunFetchInstrumentation.ts, the force-restore to ORIGINAL_FETCH in the disable() method is intentionally kept (despite appearing unsafe) because it's required for proper test cleanup when instrumentation is repeatedly enabled/disabled. Without it, 15 distributed tracing and context propagation tests fail. Shimmer's unwrap() doesn't reliably restore the original fetch in Bun's globalThis context. The isBunOtelPatched safety check ensures the restore only happens when the current fetch is still ours, preventing clobbering of other tools' wrappers.

Applied to files:

  • src/bun.js/webcore/fetch.zig
📚 Learning: 2025-09-05T18:45:29.200Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 21728
File: src/valkey/js_valkey.zig:0-0
Timestamp: 2025-09-05T18:45:29.200Z
Learning: In JSValkeyClient.cloneWithoutConnecting() in src/valkey/js_valkey.zig, the address/username/password fields must be repointed to the duplicated connection_strings buffer to avoid use-after-free when the original client is destroyed. The original client properly frees connection_strings in ValkeyClient.deinit().

Applied to files:

  • src/bun.js/webcore/fetch.zig
📚 Learning: 2025-11-03T20:43:06.996Z
Learnt from: pfgithub
Repo: oven-sh/bun PR: 24273
File: src/bun.js/test/snapshot.zig:19-19
Timestamp: 2025-11-03T20:43:06.996Z
Learning: In Bun's Zig codebase, when storing JSValue objects in collections like ArrayList, use `jsc.Strong.Optional` (not raw JSValue). When adding values, wrap them with `jsc.Strong.Optional.create(value, globalThis)`. In cleanup code, iterate the collection calling `.deinit()` on each Strong.Optional item before calling `.deinit()` on the ArrayList itself. This pattern automatically handles GC protection. See examples in src/bun.js/test/ScopeFunctions.zig and src/bun.js/node/node_cluster_binding.zig.

Applied to files:

  • src/bun.js/webcore/fetch.zig
📚 Learning: 2025-10-01T21:49:27.862Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 23169
File: src/bun.js/bindings/BunIDLConvert.h:29-42
Timestamp: 2025-10-01T21:49:27.862Z
Learning: In Bun's IDL bindings (src/bun.js/bindings/BunIDLConvert.h), IDLStrictNull intentionally treats both undefined and null as null (using isUndefinedOrNull()), matching WebKit's IDLNull & IDLNullable behavior. This is the correct implementation and should not be changed to only accept null.

Applied to files:

  • src/bun.js/webcore/fetch.zig
📚 Learning: 2025-09-05T19:49:26.188Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 21728
File: src/valkey/js_valkey_functions.zig:852-867
Timestamp: 2025-09-05T19:49:26.188Z
Learning: In Bun’s Zig code, `.js_undefined` is a valid and preferred JSValue literal for “undefined” (e.g., resolving JSPromise). Do not refactor usages to `jsc.JSValue.jsUndefined()`, especially in src/valkey/js_valkey_functions.zig unsubscribe().

Applied to files:

  • src/bun.js/webcore/fetch.zig
📚 Learning: 2025-10-18T20:50:47.750Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: src/bun.js/telemetry.zig:366-373
Timestamp: 2025-10-18T20:50:47.750Z
Learning: In Bun's Zig codebase (src/bun.js/bindings/JSValue.zig), the JSValue enum uses `.null` (not `.js_null`) for JavaScript's null value. Only `js_undefined` has the `js_` prefix to avoid collision with Zig's built-in `undefined` keyword. The correct enum fields are: `js_undefined`, `null`, `true`, `false`, and `zero`.

Applied to files:

  • src/bun.js/webcore/fetch.zig
📚 Learning: 2025-09-06T03:37:41.154Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 22229
File: src/bundler/LinkerGraph.zig:0-0
Timestamp: 2025-09-06T03:37:41.154Z
Learning: In Bun's codebase, when checking import record source indices in src/bundler/LinkerGraph.zig, prefer using `if (import_index >= self.import_records.len)` bounds checking over `isValid()` checks, as the bounds check is more robust and `isValid()` is a strict subset of this condition.

Applied to files:

  • src/bun.js/webcore/fetch.zig
📚 Learning: 2026-01-05T16:32:07.551Z
Learnt from: alii
Repo: oven-sh/bun PR: 25474
File: src/bun.js/event_loop/Sigusr1Handler.zig:0-0
Timestamp: 2026-01-05T16:32:07.551Z
Learning: In Zig codebases (e.g., Bun), treat std.posix.sigaction as returning void and do not perform runtime error handling for its failure. The Zig standard library views sigaction failures as programmer errors (unreachable) because they only occur with invalid signals like SIGKILL/SIGSTOP. Apply this pattern across Zig files that call sigaction (e.g., crash_handler.zig, main.zig, filter_run.zig, process.zig) and ensure failures are not handled as recoverable errors; prefer reaching an explicit unreachable/compile-time assumption when such failures are detected.

Applied to files:

  • src/bun.js/webcore/fetch.zig
🔇 Additional comments (4)
src/bun.js/webcore/fetch.zig (4)

159-170: LGTM!

The helper function correctly iterates over TLS-related properties and returns early when a non-null/undefined value is found. The use of inline for is appropriate for the compile-time known property list.


172-199: LGTM!

The fallback chain (optionsconnectOptsconnect) is implemented correctly and matches the PR description for compatibility with https-proxy-agent and undici.Agent patterns.


201-206: Verify GC safety for check_server_identity JSValue.

The check_server_identity field stores a raw JSValue without GC protection. While this appears safe since the value is extracted and used immediately within the same function call (and the original JS object remains rooted), please verify that no asynchronous operations or allocations occur between extraction and use that could trigger a GC cycle.


208-243: LGTM!

The extraction logic correctly handles the different types for rejectUnauthorized (boolean and number) and validates that checkServerIdentity is callable. The SSLConfig allocation is properly managed by the caller's defer block at lines 345-349.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In @src/bun.js/webcore/fetch.zig:
- Around line 201-211: The GC-safety comment above TLSSettings is overly
verbose; replace the multi-line justification with a concise one-line note
stating that check_server_identity stores an unprotected raw JSValue but this is
safe because the source agent_opts remain live on the JS stack for the
synchronous Bun__fetch_ call, so no GC can run before the value is promoted to a
Strong reference; keep the TLSSettings struct and symbol names
(reject_unauthorized, check_server_identity, ssl_config) unchanged.
- Around line 883-984: Add a short explanatory comment before the TLS extraction
block inside the fallback_to_agent_proxy logic: explain that when proxy is
sourced from an agent/dispatcher (current_agent) we must also inherit
TLS/connect options from that agent via getAgentTLSOptions and
extractTLSSettings so per-agent TLS overrides (reject_unauthorized,
check_server_identity, ssl_config) are respected when ssl_config is not already
set; place the comment immediately above the if (ssl_config == null) { ... }
block that calls getAgentTLSOptions/extractTLSSettings in fetch.zig (within the
fallback_to_agent_proxy scope).
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between f8c0885 and a22865c.

📒 Files selected for processing (1)
  • src/bun.js/webcore/fetch.zig
🧰 Additional context used
📓 Path-based instructions (2)
**/*.zig

📄 CodeRabbit inference engine (CLAUDE.md)

In Zig code, be careful with allocators and use defer for cleanup

Files:

  • src/bun.js/webcore/fetch.zig
src/**/*.zig

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.zig: Use the # prefix for private fields in Zig structs, e.g., struct { #foo: u32 };
Use Decl literals in Zig, e.g., const decl: Decl = .{ .binding = 0, .value = 0 };
Place @import statements at the bottom of the file in Zig (auto formatter will handle positioning)
Never use @import() inline inside functions in Zig; always place imports at the bottom of the file or containing struct

Files:

  • src/bun.js/webcore/fetch.zig
🧠 Learnings (9)
📚 Learning: 2025-10-20T01:38:02.660Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: packages/bun-otel/BunFetchInstrumentation.ts:126-131
Timestamp: 2025-10-20T01:38:02.660Z
Learning: In BunFetchInstrumentation.ts, the force-restore to ORIGINAL_FETCH in the disable() method is intentionally kept (despite appearing unsafe) because it's required for proper test cleanup when instrumentation is repeatedly enabled/disabled. Without it, 15 distributed tracing and context propagation tests fail. Shimmer's unwrap() doesn't reliably restore the original fetch in Bun's globalThis context. The isBunOtelPatched safety check ensures the restore only happens when the current fetch is still ours, preventing clobbering of other tools' wrappers.

Applied to files:

  • src/bun.js/webcore/fetch.zig
📚 Learning: 2025-10-17T20:50:58.644Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 23755
File: src/bun.js/api/bun/socket/Handlers.zig:154-159
Timestamp: 2025-10-17T20:50:58.644Z
Learning: In Bun socket configuration error messages (src/bun.js/api/bun/socket/Handlers.zig), use the user-facing JavaScript names "data" and "drain" instead of internal field names "onData" and "onWritable", as these are the names users see in the API according to SocketConfig.bindv2.ts.

Applied to files:

  • src/bun.js/webcore/fetch.zig
📚 Learning: 2025-09-05T18:45:29.200Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 21728
File: src/valkey/js_valkey.zig:0-0
Timestamp: 2025-09-05T18:45:29.200Z
Learning: In JSValkeyClient.cloneWithoutConnecting() in src/valkey/js_valkey.zig, the address/username/password fields must be repointed to the duplicated connection_strings buffer to avoid use-after-free when the original client is destroyed. The original client properly frees connection_strings in ValkeyClient.deinit().

Applied to files:

  • src/bun.js/webcore/fetch.zig
📚 Learning: 2025-11-03T20:43:06.996Z
Learnt from: pfgithub
Repo: oven-sh/bun PR: 24273
File: src/bun.js/test/snapshot.zig:19-19
Timestamp: 2025-11-03T20:43:06.996Z
Learning: In Bun's Zig codebase, when storing JSValue objects in collections like ArrayList, use `jsc.Strong.Optional` (not raw JSValue). When adding values, wrap them with `jsc.Strong.Optional.create(value, globalThis)`. In cleanup code, iterate the collection calling `.deinit()` on each Strong.Optional item before calling `.deinit()` on the ArrayList itself. This pattern automatically handles GC protection. See examples in src/bun.js/test/ScopeFunctions.zig and src/bun.js/node/node_cluster_binding.zig.

Applied to files:

  • src/bun.js/webcore/fetch.zig
📚 Learning: 2025-10-01T21:49:27.862Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 23169
File: src/bun.js/bindings/BunIDLConvert.h:29-42
Timestamp: 2025-10-01T21:49:27.862Z
Learning: In Bun's IDL bindings (src/bun.js/bindings/BunIDLConvert.h), IDLStrictNull intentionally treats both undefined and null as null (using isUndefinedOrNull()), matching WebKit's IDLNull & IDLNullable behavior. This is the correct implementation and should not be changed to only accept null.

Applied to files:

  • src/bun.js/webcore/fetch.zig
📚 Learning: 2025-09-05T19:49:26.188Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 21728
File: src/valkey/js_valkey_functions.zig:852-867
Timestamp: 2025-09-05T19:49:26.188Z
Learning: In Bun’s Zig code, `.js_undefined` is a valid and preferred JSValue literal for “undefined” (e.g., resolving JSPromise). Do not refactor usages to `jsc.JSValue.jsUndefined()`, especially in src/valkey/js_valkey_functions.zig unsubscribe().

Applied to files:

  • src/bun.js/webcore/fetch.zig
📚 Learning: 2025-10-18T20:50:47.750Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: src/bun.js/telemetry.zig:366-373
Timestamp: 2025-10-18T20:50:47.750Z
Learning: In Bun's Zig codebase (src/bun.js/bindings/JSValue.zig), the JSValue enum uses `.null` (not `.js_null`) for JavaScript's null value. Only `js_undefined` has the `js_` prefix to avoid collision with Zig's built-in `undefined` keyword. The correct enum fields are: `js_undefined`, `null`, `true`, `false`, and `zero`.

Applied to files:

  • src/bun.js/webcore/fetch.zig
📚 Learning: 2025-09-06T03:37:41.154Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 22229
File: src/bundler/LinkerGraph.zig:0-0
Timestamp: 2025-09-06T03:37:41.154Z
Learning: In Bun's codebase, when checking import record source indices in src/bundler/LinkerGraph.zig, prefer using `if (import_index >= self.import_records.len)` bounds checking over `isValid()` checks, as the bounds check is more robust and `isValid()` is a strict subset of this condition.

Applied to files:

  • src/bun.js/webcore/fetch.zig
📚 Learning: 2026-01-05T16:32:07.551Z
Learnt from: alii
Repo: oven-sh/bun PR: 25474
File: src/bun.js/event_loop/Sigusr1Handler.zig:0-0
Timestamp: 2026-01-05T16:32:07.551Z
Learning: In Zig codebases (e.g., Bun), treat std.posix.sigaction as returning void and do not perform runtime error handling for its failure. The Zig standard library views sigaction failures as programmer errors (unreachable) because they only occur with invalid signals like SIGKILL/SIGSTOP. Apply this pattern across Zig files that call sigaction (e.g., crash_handler.zig, main.zig, filter_run.zig, process.zig) and ensure failures are not handled as recoverable errors; prefer reaching an explicit unreachable/compile-time assumption when such failures are detected.

Applied to files:

  • src/bun.js/webcore/fetch.zig
🔇 Additional comments (3)
src/bun.js/webcore/fetch.zig (3)

159-170: LGTM! Clean property detection helper.

The implementation correctly checks for TLS-related properties using proper error propagation. The inline loop and early return optimize the check.


172-199: LGTM! Well-structured agent option extraction.

The fallback chain (options → connectOpts → connect) correctly handles multiple agent patterns from different libraries. The unprotected JSValue return is safe here since the agent remains on the stack during the synchronous extraction.


573-629: LGTM! Clean TLS fallback implementation.

The logic correctly prioritizes per-request agents over the global HTTPS agent, with proper error handling and memory ownership. The block structure and early exits are well-organized.

Add support for https.globalAgent.options as default TLS options across:
- node:https requests (via _http_client.ts)
- fetch() API (via fetch.zig)

TLS options that now support agent fallback:
- ca, cert, key (with type validation)
- passphrase, ciphers, servername, secureOptions
- rejectUnauthorized (already had fallback, now also for fetch)
- checkServerIdentity (for fetch)

Also supports agent.connectOpts fallback for compatibility with
https-proxy-agent and similar libraries.

Example usage:
```js
const https = require('node:https');
https.globalAgent.options.ca = customCA;
https.globalAgent.options.rejectUnauthorized = true;

// Both now use the global TLS options:
await fetch('https://example.com');
https.get('https://example.com');
```
…lity

Add support for extracting TLS options from agent/dispatcher objects in
fetch() and node:https, enabling compatibility with libraries like
https-proxy-agent and undici.

fetch() now checks for TLS options in this order:
1. Per-request tls option
2. options.agent.options/connectOpts/connect (node-fetch style)
3. options.dispatcher.options/connectOpts/connect (undici style)
4. https.globalAgent.options/connectOpts/connect

node:https now also checks agent.connect for TLS properties, matching
undici.Agent's API which uses connect: { rejectUnauthorized, ca, ... }

Supported properties: rejectUnauthorized, ca, cert, key, passphrase,
ciphers, servername, secureOptions, checkServerIdentity

Also adds proxy extraction from agent.proxy/dispatcher.proxy for future
proxy support.
- Move hasTLSProperties and getAgentTLSOptions from anonymous structs
  inside Bun__fetch_ to standalone private functions at file scope
- Remove function pointer parameter from getAgentTLSOptions, call
  hasTLSProperties directly
- Remove unused getHttpsGlobalAgentOptions from bindings.cpp and
  JSGlobalObject.zig (dead code that was superseded by getHttpsGlobalAgent)
- Update Dispatcher class to store options and connect properties from constructor
- Update Agent, Pool, BalancedPool, Client to pass options to parent Dispatcher
- Update DispatcherBase, ProxyAgent, EnvHttpProxyAgent, RetryAgent to store options
- Wrap undici.fetch to automatically use globalDispatcher when set via setGlobalDispatcher()
- Add tests for dispatcher TLS options storage in undici.test.ts
- Add comprehensive undici module integration tests in globalAgent-tls-options.test.ts

This enables Bun's fetch to read TLS settings (rejectUnauthorized, ca, etc.)
from dispatcher.connect when using undici Agent/Dispatcher classes.
- fetch.zig: Use getAgentTLSOptions() helper instead of manual connectOpts/connect probing in current_agent branch
- undici.js: Make DispatcherBase extend Dispatcher (matches real undici), store dispatcher in RetryAgent
- _http_client.ts: Extract getAgentTlsOption() helper for 3-step fallback chain (agent.options -> connectOpts -> connect)
- Move undici property tests to separate file (undici-properties.test.ts)
- Add hasTLSProperties validation to connectOpts and connect fallback
  paths in getAgentTLSOptions to ensure only objects with actual TLS
  properties are returned
- Extract duplicate TLS extraction code into shared extractTLSSettings
  helper function with TLSSettings struct
- Update agent TLS error messages to be generic ("agent TLS <option>
  option") since values can come from options, connectOpts, or connect
- Store constructor parameters in undici Pool, BalancedPool, and Client
  classes (origin, upstreams, url respectively)
isObject() already implies the value is not undefined or null, so the
additional checks are unnecessary.
Remove 6 redundant globalThis.hasException() checks that were
incompatible with strict exception checks. These checks were
unnecessary because all preceding operations use 'try' which
already propagates exceptions as error.JSError.
…ions

Add fallback to https.globalAgent.options for TLS settings in the
WebSocket constructor, similar to what was implemented in fetch.zig.
When no explicit TLS config or proxy is provided, fall back to the
global agent's settings.

Changes:
- Add applyGlobalAgentFallback() helper function to extract proxy and
  TLS options from https.globalAgent
- Update constructJSWebSocket1 and constructJSWebSocket2 to use the
  helper and the full WebSocket::create overload with TLS support
- Update constructJSWebSocket3 to reuse the helper instead of
  duplicating the fallback logic
- Add 6 new tests for globalAgent fallback behavior
@cirospaciari cirospaciari force-pushed the ciro/globalAgent-tls-options branch from 75d0170 to 2d29b31 Compare January 9, 2026 00:44
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 9, 2026

@cirospaciari: I'll review the current code changes in this PR, focusing on the implementation and ignoring the previous build errors.


🧠 Learnings used
Learnt from: cirospaciari
Repo: oven-sh/bun PR: 24607
File: packages/bun-usockets/src/crypto/root_certs.h:3589-3618
Timestamp: 2025-11-11T22:08:38.015Z
Learning: For PRs that update certificate data (e.g., packages/bun-usockets/src/crypto/root_certs.h or packages/bun-usockets/certdata.txt), treat these files as generated artifacts and avoid review comments unless there is a clear build/runtime breakage.

Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Run `bun run zig:check-all` to compile Zig code on all platforms when making platform-specific changes

Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2026-01-07T23:45:24.542Z
Learning: Be patient with the Zig build process
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cirospaciari cirospaciari changed the title feat(tls): add https.globalAgent.options fallback for TLS options in fetch and node:https, improve agent and dispatcher support for fetch and better agent support for node:https feat(tls): add https.globalAgent.options fallback for TLS options in fetch and node:https, improve agent and dispatcher support for fetch and better agent support for node:https and websocket Jan 9, 2026
@cirospaciari cirospaciari changed the title feat(tls): add https.globalAgent.options fallback for TLS options in fetch and node:https, improve agent and dispatcher support for fetch and better agent support for node:https and websocket feat(tls): add https.globalAgent.options fallback for fetch, node:https, and WebSocket Jan 9, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

🤖 Fix all issues with AI agents
In @src/bun.js/bindings/bindings.cpp:
- Around line 6125-6144: The function JSC__JSGlobalObject__getHttpsGlobalAgent
should be exported as Zig-callable and nothrow by adding the
[[ZIG_EXPORT(nothrow)]] attribute, and should use a catch scope instead of
DECLARE_THROW_SCOPE so exceptions are properly suppressed; replace
DECLARE_THROW_SCOPE and RETURN_IF_EXCEPTION calls with DECLARE_CATCH_SCOPE(vm),
after each operation that may throw check if (catchScope.exception()) {
catchScope.clearException(); return JSValue::encode(jsUndefined()); } (e.g.,
after requireId and get calls) so the VM has no pending exceptions and the
function returns undefined on error.

In @src/bun.js/bindings/JSGlobalObject.zig:
- Around line 803-808: The new cross-language wrapper getHttpsGlobalAgent does
not call jsc.markBinding(@src()), so add a call to jsc.markBinding(@src()) at
the start of pub fn getHttpsGlobalAgent(this: *JSGlobalObject) before invoking
JSC__JSGlobalObject__getHttpsGlobalAgent(this) so that this binding shows in
trace output; ensure you import/qualify jsc.markBinding as used elsewhere in
other JSGlobalObject-boundary helpers if needed.

In @src/bun.js/bindings/webcore/JSWebSocket.cpp:
- Around line 152-259: The fallback in applyGlobalAgentFallback currently checks
globalAgent.options then globalAgent.connectOpts for TLS settings but omits the
undici-style globalAgent.connect; update the logic in applyGlobalAgentFallback
to also check for a "connect" property (after checking "options" and
before/alongside "connectOpts") and use it as tlsSourceValue when it's an object
and not undefined/null, so that rejectUnauthorized and the filtered TLS options
(ca/cert/key/passphrase) are extracted from globalAgent.connect the same way
they are from options/connectOpts; adjust the sequence around the existing
optionsValue/connectOptsValue handling to include reading
Bun::getOwnPropertyIfExists(..., "connect"_s) and fallback accordingly.

In @src/bun.js/webcore/fetch.zig:
- Around line 879-981: The agent/dispatcher lookup is duplicated; extract it
into a helper (e.g., fn findAgent(globalThis: *JSGlobalObject, options_object:
?JSValue, request_init_object: ?JSValue) ?JSValue) that encapsulates the logic
of checking options_object/request_init_object for "agent" or "dispatcher" and
falling back to globalThis.getHttpsGlobalAgent(), then replace the inline blk in
the proxy fallback (agent_and_proxy) and the earlier TLS fallback block to call
findAgent and then query the returned object's "proxy" or TLS options as before.

In @src/js/node/_http_client.ts:
- Around line 63-70: Replace the fallback chain in getAgentTlsOption with
nullish-coalescing to make intent clearer: instead of sequentially checking
agent?.options?.[key], agent?.connectOpts?.[key], agent?.connect?.[key] with if
(value === undefined) checks, return agent?.options?.[key] ??
agent?.connectOpts?.[key] ?? agent?.connect?.[key]; preserve the same
undefined/null handling and keep the function name getAgentTlsOption and the
same property order.
- Around line 740-834: The code treats falsy but valid values (e.g.,
secureOptions: 0) as “not provided” and doesn't validate rejectUnauthorized as a
boolean; update all option checks to use strict undefined checks (e.g., if
(options.secureOptions !== undefined) rather than if (options.secureOptions)) so
explicit falsy values are honored, and add boolean validation for
options.rejectUnauthorized and agent-derived rejectUnauthorized via
getAgentTlsOption; keep existing type checks for
ca/cert/key/passphrase/ciphers/servername/secureOptions for both request and
agent fallbacks and ensure agent-derived values are validated before assigning
via _ensureTls().

In @src/js/thirdparty/undici.js:
- Around line 274-339: The Dispatcher currently assigns this.options and
this.connect making them public enumerable properties, which diverges from
upstream undici; change this to store TLS fallback data non-enumerably and
document the divergence: in the Dispatcher constructor (affecting Dispatcher,
Agent, Pool, Client, and DispatcherBase) replace direct assignments with
Object.defineProperty-style non-enumerable properties for options and connect,
add a short comment explaining this is a deliberate Bun TLS fallback shim (so
future maintainers know why it differs from upstream), and ensure no other code
relies on those properties being enumerable to avoid introspection/compatibility
breaking changes.

In @test/js/first_party/undici/undici-properties.test.ts:
- Around line 5-130: The test currently awaits stdout, stderr and proc.exited
together which makes the exitCode assertion run before you can inspect outputs;
change the ordering so you first await proc.stdout.text() and proc.stderr.text()
(e.g. await Promise.all([proc.stdout.text(), proc.stderr.text()]) to get stdout
and stderr), then separately await proc.exited to get exitCode, and then run
assertions in the order: check stderr/stdout for diagnostics first and only then
assert exitCode; also consider relaxing the strict stderr === "" check to allow
purely-whitespace output (e.g. use a trim or regex) if flaky.

In @test/js/first_party/undici/undici.test.ts:
- Around line 158-282: Replace hard-coded "http://localhost" in tests for Pool,
BalancedPool, Client with the existing hostUrl variable so constructors don't
accidentally hit a local service; hoist const { Agent, Dispatcher, Pool,
BalancedPool, Client, ProxyAgent, EnvHttpProxyAgent, RetryAgent } =
require("undici") to the top of the describe block and create a small
table-driven helper that iterates over entries for each class (Agent,
Dispatcher, Pool, BalancedPool, Client, ProxyAgent, EnvHttpProxyAgent,
RetryAgent) to assert options/connect presence and rejectUnauthorized/ca values,
so TLS assertions are written once and reused instead of duplicated across the
8+ it blocks (refer to symbols Agent, Dispatcher, Pool, BalancedPool, Client,
ProxyAgent, EnvHttpProxyAgent, RetryAgent and hostUrl).

In @test/js/node/tls/globalAgent-tls-options.test.ts:
- Around line 69-74: The test currently asserts expect(stderr).toBe("") which is
brittle; update each occurrence of expect(stderr).toBe("") (e.g., in the test
blocks that also assert stdout.trim() === "Hello" and exitCode === 0) to avoid
failing on benign platform warnings: either remove the stderr assertion entirely
and rely on expect(stdout.trim()).toBe("...") and expect(exitCode).toBe(0), or
replace it with a negative-match that only fails on real errors (e.g.,
expect(stderr).not.toMatch(/(Error|Exception|Traceback)/)). Apply this change to
every test instance that uses expect(stderr).toBe("").
- Around line 13-1121: The test suite uses describe.concurrent for several
suites (instances of describe.concurrent such as the ones titled "https.request
uses globalAgent.options", "fetch uses globalAgent.options as fallback", "fetch
uses agent/dispatcher option for TLS fallback", and "undici module
integration"); change each describe.concurrent to plain describe so the
expensive TLS + Bun.spawn tests run serially to avoid CI flakiness and resource
contention.

In @test/js/web/websocket/websocket-proxy.test.ts:
- Around line 913-929: The test replaces https.globalAgent.options with a cloned
object which can leak state and also fails to restore the new fallback fields;
capture originalConnectOpts and originalConnect in beforeEach, and in afterEach
restore the options object by mutating it (e.g.,
Object.assign(https.globalAgent.options, originalOptions)) rather than replacing
it, and restore https.globalAgent.connectOpts and https.globalAgent.connect by
reassigning them from the saved originals; also add snapshots/assertions for
https.globalAgent.connectOpts and https.globalAgent.connect (e.g.,
expect(...).toMatchSnapshot()) so the new fallback surface is validated.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 75d0170 and 2d29b31.

📒 Files selected for processing (10)
  • src/bun.js/bindings/JSGlobalObject.zig
  • src/bun.js/bindings/bindings.cpp
  • src/bun.js/bindings/webcore/JSWebSocket.cpp
  • src/bun.js/webcore/fetch.zig
  • src/js/node/_http_client.ts
  • src/js/thirdparty/undici.js
  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/first_party/undici/undici.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/web/websocket/websocket-proxy.test.ts
🧰 Additional context used
📓 Path-based instructions (8)
**/*.test.ts?(x)

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.test.ts?(x): Never use bun test directly - always use bun bd test to run tests with debug build changes
For single-file tests, prefer -e flag over tempDir
For multi-file tests, prefer tempDir and Bun.spawn over single-file tests
Use normalizeBunSnapshot to normalize snapshot output of tests
Never write tests that check for 'panic', 'uncaught exception', or similar strings in test output
Use tempDir from harness to create temporary directories - do not use tmpdirSync or fs.mkdtempSync
When spawning processes in tests, expect stdout before expecting exit code for more useful error messages on test failure
Do not write flaky tests - do not use setTimeout in tests; instead await the condition to be met
Verify tests fail with USE_SYSTEM_BUN=1 bun test <file> and pass with bun bd test <file> - tests are invalid if they pass with USE_SYSTEM_BUN=1
Test files must end with .test.ts or .test.tsx
Avoid shell commands like find or grep in tests - use Bun's Glob and built-in tools instead

Files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/first_party/undici/undici.test.ts
  • test/js/web/websocket/websocket-proxy.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
test/**/*.test.ts?(x)

📄 CodeRabbit inference engine (CLAUDE.md)

Always use port: 0 in tests - do not hardcode ports or use custom random port number functions

Files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/first_party/undici/undici.test.ts
  • test/js/web/websocket/websocket-proxy.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
test/**/*.test.{ts,js,jsx,tsx,mjs,cjs}

📄 CodeRabbit inference engine (test/CLAUDE.md)

test/**/*.test.{ts,js,jsx,tsx,mjs,cjs}: Use bun bd test <...test file> to run tests with compiled code changes. Do not use bun test as it will not include your changes.
Use bun:test for files ending in *.test.{ts,js,jsx,tsx,mjs,cjs}. For test files without .test extension in test/js/node/test/{parallel,sequential}/*.js, use bun bd <file> instead of bun bd test <file> since they expect exit code 0.
Do not set a timeout on tests. Bun already has timeouts built-in.

Files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/first_party/undici/undici.test.ts
  • test/js/web/websocket/websocket-proxy.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
src/bun.js/bindings/**/*.cpp

📄 CodeRabbit inference engine (CLAUDE.md)

src/bun.js/bindings/**/*.cpp: Create classes in three parts in C++ when there is a public constructor: Foo (JSDestructibleObject), FooPrototype (JSNonFinalObject), and FooConstructor (InternalFunction)
Define properties using HashTableValue arrays in C++ JavaScript class bindings
Add iso subspaces for C++ classes with fields in JavaScript class bindings
Cache structures in ZigGlobalObject for JavaScript class bindings

Files:

  • src/bun.js/bindings/bindings.cpp
  • src/bun.js/bindings/webcore/JSWebSocket.cpp
**/*.zig

📄 CodeRabbit inference engine (CLAUDE.md)

In Zig code, be careful with allocators and use defer for cleanup

Files:

  • src/bun.js/webcore/fetch.zig
  • src/bun.js/bindings/JSGlobalObject.zig
src/**/*.zig

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.zig: Use the # prefix for private fields in Zig structs, e.g., struct { #foo: u32 };
Use Decl literals in Zig, e.g., const decl: Decl = .{ .binding = 0, .value = 0 };
Place @import statements at the bottom of the file in Zig (auto formatter will handle positioning)
Never use @import() inline inside functions in Zig; always place imports at the bottom of the file or containing struct

Files:

  • src/bun.js/webcore/fetch.zig
  • src/bun.js/bindings/JSGlobalObject.zig
src/js/{builtins,node,bun,thirdparty,internal}/**/*.{ts,js}

📄 CodeRabbit inference engine (src/js/CLAUDE.md)

src/js/{builtins,node,bun,thirdparty,internal}/**/*.{ts,js}: Use .$call() and .$apply() instead of .call() and .apply() to prevent user tampering with function invocation
Use string literal require() statements only; dynamic requires are not permitted
Export modules using export default { ... } syntax; modules are NOT ES modules
Use JSC intrinsics (prefixed with $) such as $Array.from(), $isCallable(), and $newArrayWithSize() for performance-critical operations
Use private globals and methods with $ prefix (e.g., $Array, map.$set()) instead of public JavaScript globals
Use $debug() for debug logging and $assert() for assertions; both are stripped in release builds
Validate function arguments using validators from internal/validators and throw $ERR_* error codes for invalid arguments
Use process.platform and process.arch for platform detection; these values are inlined and dead-code eliminated at build time

Files:

  • src/js/thirdparty/undici.js
  • src/js/node/_http_client.ts
src/js/{builtins,node,bun,thirdparty,internal}/**/*.ts

📄 CodeRabbit inference engine (src/js/CLAUDE.md)

Builtin functions must include this parameter typing in TypeScript to enable direct method binding in C++

Files:

  • src/js/node/_http_client.ts
🧠 Learnings (48)
📚 Learning: 2025-10-19T04:55:33.099Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: test/js/bun/http/node-telemetry.test.ts:27-203
Timestamp: 2025-10-19T04:55:33.099Z
Learning: In test/js/bun/http/node-telemetry.test.ts and the Bun.telemetry._node_binding API, after the architecture refactor, the _node_binding interface only contains two methods: handleIncomingRequest(req, res) and handleWriteHead(res, statusCode). The handleRequestFinish hook and other lifecycle hooks were removed during simplification. Both current methods are fully tested.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/first_party/undici/undici.test.ts
  • test/js/web/websocket/websocket-proxy.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to test/**/*.test.ts?(x) : Always use `port: 0` in tests - do not hardcode ports or use custom random port number functions

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/first_party/undici/undici.test.ts
  • test/js/web/websocket/websocket-proxy.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/test/v8/v8.test.ts : Add corresponding test cases to test/v8/v8.test.ts using checkSameOutput() function to compare Node.js and Bun output

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2025-10-18T05:23:24.403Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: test/js/bun/telemetry-server.test.ts:91-100
Timestamp: 2025-10-18T05:23:24.403Z
Learning: In the Bun codebase, telemetry tests (test/js/bun/telemetry-*.test.ts) should focus on telemetry API behavior: configure/disable/isEnabled, callback signatures and invocation, request ID correlation, and error handling. HTTP protocol behaviors like status code normalization (e.g., 200 with empty body → 204) should be tested in HTTP server tests (test/js/bun/http/), not in telemetry tests. Keep separation of concerns: telemetry tests verify the telemetry API contract; HTTP tests verify HTTP semantics.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/web/websocket/websocket-proxy.test.ts
📚 Learning: 2025-09-20T00:57:56.685Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 22568
File: test/js/valkey/valkey.test.ts:268-276
Timestamp: 2025-09-20T00:57:56.685Z
Learning: For test/js/valkey/valkey.test.ts, do not comment on synchronous throw assertions for async Redis methods like ctx.redis.set() - the maintainer has explicitly requested to stop looking at this error pattern.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
  • src/bun.js/webcore/fetch.zig
📚 Learning: 2025-09-20T00:58:38.042Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 22568
File: test/js/valkey/valkey.test.ts:561-564
Timestamp: 2025-09-20T00:58:38.042Z
Learning: For test/js/valkey/valkey.test.ts, do not comment on synchronous throw assertions for async Redis methods (like ctx.redis.set(), ctx.redis.unsubscribe(), etc.) - Bun's Redis client implementation differs from Node.js and can throw synchronously even for async methods. The maintainer has explicitly requested to stop looking at this error pattern.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
  • src/bun.js/webcore/fetch.zig
📚 Learning: 2025-10-20T01:38:02.660Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: packages/bun-otel/BunFetchInstrumentation.ts:126-131
Timestamp: 2025-10-20T01:38:02.660Z
Learning: In BunFetchInstrumentation.ts, the force-restore to ORIGINAL_FETCH in the disable() method is intentionally kept (despite appearing unsafe) because it's required for proper test cleanup when instrumentation is repeatedly enabled/disabled. Without it, 15 distributed tracing and context propagation tests fail. Shimmer's unwrap() doesn't reliably restore the original fetch in Bun's globalThis context. The isBunOtelPatched safety check ensures the restore only happens when the current fetch is still ours, preventing clobbering of other tools' wrappers.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • src/bun.js/webcore/fetch.zig
  • src/js/thirdparty/undici.js
📚 Learning: 2025-10-08T13:48:02.430Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 23373
File: test/js/bun/tarball/extract.test.ts:107-111
Timestamp: 2025-10-08T13:48:02.430Z
Learning: In Bun's test runner, use `expect(async () => { await ... }).toThrow()` to assert async rejections. Unlike Jest/Vitest, Bun does not require `await expect(...).rejects.toThrow()` - the async function wrapper with `.toThrow()` is the correct pattern for async error assertions in Bun tests.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/web/websocket/websocket-proxy.test.ts
📚 Learning: 2025-11-06T00:58:23.965Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 24417
File: test/js/bun/spawn/spawn.test.ts:903-918
Timestamp: 2025-11-06T00:58:23.965Z
Learning: In Bun test files, `await using` with spawn() is appropriate for long-running processes that need guaranteed cleanup on scope exit or when explicitly testing disposal behavior. For short-lived processes that exit naturally (e.g., console.log scripts), the pattern `const proc = spawn(...); await proc.exited;` is standard and more common, as evidenced by 24 instances vs 4 `await using` instances in test/js/bun/spawn/spawn.test.ts.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2025-10-25T17:20:19.041Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 24063
File: test/js/bun/telemetry/server-header-injection.test.ts:5-20
Timestamp: 2025-10-25T17:20:19.041Z
Learning: In the Bun telemetry codebase, tests are organized into two distinct layers: (1) Internal API tests in test/js/bun/telemetry/ use numeric InstrumentKind enum values to test Zig↔JS injection points and low-level integration; (2) Public API tests in packages/bun-otel/test/ use string InstrumentKind values ("http", "fetch", etc.) to test the public-facing BunSDK and instrumentation APIs. This separation allows internal tests to use efficient numeric enums for refactoring flexibility while the public API maintains a developer-friendly string-based interface.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/web/websocket/websocket-proxy.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2025-10-19T02:44:46.354Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: packages/bun-otel/context-propagation.test.ts:1-1
Timestamp: 2025-10-19T02:44:46.354Z
Learning: In the Bun repository, standalone packages under packages/ (e.g., bun-vscode, bun-inspector-protocol, bun-plugin-yaml, bun-plugin-svelte, bun-debug-adapter-protocol, bun-otel) co-locate their tests with package source code using *.test.ts files. This follows standard npm/monorepo patterns. The test/ directory hierarchy (test/js/bun/, test/cli/, test/js/node/) is reserved for testing Bun's core runtime APIs and built-in functionality, not standalone packages.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/web/websocket/websocket-proxy.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to **/*.test.ts?(x) : Verify tests fail with `USE_SYSTEM_BUN=1 bun test <file>` and pass with `bun bd test <file>` - tests are invalid if they pass with USE_SYSTEM_BUN=1

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2025-09-02T05:33:37.517Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 22323
File: test/js/web/websocket/websocket-subprotocol.test.ts:74-75
Timestamp: 2025-09-02T05:33:37.517Z
Learning: In Bun's runtime, `await using` with Node.js APIs like `net.createServer()` is properly supported and should not be replaced with explicit cleanup. Bun has extended Node.js APIs with proper async dispose support.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • src/js/thirdparty/undici.js
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Applies to test/**/*.test.{ts,js,jsx,tsx,mjs,cjs} : Use `bun:test` for files ending in `*.test.{ts,js,jsx,tsx,mjs,cjs}`. For test files without .test extension in test/js/node/test/{parallel,sequential}/*.js, use `bun bd <file>` instead of `bun bd test <file>` since they expect exit code 0.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/web/websocket/websocket-proxy.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to src/bun.js/bindings/**/*.cpp : Cache structures in ZigGlobalObject for JavaScript class bindings

Applied to files:

  • src/bun.js/bindings/bindings.cpp
  • src/js/thirdparty/undici.js
  • src/bun.js/bindings/JSGlobalObject.zig
  • src/bun.js/bindings/webcore/JSWebSocket.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/src/napi/napi.zig : For each new V8 C++ method, add both GCC/Clang and MSVC mangled symbol names to the V8API struct in src/napi/napi.zig using extern fn declarations

Applied to files:

  • src/bun.js/bindings/bindings.cpp
  • src/bun.js/bindings/JSGlobalObject.zig
  • src/bun.js/bindings/webcore/JSWebSocket.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/test/v8/v8-module/main.cpp : Register new V8 API test functions in the Init method using NODE_SET_METHOD with exports object

Applied to files:

  • src/bun.js/bindings/bindings.cpp
  • src/bun.js/bindings/JSGlobalObject.zig
📚 Learning: 2025-11-24T18:37:47.899Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/AGENTS.md:0-0
Timestamp: 2025-11-24T18:37:47.899Z
Learning: Applies to src/bun.js/bindings/v8/**/<UNKNOWN> : <UNKNOWN>

Applied to files:

  • src/bun.js/bindings/bindings.cpp
  • src/js/thirdparty/undici.js
  • src/bun.js/bindings/JSGlobalObject.zig
  • src/bun.js/bindings/webcore/JSWebSocket.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/src/symbols.txt : Add symbol names without leading underscore to src/symbols.txt for each new V8 API method

Applied to files:

  • src/bun.js/bindings/bindings.cpp
  • src/bun.js/bindings/JSGlobalObject.zig
  • src/bun.js/bindings/webcore/JSWebSocket.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/src/symbols.dyn : Add symbol names with leading underscore and semicolons in braces to src/symbols.dyn for each new V8 API method

Applied to files:

  • src/bun.js/bindings/bindings.cpp
  • src/bun.js/bindings/JSGlobalObject.zig
📚 Learning: 2025-10-11T15:19:30.301Z
Learnt from: mastermakrela
Repo: oven-sh/bun PR: 19167
File: src/bun.js/api.zig:31-31
Timestamp: 2025-10-11T15:19:30.301Z
Learning: The learnings about `pub const js = JSC.Codegen.JS<ClassName>` and re-exporting toJS/fromJS/fromJSDirect apply to class-based Zig bindings with constructors and prototype methods (e.g., those with `new` constructors). They do NOT apply to simple namespace-style API objects like TOMLObject, YAMLObject, and CSVObject which expose static functions via a `create()` method that returns a plain JS object.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
  • src/bun.js/bindings/JSGlobalObject.zig
  • src/bun.js/bindings/webcore/JSWebSocket.cpp
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to src/bun.js/bindings/**/*.cpp : Add iso subspaces for C++ classes with fields in JavaScript class bindings

Applied to files:

  • src/bun.js/bindings/bindings.cpp
  • src/bun.js/bindings/webcore/JSWebSocket.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.h : Add BUN_EXPORT visibility attribute to all public V8 API functions to ensure proper symbol export across platforms

Applied to files:

  • src/bun.js/bindings/bindings.cpp
  • src/bun.js/bindings/JSGlobalObject.zig
  • src/bun.js/bindings/webcore/JSWebSocket.cpp
📚 Learning: 2025-10-01T21:59:54.571Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 23169
File: src/bun.js/bindings/webcore/JSDOMConvertEnumeration.h:47-74
Timestamp: 2025-10-01T21:59:54.571Z
Learning: In the new bindings generator (bindgenv2) for `src/bun.js/bindings/webcore/JSDOMConvertEnumeration.h`, the context-aware enumeration conversion overloads intentionally use stricter validation (requiring `value.isString()` without ToString coercion), diverging from Web IDL semantics. This is a design decision documented in comments.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
  • src/bun.js/bindings/webcore/JSWebSocket.cpp
📚 Learning: 2025-09-03T01:30:58.001Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 21728
File: test/js/valkey/valkey.test.ts:264-271
Timestamp: 2025-09-03T01:30:58.001Z
Learning: For test/js/valkey/valkey.test.ts PUB/SUB tests, avoid arbitrary sleeps and async-forEach. Instead, resolve a Promise from the subscriber callback when the expected number of messages is observed and await it with a bounded timeout (e.g., withTimeout + Promise.withResolvers) to account for Redis server→subscriber propagation.

Applied to files:

  • test/js/web/websocket/websocket-proxy.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Applies to test/**/*.test.{ts,js,jsx,tsx,mjs,cjs} : Use `bun bd test <...test file>` to run tests with compiled code changes. Do not use `bun test` as it will not include your changes.

Applied to files:

  • test/js/web/websocket/websocket-proxy.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Organize unit tests by module in directories like `/test/js/bun/` and `/test/js/node/`.

Applied to files:

  • test/js/web/websocket/websocket-proxy.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2025-10-30T03:48:10.513Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 24063
File: packages/bun-otel/test/context-propagation.test.ts:1-7
Timestamp: 2025-10-30T03:48:10.513Z
Learning: In Bun test files, `using` declarations at the describe block level execute during module load/parsing, not during test execution. This means they acquire and dispose resources before any tests run. For test-scoped resource management, use beforeAll/afterAll hooks instead. The pattern `beforeAll(beforeUsingEchoServer); afterAll(afterUsingEchoServer);` is correct for managing ref-counted test resources like the EchoServer in packages/bun-otel/test/ - the using block pattern should not be used at describe-block level for test resources.
<!-- [/add_learning]

Applied to files:

  • test/js/web/websocket/websocket-proxy.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2025-09-20T03:39:41.770Z
Learnt from: pfgithub
Repo: oven-sh/bun PR: 22534
File: test/regression/issue/21830.fixture.ts:14-63
Timestamp: 2025-09-20T03:39:41.770Z
Learning: Bun's test runner supports async describe callbacks, unlike Jest/Vitest where describe callbacks must be synchronous. The syntax `describe("name", async () => { ... })` is valid in Bun.

Applied to files:

  • test/js/web/websocket/websocket-proxy.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: When spawning Bun processes in tests, use `bunExe` and `bunEnv` from `harness` to ensure the same build of Bun is used and debug logging is silenced.

Applied to files:

  • test/js/web/websocket/websocket-proxy.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to **/*.test.ts?(x) : Never use `bun test` directly - always use `bun bd test` to run tests with debug build changes

Applied to files:

  • test/js/web/websocket/websocket-proxy.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Prefer async/await over callbacks in tests. When callbacks must be used for a single callback, use `Promise.withResolvers` to create a promise that can be resolved or rejected from a callback.

Applied to files:

  • test/js/web/websocket/websocket-proxy.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to **/*.test.ts?(x) : For multi-file tests, prefer `tempDir` and `Bun.spawn` over single-file tests

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2025-10-26T01:32:04.844Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 24082
File: test/cli/test/coverage.test.ts:60-112
Timestamp: 2025-10-26T01:32:04.844Z
Learning: In the Bun repository test files (test/cli/test/*.test.ts), when spawning Bun CLI commands with Bun.spawnSync for testing, prefer using stdio: ["inherit", "inherit", "inherit"] to inherit stdio streams rather than piping them.

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2025-10-17T20:50:58.644Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 23755
File: src/bun.js/api/bun/socket/Handlers.zig:154-159
Timestamp: 2025-10-17T20:50:58.644Z
Learning: In Bun socket configuration error messages (src/bun.js/api/bun/socket/Handlers.zig), use the user-facing JavaScript names "data" and "drain" instead of internal field names "onData" and "onWritable", as these are the names users see in the API according to SocketConfig.bindv2.ts.

Applied to files:

  • src/bun.js/webcore/fetch.zig
  • src/js/node/_http_client.ts
📚 Learning: 2025-09-05T18:45:29.200Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 21728
File: src/valkey/js_valkey.zig:0-0
Timestamp: 2025-09-05T18:45:29.200Z
Learning: In JSValkeyClient.cloneWithoutConnecting() in src/valkey/js_valkey.zig, the address/username/password fields must be repointed to the duplicated connection_strings buffer to avoid use-after-free when the original client is destroyed. The original client properly frees connection_strings in ValkeyClient.deinit().

Applied to files:

  • src/bun.js/webcore/fetch.zig
  • src/js/thirdparty/undici.js
📚 Learning: 2025-11-03T20:43:06.996Z
Learnt from: pfgithub
Repo: oven-sh/bun PR: 24273
File: src/bun.js/test/snapshot.zig:19-19
Timestamp: 2025-11-03T20:43:06.996Z
Learning: In Bun's Zig codebase, when storing JSValue objects in collections like ArrayList, use `jsc.Strong.Optional` (not raw JSValue). When adding values, wrap them with `jsc.Strong.Optional.create(value, globalThis)`. In cleanup code, iterate the collection calling `.deinit()` on each Strong.Optional item before calling `.deinit()` on the ArrayList itself. This pattern automatically handles GC protection. See examples in src/bun.js/test/ScopeFunctions.zig and src/bun.js/node/node_cluster_binding.zig.

Applied to files:

  • src/bun.js/webcore/fetch.zig
  • src/bun.js/bindings/JSGlobalObject.zig
📚 Learning: 2025-10-01T21:49:27.862Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 23169
File: src/bun.js/bindings/BunIDLConvert.h:29-42
Timestamp: 2025-10-01T21:49:27.862Z
Learning: In Bun's IDL bindings (src/bun.js/bindings/BunIDLConvert.h), IDLStrictNull intentionally treats both undefined and null as null (using isUndefinedOrNull()), matching WebKit's IDLNull & IDLNullable behavior. This is the correct implementation and should not be changed to only accept null.

Applied to files:

  • src/bun.js/webcore/fetch.zig
📚 Learning: 2025-09-05T19:49:26.188Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 21728
File: src/valkey/js_valkey_functions.zig:852-867
Timestamp: 2025-09-05T19:49:26.188Z
Learning: In Bun’s Zig code, `.js_undefined` is a valid and preferred JSValue literal for “undefined” (e.g., resolving JSPromise). Do not refactor usages to `jsc.JSValue.jsUndefined()`, especially in src/valkey/js_valkey_functions.zig unsubscribe().

Applied to files:

  • src/bun.js/webcore/fetch.zig
📚 Learning: 2025-10-18T20:50:47.750Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: src/bun.js/telemetry.zig:366-373
Timestamp: 2025-10-18T20:50:47.750Z
Learning: In Bun's Zig codebase (src/bun.js/bindings/JSValue.zig), the JSValue enum uses `.null` (not `.js_null`) for JavaScript's null value. Only `js_undefined` has the `js_` prefix to avoid collision with Zig's built-in `undefined` keyword. The correct enum fields are: `js_undefined`, `null`, `true`, `false`, and `zero`.

Applied to files:

  • src/bun.js/webcore/fetch.zig
📚 Learning: 2025-09-06T03:37:41.154Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 22229
File: src/bundler/LinkerGraph.zig:0-0
Timestamp: 2025-09-06T03:37:41.154Z
Learning: In Bun's codebase, when checking import record source indices in src/bundler/LinkerGraph.zig, prefer using `if (import_index >= self.import_records.len)` bounds checking over `isValid()` checks, as the bounds check is more robust and `isValid()` is a strict subset of this condition.

Applied to files:

  • src/bun.js/webcore/fetch.zig
📚 Learning: 2025-12-23T06:50:41.142Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 25429
File: src/bun.js/bindings/helpers.h:422-422
Timestamp: 2025-12-23T06:50:41.142Z
Learning: In Bun's C++ bindings (src/bun.js/bindings/helpers.h and similar files), when returning an empty JSC::Identifier and a VM is accessible, prefer using `vm.propertyNames->emptyIdentifier` over constructing with `JSC::Identifier(JSC::Identifier::EmptyIdentifierFlag::EmptyIdentifier)`. The cached identifier from the VM's property names table is more efficient and consistent with WebKit upgrade patterns.

Applied to files:

  • src/bun.js/webcore/fetch.zig
📚 Learning: 2025-10-18T20:59:45.579Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: src/bun.js/telemetry.zig:458-475
Timestamp: 2025-10-18T20:59:45.579Z
Learning: In src/bun.js/telemetry.zig, the RequestId (u64) to JavaScript number (f64) conversion in jsRequestId() is intentionally allowed to lose precision beyond 2^53-1. This is acceptable because: (1) at 1M requests/sec it takes ~285 years to overflow, (2) the counter resets per-process, and (3) these are observability IDs, not critical distributed IDs. Precision loss is an acceptable trade-off for this use case.

Applied to files:

  • src/bun.js/webcore/fetch.zig
📚 Learning: 2026-01-05T16:32:07.551Z
Learnt from: alii
Repo: oven-sh/bun PR: 25474
File: src/bun.js/event_loop/Sigusr1Handler.zig:0-0
Timestamp: 2026-01-05T16:32:07.551Z
Learning: In Zig codebases (e.g., Bun), treat std.posix.sigaction as returning void and do not perform runtime error handling for its failure. The Zig standard library views sigaction failures as programmer errors (unreachable) because they only occur with invalid signals like SIGKILL/SIGSTOP. Apply this pattern across Zig files that call sigaction (e.g., crash_handler.zig, main.zig, filter_run.zig, process.zig) and ensure failures are not handled as recoverable errors; prefer reaching an explicit unreachable/compile-time assumption when such failures are detected.

Applied to files:

  • src/bun.js/webcore/fetch.zig
  • src/bun.js/bindings/JSGlobalObject.zig
📚 Learning: 2025-11-24T18:37:11.466Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/js/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:37:11.466Z
Learning: Write JS builtins for Bun's Node.js compatibility and APIs, and run `bun bd` after changes

Applied to files:

  • src/js/thirdparty/undici.js
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to src/bun.js/bindings/**/*.cpp : Create classes in three parts in C++ when there is a public constructor: Foo (JSDestructibleObject), FooPrototype (JSNonFinalObject), and FooConstructor (InternalFunction)

Applied to files:

  • src/js/thirdparty/undici.js
  • src/bun.js/bindings/webcore/JSWebSocket.cpp
📚 Learning: 2025-11-24T18:37:11.466Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/js/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:37:11.466Z
Learning: Applies to src/js/{builtins,node,bun,thirdparty,internal}/**/*.{ts,js} : Use private globals and methods with `$` prefix (e.g., `$Array`, `map.$set()`) instead of public JavaScript globals

Applied to files:

  • src/bun.js/bindings/JSGlobalObject.zig
  • src/bun.js/bindings/webcore/JSWebSocket.cpp
📚 Learning: 2025-11-24T18:37:11.466Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/js/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:37:11.466Z
Learning: Applies to src/js/{builtins,node,bun,thirdparty,internal}/**/*.ts : Builtin functions must include `this` parameter typing in TypeScript to enable direct method binding in C++

Applied to files:

  • src/bun.js/bindings/webcore/JSWebSocket.cpp
🧬 Code graph analysis (5)
test/js/node/tls/globalAgent-tls-options.test.ts (1)
test/harness.ts (1)
  • tempDir (277-284)
test/js/web/websocket/websocket-proxy.test.ts (2)
test/js/bun/http/bun-websocket-cpu-fixture.js (1)
  • ws (25-25)
src/bun.js/bindings/webcore/WebSocket.cpp (2)
  • WebSocket (180-188)
  • WebSocket (190-224)
test/js/first_party/undici/undici-properties.test.ts (1)
test/harness.ts (1)
  • tempDir (277-284)
src/bun.js/bindings/webcore/JSWebSocket.cpp (3)
src/bun.js/bindings/webcore/WebSocket.h (2)
  • sslConfig (181-184)
  • url (135-164)
src/bun.js/bindings/ObjectBindings.cpp (2)
  • getOwnPropertyIfExists (95-108)
  • getOwnPropertyIfExists (95-95)
src/bun.js/bindings/webcore/WebSocket.cpp (18)
  • url (1100-1103)
  • url (1100-1100)
  • create (294-297)
  • create (294-294)
  • create (299-302)
  • create (299-299)
  • create (304-319)
  • create (304-304)
  • create (320-336)
  • create (320-320)
  • create (338-355)
  • create (338-338)
  • create (357-375)
  • create (357-357)
  • create (377-380)
  • create (377-377)
  • protocol (1115-1118)
  • protocol (1115-1115)
src/js/node/_http_client.ts (1)
src/js/internal/tls.ts (1)
  • isValidTLSArray (53-53)
🔇 Additional comments (6)
src/bun.js/bindings/webcore/JSWebSocket.cpp (1)

278-289: LGTM: fallback application points are correct (constructor overloads get proxy + TLS consistently).

Calling the fallback before WebSocket::create(...) in the 1-arg/2-arg constructors and as a final fallback in the options-object constructor is the right shape to keep precedence rules intact.

Also applies to: 319-333, 575-581

src/js/thirdparty/undici.js (1)

9-18: Move let globalDispatcher above the wrapper to avoid any TDZ/init-order surprises.

Proposed change
 const kEmptyObject = ObjectCreate(null);

-const bunFetch = Bun.fetch;
-
-// Wrapper fetch that uses globalDispatcher when set
-function fetch(input, init) {
+let globalDispatcher;
+
+const bunFetch = Bun.fetch;
+
+// Wrapper fetch that uses globalDispatcher when set
+function fetch(input, init) {
   // If no dispatcher/agent is provided and globalDispatcher is set, use it
   if (globalDispatcher && init?.dispatcher === undefined && init?.agent === undefined) {
     return bunFetch(input, { ...init, dispatcher: globalDispatcher });
   }
   return bunFetch(input, init);
 }
 ...
-let globalDispatcher;
-
 // Add missing dispatcher functions
 function setGlobalDispatcher(dispatcher) {
   globalDispatcher = dispatcher;
 }

Also applies to: 456-465

⛔ Skipped due to learnings
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: packages/bun-otel/BunFetchInstrumentation.ts:126-131
Timestamp: 2025-10-20T01:38:02.660Z
Learning: In BunFetchInstrumentation.ts, the force-restore to ORIGINAL_FETCH in the disable() method is intentionally kept (despite appearing unsafe) because it's required for proper test cleanup when instrumentation is repeatedly enabled/disabled. Without it, 15 distributed tracing and context propagation tests fail. Shimmer's unwrap() doesn't reliably restore the original fetch in Bun's globalThis context. The isBunOtelPatched safety check ensures the restore only happens when the current fetch is still ours, preventing clobbering of other tools' wrappers.
src/bun.js/webcore/fetch.zig (4)

159-170: LGTM: Clean TLS property detection.

The function correctly checks for TLS-related properties and handles errors appropriately. The early return optimization is good.


172-199: LGTM: Agent TLS options fallback logic is sound.

The function correctly implements the fallback chain (options → connectOpts → connect) for compatibility with different agent implementations (standard, https-proxy-agent, undici).


201-244: LGTM: TLS settings extraction is well-structured.

The extractTLSSettings function properly handles type coercion for rejectUnauthorized (boolean or number) and validates checkServerIdentity is callable. The comment about check_server_identity holding a raw JSValue is correct—it's promoted to a Strong reference at line 1652 before being passed to FetchTasklet, so there's no GC risk during the synchronous call.

Memory management for ssl_config is properly handled via the defer at lines 346-350.


569-625: LGTM: TLS fallback implements correct precedence.

The fallback logic properly prioritizes per-request agent/dispatcher options over https.globalAgent, and only applies when no explicit tls config was provided. The dual check for both agent (node-fetch style) and dispatcher (undici style) ensures broad compatibility.

- bindings.cpp: Use catch scope with nothrow export for getHttpsGlobalAgent
- JSGlobalObject.zig: Add markBinding call for proper binding tracking
- JSWebSocket.cpp: Add 'connect' property check for undici.Agent compat
- fetch.zig: Extract findAgentOrDispatcher and findAgentWithProxy helpers
- _http_client.ts: Use nullish-coalescing, add boolean validation for
  rejectUnauthorized, fix secureOptions to use strict undefined check
- undici.js: Make options/connect properties non-enumerable with docs
- Test fixes: Fix assertion ordering, use hostUrl variable, remove
  describe.concurrent, relax stderr assertions, fix state restoration
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 9, 2026

@cirospaciari: I'll review the current code changes in this PR, focusing on the implementation quality and ignoring the previous build errors as requested.


🧠 Learnings used
Learnt from: cirospaciari
Repo: oven-sh/bun PR: 24607
File: packages/bun-usockets/src/crypto/root_certs.h:3589-3618
Timestamp: 2025-11-11T22:08:38.015Z
Learning: For PRs that update certificate data (e.g., packages/bun-usockets/src/crypto/root_certs.h or packages/bun-usockets/certdata.txt), treat these files as generated artifacts and avoid review comments unless there is a clear build/runtime breakage.
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
test/js/first_party/undici/undici.test.ts (1)

120-132: Remove setTimeout usage in tests—use AbortSignal.timeout() instead.

Line 123 uses setTimeout to schedule the abort, which violates the coding guidelines and can introduce flakiness. Replace with AbortSignal.timeout(500) to create an abort signal that fires after 500ms without relying on setTimeout. This pattern is used consistently throughout the codebase.

src/js/node/_http_client.ts (1)

737-839: Fix option presence checks: use !== undefined to prevent unintended fallback to agent options.

The code uses truthy checks (if (options.ca), if (options.cert), if (options.key), if (options.passphrase), if (options.ciphers), if (options.servername)) which incorrectly treat falsy user-provided values (empty strings, false, 0) as absent, causing them to unexpectedly fall through to agent/global options. Replace with explicit presence checks (!== undefined).

Affected lines and fix
-  if (options.ca) {
+  if (options.ca !== undefined) {
     ...
   }
-  if (options.cert) {
+  if (options.cert !== undefined) {
     ...
   }
-  if (options.key) {
+  if (options.key !== undefined) {
     ...
   }
-  if (options.passphrase) {
+  if (options.passphrase !== undefined) {
     ...
   }
-  if (options.ciphers) {
+  if (options.ciphers !== undefined) {
     ...
   }
-  if (options.servername) {
+  if (options.servername !== undefined) {
     ...
   }

Note: rejectUnauthorized and secureOptions already use !== undefined correctly.

🤖 Fix all issues with AI agents
In @src/bun.js/bindings/bindings.cpp:
- Around line 6125-6150: In JSC__JSGlobalObject__getHttpsGlobalAgent replace
unconditional catchScope.clearException() calls with the variant that preserves
termination exceptions (e.g., clearExceptionExceptTermination or the project
equivalent) so shutdown/termination exceptions aren’t swallowed, and avoid
constructing the "globalAgent" Identifier twice by creating a local Identifier
(e.g., auto globalAgentId = Identifier::fromString(vm, "globalAgent"_s)) and
reusing it when calling httpsModule.getObject()->get(globalObject,
globalAgentId) and any other places in this function; keep existing
null/undefined checks and return behavior unchanged.

In @src/bun.js/bindings/webcore/JSWebSocket.cpp:
- Around line 152-266: The gating for inheriting TLS fields incorrectly requires
both rejectUnauthorized == -1 and !sslConfig; update applyGlobalAgentFallback so
the two concerns are handled separately: first, if tlsSourceValue is an object,
extract rejectUnauthorized into rejectUnauthorized only when rejectUnauthorized
== -1 (using the existing rejectValue logic), and then independently, if
(!sslConfig) build filteredTlsOpts from tlsSourceObj (ca, cert, key,
passphrase), call Bun__WebSocket__parseSSLConfig and set sslConfig; keep the
existing RETURN_IF_EXCEPTION checks and reuse tlsSourceValue/tlsSourceObj logic
but split the condition that currently reads if (rejectUnauthorized == -1 &&
!sslConfig) into separate paths for the two responsibilities.

In @src/js/node/_http_client.ts:
- Around line 63-67: getAgentTlsOption currently stops the fallback chain if an
agent explicitly sets options[key] = null; to treat null as "unset" normalize
null to undefined inside getAgentTlsOption so the chain continues (i.e., when
reading each candidate value from agent.options, agent.connectOpts, and
agent.connect treat value === null as undefined), or alternatively change the
function to check for value != null for each source before returning; update the
getAgentTlsOption implementation accordingly so callers get undefined for unset
keys instead of null.

In @src/js/thirdparty/undici.js:
- Around line 274-349: The Dispatcher constructor currently calls
Object.defineProperty directly (in the "options" and "connect" branches) which
is user-mutable; bind and use the primordials version instead. Import/bind the
primordial defineProperty once at the top of the module (e.g.,
ObjectDefineProperty or Object_defineProperty from the project's primordials
entry) and replace all direct Object.defineProperty calls in Dispatcher (and any
other places in this file that call Object.defineProperty) with that primordial
binding to prevent userland tampering; ensure the property descriptor and
configurable/writable/enumerable flags remain identical.

In @test/js/first_party/undici/undici.test.ts:
- Around line 158-282: Tests duplicate require("undici") and mostly only assert
rejectUnauthorized; import undici exports once (e.g., const { Agent, Dispatcher,
Pool, BalancedPool, Client, ProxyAgent, EnvHttpProxyAgent, RetryAgent } =
require("undici")) at top of the describe and reuse them, consolidate the
repeated connect object into a shared const connectOpts = { rejectUnauthorized:
false, ca: "test-ca" } and pass/modify as needed; add an extra TLS assertion
(e.g., expect(...connect.ca).toBe("test-ca")) for 1–2 representative classes
beyond Agent (such as Pool and Client) to guard non-boolean fields; and confirm
whether Dispatcher is intended to be constructed in this environment—if not,
remove or adapt the Dispatcher-specific test to use the supported public API
(refer to Dispatcher and RetryAgent usage) so tests match the shim's public
surface.

In @test/js/node/tls/globalAgent-tls-options.test.ts:
- Around line 1-1121: Remove the brittle stderr regex assertions (the lines
calling expect(stderr).not.toMatch(/(Error|Exception|Traceback)/i)) and instead
rely on the existing exitCode and stdout checks; keep the Bun.spawn/tempDir
pattern. Update assertions that validate stdout/exitCode (references: stdout,
stderr, exitCode, and the expect(...) calls that check stdout.trim() and
exitCode) to fail with stderr included in the failure context—e.g., drop the
stderr regex check and ensure test failures surface stderr by including the
stderr variable in the test assertion failure message or by adding an assertion
that prints/stores stderr on failure.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 2d29b31 and 995569e.

📒 Files selected for processing (10)
  • src/bun.js/bindings/JSGlobalObject.zig
  • src/bun.js/bindings/bindings.cpp
  • src/bun.js/bindings/webcore/JSWebSocket.cpp
  • src/bun.js/webcore/fetch.zig
  • src/js/node/_http_client.ts
  • src/js/thirdparty/undici.js
  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/first_party/undici/undici.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/web/websocket/websocket-proxy.test.ts
🧰 Additional context used
📓 Path-based instructions (8)
**/*.test.ts?(x)

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.test.ts?(x): Never use bun test directly - always use bun bd test to run tests with debug build changes
For single-file tests, prefer -e flag over tempDir
For multi-file tests, prefer tempDir and Bun.spawn over single-file tests
Use normalizeBunSnapshot to normalize snapshot output of tests
Never write tests that check for 'panic', 'uncaught exception', or similar strings in test output
Use tempDir from harness to create temporary directories - do not use tmpdirSync or fs.mkdtempSync
When spawning processes in tests, expect stdout before expecting exit code for more useful error messages on test failure
Do not write flaky tests - do not use setTimeout in tests; instead await the condition to be met
Verify tests fail with USE_SYSTEM_BUN=1 bun test <file> and pass with bun bd test <file> - tests are invalid if they pass with USE_SYSTEM_BUN=1
Test files must end with .test.ts or .test.tsx
Avoid shell commands like find or grep in tests - use Bun's Glob and built-in tools instead

Files:

  • test/js/first_party/undici/undici.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/web/websocket/websocket-proxy.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
test/**/*.test.ts?(x)

📄 CodeRabbit inference engine (CLAUDE.md)

Always use port: 0 in tests - do not hardcode ports or use custom random port number functions

Files:

  • test/js/first_party/undici/undici.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/web/websocket/websocket-proxy.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
test/**/*.test.{ts,js,jsx,tsx,mjs,cjs}

📄 CodeRabbit inference engine (test/CLAUDE.md)

test/**/*.test.{ts,js,jsx,tsx,mjs,cjs}: Use bun bd test <...test file> to run tests with compiled code changes. Do not use bun test as it will not include your changes.
Use bun:test for files ending in *.test.{ts,js,jsx,tsx,mjs,cjs}. For test files without .test extension in test/js/node/test/{parallel,sequential}/*.js, use bun bd <file> instead of bun bd test <file> since they expect exit code 0.
Do not set a timeout on tests. Bun already has timeouts built-in.

Files:

  • test/js/first_party/undici/undici.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/web/websocket/websocket-proxy.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
src/js/{builtins,node,bun,thirdparty,internal}/**/*.{ts,js}

📄 CodeRabbit inference engine (src/js/CLAUDE.md)

src/js/{builtins,node,bun,thirdparty,internal}/**/*.{ts,js}: Use .$call() and .$apply() instead of .call() and .apply() to prevent user tampering with function invocation
Use string literal require() statements only; dynamic requires are not permitted
Export modules using export default { ... } syntax; modules are NOT ES modules
Use JSC intrinsics (prefixed with $) such as $Array.from(), $isCallable(), and $newArrayWithSize() for performance-critical operations
Use private globals and methods with $ prefix (e.g., $Array, map.$set()) instead of public JavaScript globals
Use $debug() for debug logging and $assert() for assertions; both are stripped in release builds
Validate function arguments using validators from internal/validators and throw $ERR_* error codes for invalid arguments
Use process.platform and process.arch for platform detection; these values are inlined and dead-code eliminated at build time

Files:

  • src/js/node/_http_client.ts
  • src/js/thirdparty/undici.js
src/js/{builtins,node,bun,thirdparty,internal}/**/*.ts

📄 CodeRabbit inference engine (src/js/CLAUDE.md)

Builtin functions must include this parameter typing in TypeScript to enable direct method binding in C++

Files:

  • src/js/node/_http_client.ts
src/bun.js/bindings/**/*.cpp

📄 CodeRabbit inference engine (CLAUDE.md)

src/bun.js/bindings/**/*.cpp: Create classes in three parts in C++ when there is a public constructor: Foo (JSDestructibleObject), FooPrototype (JSNonFinalObject), and FooConstructor (InternalFunction)
Define properties using HashTableValue arrays in C++ JavaScript class bindings
Add iso subspaces for C++ classes with fields in JavaScript class bindings
Cache structures in ZigGlobalObject for JavaScript class bindings

Files:

  • src/bun.js/bindings/bindings.cpp
  • src/bun.js/bindings/webcore/JSWebSocket.cpp
**/*.zig

📄 CodeRabbit inference engine (CLAUDE.md)

In Zig code, be careful with allocators and use defer for cleanup

Files:

  • src/bun.js/webcore/fetch.zig
  • src/bun.js/bindings/JSGlobalObject.zig
src/**/*.zig

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.zig: Use the # prefix for private fields in Zig structs, e.g., struct { #foo: u32 };
Use Decl literals in Zig, e.g., const decl: Decl = .{ .binding = 0, .value = 0 };
Place @import statements at the bottom of the file in Zig (auto formatter will handle positioning)
Never use @import() inline inside functions in Zig; always place imports at the bottom of the file or containing struct

Files:

  • src/bun.js/webcore/fetch.zig
  • src/bun.js/bindings/JSGlobalObject.zig
🧠 Learnings (65)
📚 Learning: 2025-10-19T04:55:33.099Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: test/js/bun/http/node-telemetry.test.ts:27-203
Timestamp: 2025-10-19T04:55:33.099Z
Learning: In test/js/bun/http/node-telemetry.test.ts and the Bun.telemetry._node_binding API, after the architecture refactor, the _node_binding interface only contains two methods: handleIncomingRequest(req, res) and handleWriteHead(res, statusCode). The handleRequestFinish hook and other lifecycle hooks were removed during simplification. Both current methods are fully tested.

Applied to files:

  • test/js/first_party/undici/undici.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/web/websocket/websocket-proxy.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to test/**/*.test.ts?(x) : Always use `port: 0` in tests - do not hardcode ports or use custom random port number functions

Applied to files:

  • test/js/first_party/undici/undici.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/web/websocket/websocket-proxy.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-10-18T05:23:24.403Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: test/js/bun/telemetry-server.test.ts:91-100
Timestamp: 2025-10-18T05:23:24.403Z
Learning: In the Bun codebase, telemetry tests (test/js/bun/telemetry-*.test.ts) should focus on telemetry API behavior: configure/disable/isEnabled, callback signatures and invocation, request ID correlation, and error handling. HTTP protocol behaviors like status code normalization (e.g., 200 with empty body → 204) should be tested in HTTP server tests (test/js/bun/http/), not in telemetry tests. Keep separation of concerns: telemetry tests verify the telemetry API contract; HTTP tests verify HTTP semantics.

Applied to files:

  • test/js/first_party/undici/undici.test.ts
  • test/js/web/websocket/websocket-proxy.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-09-03T01:30:58.001Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 21728
File: test/js/valkey/valkey.test.ts:264-271
Timestamp: 2025-09-03T01:30:58.001Z
Learning: For test/js/valkey/valkey.test.ts PUB/SUB tests, avoid arbitrary sleeps and async-forEach. Instead, resolve a Promise from the subscriber callback when the expected number of messages is observed and await it with a bounded timeout (e.g., withTimeout + Promise.withResolvers) to account for Redis server→subscriber propagation.

Applied to files:

  • test/js/first_party/undici/undici.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/web/websocket/websocket-proxy.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-09-20T00:57:56.685Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 22568
File: test/js/valkey/valkey.test.ts:268-276
Timestamp: 2025-09-20T00:57:56.685Z
Learning: For test/js/valkey/valkey.test.ts, do not comment on synchronous throw assertions for async Redis methods like ctx.redis.set() - the maintainer has explicitly requested to stop looking at this error pattern.

Applied to files:

  • test/js/first_party/undici/undici.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/web/websocket/websocket-proxy.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
  • src/bun.js/webcore/fetch.zig
📚 Learning: 2025-09-20T00:58:38.042Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 22568
File: test/js/valkey/valkey.test.ts:561-564
Timestamp: 2025-09-20T00:58:38.042Z
Learning: For test/js/valkey/valkey.test.ts, do not comment on synchronous throw assertions for async Redis methods (like ctx.redis.set(), ctx.redis.unsubscribe(), etc.) - Bun's Redis client implementation differs from Node.js and can throw synchronously even for async methods. The maintainer has explicitly requested to stop looking at this error pattern.

Applied to files:

  • test/js/first_party/undici/undici.test.ts
  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/web/websocket/websocket-proxy.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
  • src/bun.js/webcore/fetch.zig
  • src/js/thirdparty/undici.js
📚 Learning: 2025-10-17T20:50:58.644Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 23755
File: src/bun.js/api/bun/socket/Handlers.zig:154-159
Timestamp: 2025-10-17T20:50:58.644Z
Learning: In Bun socket configuration error messages (src/bun.js/api/bun/socket/Handlers.zig), use the user-facing JavaScript names "data" and "drain" instead of internal field names "onData" and "onWritable", as these are the names users see in the API according to SocketConfig.bindv2.ts.

Applied to files:

  • src/js/node/_http_client.ts
  • src/bun.js/webcore/fetch.zig
  • src/js/thirdparty/undici.js
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/test/v8/v8.test.ts : Add corresponding test cases to test/v8/v8.test.ts using checkSameOutput() function to compare Node.js and Bun output

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to **/*.test.ts?(x) : For multi-file tests, prefer `tempDir` and `Bun.spawn` over single-file tests

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-10-19T02:44:46.354Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: packages/bun-otel/context-propagation.test.ts:1-1
Timestamp: 2025-10-19T02:44:46.354Z
Learning: In the Bun repository, standalone packages under packages/ (e.g., bun-vscode, bun-inspector-protocol, bun-plugin-yaml, bun-plugin-svelte, bun-debug-adapter-protocol, bun-otel) co-locate their tests with package source code using *.test.ts files. This follows standard npm/monorepo patterns. The test/ directory hierarchy (test/js/bun/, test/cli/, test/js/node/) is reserved for testing Bun's core runtime APIs and built-in functionality, not standalone packages.

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/web/websocket/websocket-proxy.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Applies to test/**/*.test.{ts,js,jsx,tsx,mjs,cjs} : Use `bun bd test <...test file>` to run tests with compiled code changes. Do not use `bun test` as it will not include your changes.

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/web/websocket/websocket-proxy.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Applies to test/**/*.test.{ts,js,jsx,tsx,mjs,cjs} : Use `bun:test` for files ending in `*.test.{ts,js,jsx,tsx,mjs,cjs}`. For test files without .test extension in test/js/node/test/{parallel,sequential}/*.js, use `bun bd <file>` instead of `bun bd test <file>` since they expect exit code 0.

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/web/websocket/websocket-proxy.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to **/*.test.ts?(x) : When spawning processes in tests, expect stdout before expecting exit code for more useful error messages on test failure

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-10-26T01:32:04.844Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 24082
File: test/cli/test/coverage.test.ts:60-112
Timestamp: 2025-10-26T01:32:04.844Z
Learning: In the Bun repository test files (test/cli/test/*.test.ts), when spawning Bun CLI commands with Bun.spawnSync for testing, prefer using stdio: ["inherit", "inherit", "inherit"] to inherit stdio streams rather than piping them.

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-11-06T00:58:23.965Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 24417
File: test/js/bun/spawn/spawn.test.ts:903-918
Timestamp: 2025-11-06T00:58:23.965Z
Learning: In Bun test files, `await using` with spawn() is appropriate for long-running processes that need guaranteed cleanup on scope exit or when explicitly testing disposal behavior. For short-lived processes that exit naturally (e.g., console.log scripts), the pattern `const proc = spawn(...); await proc.exited;` is standard and more common, as evidenced by 24 instances vs 4 `await using` instances in test/js/bun/spawn/spawn.test.ts.

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to **/*.test.ts?(x) : Never write tests that check for 'panic', 'uncaught exception', or similar strings in test output

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-11-08T04:06:33.198Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 24491
File: test/js/bun/transpiler/declare-global.test.ts:17-17
Timestamp: 2025-11-08T04:06:33.198Z
Learning: In Bun test files, `await using` with Bun.spawn() is the preferred pattern for spawned processes regardless of whether they are short-lived or long-running. Do not suggest replacing `await using proc = Bun.spawn(...)` with `const proc = Bun.spawn(...); await proc.exited;`.

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to **/*.test.ts?(x) : Do not write flaky tests - do not use `setTimeout` in tests; instead await the condition to be met

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Always check exit codes and test error scenarios when spawning processes in tests.

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to **/*.test.ts?(x) : Verify tests fail with `USE_SYSTEM_BUN=1 bun test <file>` and pass with `bun bd test <file>` - tests are invalid if they pass with USE_SYSTEM_BUN=1

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2025-10-25T17:20:19.041Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 24063
File: test/js/bun/telemetry/server-header-injection.test.ts:5-20
Timestamp: 2025-10-25T17:20:19.041Z
Learning: In the Bun telemetry codebase, tests are organized into two distinct layers: (1) Internal API tests in test/js/bun/telemetry/ use numeric InstrumentKind enum values to test Zig↔JS injection points and low-level integration; (2) Public API tests in packages/bun-otel/test/ use string InstrumentKind values ("http", "fetch", etc.) to test the public-facing BunSDK and instrumentation APIs. This separation allows internal tests to use efficient numeric enums for refactoring flexibility while the public API maintains a developer-friendly string-based interface.

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/web/websocket/websocket-proxy.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Organize unit tests by module in directories like `/test/js/bun/` and `/test/js/node/`.

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/web/websocket/websocket-proxy.test.ts
📚 Learning: 2025-10-30T03:48:10.513Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 24063
File: packages/bun-otel/test/context-propagation.test.ts:1-7
Timestamp: 2025-10-30T03:48:10.513Z
Learning: In Bun test files, `using` declarations at the describe block level execute during module load/parsing, not during test execution. This means they acquire and dispose resources before any tests run. For test-scoped resource management, use beforeAll/afterAll hooks instead. The pattern `beforeAll(beforeUsingEchoServer); afterAll(afterUsingEchoServer);` is correct for managing ref-counted test resources like the EchoServer in packages/bun-otel/test/ - the using block pattern should not be used at describe-block level for test resources.
<!-- [/add_learning]

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/web/websocket/websocket-proxy.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Ensure V8 API tests compare identical C++ code output between Node.js and Bun through the test suite validation process

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to src/bun.js/bindings/**/*.cpp : Cache structures in ZigGlobalObject for JavaScript class bindings

Applied to files:

  • src/bun.js/bindings/bindings.cpp
  • src/bun.js/bindings/webcore/JSWebSocket.cpp
  • src/js/thirdparty/undici.js
  • src/bun.js/bindings/JSGlobalObject.zig
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/src/napi/napi.zig : For each new V8 C++ method, add both GCC/Clang and MSVC mangled symbol names to the V8API struct in src/napi/napi.zig using extern fn declarations

Applied to files:

  • src/bun.js/bindings/bindings.cpp
  • src/bun.js/bindings/webcore/JSWebSocket.cpp
  • src/bun.js/bindings/JSGlobalObject.zig
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/test/v8/v8-module/main.cpp : Register new V8 API test functions in the Init method using NODE_SET_METHOD with exports object

Applied to files:

  • src/bun.js/bindings/bindings.cpp
  • src/bun.js/bindings/JSGlobalObject.zig
📚 Learning: 2025-11-24T18:37:47.899Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/AGENTS.md:0-0
Timestamp: 2025-11-24T18:37:47.899Z
Learning: Applies to src/bun.js/bindings/v8/**/<UNKNOWN> : <UNKNOWN>

Applied to files:

  • src/bun.js/bindings/bindings.cpp
  • src/js/thirdparty/undici.js
  • src/bun.js/bindings/JSGlobalObject.zig
📚 Learning: 2025-10-11T15:19:30.301Z
Learnt from: mastermakrela
Repo: oven-sh/bun PR: 19167
File: src/bun.js/api.zig:31-31
Timestamp: 2025-10-11T15:19:30.301Z
Learning: The learnings about `pub const js = JSC.Codegen.JS<ClassName>` and re-exporting toJS/fromJS/fromJSDirect apply to class-based Zig bindings with constructors and prototype methods (e.g., those with `new` constructors). They do NOT apply to simple namespace-style API objects like TOMLObject, YAMLObject, and CSVObject which expose static functions via a `create()` method that returns a plain JS object.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
  • src/bun.js/bindings/webcore/JSWebSocket.cpp
  • src/bun.js/bindings/JSGlobalObject.zig
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/src/symbols.txt : Add symbol names without leading underscore to src/symbols.txt for each new V8 API method

Applied to files:

  • src/bun.js/bindings/bindings.cpp
  • src/bun.js/bindings/JSGlobalObject.zig
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/src/symbols.dyn : Add symbol names with leading underscore and semicolons in braces to src/symbols.dyn for each new V8 API method

Applied to files:

  • src/bun.js/bindings/bindings.cpp
  • src/bun.js/bindings/JSGlobalObject.zig
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to src/bun.js/bindings/**/*.cpp : Add iso subspaces for C++ classes with fields in JavaScript class bindings

Applied to files:

  • src/bun.js/bindings/bindings.cpp
  • src/bun.js/bindings/webcore/JSWebSocket.cpp
📚 Learning: 2025-10-01T21:59:54.571Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 23169
File: src/bun.js/bindings/webcore/JSDOMConvertEnumeration.h:47-74
Timestamp: 2025-10-01T21:59:54.571Z
Learning: In the new bindings generator (bindgenv2) for `src/bun.js/bindings/webcore/JSDOMConvertEnumeration.h`, the context-aware enumeration conversion overloads intentionally use stricter validation (requiring `value.isString()` without ToString coercion), diverging from Web IDL semantics. This is a design decision documented in comments.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
  • src/bun.js/bindings/webcore/JSWebSocket.cpp
  • src/js/thirdparty/undici.js
  • src/bun.js/bindings/JSGlobalObject.zig
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.h : Add BUN_EXPORT visibility attribute to all public V8 API functions to ensure proper symbol export across platforms

Applied to files:

  • src/bun.js/bindings/bindings.cpp
  • src/bun.js/bindings/JSGlobalObject.zig
📚 Learning: 2025-11-03T20:40:59.655Z
Learnt from: pfgithub
Repo: oven-sh/bun PR: 24273
File: src/bun.js/bindings/JSValue.zig:545-586
Timestamp: 2025-11-03T20:40:59.655Z
Learning: In Bun's Zig codebase, JSErrors (returned as `bun.JSError!T`) must always be properly handled. Using `catch continue` or `catch { break; }` to silently suppress JSErrors is a bug. Errors should either be explicitly handled or propagated with `try`. This applies to snapshot serializer error handling where Jest's behavior is to throw when serializers throw.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-09-05T19:49:26.188Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 21728
File: src/valkey/js_valkey_functions.zig:852-867
Timestamp: 2025-09-05T19:49:26.188Z
Learning: In Bun’s Zig code, `.js_undefined` is a valid and preferred JSValue literal for “undefined” (e.g., resolving JSPromise). Do not refactor usages to `jsc.JSValue.jsUndefined()`, especially in src/valkey/js_valkey_functions.zig unsubscribe().

Applied to files:

  • src/bun.js/bindings/bindings.cpp
  • src/bun.js/webcore/fetch.zig
  • src/bun.js/bindings/JSGlobalObject.zig
📚 Learning: 2025-11-03T20:43:06.996Z
Learnt from: pfgithub
Repo: oven-sh/bun PR: 24273
File: src/bun.js/test/snapshot.zig:19-19
Timestamp: 2025-11-03T20:43:06.996Z
Learning: In Bun's Zig codebase, when storing JSValue objects in collections like ArrayList, use `jsc.Strong.Optional` (not raw JSValue). When adding values, wrap them with `jsc.Strong.Optional.create(value, globalThis)`. In cleanup code, iterate the collection calling `.deinit()` on each Strong.Optional item before calling `.deinit()` on the ArrayList itself. This pattern automatically handles GC protection. See examples in src/bun.js/test/ScopeFunctions.zig and src/bun.js/node/node_cluster_binding.zig.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
  • src/bun.js/webcore/fetch.zig
  • src/bun.js/bindings/JSGlobalObject.zig
📚 Learning: 2025-09-05T19:49:26.188Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 21728
File: src/valkey/js_valkey_functions.zig:852-867
Timestamp: 2025-09-05T19:49:26.188Z
Learning: In Bun's Zig codebase, `.js_undefined` is a valid way to represent JavaScript's undefined value when working with JSPromise.resolve() and similar JavaScript interop functions. This is the correct pattern to use rather than `jsc.JSValue.jsUndefined()`.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-09-02T18:09:21.647Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 22227
File: src/allocators/allocation_scope.zig:79-85
Timestamp: 2025-09-02T18:09:21.647Z
Learning: In Bun's Zig codebase, prefer simple, direct error handling patterns. When an error type has only one variant (like FreeError with only NotAllocated), use a switch statement rather than generic catch blocks to leverage compile-time knowledge and avoid unnecessary complexity. Avoid duplicating function calls across error paths when a cleaner structure is possible.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2026-01-05T16:32:15.175Z
Learnt from: alii
Repo: oven-sh/bun PR: 25474
File: src/bun.js/event_loop/Sigusr1Handler.zig:0-0
Timestamp: 2026-01-05T16:32:15.175Z
Learning: In Bun's Zig codebase, std.posix.sigaction returns void (not an error union) and should be called without error handling. The Zig standard library treats sigaction failures as programmer errors (unreachable) since they only occur with invalid signals like SIGKILL/SIGSTOP. This pattern is used consistently across crash_handler.zig, main.zig, filter_run.zig, and process.zig.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-12-23T06:50:41.142Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 25429
File: src/bun.js/bindings/helpers.h:422-422
Timestamp: 2025-12-23T06:50:41.142Z
Learning: In Bun's C++ bindings (src/bun.js/bindings/helpers.h and similar files), when returning an empty JSC::Identifier and a VM is accessible, prefer using `vm.propertyNames->emptyIdentifier` over constructing with `JSC::Identifier(JSC::Identifier::EmptyIdentifierFlag::EmptyIdentifier)`. The cached identifier from the VM's property names table is more efficient and consistent with WebKit upgrade patterns.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
  • src/bun.js/webcore/fetch.zig
  • src/bun.js/bindings/JSGlobalObject.zig
📚 Learning: 2025-10-18T20:50:47.750Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: src/bun.js/telemetry.zig:366-373
Timestamp: 2025-10-18T20:50:47.750Z
Learning: In Bun's Zig codebase (src/bun.js/bindings/JSValue.zig), the JSValue enum uses `.null` (not `.js_null`) for JavaScript's null value. Only `js_undefined` has the `js_` prefix to avoid collision with Zig's built-in `undefined` keyword. The correct enum fields are: `js_undefined`, `null`, `true`, `false`, and `zero`.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
  • src/bun.js/webcore/fetch.zig
  • src/bun.js/bindings/JSGlobalObject.zig
📚 Learning: 2025-10-20T01:38:02.660Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: packages/bun-otel/BunFetchInstrumentation.ts:126-131
Timestamp: 2025-10-20T01:38:02.660Z
Learning: In BunFetchInstrumentation.ts, the force-restore to ORIGINAL_FETCH in the disable() method is intentionally kept (despite appearing unsafe) because it's required for proper test cleanup when instrumentation is repeatedly enabled/disabled. Without it, 15 distributed tracing and context propagation tests fail. Shimmer's unwrap() doesn't reliably restore the original fetch in Bun's globalThis context. The isBunOtelPatched safety check ensures the restore only happens when the current fetch is still ours, preventing clobbering of other tools' wrappers.

Applied to files:

  • test/js/web/websocket/websocket-proxy.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
  • src/bun.js/webcore/fetch.zig
  • src/js/thirdparty/undici.js
📚 Learning: 2025-09-20T03:39:41.770Z
Learnt from: pfgithub
Repo: oven-sh/bun PR: 22534
File: test/regression/issue/21830.fixture.ts:14-63
Timestamp: 2025-09-20T03:39:41.770Z
Learning: Bun's test runner supports async describe callbacks, unlike Jest/Vitest where describe callbacks must be synchronous. The syntax `describe("name", async () => { ... })` is valid in Bun.

Applied to files:

  • test/js/web/websocket/websocket-proxy.test.ts
📚 Learning: 2025-10-08T13:48:02.430Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 23373
File: test/js/bun/tarball/extract.test.ts:107-111
Timestamp: 2025-10-08T13:48:02.430Z
Learning: In Bun's test runner, use `expect(async () => { await ... }).toThrow()` to assert async rejections. Unlike Jest/Vitest, Bun does not require `await expect(...).rejects.toThrow()` - the async function wrapper with `.toThrow()` is the correct pattern for async error assertions in Bun tests.

Applied to files:

  • test/js/web/websocket/websocket-proxy.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: When spawning Bun processes in tests, use `bunExe` and `bunEnv` from `harness` to ensure the same build of Bun is used and debug logging is silenced.

Applied to files:

  • test/js/web/websocket/websocket-proxy.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to **/*.test.ts?(x) : Never use `bun test` directly - always use `bun bd test` to run tests with debug build changes

Applied to files:

  • test/js/web/websocket/websocket-proxy.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Prefer async/await over callbacks in tests. When callbacks must be used for a single callback, use `Promise.withResolvers` to create a promise that can be resolved or rejected from a callback.

Applied to files:

  • test/js/web/websocket/websocket-proxy.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Applies to test/**/*.test.{ts,js,jsx,tsx,mjs,cjs} : Do not set a timeout on tests. Bun already has timeouts built-in.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Prefer concurrent tests over sequential tests. Use `test.concurrent` or `describe.concurrent` when multiple tests spawn processes or write files, unless it is very difficult to make them concurrent.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to **/*.test.ts?(x) : For single-file tests, prefer `-e` flag over `tempDir`

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-11-24T18:37:11.466Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/js/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:37:11.466Z
Learning: Applies to src/js/{builtins,node,bun,thirdparty,internal}/**/*.{ts,js} : Use `$debug()` for debug logging and `$assert()` for assertions; both are stripped in release builds

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to **/*.test.ts?(x) : Avoid shell commands like `find` or `grep` in tests - use Bun's Glob and built-in tools instead

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-09-02T05:33:37.517Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 22323
File: test/js/web/websocket/websocket-subprotocol.test.ts:74-75
Timestamp: 2025-09-02T05:33:37.517Z
Learning: In Bun's runtime, `await using` with Node.js APIs like `net.createServer()` is properly supported and should not be replaced with explicit cleanup. Bun has extended Node.js APIs with proper async dispose support.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • src/js/thirdparty/undici.js
📚 Learning: 2025-09-05T18:45:29.200Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 21728
File: src/valkey/js_valkey.zig:0-0
Timestamp: 2025-09-05T18:45:29.200Z
Learning: In JSValkeyClient.cloneWithoutConnecting() in src/valkey/js_valkey.zig, the address/username/password fields must be repointed to the duplicated connection_strings buffer to avoid use-after-free when the original client is destroyed. The original client properly frees connection_strings in ValkeyClient.deinit().

Applied to files:

  • src/bun.js/webcore/fetch.zig
  • src/js/thirdparty/undici.js
📚 Learning: 2025-10-01T21:49:27.862Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 23169
File: src/bun.js/bindings/BunIDLConvert.h:29-42
Timestamp: 2025-10-01T21:49:27.862Z
Learning: In Bun's IDL bindings (src/bun.js/bindings/BunIDLConvert.h), IDLStrictNull intentionally treats both undefined and null as null (using isUndefinedOrNull()), matching WebKit's IDLNull & IDLNullable behavior. This is the correct implementation and should not be changed to only accept null.

Applied to files:

  • src/bun.js/webcore/fetch.zig
📚 Learning: 2025-09-06T03:37:41.154Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 22229
File: src/bundler/LinkerGraph.zig:0-0
Timestamp: 2025-09-06T03:37:41.154Z
Learning: In Bun's codebase, when checking import record source indices in src/bundler/LinkerGraph.zig, prefer using `if (import_index >= self.import_records.len)` bounds checking over `isValid()` checks, as the bounds check is more robust and `isValid()` is a strict subset of this condition.

Applied to files:

  • src/bun.js/webcore/fetch.zig
📚 Learning: 2025-10-18T20:59:45.579Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: src/bun.js/telemetry.zig:458-475
Timestamp: 2025-10-18T20:59:45.579Z
Learning: In src/bun.js/telemetry.zig, the RequestId (u64) to JavaScript number (f64) conversion in jsRequestId() is intentionally allowed to lose precision beyond 2^53-1. This is acceptable because: (1) at 1M requests/sec it takes ~285 years to overflow, (2) the counter resets per-process, and (3) these are observability IDs, not critical distributed IDs. Precision loss is an acceptable trade-off for this use case.

Applied to files:

  • src/bun.js/webcore/fetch.zig
📚 Learning: 2026-01-05T16:32:07.551Z
Learnt from: alii
Repo: oven-sh/bun PR: 25474
File: src/bun.js/event_loop/Sigusr1Handler.zig:0-0
Timestamp: 2026-01-05T16:32:07.551Z
Learning: In Zig codebases (e.g., Bun), treat std.posix.sigaction as returning void and do not perform runtime error handling for its failure. The Zig standard library views sigaction failures as programmer errors (unreachable) because they only occur with invalid signals like SIGKILL/SIGSTOP. Apply this pattern across Zig files that call sigaction (e.g., crash_handler.zig, main.zig, filter_run.zig, process.zig) and ensure failures are not handled as recoverable errors; prefer reaching an explicit unreachable/compile-time assumption when such failures are detected.

Applied to files:

  • src/bun.js/webcore/fetch.zig
  • src/bun.js/bindings/JSGlobalObject.zig
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to src/bun.js/bindings/**/*.cpp : Create classes in three parts in C++ when there is a public constructor: Foo (JSDestructibleObject), FooPrototype (JSNonFinalObject), and FooConstructor (InternalFunction)

Applied to files:

  • src/bun.js/bindings/webcore/JSWebSocket.cpp
  • src/js/thirdparty/undici.js
📚 Learning: 2025-11-14T16:07:01.064Z
Learnt from: RiskyMH
Repo: oven-sh/bun PR: 24719
File: docs/bundler/executables.mdx:527-560
Timestamp: 2025-11-14T16:07:01.064Z
Learning: In the Bun repository, certain bundler features like compile with code splitting (--compile --splitting) are CLI-only and not supported in the Bun.build() JavaScript API. Tests for CLI-only features use backend: "cli" flag (e.g., test/bundler/bundler_compile_splitting.test.ts). The CompileBuildConfig interface correctly restricts these with splitting?: never;. When documenting CLI-only bundler features, add a note clarifying they're not available via the programmatic API.

Applied to files:

  • src/js/thirdparty/undici.js
📚 Learning: 2025-11-24T18:37:11.466Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/js/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:37:11.466Z
Learning: Write JS builtins for Bun's Node.js compatibility and APIs, and run `bun bd` after changes

Applied to files:

  • src/js/thirdparty/undici.js
📚 Learning: 2025-11-24T18:37:11.466Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/js/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:37:11.466Z
Learning: Applies to src/js/{builtins,node,bun,thirdparty,internal}/**/*.{ts,js} : Use private globals and methods with `$` prefix (e.g., `$Array`, `map.$set()`) instead of public JavaScript globals

Applied to files:

  • src/bun.js/bindings/JSGlobalObject.zig
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.cpp : Use localToJSValue() to convert V8 handles to JSC values and perform JSC operations within V8 method implementations

Applied to files:

  • src/bun.js/bindings/JSGlobalObject.zig
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.cpp : Use JSC::WriteBarrier for heap-allocated references in V8 objects and implement visitChildren() for custom heap objects to support garbage collection

Applied to files:

  • src/bun.js/bindings/JSGlobalObject.zig
🧬 Code graph analysis (5)
test/js/first_party/undici/undici.test.ts (1)
src/js/node/_http_client.ts (2)
  • agent (1049-1051)
  • agent (1053-1055)
src/js/node/_http_client.ts (1)
src/js/internal/tls.ts (1)
  • isValidTLSArray (53-53)
test/js/first_party/undici/undici-properties.test.ts (1)
test/harness.ts (1)
  • tempDir (277-284)
test/js/web/websocket/websocket-proxy.test.ts (1)
src/bun.js/bindings/webcore/WebSocket.cpp (2)
  • WebSocket (180-188)
  • WebSocket (190-224)
test/js/node/tls/globalAgent-tls-options.test.ts (1)
test/harness.ts (1)
  • tempDir (277-284)
🔇 Additional comments (10)
src/bun.js/bindings/JSGlobalObject.zig (1)

803-809: Binding wrapper looks correct; confirm the extern never throws.

getHttpsGlobalAgent() is consistent (marks binding, delegates). If JSC__JSGlobalObject__getHttpsGlobalAgent() can ever raise a JS exception, this wrapper should use bun.jsc.fromJSHostCall(...) to ensure proper propagation/handling instead of returning an arbitrary JSValue.

test/js/web/websocket/websocket-proxy.test.ts (2)

913-936: Global agent state restore is correct (preserves object identity).

Good call mutating https.globalAgent.options instead of replacing it, which avoids breaking consumers holding the original reference.


1007-1037: Potential flake: TLS failure may surface as close-only in some implementations.

The “fails without globalAgent TLS options” case assumes an error event must fire. If this flakes on a platform/engine path, consider allowing either:

  • error event, or
  • close without open (and no messages), with a stronger assertion that onopen never fired.
src/bun.js/bindings/webcore/JSWebSocket.cpp (1)

272-306: Wiring fallback into ctor paths is good; keep precedence consistent with 3-arg path.

Calling applyGlobalAgentFallback() in the 1/2-arg constructors closes the feature gap nicely, and doing it in the 3-arg path after parsing explicit options matches the intended precedence. Once the TLS gating issue above is fixed, this should behave consistently across all constructor overloads.

Also applies to: 313-350, 582-599

src/js/thirdparty/undici.js (1)

9-18: Global-dispatcher fetch wrapper is reasonable; verify null handling matches undici.

You only apply globalDispatcher when init.dispatcher === undefined && init.agent === undefined. If callers pass dispatcher: null (or agent: null), they won’t get the global fallback. Please confirm that matches the intended undici compatibility expectations (undefined vs null).

src/bun.js/webcore/fetch.zig (5)

159-170: LGTM! Lightweight TLS property detection.

The function appropriately checks for presence of TLS properties without deep type validation. Type validation is handled downstream in SSLConfig.fromJS, keeping this helper fast and focused.


271-314: Excellent documentation and proper memory management.

The detailed comment on line 272 about check_server_identity being safe as an unprotected JSValue is exemplary documentation. The explanation is correct—the value is used synchronously and immediately promoted to a Strong reference at line 1645.

Memory management is sound:

  • ssl_config is heap-allocated only when SSLConfig.fromJS succeeds
  • Caller owns cleanup via the defer block at lines 416-420
  • No leak paths exist

639-660: TLS fallback logic correctly implements the resolution priority.

The fallback runs only when no explicit TLS configuration is provided, properly checking for null before proceeding. Error handling is correct, and all extracted settings are applied conditionally based on their presence.

Resolution order: per-request tls option → agent TLS options → global agent TLS options.


914-974: Proxy fallback with nested TLS extraction is correctly implemented.

The logic properly handles both string and object proxy formats, and the nested TLS extraction (lines 956-972) correctly runs only when:

  1. No explicit proxy was provided (proxy == null at line 916)
  2. An agent/dispatcher with a proxy is found
  3. No TLS config has been set yet (ssl_config == null at line 956)

This ensures per-agent TLS settings are inherited when using an agent's proxy, maintaining the correct resolution priority: per-request options → agent-specific settings → global agent settings.

Memory management is sound: old url_proxy_buffer is freed (line 951) before the new buffer is assigned (line 952).


172-269: Well-structured agent resolution with proper fallback chain.

The priority order (agent.optionsagent.connectOptsagent.connecthttps.globalAgent) correctly implements the resolution strategy. The connectOpts fallback ensures compatibility with libraries like https-proxy-agent. The getHttpsGlobalAgent() binding is properly exported from JSGlobalObject.zig and integrated across the codebase.

… feedback

- Use clearExceptionExceptTermination() to preserve termination exceptions
- Reuse Identifier for globalAgent lookup instead of constructing twice
- Pass full TLS source object to SSLConfig.fromJS instead of building
  filtered object - the parser extracts only properties it needs
- Split combined condition (rejectUnauthorized == -1 && !sslConfig) into
  separate paths so each can be extracted independently
- Treat null as undefined in getAgentTlsOption fallback chain
- Use primordial ObjectDefineProperty in undici.js
- Hoist undici imports to describe level and share connectOpts in tests
- Add ca assertions for Pool and Client tests
- Remove brittle stderr regex assertions from TLS tests
- Convert undici-properties test to use -e flag instead of tempDir
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 9, 2026

@cirospaciari: I'll review the current code changes in this PR, focusing on the implementation details.


🧠 Learnings used
Learnt from: cirospaciari
Repo: oven-sh/bun PR: 24607
File: packages/bun-usockets/src/crypto/root_certs.h:3589-3618
Timestamp: 2025-11-11T22:08:38.015Z
Learning: For PRs that update certificate data (e.g., packages/bun-usockets/src/crypto/root_certs.h or packages/bun-usockets/certdata.txt), treat these files as generated artifacts and avoid review comments unless there is a clear build/runtime breakage.
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/js/node/_http_client.ts (1)

744-846: Fix option “presence” checks to avoid treating empty strings as “unset”.

Several TLS options use truthiness checks (if (options.ca), if (options.passphrase), if (options.servername), etc.). This will skip intentionally-provided empty strings and then incorrectly fall back to agent-derived values.

Proposed fix
-  if (options.ca) {
+  if (options.ca !== undefined) {
     if (!isValidTLSArray(options.ca))
       throw new TypeError(
         "ca argument must be an string, Buffer, TypedArray, BunFile or an array containing string, Buffer, TypedArray or BunFile",
       );
     this._ensureTls().ca = options.ca;
   } else {
     const agentCa = getAgentTlsOption(agent, "ca");
     if (agentCa !== undefined) {
       if (!isValidTLSArray(agentCa))
         throw new TypeError(
           "agent TLS ca option must be a string, Buffer, TypedArray, BunFile or an array containing string, Buffer, TypedArray or BunFile",
         );
       this._ensureTls().ca = agentCa;
     }
   }

-  if (options.cert) {
+  if (options.cert !== undefined) {
     if (!isValidTLSArray(options.cert))
       throw new TypeError(
         "cert argument must be an string, Buffer, TypedArray, BunFile or an array containing string, Buffer, TypedArray or BunFile",
       );
     this._ensureTls().cert = options.cert;
   } else {
     const agentCert = getAgentTlsOption(agent, "cert");
     if (agentCert !== undefined) {
       if (!isValidTLSArray(agentCert))
         throw new TypeError(
           "agent TLS cert option must be a string, Buffer, TypedArray, BunFile or an array containing string, Buffer, TypedArray or BunFile",
         );
       this._ensureTls().cert = agentCert;
     }
   }

-  if (options.key) {
+  if (options.key !== undefined) {
     if (!isValidTLSArray(options.key))
       throw new TypeError(
         "key argument must be an string, Buffer, TypedArray, BunFile or an array containing string, Buffer, TypedArray or BunFile",
       );
     this._ensureTls().key = options.key;
   } else {
     const agentKey = getAgentTlsOption(agent, "key");
     if (agentKey !== undefined) {
       if (!isValidTLSArray(agentKey))
         throw new TypeError(
           "agent TLS key option must be a string, Buffer, TypedArray, BunFile or an array containing string, Buffer, TypedArray or BunFile",
         );
       this._ensureTls().key = agentKey;
     }
   }

-  if (options.passphrase) {
+  if (options.passphrase !== undefined) {
     if (typeof options.passphrase !== "string") throw new TypeError("passphrase argument must be a string");
     this._ensureTls().passphrase = options.passphrase;
   } else {
     const agentPassphrase = getAgentTlsOption(agent, "passphrase");
     if (agentPassphrase !== undefined) {
       if (typeof agentPassphrase !== "string") throw new TypeError("agent TLS passphrase option must be a string");
       this._ensureTls().passphrase = agentPassphrase;
     }
   }

-  if (options.ciphers) {
+  if (options.ciphers !== undefined) {
     if (typeof options.ciphers !== "string") throw new TypeError("ciphers argument must be a string");
     this._ensureTls().ciphers = options.ciphers;
   } else {
     const agentCiphers = getAgentTlsOption(agent, "ciphers");
     if (agentCiphers !== undefined) {
       if (typeof agentCiphers !== "string") throw new TypeError("agent TLS ciphers option must be a string");
       this._ensureTls().ciphers = agentCiphers;
     }
   }

-  if (options.servername) {
+  if (options.servername !== undefined) {
     if (typeof options.servername !== "string") throw new TypeError("servername argument must be a string");
     this._ensureTls().servername = options.servername;
   } else {
     const agentServername = getAgentTlsOption(agent, "servername");
     if (agentServername !== undefined) {
       if (typeof agentServername !== "string") throw new TypeError("agent TLS servername option must be a string");
       this._ensureTls().servername = agentServername;
     }
   }
🤖 Fix all issues with AI agents
In @src/bun.js/bindings/bindings.cpp:
- Around line 6125-6150: In JSC__JSGlobalObject__getHttpsGlobalAgent ensure you
return undefined immediately when a non-termination exception was cleared so you
never use JSValues created under an exception: after the requireId(...) call, if
catchScope.exception() and clearExceptionExceptTermination() returns true,
immediately return JSValue::encode(jsUndefined()); do the same after the
get(...) call (i.e. check catchScope.exception() and return jsUndefined() if
clearExceptionExceptTermination() cleared a non-termination exception) so
httpsModule or globalAgent are never used when an exception was pending.

In @test/js/first_party/undici/undici-properties.test.ts:
- Around line 114-125: Add a stderr diagnostic when the spawned process fails:
after awaiting proc.stdout, proc.stderr, and proc.exited (variables stdout,
stderr, exitCode) insert a conditional like if (exitCode !== 0)
console.error("Test stderr:", stderr); before the existing
expect(exitCode).toBe(0) so test failures print the child process stderr for
easier debugging.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 995569e and d5adb06.

📒 Files selected for processing (7)
  • src/bun.js/bindings/bindings.cpp
  • src/bun.js/bindings/webcore/JSWebSocket.cpp
  • src/js/node/_http_client.ts
  • src/js/thirdparty/undici.js
  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/first_party/undici/undici.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
🧰 Additional context used
📓 Path-based instructions (6)
src/js/{builtins,node,bun,thirdparty,internal}/**/*.{ts,js}

📄 CodeRabbit inference engine (src/js/CLAUDE.md)

src/js/{builtins,node,bun,thirdparty,internal}/**/*.{ts,js}: Use .$call() and .$apply() instead of .call() and .apply() to prevent user tampering with function invocation
Use string literal require() statements only; dynamic requires are not permitted
Export modules using export default { ... } syntax; modules are NOT ES modules
Use JSC intrinsics (prefixed with $) such as $Array.from(), $isCallable(), and $newArrayWithSize() for performance-critical operations
Use private globals and methods with $ prefix (e.g., $Array, map.$set()) instead of public JavaScript globals
Use $debug() for debug logging and $assert() for assertions; both are stripped in release builds
Validate function arguments using validators from internal/validators and throw $ERR_* error codes for invalid arguments
Use process.platform and process.arch for platform detection; these values are inlined and dead-code eliminated at build time

Files:

  • src/js/node/_http_client.ts
  • src/js/thirdparty/undici.js
src/js/{builtins,node,bun,thirdparty,internal}/**/*.ts

📄 CodeRabbit inference engine (src/js/CLAUDE.md)

Builtin functions must include this parameter typing in TypeScript to enable direct method binding in C++

Files:

  • src/js/node/_http_client.ts
**/*.test.ts?(x)

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.test.ts?(x): Never use bun test directly - always use bun bd test to run tests with debug build changes
For single-file tests, prefer -e flag over tempDir
For multi-file tests, prefer tempDir and Bun.spawn over single-file tests
Use normalizeBunSnapshot to normalize snapshot output of tests
Never write tests that check for 'panic', 'uncaught exception', or similar strings in test output
Use tempDir from harness to create temporary directories - do not use tmpdirSync or fs.mkdtempSync
When spawning processes in tests, expect stdout before expecting exit code for more useful error messages on test failure
Do not write flaky tests - do not use setTimeout in tests; instead await the condition to be met
Verify tests fail with USE_SYSTEM_BUN=1 bun test <file> and pass with bun bd test <file> - tests are invalid if they pass with USE_SYSTEM_BUN=1
Test files must end with .test.ts or .test.tsx
Avoid shell commands like find or grep in tests - use Bun's Glob and built-in tools instead

Files:

  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/first_party/undici/undici.test.ts
test/**/*.test.ts?(x)

📄 CodeRabbit inference engine (CLAUDE.md)

Always use port: 0 in tests - do not hardcode ports or use custom random port number functions

Files:

  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/first_party/undici/undici.test.ts
test/**/*.test.{ts,js,jsx,tsx,mjs,cjs}

📄 CodeRabbit inference engine (test/CLAUDE.md)

test/**/*.test.{ts,js,jsx,tsx,mjs,cjs}: Use bun bd test <...test file> to run tests with compiled code changes. Do not use bun test as it will not include your changes.
Use bun:test for files ending in *.test.{ts,js,jsx,tsx,mjs,cjs}. For test files without .test extension in test/js/node/test/{parallel,sequential}/*.js, use bun bd <file> instead of bun bd test <file> since they expect exit code 0.
Do not set a timeout on tests. Bun already has timeouts built-in.

Files:

  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/first_party/undici/undici.test.ts
src/bun.js/bindings/**/*.cpp

📄 CodeRabbit inference engine (CLAUDE.md)

src/bun.js/bindings/**/*.cpp: Create classes in three parts in C++ when there is a public constructor: Foo (JSDestructibleObject), FooPrototype (JSNonFinalObject), and FooConstructor (InternalFunction)
Define properties using HashTableValue arrays in C++ JavaScript class bindings
Add iso subspaces for C++ classes with fields in JavaScript class bindings
Cache structures in ZigGlobalObject for JavaScript class bindings

Files:

  • src/bun.js/bindings/webcore/JSWebSocket.cpp
  • src/bun.js/bindings/bindings.cpp
🧠 Learnings (63)
📚 Learning: 2025-10-17T20:50:58.644Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 23755
File: src/bun.js/api/bun/socket/Handlers.zig:154-159
Timestamp: 2025-10-17T20:50:58.644Z
Learning: In Bun socket configuration error messages (src/bun.js/api/bun/socket/Handlers.zig), use the user-facing JavaScript names "data" and "drain" instead of internal field names "onData" and "onWritable", as these are the names users see in the API according to SocketConfig.bindv2.ts.

Applied to files:

  • src/js/node/_http_client.ts
  • src/js/thirdparty/undici.js
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/test/v8/v8.test.ts : Add corresponding test cases to test/v8/v8.test.ts using checkSameOutput() function to compare Node.js and Bun output

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to **/*.test.ts?(x) : For multi-file tests, prefer `tempDir` and `Bun.spawn` over single-file tests

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to test/**/*.test.ts?(x) : Always use `port: 0` in tests - do not hardcode ports or use custom random port number functions

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/first_party/undici/undici.test.ts
📚 Learning: 2025-09-20T00:58:38.042Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 22568
File: test/js/valkey/valkey.test.ts:561-564
Timestamp: 2025-09-20T00:58:38.042Z
Learning: For test/js/valkey/valkey.test.ts, do not comment on synchronous throw assertions for async Redis methods (like ctx.redis.set(), ctx.redis.unsubscribe(), etc.) - Bun's Redis client implementation differs from Node.js and can throw synchronously even for async methods. The maintainer has explicitly requested to stop looking at this error pattern.

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/first_party/undici/undici.test.ts
  • src/js/thirdparty/undici.js
📚 Learning: 2025-10-19T02:44:46.354Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: packages/bun-otel/context-propagation.test.ts:1-1
Timestamp: 2025-10-19T02:44:46.354Z
Learning: In the Bun repository, standalone packages under packages/ (e.g., bun-vscode, bun-inspector-protocol, bun-plugin-yaml, bun-plugin-svelte, bun-debug-adapter-protocol, bun-otel) co-locate their tests with package source code using *.test.ts files. This follows standard npm/monorepo patterns. The test/ directory hierarchy (test/js/bun/, test/cli/, test/js/node/) is reserved for testing Bun's core runtime APIs and built-in functionality, not standalone packages.

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-09-20T00:57:56.685Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 22568
File: test/js/valkey/valkey.test.ts:268-276
Timestamp: 2025-09-20T00:57:56.685Z
Learning: For test/js/valkey/valkey.test.ts, do not comment on synchronous throw assertions for async Redis methods like ctx.redis.set() - the maintainer has explicitly requested to stop looking at this error pattern.

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/first_party/undici/undici.test.ts
📚 Learning: 2025-10-19T04:55:33.099Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: test/js/bun/http/node-telemetry.test.ts:27-203
Timestamp: 2025-10-19T04:55:33.099Z
Learning: In test/js/bun/http/node-telemetry.test.ts and the Bun.telemetry._node_binding API, after the architecture refactor, the _node_binding interface only contains two methods: handleIncomingRequest(req, res) and handleWriteHead(res, statusCode). The handleRequestFinish hook and other lifecycle hooks were removed during simplification. Both current methods are fully tested.

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/first_party/undici/undici.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Applies to test/**/*.test.{ts,js,jsx,tsx,mjs,cjs} : Use `bun bd test <...test file>` to run tests with compiled code changes. Do not use `bun test` as it will not include your changes.

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Applies to test/**/*.test.{ts,js,jsx,tsx,mjs,cjs} : Use `bun:test` for files ending in `*.test.{ts,js,jsx,tsx,mjs,cjs}`. For test files without .test extension in test/js/node/test/{parallel,sequential}/*.js, use `bun bd <file>` instead of `bun bd test <file>` since they expect exit code 0.

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to **/*.test.ts?(x) : When spawning processes in tests, expect stdout before expecting exit code for more useful error messages on test failure

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-10-26T01:32:04.844Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 24082
File: test/cli/test/coverage.test.ts:60-112
Timestamp: 2025-10-26T01:32:04.844Z
Learning: In the Bun repository test files (test/cli/test/*.test.ts), when spawning Bun CLI commands with Bun.spawnSync for testing, prefer using stdio: ["inherit", "inherit", "inherit"] to inherit stdio streams rather than piping them.

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-11-06T00:58:23.965Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 24417
File: test/js/bun/spawn/spawn.test.ts:903-918
Timestamp: 2025-11-06T00:58:23.965Z
Learning: In Bun test files, `await using` with spawn() is appropriate for long-running processes that need guaranteed cleanup on scope exit or when explicitly testing disposal behavior. For short-lived processes that exit naturally (e.g., console.log scripts), the pattern `const proc = spawn(...); await proc.exited;` is standard and more common, as evidenced by 24 instances vs 4 `await using` instances in test/js/bun/spawn/spawn.test.ts.

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to **/*.test.ts?(x) : Never write tests that check for 'panic', 'uncaught exception', or similar strings in test output

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-11-08T04:06:33.198Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 24491
File: test/js/bun/transpiler/declare-global.test.ts:17-17
Timestamp: 2025-11-08T04:06:33.198Z
Learning: In Bun test files, `await using` with Bun.spawn() is the preferred pattern for spawned processes regardless of whether they are short-lived or long-running. Do not suggest replacing `await using proc = Bun.spawn(...)` with `const proc = Bun.spawn(...); await proc.exited;`.

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to **/*.test.ts?(x) : Do not write flaky tests - do not use `setTimeout` in tests; instead await the condition to be met

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Always check exit codes and test error scenarios when spawning processes in tests.

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to **/*.test.ts?(x) : For single-file tests, prefer `-e` flag over `tempDir`

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Use `-e` flag for single-file tests when spawning Bun processes with `Bun.spawn()`.

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to **/*.test.ts?(x) : Verify tests fail with `USE_SYSTEM_BUN=1 bun test <file>` and pass with `bun bd test <file>` - tests are invalid if they pass with USE_SYSTEM_BUN=1

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-10-25T17:20:19.041Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 24063
File: test/js/bun/telemetry/server-header-injection.test.ts:5-20
Timestamp: 2025-10-25T17:20:19.041Z
Learning: In the Bun telemetry codebase, tests are organized into two distinct layers: (1) Internal API tests in test/js/bun/telemetry/ use numeric InstrumentKind enum values to test Zig↔JS injection points and low-level integration; (2) Public API tests in packages/bun-otel/test/ use string InstrumentKind values ("http", "fetch", etc.) to test the public-facing BunSDK and instrumentation APIs. This separation allows internal tests to use efficient numeric enums for refactoring flexibility while the public API maintains a developer-friendly string-based interface.

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-10-30T03:48:10.513Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 24063
File: packages/bun-otel/test/context-propagation.test.ts:1-7
Timestamp: 2025-10-30T03:48:10.513Z
Learning: In Bun test files, `using` declarations at the describe block level execute during module load/parsing, not during test execution. This means they acquire and dispose resources before any tests run. For test-scoped resource management, use beforeAll/afterAll hooks instead. The pattern `beforeAll(beforeUsingEchoServer); afterAll(afterUsingEchoServer);` is correct for managing ref-counted test resources like the EchoServer in packages/bun-otel/test/ - the using block pattern should not be used at describe-block level for test resources.
<!-- [/add_learning]

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Organize unit tests by module in directories like `/test/js/bun/` and `/test/js/node/`.

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2025-09-20T03:39:41.770Z
Learnt from: pfgithub
Repo: oven-sh/bun PR: 22534
File: test/regression/issue/21830.fixture.ts:14-63
Timestamp: 2025-09-20T03:39:41.770Z
Learning: Bun's test runner supports async describe callbacks, unlike Jest/Vitest where describe callbacks must be synchronous. The syntax `describe("name", async () => { ... })` is valid in Bun.

Applied to files:

  • test/js/first_party/undici/undici-properties.test.ts
📚 Learning: 2025-10-18T05:23:24.403Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: test/js/bun/telemetry-server.test.ts:91-100
Timestamp: 2025-10-18T05:23:24.403Z
Learning: In the Bun codebase, telemetry tests (test/js/bun/telemetry-*.test.ts) should focus on telemetry API behavior: configure/disable/isEnabled, callback signatures and invocation, request ID correlation, and error handling. HTTP protocol behaviors like status code normalization (e.g., 200 with empty body → 204) should be tested in HTTP server tests (test/js/bun/http/), not in telemetry tests. Keep separation of concerns: telemetry tests verify the telemetry API contract; HTTP tests verify HTTP semantics.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/first_party/undici/undici.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Applies to test/**/*.test.{ts,js,jsx,tsx,mjs,cjs} : Do not set a timeout on tests. Bun already has timeouts built-in.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Prefer concurrent tests over sequential tests. Use `test.concurrent` or `describe.concurrent` when multiple tests spawn processes or write files, unless it is very difficult to make them concurrent.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-09-03T01:30:58.001Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 21728
File: test/js/valkey/valkey.test.ts:264-271
Timestamp: 2025-09-03T01:30:58.001Z
Learning: For test/js/valkey/valkey.test.ts PUB/SUB tests, avoid arbitrary sleeps and async-forEach. Instead, resolve a Promise from the subscriber callback when the expected number of messages is observed and await it with a bounded timeout (e.g., withTimeout + Promise.withResolvers) to account for Redis server→subscriber propagation.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • test/js/first_party/undici/undici.test.ts
📚 Learning: 2025-11-24T18:37:11.466Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/js/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:37:11.466Z
Learning: Applies to src/js/{builtins,node,bun,thirdparty,internal}/**/*.{ts,js} : Use `$debug()` for debug logging and `$assert()` for assertions; both are stripped in release builds

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to **/*.test.ts?(x) : Avoid shell commands like `find` or `grep` in tests - use Bun's Glob and built-in tools instead

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Applies to test/**/*-fixture.ts : Test files that spawn Bun processes should end in `*-fixture.ts` to identify them as test fixtures rather than tests themselves.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-10-20T01:38:02.660Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: packages/bun-otel/BunFetchInstrumentation.ts:126-131
Timestamp: 2025-10-20T01:38:02.660Z
Learning: In BunFetchInstrumentation.ts, the force-restore to ORIGINAL_FETCH in the disable() method is intentionally kept (despite appearing unsafe) because it's required for proper test cleanup when instrumentation is repeatedly enabled/disabled. Without it, 15 distributed tracing and context propagation tests fail. Shimmer's unwrap() doesn't reliably restore the original fetch in Bun's globalThis context. The isBunOtelPatched safety check ensures the restore only happens when the current fetch is still ours, preventing clobbering of other tools' wrappers.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • src/js/thirdparty/undici.js
📚 Learning: 2025-10-08T13:48:02.430Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 23373
File: test/js/bun/tarball/extract.test.ts:107-111
Timestamp: 2025-10-08T13:48:02.430Z
Learning: In Bun's test runner, use `expect(async () => { await ... }).toThrow()` to assert async rejections. Unlike Jest/Vitest, Bun does not require `await expect(...).rejects.toThrow()` - the async function wrapper with `.toThrow()` is the correct pattern for async error assertions in Bun tests.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
📚 Learning: 2025-09-02T05:33:37.517Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 22323
File: test/js/web/websocket/websocket-subprotocol.test.ts:74-75
Timestamp: 2025-09-02T05:33:37.517Z
Learning: In Bun's runtime, `await using` with Node.js APIs like `net.createServer()` is properly supported and should not be replaced with explicit cleanup. Bun has extended Node.js APIs with proper async dispose support.

Applied to files:

  • test/js/node/tls/globalAgent-tls-options.test.ts
  • src/js/thirdparty/undici.js
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Prefer async/await over callbacks in tests. When callbacks must be used for a single callback, use `Promise.withResolvers` to create a promise that can be resolved or rejected from a callback.

Applied to files:

  • test/js/first_party/undici/undici.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to src/bun.js/bindings/**/*.cpp : Cache structures in ZigGlobalObject for JavaScript class bindings

Applied to files:

  • src/bun.js/bindings/webcore/JSWebSocket.cpp
  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/src/napi/napi.zig : For each new V8 C++ method, add both GCC/Clang and MSVC mangled symbol names to the V8API struct in src/napi/napi.zig using extern fn declarations

Applied to files:

  • src/bun.js/bindings/webcore/JSWebSocket.cpp
  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to src/bun.js/bindings/**/*.cpp : Add iso subspaces for C++ classes with fields in JavaScript class bindings

Applied to files:

  • src/bun.js/bindings/webcore/JSWebSocket.cpp
  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-10-01T21:59:54.571Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 23169
File: src/bun.js/bindings/webcore/JSDOMConvertEnumeration.h:47-74
Timestamp: 2025-10-01T21:59:54.571Z
Learning: In the new bindings generator (bindgenv2) for `src/bun.js/bindings/webcore/JSDOMConvertEnumeration.h`, the context-aware enumeration conversion overloads intentionally use stricter validation (requiring `value.isString()` without ToString coercion), diverging from Web IDL semantics. This is a design decision documented in comments.

Applied to files:

  • src/bun.js/bindings/webcore/JSWebSocket.cpp
  • src/js/thirdparty/undici.js
  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to src/bun.js/bindings/**/*.cpp : Create classes in three parts in C++ when there is a public constructor: Foo (JSDestructibleObject), FooPrototype (JSNonFinalObject), and FooConstructor (InternalFunction)

Applied to files:

  • src/bun.js/bindings/webcore/JSWebSocket.cpp
  • src/js/thirdparty/undici.js
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.h : Add BUN_EXPORT visibility attribute to all public V8 API functions to ensure proper symbol export across platforms

Applied to files:

  • src/bun.js/bindings/webcore/JSWebSocket.cpp
  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/src/symbols.txt : Add symbol names without leading underscore to src/symbols.txt for each new V8 API method

Applied to files:

  • src/bun.js/bindings/webcore/JSWebSocket.cpp
  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-10-11T15:19:30.301Z
Learnt from: mastermakrela
Repo: oven-sh/bun PR: 19167
File: src/bun.js/api.zig:31-31
Timestamp: 2025-10-11T15:19:30.301Z
Learning: The learnings about `pub const js = JSC.Codegen.JS<ClassName>` and re-exporting toJS/fromJS/fromJSDirect apply to class-based Zig bindings with constructors and prototype methods (e.g., those with `new` constructors). They do NOT apply to simple namespace-style API objects like TOMLObject, YAMLObject, and CSVObject which expose static functions via a `create()` method that returns a plain JS object.

Applied to files:

  • src/bun.js/bindings/webcore/JSWebSocket.cpp
  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:37:11.466Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/js/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:37:11.466Z
Learning: Applies to src/js/{builtins,node,bun,thirdparty,internal}/**/*.ts : Builtin functions must include `this` parameter typing in TypeScript to enable direct method binding in C++

Applied to files:

  • src/bun.js/bindings/webcore/JSWebSocket.cpp
📚 Learning: 2025-09-03T22:12:26.870Z
Learnt from: cirospaciari
Repo: oven-sh/bun PR: 22378
File: src/sql/mysql/MySQLConnection.zig:0-0
Timestamp: 2025-09-03T22:12:26.870Z
Learning: In Bun's MySQL SSL implementation, the .require SSL mode is designed to behave the same as .prefer for postgres.js compatibility, allowing graceful fallback to non-SSL connections when the server doesn't support SSL. Only .verify_ca and .verify_full modes will fail when SSL is not available.

Applied to files:

  • src/bun.js/bindings/webcore/JSWebSocket.cpp
📚 Learning: 2025-09-05T18:45:29.200Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 21728
File: src/valkey/js_valkey.zig:0-0
Timestamp: 2025-09-05T18:45:29.200Z
Learning: In JSValkeyClient.cloneWithoutConnecting() in src/valkey/js_valkey.zig, the address/username/password fields must be repointed to the duplicated connection_strings buffer to avoid use-after-free when the original client is destroyed. The original client properly frees connection_strings in ValkeyClient.deinit().

Applied to files:

  • src/js/thirdparty/undici.js
  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-14T16:07:01.064Z
Learnt from: RiskyMH
Repo: oven-sh/bun PR: 24719
File: docs/bundler/executables.mdx:527-560
Timestamp: 2025-11-14T16:07:01.064Z
Learning: In the Bun repository, certain bundler features like compile with code splitting (--compile --splitting) are CLI-only and not supported in the Bun.build() JavaScript API. Tests for CLI-only features use backend: "cli" flag (e.g., test/bundler/bundler_compile_splitting.test.ts). The CompileBuildConfig interface correctly restricts these with splitting?: never;. When documenting CLI-only bundler features, add a note clarifying they're not available via the programmatic API.

Applied to files:

  • src/js/thirdparty/undici.js
📚 Learning: 2025-11-24T18:37:11.466Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/js/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:37:11.466Z
Learning: Applies to src/js/{builtins,node,bun,thirdparty,internal}/**/*.{ts,js} : Use private globals and methods with `$` prefix (e.g., `$Array`, `map.$set()`) instead of public JavaScript globals

Applied to files:

  • src/js/thirdparty/undici.js
📚 Learning: 2025-11-24T18:37:11.466Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/js/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:37:11.466Z
Learning: Applies to src/js/{builtins,node,bun,thirdparty,internal}/**/*.{ts,js} : Use `.$call()` and `.$apply()` instead of `.call()` and `.apply()` to prevent user tampering with function invocation

Applied to files:

  • src/js/thirdparty/undici.js
📚 Learning: 2025-11-24T18:37:47.899Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/AGENTS.md:0-0
Timestamp: 2025-11-24T18:37:47.899Z
Learning: Applies to src/bun.js/bindings/v8/**/<UNKNOWN> : <UNKNOWN>

Applied to files:

  • src/js/thirdparty/undici.js
  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:37:11.466Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/js/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:37:11.466Z
Learning: Write JS builtins for Bun's Node.js compatibility and APIs, and run `bun bd` after changes

Applied to files:

  • src/js/thirdparty/undici.js
📚 Learning: 2025-10-01T21:49:27.862Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 23169
File: src/bun.js/bindings/BunIDLConvert.h:29-42
Timestamp: 2025-10-01T21:49:27.862Z
Learning: In Bun's IDL bindings (src/bun.js/bindings/BunIDLConvert.h), IDLStrictNull intentionally treats both undefined and null as null (using isUndefinedOrNull()), matching WebKit's IDLNull & IDLNullable behavior. This is the correct implementation and should not be changed to only accept null.

Applied to files:

  • src/js/thirdparty/undici.js
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/test/v8/v8-module/main.cpp : Register new V8 API test functions in the Init method using NODE_SET_METHOD with exports object

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/src/symbols.dyn : Add symbol names with leading underscore and semicolons in braces to src/symbols.dyn for each new V8 API method

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-03T20:40:59.655Z
Learnt from: pfgithub
Repo: oven-sh/bun PR: 24273
File: src/bun.js/bindings/JSValue.zig:545-586
Timestamp: 2025-11-03T20:40:59.655Z
Learning: In Bun's Zig codebase, JSErrors (returned as `bun.JSError!T`) must always be properly handled. Using `catch continue` or `catch { break; }` to silently suppress JSErrors is a bug. Errors should either be explicitly handled or propagated with `try`. This applies to snapshot serializer error handling where Jest's behavior is to throw when serializers throw.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-09-05T19:49:26.188Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 21728
File: src/valkey/js_valkey_functions.zig:852-867
Timestamp: 2025-09-05T19:49:26.188Z
Learning: In Bun’s Zig code, `.js_undefined` is a valid and preferred JSValue literal for “undefined” (e.g., resolving JSPromise). Do not refactor usages to `jsc.JSValue.jsUndefined()`, especially in src/valkey/js_valkey_functions.zig unsubscribe().

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-03T20:43:06.996Z
Learnt from: pfgithub
Repo: oven-sh/bun PR: 24273
File: src/bun.js/test/snapshot.zig:19-19
Timestamp: 2025-11-03T20:43:06.996Z
Learning: In Bun's Zig codebase, when storing JSValue objects in collections like ArrayList, use `jsc.Strong.Optional` (not raw JSValue). When adding values, wrap them with `jsc.Strong.Optional.create(value, globalThis)`. In cleanup code, iterate the collection calling `.deinit()` on each Strong.Optional item before calling `.deinit()` on the ArrayList itself. This pattern automatically handles GC protection. See examples in src/bun.js/test/ScopeFunctions.zig and src/bun.js/node/node_cluster_binding.zig.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-09-05T19:49:26.188Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 21728
File: src/valkey/js_valkey_functions.zig:852-867
Timestamp: 2025-09-05T19:49:26.188Z
Learning: In Bun's Zig codebase, `.js_undefined` is a valid way to represent JavaScript's undefined value when working with JSPromise.resolve() and similar JavaScript interop functions. This is the correct pattern to use rather than `jsc.JSValue.jsUndefined()`.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-09-02T18:09:21.647Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 22227
File: src/allocators/allocation_scope.zig:79-85
Timestamp: 2025-09-02T18:09:21.647Z
Learning: In Bun's Zig codebase, prefer simple, direct error handling patterns. When an error type has only one variant (like FreeError with only NotAllocated), use a switch statement rather than generic catch blocks to leverage compile-time knowledge and avoid unnecessary complexity. Avoid duplicating function calls across error paths when a cleaner structure is possible.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2026-01-05T16:32:15.175Z
Learnt from: alii
Repo: oven-sh/bun PR: 25474
File: src/bun.js/event_loop/Sigusr1Handler.zig:0-0
Timestamp: 2026-01-05T16:32:15.175Z
Learning: In Bun's Zig codebase, std.posix.sigaction returns void (not an error union) and should be called without error handling. The Zig standard library treats sigaction failures as programmer errors (unreachable) since they only occur with invalid signals like SIGKILL/SIGSTOP. This pattern is used consistently across crash_handler.zig, main.zig, filter_run.zig, and process.zig.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-12-23T06:50:41.142Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 25429
File: src/bun.js/bindings/helpers.h:422-422
Timestamp: 2025-12-23T06:50:41.142Z
Learning: In Bun's C++ bindings (src/bun.js/bindings/helpers.h and similar files), when returning an empty JSC::Identifier and a VM is accessible, prefer using `vm.propertyNames->emptyIdentifier` over constructing with `JSC::Identifier(JSC::Identifier::EmptyIdentifierFlag::EmptyIdentifier)`. The cached identifier from the VM's property names table is more efficient and consistent with WebKit upgrade patterns.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-10-18T20:50:47.750Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: src/bun.js/telemetry.zig:366-373
Timestamp: 2025-10-18T20:50:47.750Z
Learning: In Bun's Zig codebase (src/bun.js/bindings/JSValue.zig), the JSValue enum uses `.null` (not `.js_null`) for JavaScript's null value. Only `js_undefined` has the `js_` prefix to avoid collision with Zig's built-in `undefined` keyword. The correct enum fields are: `js_undefined`, `null`, `true`, `false`, and `zero`.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-10-18T20:59:45.579Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: src/bun.js/telemetry.zig:458-475
Timestamp: 2025-10-18T20:59:45.579Z
Learning: In src/bun.js/telemetry.zig, the RequestId (u64) to JavaScript number (f64) conversion in jsRequestId() is intentionally allowed to lose precision beyond 2^53-1. This is acceptable because: (1) at 1M requests/sec it takes ~285 years to overflow, (2) the counter resets per-process, and (3) these are observability IDs, not critical distributed IDs. Precision loss is an acceptable trade-off for this use case.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
🧬 Code graph analysis (5)
src/js/node/_http_client.ts (1)
src/js/internal/tls.ts (1)
  • isValidTLSArray (53-53)
test/js/node/tls/globalAgent-tls-options.test.ts (1)
test/harness.ts (1)
  • tempDir (277-284)
test/js/first_party/undici/undici.test.ts (1)
src/js/node/_http_client.ts (2)
  • agent (1056-1058)
  • agent (1060-1062)
src/bun.js/bindings/webcore/JSWebSocket.cpp (3)
src/bun.js/bindings/webcore/WebSocket.h (2)
  • sslConfig (181-184)
  • url (135-164)
src/bun.js/bindings/ObjectBindings.cpp (2)
  • getOwnPropertyIfExists (95-108)
  • getOwnPropertyIfExists (95-95)
src/bun.js/bindings/webcore/WebSocket.cpp (18)
  • url (1100-1103)
  • url (1100-1100)
  • create (294-297)
  • create (294-294)
  • create (299-302)
  • create (299-299)
  • create (304-319)
  • create (304-304)
  • create (320-336)
  • create (320-320)
  • create (338-355)
  • create (338-338)
  • create (357-375)
  • create (357-357)
  • create (377-380)
  • create (377-377)
  • protocol (1115-1118)
  • protocol (1115-1115)
src/js/thirdparty/undici.js (1)
test/js/web/websocket/websocket-proxy.test.ts (2)
  • fetch (40-45)
  • fetch (65-70)
🔇 Additional comments (13)
src/bun.js/bindings/webcore/JSWebSocket.cpp (5)

70-72: LGTM: Extern declaration for Zig binding.

The extern "C" declaration correctly exposes the Zig-side getHttpsGlobalAgent function for use in C++.


152-238: Well-structured helper for globalAgent fallback.

The applyGlobalAgentFallback function properly:

  • Checks exception state after each property access via RETURN_IF_EXCEPTION
  • Handles proxy URL extraction from both string and URL objects (via .href)
  • Follows correct TLS source priority: optionsconnectOptsconnect
  • Only modifies rejectUnauthorized and sslConfig when not already set (respecting per-request overrides)

The sentinel value -1 for rejectUnauthorized cleanly distinguishes "not set" from explicit false (0) or true (1).


240-279: LGTM: constructJSWebSocket1 with globalAgent fallback.

The 1-argument constructor path now correctly applies globalAgent fallback for proxy and TLS options. The conditional WebSocket::create call properly handles the tri-state rejectUnauthorized value.


281-323: LGTM: constructJSWebSocket2 with globalAgent fallback.

The 2-argument constructor (URL + single protocol string) correctly converts the protocol to a Vector<String> and applies the globalAgent fallback, maintaining consistency with the other constructor paths.


491-526: LGTM: Proper fallback ordering in constructJSWebSocket3.

The 3-argument constructor correctly:

  1. First extracts TLS options from explicit tls option
  2. Then checks agent.connectOpts / agent.options if proxy wasn't explicitly set
  3. Finally falls back to https.globalAgent via applyGlobalAgentFallback

This ensures per-request options take precedence over agent options, which take precedence over globalAgent options.

test/js/first_party/undici/undici.test.ts (1)

159-276: Comprehensive test coverage for undici TLS option storage.

The tests thoroughly verify that:

  • All dispatcher types (Agent, Dispatcher, Pool, BalancedPool, Client, ProxyAgent, EnvHttpProxyAgent, RetryAgent) correctly store options and connect properties
  • Edge cases are covered: Agent without options has undefined for both, Agent with options but no connect only has options

The test structure follows best practices by importing undici components at the describe level and using shared connectOpts for consistency.

test/js/node/tls/globalAgent-tls-options.test.ts (3)

1-12: Excellent test organization and setup.

The test file correctly:

  • Uses tempDir from harness for multi-file test scenarios (per coding guidelines)
  • Loads TLS fixtures at module level for reuse across tests
  • Organizes tests into logical describe blocks by feature area

15-73: Well-designed baseline test for globalAgent.options.rejectUnauthorized.

The test properly:

  • Uses port: 0 for dynamic port allocation
  • Uses await using for automatic process cleanup
  • Awaits stdout before checking exit code (better error messages)
  • Sets up a self-signed cert server and verifies globalAgent fallback works

679-1102: Comprehensive undici integration tests.

The tests thoroughly cover:

  • undici.Agent, Pool, Client, ProxyAgent with Bun's fetch via dispatcher option
  • undici.fetch using https.globalAgent.options as fallback
  • undici.fetch with explicit dispatcher overriding globalAgent
  • setGlobalDispatcher affecting subsequent undici.fetch calls

This provides excellent coverage for the TLS option propagation through the undici compatibility layer.

src/js/thirdparty/undici.js (3)

10-19: Verify fetch wrapper handles all edge cases correctly.

The wrapper correctly falls back to globalDispatcher when:

  1. globalDispatcher is set
  2. No explicit dispatcher in init
  3. No explicit agent in init

However, consider edge case: if init is undefined or null, accessing init?.dispatcher is safe, but spreading { ...init, dispatcher: globalDispatcher } with init = undefined is also safe in JS.

One minor observation: the wrapper uses standard Bun.fetch reference which is correct, but per coding guidelines for src/js/thirdparty/, consider if bunFetch.$call(undefined, ...) pattern is needed to prevent user tampering. Given this is a thirdparty shim and fetch is a global, the current approach is acceptable.


275-298: Well-designed non-enumerable storage for TLS options.

Using Object.defineProperty with enumerable: false is the correct approach to:

  1. Store options for Bun's fetch to extract TLS settings
  2. Avoid polluting object enumeration (e.g., Object.keys(), for...in)
  3. Allow the properties to be writable and configurable for flexibility

The comment clearly explains this differs from upstream undici, which is helpful for maintainability.


345-350: RetryAgent correctly stores dispatcher reference.

The RetryAgent properly:

  1. Calls super(options) to store options/connect via Dispatcher
  2. Stores the wrapped dispatcher reference for delegation

This matches the test expectations in undici-properties.test.ts that verify retryAgent.dispatcher === dispatcher.

src/js/node/_http_client.ts (1)

63-74: The fallback chain is sound and follows established patterns in the codebase.

The implementation correctly handles multiple agent types (standard HTTP Agent, https-proxy-agent, undici). The optional chaining (?.connect?.[key]) safely handles cases where intermediate properties don't exist, and type validation occurs after retrieval for each TLS option. This mirrors the pattern already used in src/js/thirdparty/ws.js (line 118), confirming it's an established convention. The defensive design means even if agent structures vary, the code gracefully falls back to undefined rather than throwing errors.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @src/bun.js/bindings/bindings.cpp:
- Around line 6125-6150: The function JSC__JSGlobalObject__getHttpsGlobalAgent
can clear a pre-existing exception via
catchScope.clearExceptionExceptTermination(); capture the VM's existing
exception before your operations (e.g., auto* prevException = vm.exception() or
save vm.exception()) and only call clearExceptionExceptTermination() (or
otherwise clear the catchScope) when there was no pre-existing exception; i.e.,
replace unconditional clearExceptionExceptTermination() calls with logic that
preserves prevException and only clears the scope if prevException is null,
ensuring you don't clobber an upstream pending exception in
JSC__JSGlobalObject__getHttpsGlobalAgent.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d5adb06 and bc87429.

📒 Files selected for processing (1)
  • src/bun.js/bindings/bindings.cpp
🧰 Additional context used
📓 Path-based instructions (1)
src/bun.js/bindings/**/*.cpp

📄 CodeRabbit inference engine (CLAUDE.md)

src/bun.js/bindings/**/*.cpp: Create classes in three parts in C++ when there is a public constructor: Foo (JSDestructibleObject), FooPrototype (JSNonFinalObject), and FooConstructor (InternalFunction)
Define properties using HashTableValue arrays in C++ JavaScript class bindings
Add iso subspaces for C++ classes with fields in JavaScript class bindings
Cache structures in ZigGlobalObject for JavaScript class bindings

Files:

  • src/bun.js/bindings/bindings.cpp
🧠 Learnings (21)
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to src/bun.js/bindings/**/*.cpp : Cache structures in ZigGlobalObject for JavaScript class bindings

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/src/napi/napi.zig : For each new V8 C++ method, add both GCC/Clang and MSVC mangled symbol names to the V8API struct in src/napi/napi.zig using extern fn declarations

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:37:47.899Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/AGENTS.md:0-0
Timestamp: 2025-11-24T18:37:47.899Z
Learning: Applies to src/bun.js/bindings/v8/**/<UNKNOWN> : <UNKNOWN>

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/test/v8/v8-module/main.cpp : Register new V8 API test functions in the Init method using NODE_SET_METHOD with exports object

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to src/bun.js/bindings/**/*.cpp : Add iso subspaces for C++ classes with fields in JavaScript class bindings

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/src/symbols.txt : Add symbol names without leading underscore to src/symbols.txt for each new V8 API method

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/src/symbols.dyn : Add symbol names with leading underscore and semicolons in braces to src/symbols.dyn for each new V8 API method

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-10-11T15:19:30.301Z
Learnt from: mastermakrela
Repo: oven-sh/bun PR: 19167
File: src/bun.js/api.zig:31-31
Timestamp: 2025-10-11T15:19:30.301Z
Learning: The learnings about `pub const js = JSC.Codegen.JS<ClassName>` and re-exporting toJS/fromJS/fromJSDirect apply to class-based Zig bindings with constructors and prototype methods (e.g., those with `new` constructors). They do NOT apply to simple namespace-style API objects like TOMLObject, YAMLObject, and CSVObject which expose static functions via a `create()` method that returns a plain JS object.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.h : Add BUN_EXPORT visibility attribute to all public V8 API functions to ensure proper symbol export across platforms

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-10-01T21:59:54.571Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 23169
File: src/bun.js/bindings/webcore/JSDOMConvertEnumeration.h:47-74
Timestamp: 2025-10-01T21:59:54.571Z
Learning: In the new bindings generator (bindgenv2) for `src/bun.js/bindings/webcore/JSDOMConvertEnumeration.h`, the context-aware enumeration conversion overloads intentionally use stricter validation (requiring `value.isString()` without ToString coercion), diverging from Web IDL semantics. This is a design decision documented in comments.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-03T20:40:59.655Z
Learnt from: pfgithub
Repo: oven-sh/bun PR: 24273
File: src/bun.js/bindings/JSValue.zig:545-586
Timestamp: 2025-11-03T20:40:59.655Z
Learning: In Bun's Zig codebase, JSErrors (returned as `bun.JSError!T`) must always be properly handled. Using `catch continue` or `catch { break; }` to silently suppress JSErrors is a bug. Errors should either be explicitly handled or propagated with `try`. This applies to snapshot serializer error handling where Jest's behavior is to throw when serializers throw.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-09-05T19:49:26.188Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 21728
File: src/valkey/js_valkey_functions.zig:852-867
Timestamp: 2025-09-05T19:49:26.188Z
Learning: In Bun’s Zig code, `.js_undefined` is a valid and preferred JSValue literal for “undefined” (e.g., resolving JSPromise). Do not refactor usages to `jsc.JSValue.jsUndefined()`, especially in src/valkey/js_valkey_functions.zig unsubscribe().

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-03T20:43:06.996Z
Learnt from: pfgithub
Repo: oven-sh/bun PR: 24273
File: src/bun.js/test/snapshot.zig:19-19
Timestamp: 2025-11-03T20:43:06.996Z
Learning: In Bun's Zig codebase, when storing JSValue objects in collections like ArrayList, use `jsc.Strong.Optional` (not raw JSValue). When adding values, wrap them with `jsc.Strong.Optional.create(value, globalThis)`. In cleanup code, iterate the collection calling `.deinit()` on each Strong.Optional item before calling `.deinit()` on the ArrayList itself. This pattern automatically handles GC protection. See examples in src/bun.js/test/ScopeFunctions.zig and src/bun.js/node/node_cluster_binding.zig.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-09-05T19:49:26.188Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 21728
File: src/valkey/js_valkey_functions.zig:852-867
Timestamp: 2025-09-05T19:49:26.188Z
Learning: In Bun's Zig codebase, `.js_undefined` is a valid way to represent JavaScript's undefined value when working with JSPromise.resolve() and similar JavaScript interop functions. This is the correct pattern to use rather than `jsc.JSValue.jsUndefined()`.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-09-02T18:09:21.647Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 22227
File: src/allocators/allocation_scope.zig:79-85
Timestamp: 2025-09-02T18:09:21.647Z
Learning: In Bun's Zig codebase, prefer simple, direct error handling patterns. When an error type has only one variant (like FreeError with only NotAllocated), use a switch statement rather than generic catch blocks to leverage compile-time knowledge and avoid unnecessary complexity. Avoid duplicating function calls across error paths when a cleaner structure is possible.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2026-01-05T16:32:15.175Z
Learnt from: alii
Repo: oven-sh/bun PR: 25474
File: src/bun.js/event_loop/Sigusr1Handler.zig:0-0
Timestamp: 2026-01-05T16:32:15.175Z
Learning: In Bun's Zig codebase, std.posix.sigaction returns void (not an error union) and should be called without error handling. The Zig standard library treats sigaction failures as programmer errors (unreachable) since they only occur with invalid signals like SIGKILL/SIGSTOP. This pattern is used consistently across crash_handler.zig, main.zig, filter_run.zig, and process.zig.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-12-23T06:50:41.142Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 25429
File: src/bun.js/bindings/helpers.h:422-422
Timestamp: 2025-12-23T06:50:41.142Z
Learning: In Bun's C++ bindings (src/bun.js/bindings/helpers.h and similar files), when returning an empty JSC::Identifier and a VM is accessible, prefer using `vm.propertyNames->emptyIdentifier` over constructing with `JSC::Identifier(JSC::Identifier::EmptyIdentifierFlag::EmptyIdentifier)`. The cached identifier from the VM's property names table is more efficient and consistent with WebKit upgrade patterns.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-10-18T20:50:47.750Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: src/bun.js/telemetry.zig:366-373
Timestamp: 2025-10-18T20:50:47.750Z
Learning: In Bun's Zig codebase (src/bun.js/bindings/JSValue.zig), the JSValue enum uses `.null` (not `.js_null`) for JavaScript's null value. Only `js_undefined` has the `js_` prefix to avoid collision with Zig's built-in `undefined` keyword. The correct enum fields are: `js_undefined`, `null`, `true`, `false`, and `zero`.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-10-18T20:59:45.579Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: src/bun.js/telemetry.zig:458-475
Timestamp: 2025-10-18T20:59:45.579Z
Learning: In src/bun.js/telemetry.zig, the RequestId (u64) to JavaScript number (f64) conversion in jsRequestId() is intentionally allowed to lose precision beyond 2^53-1. This is acceptable because: (1) at 1M requests/sec it takes ~285 years to overflow, (2) the counter resets per-process, and (3) these are observability IDs, not critical distributed IDs. Precision loss is an acceptable trade-off for this use case.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-09-05T18:45:29.200Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 21728
File: src/valkey/js_valkey.zig:0-0
Timestamp: 2025-09-05T18:45:29.200Z
Learning: In JSValkeyClient.cloneWithoutConnecting() in src/valkey/js_valkey.zig, the address/username/password fields must be repointed to the duplicated connection_strings buffer to avoid use-after-free when the original client is destroyed. The original client properly frees connection_strings in ValkeyClient.deinit().

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to **/*.zig : In Zig code, be careful with allocators and use defer for cleanup

Applied to files:

  • src/bun.js/bindings/bindings.cpp

@cirospaciari cirospaciari marked this pull request as draft January 9, 2026 01:54
cirospaciari and others added 3 commits January 8, 2026 18:18
- Add array support to ALPNProtocols union for compatibility with
  HttpsProxyAgent which sets ALPNProtocols to ['http/1.1']
- Convert array strings to ALPN wire format (length-prefixed protocols)
- Use stack fallback allocator to avoid heap allocations for typical cases
- Use toUTF8() for proper Windows UTF-16 string handling
- Fix exception handling in getHttpsGlobalAgent to not clobber
  pre-existing exceptions from upstream code
@cirospaciari cirospaciari marked this pull request as ready for review January 9, 2026 17:34
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In @src/bun.js/bindings/bindings.cpp:
- Around line 6125-6154: The binding currently swallows any pre-existing
exception by returning undefined; change the initial check in
JSC__JSGlobalObject__getHttpsGlobalAgent (the if (catchScope.exception()) block)
to propagate the pending exception back to Zig by returning the encoded
exception (i.e., return JSValue::encode(catchScope.exception())) or otherwise
rethrowing it so the Zig caller sees the JSError rather than losing it. Also
update the comment near the identifier creation for globalAgent ("(reuse
identifier)") to accurately reflect that a fresh Identifier is created each call
(remove or rephrase the comment) or implement caching if reuse is intended.

In @test/js/web/fetch/fetch-tls-abortsignal-timeout.test.ts:
- Line 16: The THRESHOLD of 60 makes the lower-bound assertion ineffective for
small timeout values; update the test in fetch-tls-abortsignal-timeout.test.ts
to compute the lower bound as Math.max(0, timeout - THRESHOLD) (or remove tiny
timeout cases) before asserting diff >= lowerBound, so the check is meaningful
for timeouts like 0, 1, and 10; locate the THRESHOLD constant and the assertion
that compares diff against timeout - THRESHOLD and replace the literal
subtraction with the conditional Math.max approach (or prune the test timeouts
to start at a larger minimum such as 100ms).
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between bc87429 and 2790250.

📒 Files selected for processing (4)
  • src/bun.js/api/server/SSLConfig.bindv2.ts
  • src/bun.js/api/server/SSLConfig.zig
  • src/bun.js/bindings/bindings.cpp
  • test/js/web/fetch/fetch-tls-abortsignal-timeout.test.ts
🧰 Additional context used
📓 Path-based instructions (6)
src/bun.js/bindings/**/*.cpp

📄 CodeRabbit inference engine (CLAUDE.md)

src/bun.js/bindings/**/*.cpp: Create classes in three parts in C++ when there is a public constructor: Foo (JSDestructibleObject), FooPrototype (JSNonFinalObject), and FooConstructor (InternalFunction)
Define properties using HashTableValue arrays in C++ JavaScript class bindings
Add iso subspaces for C++ classes with fields in JavaScript class bindings
Cache structures in ZigGlobalObject for JavaScript class bindings

Files:

  • src/bun.js/bindings/bindings.cpp
**/*.test.ts?(x)

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.test.ts?(x): Never use bun test directly - always use bun bd test to run tests with debug build changes
For single-file tests, prefer -e flag over tempDir
For multi-file tests, prefer tempDir and Bun.spawn over single-file tests
Use normalizeBunSnapshot to normalize snapshot output of tests
Never write tests that check for 'panic', 'uncaught exception', or similar strings in test output
Use tempDir from harness to create temporary directories - do not use tmpdirSync or fs.mkdtempSync
When spawning processes in tests, expect stdout before expecting exit code for more useful error messages on test failure
Do not write flaky tests - do not use setTimeout in tests; instead await the condition to be met
Verify tests fail with USE_SYSTEM_BUN=1 bun test <file> and pass with bun bd test <file> - tests are invalid if they pass with USE_SYSTEM_BUN=1
Test files must end with .test.ts or .test.tsx
Avoid shell commands like find or grep in tests - use Bun's Glob and built-in tools instead

Files:

  • test/js/web/fetch/fetch-tls-abortsignal-timeout.test.ts
test/**/*.test.ts?(x)

📄 CodeRabbit inference engine (CLAUDE.md)

Always use port: 0 in tests - do not hardcode ports or use custom random port number functions

Files:

  • test/js/web/fetch/fetch-tls-abortsignal-timeout.test.ts
test/**/*.test.{ts,js,jsx,tsx,mjs,cjs}

📄 CodeRabbit inference engine (test/CLAUDE.md)

test/**/*.test.{ts,js,jsx,tsx,mjs,cjs}: Use bun bd test <...test file> to run tests with compiled code changes. Do not use bun test as it will not include your changes.
Use bun:test for files ending in *.test.{ts,js,jsx,tsx,mjs,cjs}. For test files without .test extension in test/js/node/test/{parallel,sequential}/*.js, use bun bd <file> instead of bun bd test <file> since they expect exit code 0.
Do not set a timeout on tests. Bun already has timeouts built-in.

Files:

  • test/js/web/fetch/fetch-tls-abortsignal-timeout.test.ts
**/*.zig

📄 CodeRabbit inference engine (CLAUDE.md)

In Zig code, be careful with allocators and use defer for cleanup

Files:

  • src/bun.js/api/server/SSLConfig.zig
src/**/*.zig

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.zig: Use the # prefix for private fields in Zig structs, e.g., struct { #foo: u32 };
Use Decl literals in Zig, e.g., const decl: Decl = .{ .binding = 0, .value = 0 };
Place @import statements at the bottom of the file in Zig (auto formatter will handle positioning)
Never use @import() inline inside functions in Zig; always place imports at the bottom of the file or containing struct

Files:

  • src/bun.js/api/server/SSLConfig.zig
🧠 Learnings (32)
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to src/bun.js/bindings/**/*.cpp : Cache structures in ZigGlobalObject for JavaScript class bindings

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/src/napi/napi.zig : For each new V8 C++ method, add both GCC/Clang and MSVC mangled symbol names to the V8API struct in src/napi/napi.zig using extern fn declarations

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:37:47.899Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/AGENTS.md:0-0
Timestamp: 2025-11-24T18:37:47.899Z
Learning: Applies to src/bun.js/bindings/v8/**/<UNKNOWN> : <UNKNOWN>

Applied to files:

  • src/bun.js/bindings/bindings.cpp
  • src/bun.js/api/server/SSLConfig.bindv2.ts
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/test/v8/v8-module/main.cpp : Register new V8 API test functions in the Init method using NODE_SET_METHOD with exports object

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/src/symbols.txt : Add symbol names without leading underscore to src/symbols.txt for each new V8 API method

Applied to files:

  • src/bun.js/bindings/bindings.cpp
  • src/bun.js/api/server/SSLConfig.bindv2.ts
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/src/symbols.dyn : Add symbol names with leading underscore and semicolons in braces to src/symbols.dyn for each new V8 API method

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to src/bun.js/bindings/**/*.cpp : Add iso subspaces for C++ classes with fields in JavaScript class bindings

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.h : Add BUN_EXPORT visibility attribute to all public V8 API functions to ensure proper symbol export across platforms

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-10-11T15:19:30.301Z
Learnt from: mastermakrela
Repo: oven-sh/bun PR: 19167
File: src/bun.js/api.zig:31-31
Timestamp: 2025-10-11T15:19:30.301Z
Learning: The learnings about `pub const js = JSC.Codegen.JS<ClassName>` and re-exporting toJS/fromJS/fromJSDirect apply to class-based Zig bindings with constructors and prototype methods (e.g., those with `new` constructors). They do NOT apply to simple namespace-style API objects like TOMLObject, YAMLObject, and CSVObject which expose static functions via a `create()` method that returns a plain JS object.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-10-01T21:59:54.571Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 23169
File: src/bun.js/bindings/webcore/JSDOMConvertEnumeration.h:47-74
Timestamp: 2025-10-01T21:59:54.571Z
Learning: In the new bindings generator (bindgenv2) for `src/bun.js/bindings/webcore/JSDOMConvertEnumeration.h`, the context-aware enumeration conversion overloads intentionally use stricter validation (requiring `value.isString()` without ToString coercion), diverging from Web IDL semantics. This is a design decision documented in comments.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-03T20:40:59.655Z
Learnt from: pfgithub
Repo: oven-sh/bun PR: 24273
File: src/bun.js/bindings/JSValue.zig:545-586
Timestamp: 2025-11-03T20:40:59.655Z
Learning: In Bun's Zig codebase, JSErrors (returned as `bun.JSError!T`) must always be properly handled. Using `catch continue` or `catch { break; }` to silently suppress JSErrors is a bug. Errors should either be explicitly handled or propagated with `try`. This applies to snapshot serializer error handling where Jest's behavior is to throw when serializers throw.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-09-05T19:49:26.188Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 21728
File: src/valkey/js_valkey_functions.zig:852-867
Timestamp: 2025-09-05T19:49:26.188Z
Learning: In Bun’s Zig code, `.js_undefined` is a valid and preferred JSValue literal for “undefined” (e.g., resolving JSPromise). Do not refactor usages to `jsc.JSValue.jsUndefined()`, especially in src/valkey/js_valkey_functions.zig unsubscribe().

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-03T20:43:06.996Z
Learnt from: pfgithub
Repo: oven-sh/bun PR: 24273
File: src/bun.js/test/snapshot.zig:19-19
Timestamp: 2025-11-03T20:43:06.996Z
Learning: In Bun's Zig codebase, when storing JSValue objects in collections like ArrayList, use `jsc.Strong.Optional` (not raw JSValue). When adding values, wrap them with `jsc.Strong.Optional.create(value, globalThis)`. In cleanup code, iterate the collection calling `.deinit()` on each Strong.Optional item before calling `.deinit()` on the ArrayList itself. This pattern automatically handles GC protection. See examples in src/bun.js/test/ScopeFunctions.zig and src/bun.js/node/node_cluster_binding.zig.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-09-05T19:49:26.188Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 21728
File: src/valkey/js_valkey_functions.zig:852-867
Timestamp: 2025-09-05T19:49:26.188Z
Learning: In Bun's Zig codebase, `.js_undefined` is a valid way to represent JavaScript's undefined value when working with JSPromise.resolve() and similar JavaScript interop functions. This is the correct pattern to use rather than `jsc.JSValue.jsUndefined()`.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-09-02T18:09:21.647Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 22227
File: src/allocators/allocation_scope.zig:79-85
Timestamp: 2025-09-02T18:09:21.647Z
Learning: In Bun's Zig codebase, prefer simple, direct error handling patterns. When an error type has only one variant (like FreeError with only NotAllocated), use a switch statement rather than generic catch blocks to leverage compile-time knowledge and avoid unnecessary complexity. Avoid duplicating function calls across error paths when a cleaner structure is possible.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2026-01-05T16:32:15.175Z
Learnt from: alii
Repo: oven-sh/bun PR: 25474
File: src/bun.js/event_loop/Sigusr1Handler.zig:0-0
Timestamp: 2026-01-05T16:32:15.175Z
Learning: In Bun's Zig codebase, std.posix.sigaction returns void (not an error union) and should be called without error handling. The Zig standard library treats sigaction failures as programmer errors (unreachable) since they only occur with invalid signals like SIGKILL/SIGSTOP. This pattern is used consistently across crash_handler.zig, main.zig, filter_run.zig, and process.zig.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-10-18T20:50:47.750Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: src/bun.js/telemetry.zig:366-373
Timestamp: 2025-10-18T20:50:47.750Z
Learning: In Bun's Zig codebase (src/bun.js/bindings/JSValue.zig), the JSValue enum uses `.null` (not `.js_null`) for JavaScript's null value. Only `js_undefined` has the `js_` prefix to avoid collision with Zig's built-in `undefined` keyword. The correct enum fields are: `js_undefined`, `null`, `true`, `false`, and `zero`.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-10-24T10:43:09.398Z
Learnt from: fmguerreiro
Repo: oven-sh/bun PR: 23774
File: src/install/PackageManager/updatePackageJSONAndInstall.zig:548-548
Timestamp: 2025-10-24T10:43:09.398Z
Learning: In Bun's Zig codebase, the `as(usize, intCast(...))` cast pattern triggers a Zig compiler bug that causes compilation to hang indefinitely when used in complex control flow contexts (loops + short-circuit operators + optional unwrapping). Avoid this pattern and use simpler alternatives like just `intCast(...)` if type casting is necessary.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.cpp : Use JSC::WriteBarrier for heap-allocated references in V8 objects and implement visitChildren() for custom heap objects to support garbage collection

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to **/*.zig : In Zig code, be careful with allocators and use defer for cleanup

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-12-23T06:50:41.142Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 25429
File: src/bun.js/bindings/helpers.h:422-422
Timestamp: 2025-12-23T06:50:41.142Z
Learning: In Bun's C++ bindings (src/bun.js/bindings/helpers.h and similar files), when returning an empty JSC::Identifier and a VM is accessible, prefer using `vm.propertyNames->emptyIdentifier` over constructing with `JSC::Identifier(JSC::Identifier::EmptyIdentifierFlag::EmptyIdentifier)`. The cached identifier from the VM's property names table is more efficient and consistent with WebKit upgrade patterns.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-10-18T01:49:31.037Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 23755
File: src/bun.js/api/bun/socket/SocketConfig.bindv2.ts:58-58
Timestamp: 2025-10-18T01:49:31.037Z
Learning: In Bun's bindgenv2 TypeScript bindings (e.g., src/bun.js/api/bun/socket/SocketConfig.bindv2.ts), the pattern `b.String.loose.nullable.loose` is intentional and not a duplicate. The first `.loose` applies to the String type (loose string conversion), while the second `.loose` applies to the nullable (loose nullable, treating all falsy values as null rather than just null/undefined).

Applied to files:

  • src/bun.js/api/server/SSLConfig.bindv2.ts
📚 Learning: 2025-10-17T20:50:58.644Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 23755
File: src/bun.js/api/bun/socket/Handlers.zig:154-159
Timestamp: 2025-10-17T20:50:58.644Z
Learning: In Bun socket configuration error messages (src/bun.js/api/bun/socket/Handlers.zig), use the user-facing JavaScript names "data" and "drain" instead of internal field names "onData" and "onWritable", as these are the names users see in the API according to SocketConfig.bindv2.ts.

Applied to files:

  • src/bun.js/api/server/SSLConfig.bindv2.ts
📚 Learning: 2025-10-19T04:55:33.099Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: test/js/bun/http/node-telemetry.test.ts:27-203
Timestamp: 2025-10-19T04:55:33.099Z
Learning: In test/js/bun/http/node-telemetry.test.ts and the Bun.telemetry._node_binding API, after the architecture refactor, the _node_binding interface only contains two methods: handleIncomingRequest(req, res) and handleWriteHead(res, statusCode). The handleRequestFinish hook and other lifecycle hooks were removed during simplification. Both current methods are fully tested.

Applied to files:

  • src/bun.js/api/server/SSLConfig.bindv2.ts
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/test/v8/v8.test.ts : Add corresponding test cases to test/v8/v8.test.ts using checkSameOutput() function to compare Node.js and Bun output

Applied to files:

  • src/bun.js/api/server/SSLConfig.bindv2.ts
📚 Learning: 2026-01-05T23:04:01.518Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2026-01-05T23:04:01.518Z
Learning: Applies to test/**/*.test.{ts,js,jsx,tsx,mjs,cjs} : Do not set a timeout on tests. Bun already has timeouts built-in.

Applied to files:

  • test/js/web/fetch/fetch-tls-abortsignal-timeout.test.ts
📚 Learning: 2025-09-03T01:30:58.001Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 21728
File: test/js/valkey/valkey.test.ts:264-271
Timestamp: 2025-09-03T01:30:58.001Z
Learning: For test/js/valkey/valkey.test.ts PUB/SUB tests, avoid arbitrary sleeps and async-forEach. Instead, resolve a Promise from the subscriber callback when the expected number of messages is observed and await it with a bounded timeout (e.g., withTimeout + Promise.withResolvers) to account for Redis server→subscriber propagation.

Applied to files:

  • test/js/web/fetch/fetch-tls-abortsignal-timeout.test.ts
📚 Learning: 2025-12-16T00:21:32.179Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-16T00:21:32.179Z
Learning: Applies to **/*.test.ts?(x) : Do not write flaky tests - do not use `setTimeout` in tests; instead await the condition to be met

Applied to files:

  • test/js/web/fetch/fetch-tls-abortsignal-timeout.test.ts
📚 Learning: 2025-09-20T00:57:56.685Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 22568
File: test/js/valkey/valkey.test.ts:268-276
Timestamp: 2025-09-20T00:57:56.685Z
Learning: For test/js/valkey/valkey.test.ts, do not comment on synchronous throw assertions for async Redis methods like ctx.redis.set() - the maintainer has explicitly requested to stop looking at this error pattern.

Applied to files:

  • test/js/web/fetch/fetch-tls-abortsignal-timeout.test.ts
📚 Learning: 2025-09-20T00:58:38.042Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 22568
File: test/js/valkey/valkey.test.ts:561-564
Timestamp: 2025-09-20T00:58:38.042Z
Learning: For test/js/valkey/valkey.test.ts, do not comment on synchronous throw assertions for async Redis methods (like ctx.redis.set(), ctx.redis.unsubscribe(), etc.) - Bun's Redis client implementation differs from Node.js and can throw synchronously even for async methods. The maintainer has explicitly requested to stop looking at this error pattern.

Applied to files:

  • test/js/web/fetch/fetch-tls-abortsignal-timeout.test.ts
📚 Learning: 2025-09-02T17:07:29.377Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 22227
File: src/allocators.zig:873-879
Timestamp: 2025-09-02T17:07:29.377Z
Learning: In Zig's bun codebase, in functions like `unpackNullable` that return `?Allocator`, anonymous method calls like `.get()` are preferred over fully qualified calls like `Nullable(Allocator).get(allocator)` because the compiler can infer the correct type from the return type context. This follows Zig's anonymous literal syntax conventions.

Applied to files:

  • src/bun.js/api/server/SSLConfig.zig
📚 Learning: 2026-01-05T16:32:07.551Z
Learnt from: alii
Repo: oven-sh/bun PR: 25474
File: src/bun.js/event_loop/Sigusr1Handler.zig:0-0
Timestamp: 2026-01-05T16:32:07.551Z
Learning: In Zig codebases (e.g., Bun), treat std.posix.sigaction as returning void and do not perform runtime error handling for its failure. The Zig standard library views sigaction failures as programmer errors (unreachable) because they only occur with invalid signals like SIGKILL/SIGSTOP. Apply this pattern across Zig files that call sigaction (e.g., crash_handler.zig, main.zig, filter_run.zig, process.zig) and ensure failures are not handled as recoverable errors; prefer reaching an explicit unreachable/compile-time assumption when such failures are detected.

Applied to files:

  • src/bun.js/api/server/SSLConfig.zig
🔇 Additional comments (3)
src/bun.js/api/server/SSLConfig.bindv2.ts (1)

21-21: LGTM!

The array variant addition is correct and follows the established pattern used in SSLConfigFile. This allows users to specify ALPN protocols as an array of strings.

src/bun.js/api/server/SSLConfig.zig (2)

327-342: ALPN wire format construction is correct.

The buffer allocation and wire format construction properly implements the ALPN protocol format (length-prefixed strings). The @intCast at line 335 is safe due to the prior length validation, and memory management uses appropriate cleanup patterns.

Note: This code will work correctly once the cleanup bug in lines 304-325 is fixed.


302-303: Good use of stack fallback allocator.

The stack allocation of 8 slots for ZigString.Slice is well-sized for typical ALPN usage (1-3 protocols), with automatic heap fallback for edge cases.

…ance

Split globalAgent-tls-options.test.ts (19 tests) into 3 smaller files:
- globalAgent-https-request.test.ts (4 tests)
- globalAgent-fetch.test.ts (7 tests)
- globalAgent-undici.test.ts (8 tests)

Changes:
- Use bunRun (spawnSync) instead of async Bun.spawn for simpler code
- Add describe.concurrent for parallel test execution within files
- Reduces ASAN build timeout issues by splitting subprocess spawns
}

// Allocate buffer with null terminator
const buf = try bun.default_allocator.allocSentinel(u8, total_len, 0);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where does this memory get freed?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when SSLConfig deinit we free protos

@Jarred-Sumner
Copy link
Collaborator

Closing per IRL discussion

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants