Skip to content

Conversation

@cirospaciari
Copy link
Member

@cirospaciari cirospaciari commented Dec 19, 2025

Summary

Add proxy option to WebSocket constructor for connecting through HTTP CONNECT proxies.

Features

  • Support for ws:// and wss:// through HTTP proxies
  • Support for ws:// and wss:// through HTTPS proxies (with rejectUnauthorized: false)
  • Proxy authentication via URL credentials (Basic auth)
  • Custom proxy headers support
  • Full TLS options (ca, cert, key, etc.) for target connections using SSLConfig.fromJS

API

// String format
new WebSocket("wss://example.com", { proxy: "http://proxy:8080" })

// With credentials
new WebSocket("wss://example.com", { proxy: "http://user:pass@proxy:8080" })

// Object format with custom headers
new WebSocket("wss://example.com", {
  proxy: { url: "http://proxy:8080", headers: { "X-Custom": "value" } }
})

// HTTPS proxy
new WebSocket("ws://example.com", {
  proxy: "https://proxy:8443",
  tls: { rejectUnauthorized: false }
})

Implementation

File Changes
WebSocketUpgradeClient.zig Proxy state machine and CONNECT handling
WebSocketProxyTunnel.zig New - TLS tunnel inside CONNECT for wss:// through HTTP proxy
JSWebSocket.cpp Parse proxy option and TLS options using SSLConfig.fromJS
WebSocket.cpp Pass proxy parameters to Zig, handle HTTPS proxy socket selection
bun.d.ts Add proxy and full TLS options to WebSocket types

Supported Scenarios

Scenario Status
ws:// through HTTP proxy ✅ Working
wss:// through HTTP proxy ✅ Working (TLS tunnel)
ws:// through HTTPS proxy ✅ Working (with rejectUnauthorized: false)
wss:// through HTTPS proxy ✅ Working (with rejectUnauthorized: false)
Proxy authentication (Basic) ✅ Working
Custom proxy headers ✅ Working
Custom CA for HTTPS proxy ✅ Working

Test plan

  • API tests verify proxy option is accepted in various formats
  • Functional tests with local HTTP CONNECT proxy server
  • Proxy authentication tests (Basic auth)
  • HTTPS proxy tests with rejectUnauthorized: false
  • Error handling tests (auth failures, wrong credentials)

Run tests: bun test test/js/web/websocket/websocket-proxy.test.ts

Changelog

  • Added proxy option to WebSocket constructor for HTTP/HTTPS proxy support
  • Added full TLS options (ca, cert, key, passphrase, etc.) to WebSocket constructor

🤖 Generated with Claude Code

Add `proxy` option to WebSocket constructor for connecting through HTTP CONNECT proxies.

Features:
- Support for ws:// and wss:// through HTTP proxies
- Support for ws:// and wss:// through HTTPS proxies (with rejectUnauthorized: false)
- Proxy authentication via URL credentials (Basic auth)
- Custom proxy headers support
- Full TLS options (ca, cert, key, etc.) for target connections using SSLConfig.fromJS

API:
```javascript
// String format
new WebSocket("wss://example.com", { proxy: "http://proxy:8080" })

// With credentials
new WebSocket("wss://example.com", { proxy: "http://user:pass@proxy:8080" })

// Object format with custom headers
new WebSocket("wss://example.com", {
  proxy: { url: "http://proxy:8080", headers: { "X-Custom": "value" } }
})

// HTTPS proxy
new WebSocket("ws://example.com", {
  proxy: "https://proxy:8443",
  tls: { rejectUnauthorized: false }
})
```

Implementation:
- WebSocketUpgradeClient.zig: Proxy state machine and CONNECT handling
- WebSocketProxyTunnel.zig: TLS tunnel inside CONNECT for wss:// through HTTP proxy
- JSWebSocket.cpp: Parse proxy option and TLS options using SSLConfig.fromJS
- WebSocket.cpp: Pass proxy parameters to Zig, handle HTTPS proxy socket selection

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@robobun
Copy link
Collaborator

robobun commented Dec 19, 2025

Updated 6:31 PM PT - Jan 7th, 2026

@autofix-ci[bot], your commit 9b40282 has 4 failures in Build #34209 (All Failures):


🧪   To try this PR locally:

bunx bun-pr 25614

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

bun-25614 --bun

@cirospaciari cirospaciari marked this pull request as draft December 19, 2025 22:34
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 19, 2025

Walkthrough

Adds HTTP CONNECT proxy support and per-connection SSL config for WebSockets, implements TLS-in-tunnel handling and proxy tunneling, expands C++/Zig init/connect signatures to carry proxy and SSL context, introduces proxy error codes, and adds comprehensive tests and Docker squid proxy scaffolding.

Changes

Cohort / File(s) Summary
Type definitions
packages/bun-types/bun.d.ts
Added WebSocketOptionsProxy (string or { url, headers? }); updated WebSocketOptions to include proxy; changed WebSocketOptionsTLS.tls to TLSOptions.
C++ binding headers
src/bun.js/bindings/headers.h
Expanded Bun__WebSocketHTTPClient__connect / Bun__WebSocketHTTPSClient__connect signatures to accept proxy params, proxy headers, sslConfig, and targetIsSecure; added Bun__WebSocket__parseSSLConfig; added customSSLCtx to WebSocket client init signatures.
WebCore bindings / WebSocket implementation
src/bun.js/bindings/webcore/JSWebSocket.cpp, WebSocket.cpp, WebSocket.h
Parse TLS/proxy options from JS (including agent.*), added setupProxy, proxy headers handling, proxy-aware create overloads, didConnectWithTunnel, setExtensionsFromDeflateParams, SSL config ownership and customSSLCtx plumbing; added C interop wrappers for tunnel wiring.
WebSocket error codes
src/bun.js/bindings/webcore/WebSocketErrorCode.h
Added proxy-related error codes: proxy_connect_failed, proxy_authentication_required, proxy_connection_refused, proxy_tunnel_failed.
Zig: SSL wrapper
src/bun.js/api/bun/ssl_wrapper.zig
Added early-exit guards after data-callbacks in handleReading to stop processing if SSL pointer is null or connection closed.
Zig: WebSocket client core
src/http/websocket_client/websocket_client.zig
Added custom_ssl_ctx and proxy_tunnel fields; initWithTunnel method; tunnel-aware write/hasTCP paths; handleTunnelData; cleanup for SSL context and tunnel; exported initWithTunnel.
Zig ⇄ C++ interop
src/http/websocket_client/CppWebSocket.zig
Added didConnectWithTunnel wrapper; extended didConnect to accept custom_ssl_ctx and forward to C++ externs.
Zig: WebSocket proxy tunnel
src/http/websocket_client/WebSocketProxyTunnel.zig
New module implementing TLS inside HTTP CONNECT tunnels: handshake orchestration, decrypted/encrypted data routing, buffering/backpressure, lifecycle and C ABI WebSocketProxyTunnel__setConnectedWebSocket.
Zig: WebSocket upgrade client
src/http/websocket_client/WebSocketUpgradeClient.zig
Added proxy fields and states, CONNECT request builder, proxy response handling, tunnel TLS handshake and tunneling integration, parseSSLConfig exported as Bun__WebSocket__parseSSLConfig, and ownership transfer of custom SSL ctx.
JS ws shim / wrapper
src/js/thirdparty/ws.js
Extended #createWebSocket signature to accept proxy, tls, agent; extract proxy/tls from agent; propagate proxy/tls options into WebSocket options.
Tests: proxy utilities & suites
test/js/web/websocket/proxy-test-utils.ts, test/js/first_party/ws/ws-proxy.test.ts, test/js/web/websocket/websocket-proxy.test.ts
Added proxy test utilities (createConnectProxy, createTLSConnectProxy, startProxy) and extensive tests covering HTTP CONNECT, HTTPS proxy, auth, agent interactions, and tunneling wss scenarios.
Docker test infra
test/docker/config/squid.conf, test/docker/docker-compose.yml, test/docker/index.ts
Added Squid proxy config, docker-compose service, healthcheck, and test helper withSquid() plus service wiring and env exposure.
Tests deps
test/package.json
Bumped https-proxy-agent from 7.0.5 to ^7.0.6.

Possibly related PRs

Suggested reviewers

  • alii
  • dylan-conway
  • Jarred-Sumner
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(websocket): add HTTP/HTTPS proxy support' clearly and concisely describes the main feature being added. It is specific enough for a developer scanning history to understand the primary change.
Description check ✅ Passed The PR description includes both required sections: a comprehensive 'Summary' section explaining what the PR does and a detailed 'Test plan' section describing how the code was verified. The description goes beyond the template with API examples, implementation details, and a changelog.

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


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

@moinnadeem
Copy link

@cirospaciari Wow, great timing! I just spent 4 hours trying to run Bun websockets with proxies. Do you have any clue when this PR will land? Is there a binary of Bun with this PR that you already have?

The outer connection TLS decision was incorrectly based on target protocol
instead of proxy protocol. For wss:// through HTTP proxy:
- Old: useTLSClient = is_secure || m_proxyIsHTTPS (true, wrong!)
- New: useTLSClient = m_proxyUrl.isValid() ? m_proxyIsHTTPS : is_secure (false, correct)

This caused Bun to attempt TLS handshake with HTTP proxy, which expects
plaintext CONNECT request. The fix uses proxy protocol for outer connection
and handles TLS inside the tunnel via WebSocketProxyTunnel.

Additional fixes:
- Fix use-after-free in SSLWrapper during callbacks
- Fix recursive clearData causing double-deref of tunnel
- Add tunnel support to WebSocket client for post-upgrade I/O
- Add didConnectWithTunnel for proper tunnel handoff
- Fix InitialDataHandler to check tunnel mode connection status

The wss:// through HTTP proxy test is now enabled and passing.

Claude-Generated-By: Claude Code (cli/claude=100%)
Claude-Steers: 15
Claude-Permission-Prompts: 7
Claude-Escapes: 0
Claude-Plan:
<claude-plan>
# Plan: Fix WebSocket TLS Client Selection for Proxy Connections

## Problem Statement

The test for **wss:// through HTTP proxy** is skipped because it doesn't work. The bug is in how Bun decides whether to use a TLS or plain TCP client for the outer connection.

## Root Cause

**Location:** `src/bun.js/bindings/webcore/WebSocket.cpp` lines 574-577

```cpp
// BUGGY CODE:
bool useTLSClient = is_secure || m_proxyIsHTTPS;
```

For **wss:// through HTTP proxy**:
- `is_secure = true` (target is wss://)
- `m_proxyIsHTTPS = false` (proxy is http://)
- Result: `useTLSClient = true` → **WRONG!**

This causes Bun to attempt a TLS handshake with an HTTP proxy, which fails because the proxy expects a plaintext CONNECT request.

## Solution

The outer connection TLS decision should be based on:
- **Proxy protocol** (if using a proxy)
- **Target protocol** (if direct connection)

```cpp
// CORRECT LOGIC:
bool useTLSClient = m_proxyUrl.isValid() ? m_proxyIsHTTPS : is_secure;
```

| Scenario | is_secure | m_proxyIsHTTPS | Correct useTLSClient |
|----------|-----------|----------------|----------------------|
| wss:// direct | true | N/A | true |
| ws:// direct | false | N/A | false |
| wss:// through HTTP proxy | true | false | **false** |
| ws:// through HTTP proxy | false | false | false |
| wss:// through HTTPS proxy | true | true | true |
| ws:// through HTTPS proxy | false | true | true |

## Files to Modify

### 1. `src/bun.js/bindings/webcore/WebSocket.cpp` (line 577)

Change:
```cpp
// Use TLS client if either:
// 1. Target is wss:// (is_secure), OR
// 2. Proxy is https:// (m_proxyIsHTTPS)
bool useTLSClient = is_secure || m_proxyIsHTTPS;
```

To:
```cpp
// Use TLS client based on:
// - Proxy protocol (if using proxy): TLS for https:// proxy, plain for http:// proxy
// - Target protocol (if direct): TLS for wss://, plain for ws://
// The inner TLS tunnel (for wss:// through proxy) is handled by WebSocketProxyTunnel
bool useTLSClient = m_proxyUrl.isValid() ? m_proxyIsHTTPS : is_secure;
```

### 2. `test/js/web/websocket/websocket-proxy.test.ts` (line 384)

Remove `test.skip` and enable the wss:// through HTTP proxy test. The test may need to use a local wss:// server instead of external echo.websocket.org.

## How It Works After Fix

**wss:// through HTTP proxy flow:**
1. C++ chooses `useTLSClient = false` (because proxy is HTTP)
2. Calls `Bun__WebSocketHTTPClient__connect` (plain TCP)
3. Sends plaintext CONNECT request to HTTP proxy
4. Proxy responds "200 Connection Established"
5. `handleProxyResponse` in Zig detects `target_is_https = true`
6. Calls `startProxyTLSHandshake` to start TLS **inside the tunnel**
7. `WebSocketProxyTunnel` performs TLS handshake with target server
8. WebSocket upgrade is sent through the encrypted tunnel
9. Connection succeeds!

## Verification

```bash
# Run all proxy tests including the previously skipped one
bun bd test test/js/web/websocket/websocket-proxy.test.ts

# Specifically test wss:// through HTTP proxy
bun bd test test/js/web/websocket/websocket-proxy.test.ts -t "wss:// through HTTP proxy"
```

Expected result: All proxy tests pass, including wss:// through HTTP proxy.
</claude-plan>
cirospaciari and others added 3 commits January 6, 2026 14:26
…tests

Add squid proxy service to the docker-compose test infrastructure:
- Add squid.conf with minimal config allowing CONNECT to any port
- Add squid service to docker-compose.yml with healthcheck
- Add squid support to test/docker/index.ts (ensure, envFor, withSquid)

Update WebSocket proxy tests:
- Add Docker squid tests (currently disabled pending lifecycle fix)
- Fix tunnel ref/deref to prevent use-after-free during forwarding
- Remove premature deref in processResponse for tunnel mode

The Docker squid tests are temporarily disabled due to a use-after-free
issue when squid closes connections unexpectedly. The local mock proxy
tests provide complete coverage of the WebSocket proxy functionality.

Claude-Generated-By: Claude Code (cli/claude=100%)
Claude-Steers: 2
Claude-Permission-Prompts: 2
Claude-Escapes: 0
Claude-Plan:
<claude-plan>
# Plan: Fix WebSocket TLS Client Selection for Proxy Connections

## Problem Statement

The test for **wss:// through HTTP proxy** is skipped because it doesn't work. The bug is in how Bun decides whether to use a TLS or plain TCP client for the outer connection.

## Root Cause

**Location:** `src/bun.js/bindings/webcore/WebSocket.cpp` lines 574-577

```cpp
// BUGGY CODE:
bool useTLSClient = is_secure || m_proxyIsHTTPS;
```

For **wss:// through HTTP proxy**:
- `is_secure = true` (target is wss://)
- `m_proxyIsHTTPS = false` (proxy is http://)
- Result: `useTLSClient = true` → **WRONG!**

This causes Bun to attempt a TLS handshake with an HTTP proxy, which fails because the proxy expects a plaintext CONNECT request.

## Solution

The outer connection TLS decision should be based on:
- **Proxy protocol** (if using a proxy)
- **Target protocol** (if direct connection)

```cpp
// CORRECT LOGIC:
bool useTLSClient = m_proxyUrl.isValid() ? m_proxyIsHTTPS : is_secure;
```

| Scenario | is_secure | m_proxyIsHTTPS | Correct useTLSClient |
|----------|-----------|----------------|----------------------|
| wss:// direct | true | N/A | true |
| ws:// direct | false | N/A | false |
| wss:// through HTTP proxy | true | false | **false** |
| ws:// through HTTP proxy | false | false | false |
| wss:// through HTTPS proxy | true | true | true |
| ws:// through HTTPS proxy | false | true | true |

## Files to Modify

### 1. `src/bun.js/bindings/webcore/WebSocket.cpp` (line 577)

Change:
```cpp
// Use TLS client if either:
// 1. Target is wss:// (is_secure), OR
// 2. Proxy is https:// (m_proxyIsHTTPS)
bool useTLSClient = is_secure || m_proxyIsHTTPS;
```

To:
```cpp
// Use TLS client based on:
// - Proxy protocol (if using proxy): TLS for https:// proxy, plain for http:// proxy
// - Target protocol (if direct): TLS for wss://, plain for ws://
// The inner TLS tunnel (for wss:// through proxy) is handled by WebSocketProxyTunnel
bool useTLSClient = m_proxyUrl.isValid() ? m_proxyIsHTTPS : is_secure;
```

### 2. `test/js/web/websocket/websocket-proxy.test.ts` (line 384)

Remove `test.skip` and enable the wss:// through HTTP proxy test. The test may need to use a local wss:// server instead of external echo.websocket.org.

## How It Works After Fix

**wss:// through HTTP proxy flow:**
1. C++ chooses `useTLSClient = false` (because proxy is HTTP)
2. Calls `Bun__WebSocketHTTPClient__connect` (plain TCP)
3. Sends plaintext CONNECT request to HTTP proxy
4. Proxy responds "200 Connection Established"
5. `handleProxyResponse` in Zig detects `target_is_https = true`
6. Calls `startProxyTLSHandshake` to start TLS **inside the tunnel**
7. `WebSocketProxyTunnel` performs TLS handshake with target server
8. WebSocket upgrade is sent through the encrypted tunnel
9. Connection succeeds!

## Verification

```bash
# Run all proxy tests including the previously skipped one
bun bd test test/js/web/websocket/websocket-proxy.test.ts

# Specifically test wss:// through HTTP proxy
bun bd test test/js/web/websocket/websocket-proxy.test.ts -t "wss:// through HTTP proxy"
```

Expected result: All proxy tests pass, including wss:// through HTTP proxy.
</claude-plan>
@cirospaciari cirospaciari marked this pull request as ready for review January 7, 2026 00:54
@cirospaciari cirospaciari marked this pull request as draft January 7, 2026 00:56
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: 6

🤖 Fix all issues with AI agents
In @src/bun.js/api/server/SSLConfig.zig:
- Around line 404-417: The hasCustomOptions function currently omits fields that
set requires_custom_request_ctx in fromGenerated and includes fields that don't;
update hasCustomOptions (function name hasCustomOptions in SSLConfig) to include
server_name and protos so it matches the conditions that set
requires_custom_request_ctx in fromGenerated, and either remove
dh_params_file_name and passphrase from hasCustomOptions or update fromGenerated
to mark requires_custom_request_ctx for those fields—pick one approach and make
the checks consistent between hasCustomOptions and the logic in fromGenerated.

In @src/bun.js/bindings/webcore/WebSocket.cpp:
- Around line 268-311: Duplicate proxy URL parsing and header processing in
WebSocket::create should be extracted into a private helper to avoid repetition;
implement a WebSocket::setupProxy(const String& proxyUrl,
std::optional<FetchHeaders::Init>&& proxyHeaders) (or similar) that performs:
validation of proxyUrl and returns/communicates failure (e.g., by returning
ExceptionOr<void> or a bool so callers can surface a SyntaxError like the
current code), setting m_proxyUrl, m_proxyIsHTTPS, computing
m_proxyAuthorization from URL credentials, and copying proxy headers into
m_proxyHeaders; then replace the duplicated blocks in both WebSocket::create
overloads with calls to this helper and propagate/return any error the helper
reports.
- Around line 1674-1691: Duplicate permessage-deflate extension string
construction appears in two places (the block using deflate_params here and the
identical block in didConnect); extract that logic into a private helper on the
WebSocket class (e.g., void WebSocket::setExtensionsFromDeflateParams(const
PerMessageDeflateParams* deflate_params)) that returns early for nullptr, builds
the StringBuilder exactly as shown, sets m_extensions from
extensions.toString(), and then replace both original blocks with a single call
to WebSocket::setExtensionsFromDeflateParams(deflate_params).

In @src/http/websocket_client/WebSocketProxyTunnel.zig:
- Around line 77-100: Update the comment above the TLS setup in
WebSocketProxyTunnel.start to explain that options.reject_unauthorized is
intentionally set to 0 and options.request_cert to 1 so the SSL wrapper
(SSLWrapperType) will complete the handshake and provide the peer certificate to
the tunnel for manual verification in onHandshake using
this.reject_unauthorized; mention this enables hostname/CA checks after the
handshake and that onHandshake performs the actual accept/reject decision while
allowing access to the peer cert for verification and logging.

In @test/js/first_party/ws/ws-proxy.test.ts:
- Around line 26-190: The two identical functions createConnectProxy and
createTLSConnectProxy are duplicated across tests; extract them into a single
shared test utility module (e.g., export createConnectProxy and
createTLSConnectProxy from a new proxy-test-utils module) and update both test
files to import and use those exported functions, removing the local duplicated
implementations and keeping behavior and signatures unchanged.
📜 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 4c492c6 and 0f00dbf.

📒 Files selected for processing (18)
  • packages/bun-types/bun.d.ts
  • src/bun.js/api/bun/ssl_wrapper.zig
  • src/bun.js/api/server/SSLConfig.zig
  • src/bun.js/bindings/headers.h
  • src/bun.js/bindings/webcore/JSWebSocket.cpp
  • src/bun.js/bindings/webcore/WebSocket.cpp
  • src/bun.js/bindings/webcore/WebSocket.h
  • src/bun.js/bindings/webcore/WebSocketErrorCode.h
  • src/http/websocket_client.zig
  • src/http/websocket_client/CppWebSocket.zig
  • src/http/websocket_client/WebSocketProxyTunnel.zig
  • src/http/websocket_client/WebSocketUpgradeClient.zig
  • src/js/thirdparty/ws.js
  • test/docker/config/squid.conf
  • test/docker/docker-compose.yml
  • test/docker/index.ts
  • test/js/first_party/ws/ws-proxy.test.ts
  • test/js/web/websocket/websocket-proxy.test.ts
🧰 Additional context used
📓 Path-based instructions (7)
src/**/*.zig

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.zig: Private fields in Zig are fully supported using the # prefix: struct { #foo: u32 };
Use decl literals in Zig for declaration initialization: const decl: Decl = .{ .binding = 0, .value = 0 };
Prefer @import at the bottom of the file (auto formatter will move them automatically)

Files:

  • src/bun.js/api/server/SSLConfig.zig
  • src/http/websocket_client/CppWebSocket.zig
  • src/http/websocket_client.zig
  • src/http/websocket_client/WebSocketProxyTunnel.zig
  • src/http/websocket_client/WebSocketUpgradeClient.zig
  • src/bun.js/api/bun/ssl_wrapper.zig
**/*.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/http/websocket_client/CppWebSocket.zig
  • src/http/websocket_client.zig
  • src/http/websocket_client/WebSocketProxyTunnel.zig
  • src/http/websocket_client/WebSocketUpgradeClient.zig
  • src/bun.js/api/bun/ssl_wrapper.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/ws.js
**/*.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/ws/ws-proxy.test.ts
  • test/js/web/websocket/websocket-proxy.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/ws/ws-proxy.test.ts
  • test/js/web/websocket/websocket-proxy.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/ws/ws-proxy.test.ts
  • test/js/web/websocket/websocket-proxy.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/webcore/WebSocket.cpp
🧠 Learnings (42)
📚 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/WebSocketErrorCode.h
  • src/bun.js/bindings/webcore/JSWebSocket.cpp
  • src/http/websocket_client/WebSocketUpgradeClient.zig
  • src/bun.js/bindings/headers.h
📚 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/WebSocketErrorCode.h
  • src/bun.js/bindings/webcore/JSWebSocket.cpp
  • src/bun.js/bindings/headers.h
📚 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/WebSocketErrorCode.h
  • src/bun.js/bindings/headers.h
📚 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/WebSocketErrorCode.h
  • src/bun.js/bindings/headers.h
📚 Learning: 2025-12-23T06:50:31.577Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 25429
File: src/bun.js/bindings/helpers.h:422-422
Timestamp: 2025-12-23T06:50:31.577Z
Learning: In Bun's C++ bindings, 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. Apply this guidance to src/bun.js/bindings/helpers.h and similar header files in the same bindings directory (i.e., any file that constructs an EmptyIdentifier).

Applied to files:

  • src/bun.js/bindings/webcore/WebSocketErrorCode.h
  • src/bun.js/bindings/webcore/WebSocket.h
  • src/bun.js/bindings/headers.h
📚 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
  • src/http/websocket_client/CppWebSocket.zig
  • src/http/websocket_client.zig
  • src/http/websocket_client/WebSocketProxyTunnel.zig
  • src/http/websocket_client/WebSocketUpgradeClient.zig
  • src/bun.js/api/bun/ssl_wrapper.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/js/thirdparty/ws.js
  • src/bun.js/bindings/webcore/JSWebSocket.cpp
  • src/http/websocket_client.zig
  • src/http/websocket_client/WebSocketProxyTunnel.zig
  • src/http/websocket_client/WebSocketUpgradeClient.zig
  • packages/bun-types/bun.d.ts
  • src/bun.js/bindings/headers.h
  • src/bun.js/api/bun/ssl_wrapper.zig
📚 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/js/thirdparty/ws.js
  • test/js/first_party/ws/ws-proxy.test.ts
  • packages/bun-types/bun.d.ts
  • src/bun.js/bindings/headers.h
📚 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/ws/ws-proxy.test.ts
  • test/docker/index.ts
  • test/js/web/websocket/websocket-proxy.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/ws/ws-proxy.test.ts
  • test/js/web/websocket/websocket-proxy.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/ws/ws-proxy.test.ts
  • test/js/web/websocket/websocket-proxy.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/docker/index.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: Write JS builtins for Bun's Node.js compatibility and APIs, and run `bun bd` after changes

Applied to files:

  • test/docker/index.ts
  • src/http/websocket_client/WebSocketUpgradeClient.zig
📚 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/docker/index.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/docker/index.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/docker/index.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/docker/index.ts
📚 Learning: 2025-10-08T13:56:00.875Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 23373
File: src/bun.js/api/BunObject.zig:2514-2521
Timestamp: 2025-10-08T13:56:00.875Z
Learning: For Bun codebase: prefer using `bun.path` utilities (e.g., `bun.path.joinAbsStringBuf`, `bun.path.join`) over `std.fs.path` functions for path operations.

Applied to files:

  • test/docker/index.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/docker/index.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/docker/index.ts
📚 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:

  • test/docker/index.ts
  • src/http/websocket_client/WebSocketUpgradeClient.zig
  • src/bun.js/bindings/headers.h
📚 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/docker/index.ts
📚 Learning: 2025-09-17T23:42:05.812Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 22568
File: docs/api/redis.md:240-246
Timestamp: 2025-09-17T23:42:05.812Z
Learning: The RedisClient.duplicate() method in Bun's Redis implementation returns Promise<RedisClient>, not RedisClient synchronously, so await is required when calling it.

Applied to files:

  • test/docker/index.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 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/bun.js/bindings/headers.h
📚 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/http/websocket_client.zig
  • src/http/websocket_client/WebSocketUpgradeClient.zig
  • src/bun.js/bindings/headers.h
📚 Learning: 2025-09-02T06:10:17.252Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 22323
File: test/js/web/websocket/websocket-subprotocol-strict.test.ts:80-91
Timestamp: 2025-09-02T06:10:17.252Z
Learning: Bun's WebSocket implementation includes a terminate() method, which is available even though it's not part of the standard WebSocket API. This method can be used in Bun test files and applications for immediate WebSocket closure.

Applied to files:

  • src/http/websocket_client.zig
📚 Learning: 2025-10-26T04:50:17.892Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 24086
File: src/bun.js/api/server.zig:2534-2535
Timestamp: 2025-10-26T04:50:17.892Z
Learning: In src/bun.js/api/server.zig, u32 is acceptable for route indices and websocket_context_index fields, as the practical limit of 4 billion contexts will never be reached.

Applied to files:

  • src/http/websocket_client.zig
  • src/bun.js/bindings/headers.h
📚 Learning: 2025-11-12T04:11:52.293Z
Learnt from: cirospaciari
Repo: oven-sh/bun PR: 24622
File: src/deps/uws/us_socket_t.zig:112-113
Timestamp: 2025-11-12T04:11:52.293Z
Learning: In Bun's Zig codebase, when passing u32 values to C FFI functions that expect c_uint parameters, no explicit intCast is needed because c_uint is equivalent to u32 on Bun's target platforms and Zig allows implicit coercion between equivalent types. This pattern is used consistently throughout src/deps/uws/us_socket_t.zig in functions like setTimeout, setLongTimeout, and setKeepalive.

Applied to files:

  • src/http/websocket_client.zig
  • src/bun.js/bindings/headers.h
📚 Learning: 2025-09-19T21:17:04.690Z
Learnt from: cirospaciari
Repo: oven-sh/bun PR: 22756
File: src/js/node/_http_server.ts:945-947
Timestamp: 2025-09-19T21:17:04.690Z
Learning: JSNodeHTTPServerSocket in src/bun.js/bindings/NodeHTTP.cpp implements both end() and close() methods. The end() method properly handles socket termination for both HTTP responses and raw CONNECT sockets by setting ended=true, checking buffered data, and flushing remaining data through the response context.

Applied to files:

  • src/http/websocket_client/WebSocketUpgradeClient.zig
  • src/bun.js/bindings/webcore/WebSocket.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/http/websocket_client/WebSocketUpgradeClient.zig
  • src/bun.js/bindings/headers.h
📚 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/http/websocket_client/WebSocketUpgradeClient.zig
  • src/bun.js/bindings/headers.h
📚 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/WebSocket.cpp
  • src/bun.js/bindings/headers.h
📚 Learning: 2025-10-19T02:52:37.412Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: packages/bun-otel/tsconfig.json:1-15
Timestamp: 2025-10-19T02:52:37.412Z
Learning: In the Bun repository, packages under packages/ (e.g., bun-otel) can follow a TypeScript-first pattern where package.json exports point directly to .ts files (not compiled .js files). Bun natively runs TypeScript, so consumers import .ts sources directly and receive full type information without needing compiled .d.ts declaration files. For such packages, adding "declaration": true or "outDir" in tsconfig.json is unnecessary and would break the export structure.
<!-- [remove_learning]
ceedde95-980e-4898-a2c6-40ff73913664

Applied to files:

  • packages/bun-types/bun.d.ts
📚 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:

  • packages/bun-types/bun.d.ts
📚 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:

  • packages/bun-types/bun.d.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/V8*.h : Create V8 class headers with .h extension following the pattern V8ClassName.h that include pragma once, v8.h, V8Local.h, V8Isolate.h, and declare classes extending from Data with BUN_EXPORT static methods

Applied to files:

  • src/bun.js/bindings/headers.h
📚 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/headers.h
📚 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/headers.h
📚 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/headers.h
📚 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/headers.h
📚 Learning: 2025-09-02T17:14:46.924Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 22227
File: src/safety/alloc.zig:93-95
Timestamp: 2025-09-02T17:14:46.924Z
Learning: In bun's Zig codebase, they use a custom extension of Zig that supports private field syntax with the `#` prefix (e.g., `#allocator`, `#trace`). This is not standard Zig syntax but is valid in their custom implementation. Fields prefixed with `#` are private fields that cannot be accessed from outside the defining struct.

Applied to files:

  • src/bun.js/bindings/headers.h
🧬 Code graph analysis (5)
src/js/thirdparty/ws.js (2)
src/js/internal/util/inspect.js (1)
  • proxy (1180-1180)
test/js/bun/http/bun-websocket-cpu-fixture.js (1)
  • ws (25-25)
test/js/web/websocket/websocket-proxy.test.ts (2)
test/harness.ts (1)
  • isDockerEnabled (865-888)
test/js/first_party/ws/ws-proxy.test.ts (2)
  • message (233-236)
  • message (258-261)
src/bun.js/bindings/webcore/WebSocket.h (2)
src/bun.js/bindings/webcore/WebSocket.cpp (24)
  • WebSocket (180-188)
  • WebSocket (190-222)
  • create (224-227)
  • create (224-224)
  • create (229-232)
  • create (229-229)
  • create (234-249)
  • create (234-234)
  • create (250-266)
  • create (250-250)
  • create (268-311)
  • create (268-268)
  • create (313-357)
  • create (313-313)
  • create (359-362)
  • create (359-359)
  • url (1063-1066)
  • url (1063-1063)
  • didConnect (1173-1203)
  • didConnect (1173-1173)
  • didConnect (1436-1477)
  • didConnect (1436-1436)
  • didConnectWithTunnel (1669-1713)
  • didConnectWithTunnel (1669-1669)
src/bun.js/bindings/webcore/MessageEvent.cpp (2)
  • create (68-71)
  • create (68-68)
src/bun.js/bindings/webcore/WebSocket.cpp (1)
src/bun.js/bindings/webcore/WebSocket.h (1)
  • url (124-153)
src/bun.js/bindings/headers.h (1)
src/bun.js/bindings/webcore/WebSocket.h (2)
  • JSC (52-55)
  • sslConfig (170-173)
🪛 ast-grep (0.40.3)
test/js/first_party/ws/ws-proxy.test.ts

[warning] 279-281: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: http://127.0.0.1:${proxyPort},
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)


[warning] 287-290: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: https://127.0.0.1:${httpsProxyPort},
tls: { rejectUnauthorized: false },
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)


[warning] 296-298: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: { url: http://127.0.0.1:${proxyPort} },
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)


[warning] 304-306: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: http://user:[email protected]:${authProxyPort},
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)


[warning] 312-315: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", ["graphql-ws"], {
proxy: http://127.0.0.1:${proxyPort},
headers: { Authorization: "Bearer token" },
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)


[warning] 322-324: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: "not-a-valid-url",
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)

test/js/web/websocket/websocket-proxy.test.ts

[warning] 206-208: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: http://127.0.0.1:${proxyPort},
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)


[warning] 216-219: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: https://127.0.0.1:${proxyPort},
tls: { rejectUnauthorized: false },
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)


[warning] 235-237: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: { url: http://127.0.0.1:${proxyPort} },
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)


[warning] 243-248: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: {
url: http://127.0.0.1:${proxyPort},
headers: { "X-Custom-Header": "test-value" },
},
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)


[warning] 254-256: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: http://user:[email protected]:${authProxyPort},
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)


[warning] 262-266: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: http://127.0.0.1:${proxyPort},
headers: { Authorization: "Bearer token" },
protocols: ["graphql-ws"],
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)


[warning] 273-275: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: "not-a-valid-url",
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)

🪛 Biome (2.1.2)
test/js/web/websocket/websocket-proxy.test.ts

[error] 669-669: Unexpected constant condition.

(lint/correctness/noConstantCondition)

🪛 Cppcheck (2.19.0)
src/bun.js/bindings/webcore/WebSocket.cpp

[information] 39-39: Include file

(missingIncludeSystem)

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 @test/js/first_party/ws/ws-proxy.test.ts:
- Around line 215-237: The negative-path tests ("proxy auth failure returns
error", "proxy wrong credentials returns error", "ws:// through HTTPS proxy
fails without CA certificate") currently resolve their Promise.whenResolvers on
any of ws.on("open"), ws.on("error"), or ws.on("close"), so a successful
connection can incorrectly make the test pass; change each test's logic to only
resolve on the error path (ws.on("error") or a specific TLS/auth rejection) and
explicitly fail/reject the test if ws.on("open") fires (or if a clean open+close
happens), e.g. use the existing Promise.withResolvers<void>() but call resolve
only from the error handler and call reject (or assert.fail) from the open
handler, and ensure close without prior error also fails; apply the same fix
pattern to the other two tests that use the ws variable and the same
open/error/close handlers.
📜 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 0f00dbf and 7105189.

📒 Files selected for processing (9)
  • packages/bun-types/bun.d.ts
  • src/bun.js/bindings/webcore/JSWebSocket.cpp
  • src/bun.js/bindings/webcore/WebSocket.cpp
  • src/bun.js/bindings/webcore/WebSocket.h
  • src/http/websocket_client/WebSocketProxyTunnel.zig
  • src/http/websocket_client/WebSocketUpgradeClient.zig
  • test/js/first_party/ws/ws-proxy.test.ts
  • test/js/web/websocket/proxy-test-utils.ts
  • test/js/web/websocket/websocket-proxy.test.ts
🧰 Additional context used
📓 Path-based instructions (6)
**/*.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/websocket/websocket-proxy.test.ts
  • test/js/first_party/ws/ws-proxy.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/websocket/websocket-proxy.test.ts
  • test/js/first_party/ws/ws-proxy.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/websocket/websocket-proxy.test.ts
  • test/js/first_party/ws/ws-proxy.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/webcore/WebSocket.cpp
src/**/*.zig

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.zig: Private fields in Zig are fully supported using the # prefix: struct { #foo: u32 };
Use decl literals in Zig for declaration initialization: const decl: Decl = .{ .binding = 0, .value = 0 };
Prefer @import at the bottom of the file (auto formatter will move them automatically)

Files:

  • src/http/websocket_client/WebSocketProxyTunnel.zig
  • src/http/websocket_client/WebSocketUpgradeClient.zig
**/*.zig

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • src/http/websocket_client/WebSocketProxyTunnel.zig
  • src/http/websocket_client/WebSocketUpgradeClient.zig
🧠 Learnings (29)
📚 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/web/websocket/proxy-test-utils.ts
  • test/js/web/websocket/websocket-proxy.test.ts
  • test/js/first_party/ws/ws-proxy.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/web/websocket/websocket-proxy.test.ts
  • test/js/first_party/ws/ws-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 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/webcore/WebSocket.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
📚 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
📚 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/bindings/webcore/JSWebSocket.cpp
  • packages/bun-types/bun.d.ts
  • src/http/websocket_client/WebSocketUpgradeClient.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/webcore/JSWebSocket.cpp
  • src/http/websocket_client/WebSocketUpgradeClient.zig
📚 Learning: 2025-10-19T02:52:37.412Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: packages/bun-otel/tsconfig.json:1-15
Timestamp: 2025-10-19T02:52:37.412Z
Learning: In the Bun repository, packages under packages/ (e.g., bun-otel) can follow a TypeScript-first pattern where package.json exports point directly to .ts files (not compiled .js files). Bun natively runs TypeScript, so consumers import .ts sources directly and receive full type information without needing compiled .d.ts declaration files. For such packages, adding "declaration": true or "outDir" in tsconfig.json is unnecessary and would break the export structure.
<!-- [remove_learning]
ceedde95-980e-4898-a2c6-40ff73913664

Applied to files:

  • packages/bun-types/bun.d.ts
📚 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:

  • packages/bun-types/bun.d.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:

  • packages/bun-types/bun.d.ts
  • test/js/first_party/ws/ws-proxy.test.ts
📚 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:

  • packages/bun-types/bun.d.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:

  • packages/bun-types/bun.d.ts
📚 Learning: 2025-11-20T19:51:32.288Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 24880
File: packages/bun-vscode/package.json:382-385
Timestamp: 2025-11-20T19:51:32.288Z
Learning: In the Bun repository, dependencies may be explicitly added to package.json files (even when not directly imported in code) to force version upgrades on transitive dependencies, particularly as part of Aikido security scanner remediation to ensure vulnerable transitive dependencies resolve to patched versions.

Applied to files:

  • packages/bun-types/bun.d.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:

  • packages/bun-types/bun.d.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:

  • packages/bun-types/bun.d.ts
📚 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:

  • packages/bun-types/bun.d.ts
  • src/http/websocket_client/WebSocketUpgradeClient.zig
📚 Learning: 2025-10-18T04:46:33.434Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: src/bun.js/telemetry.zig:80-156
Timestamp: 2025-10-18T04:46:33.434Z
Learning: In src/bun.js/telemetry.zig, the Bun.telemetry.configure() API is designed for a single telemetry adapter use case (primarily bun-otel). The merge semantics (where omitted callbacks are left intact) is intentional. If multiplexing multiple telemetry consumers is needed, it should be implemented in userspace by overriding the BunSDK class, not in the core API.

Applied to files:

  • packages/bun-types/bun.d.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: Write JS builtins for Bun's Node.js compatibility and APIs, and run `bun bd` after changes

Applied to files:

  • packages/bun-types/bun.d.ts
  • src/http/websocket_client/WebSocketUpgradeClient.zig
📚 Learning: 2025-10-08T13:56:00.875Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 23373
File: src/bun.js/api/BunObject.zig:2514-2521
Timestamp: 2025-10-08T13:56:00.875Z
Learning: For Bun codebase: prefer using `bun.path` utilities (e.g., `bun.path.joinAbsStringBuf`, `bun.path.join`) over `std.fs.path` functions for path operations.

Applied to files:

  • packages/bun-types/bun.d.ts
📚 Learning: 2025-09-12T18:16:50.754Z
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.

Applied to files:

  • packages/bun-types/bun.d.ts
📚 Learning: 2025-12-23T06:50:31.577Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 25429
File: src/bun.js/bindings/helpers.h:422-422
Timestamp: 2025-12-23T06:50:31.577Z
Learning: In Bun's C++ bindings, 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. Apply this guidance to src/bun.js/bindings/helpers.h and similar header files in the same bindings directory (i.e., any file that constructs an EmptyIdentifier).

Applied to files:

  • src/bun.js/bindings/webcore/WebSocket.h
📚 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/ws/ws-proxy.test.ts
📚 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/http/websocket_client/WebSocketProxyTunnel.zig
  • src/http/websocket_client/WebSocketUpgradeClient.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/http/websocket_client/WebSocketUpgradeClient.zig
  • src/bun.js/bindings/webcore/WebSocket.cpp
📚 Learning: 2025-09-19T21:17:04.690Z
Learnt from: cirospaciari
Repo: oven-sh/bun PR: 22756
File: src/js/node/_http_server.ts:945-947
Timestamp: 2025-09-19T21:17:04.690Z
Learning: JSNodeHTTPServerSocket in src/bun.js/bindings/NodeHTTP.cpp implements both end() and close() methods. The end() method properly handles socket termination for both HTTP responses and raw CONNECT sockets by setting ended=true, checking buffered data, and flushing remaining data through the response context.

Applied to files:

  • src/http/websocket_client/WebSocketUpgradeClient.zig
  • src/bun.js/bindings/webcore/WebSocket.cpp
📚 Learning: 2025-09-02T06:10:17.252Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 22323
File: test/js/web/websocket/websocket-subprotocol-strict.test.ts:80-91
Timestamp: 2025-09-02T06:10:17.252Z
Learning: Bun's WebSocket implementation includes a terminate() method, which is available even though it's not part of the standard WebSocket API. This method can be used in Bun test files and applications for immediate WebSocket closure.

Applied to files:

  • src/http/websocket_client/WebSocketUpgradeClient.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/http/websocket_client/WebSocketUpgradeClient.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/http/websocket_client/WebSocketUpgradeClient.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 : Cache structures in ZigGlobalObject for JavaScript class bindings

Applied to files:

  • src/bun.js/bindings/webcore/WebSocket.cpp
🧬 Code graph analysis (3)
test/js/web/websocket/websocket-proxy.test.ts (1)
test/js/web/websocket/proxy-test-utils.ts (3)
  • createConnectProxy (18-113)
  • startProxy (190-197)
  • createTLSConnectProxy (119-185)
src/bun.js/bindings/webcore/JSWebSocket.cpp (2)
src/bun.js/bindings/webcore/WebSocket.h (2)
  • sslConfig (170-173)
  • url (124-153)
src/bun.js/bindings/webcore/WebSocket.cpp (16)
  • create (280-283)
  • create (280-280)
  • create (285-288)
  • create (285-285)
  • create (290-305)
  • create (290-290)
  • create (306-322)
  • create (306-306)
  • create (324-341)
  • create (324-324)
  • create (343-361)
  • create (343-343)
  • create (363-366)
  • create (363-363)
  • url (1067-1070)
  • url (1067-1067)
src/bun.js/bindings/webcore/WebSocket.h (1)
src/bun.js/bindings/webcore/WebSocket.cpp (28)
  • WebSocket (180-188)
  • WebSocket (190-222)
  • create (280-283)
  • create (280-280)
  • create (285-288)
  • create (285-285)
  • create (290-305)
  • create (290-290)
  • create (306-322)
  • create (306-306)
  • create (324-341)
  • create (324-324)
  • create (343-361)
  • create (343-343)
  • create (363-366)
  • create (363-363)
  • url (1067-1070)
  • url (1067-1067)
  • didConnect (1177-1207)
  • didConnect (1177-1177)
  • didConnect (1440-1461)
  • didConnect (1440-1440)
  • didConnectWithTunnel (1653-1677)
  • didConnectWithTunnel (1653-1653)
  • setupProxy (224-256)
  • setupProxy (224-224)
  • setExtensionsFromDeflateParams (258-278)
  • setExtensionsFromDeflateParams (258-258)
🪛 ast-grep (0.40.4)
test/js/web/websocket/websocket-proxy.test.ts

[warning] 97-99: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: http://127.0.0.1:${proxyPort},
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)


[warning] 107-110: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: https://127.0.0.1:${proxyPort},
tls: { rejectUnauthorized: false },
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)


[warning] 126-128: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: { url: http://127.0.0.1:${proxyPort} },
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)


[warning] 134-139: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: {
url: http://127.0.0.1:${proxyPort},
headers: { "X-Custom-Header": "test-value" },
},
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)


[warning] 146-151: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: {
url: http://127.0.0.1:${proxyPort},
headers: headers,
},
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)


[warning] 157-159: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: http://user:[email protected]:${authProxyPort},
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)


[warning] 165-169: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: http://127.0.0.1:${proxyPort},
headers: { Authorization: "Bearer token" },
protocols: ["graphql-ws"],
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)


[warning] 176-178: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: "not-a-valid-url",
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)

test/js/first_party/ws/ws-proxy.test.ts

[warning] 95-97: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: http://127.0.0.1:${proxyPort},
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)


[warning] 103-106: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: https://127.0.0.1:${httpsProxyPort},
tls: { rejectUnauthorized: false },
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)


[warning] 112-114: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: { url: http://127.0.0.1:${proxyPort} },
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)


[warning] 120-122: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: http://user:[email protected]:${authProxyPort},
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)


[warning] 128-131: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", ["graphql-ws"], {
proxy: http://127.0.0.1:${proxyPort},
headers: { Authorization: "Bearer token" },
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)


[warning] 138-140: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: "not-a-valid-url",
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)

🪛 Biome (2.1.2)
test/js/web/websocket/websocket-proxy.test.ts

[error] 521-521: Unexpected constant condition.

(lint/correctness/noConstantCondition)

🪛 Cppcheck (2.19.0)
src/bun.js/bindings/webcore/WebSocket.cpp

[information] 39-39: Include file

(missingIncludeSystem)

🔇 Additional comments (35)
test/js/web/websocket/proxy-test-utils.ts (1)

18-112: Shared CONNECT proxy utilities look correct and test-appropriate

The HTTP and HTTPS CONNECT proxy helpers correctly parse the CONNECT request, optionally enforce basic auth, establish the tunnel, and forward data bidirectionally with reasonable error/close handling for test usage. Using listen(0, "127.0.0.1") and a shared startProxy helper also aligns with the test port guidelines.

Also applies to: 119-197

packages/bun-types/bun.d.ts (1)

3073-3097: WebSocket TLS and proxy option typing is consistent and aligned with runtime

Switching WebSocketOptionsTLS.tls to reuse the shared TLSOptions interface and introducing WebSocketOptionsProxy with string/object forms plus optional proxy headers (including Headers) makes the WebSocket client options consistent with other Bun networking APIs and with the proxy/TLS behavior implemented in this PR.

Also applies to: 3151-3157

test/js/first_party/ws/ws-proxy.test.ts (1)

26-92: Proxy test setup and positive-path coverage look solid

The shared proxy setup (createConnectProxy/createTLSConnectProxy + startProxy), local ws/wss echo servers on port: 0, and the positive-path tests (HTTP/HTTPS proxies, wss tunnels, HttpsProxyAgent integration, precedence rules) are well-structured and non-flaky: they wait for expected messages, close connections deterministically, and clean up servers in afterAll.

Also applies to: 94-213, 264-377, 404-582

src/bun.js/bindings/webcore/JSWebSocket.cpp (4)

66-67: LGTM!

The new includes support Headers class handling (JSFetchHeaders) and TLS parsing utilities (headers.h), which are essential for the proxy and TLS features being added.


215-310: Well-structured proxy and TLS parsing.

The implementation cleanly handles:

  • TLS options via Bun__WebSocket__parseSSLConfig (delegating to Zig's SSLConfig.fromJS)
  • Proxy as string or object with url/headers
  • Headers class instances with proper conversion pattern (lines 292-305)
  • Comprehensive error handling with RETURN_IF_EXCEPTION checks

The ownership transfer of sslConfig is correct - it's passed to WebSocket::create and managed there.


312-428: Comprehensive agent support with proper precedence.

The implementation correctly:

  • Extracts proxy from agent only when no explicit proxy is provided (line 314)
  • Supports callable agent.proxyHeaders for dynamic header generation (lines 343-346)
  • Handles URL objects via .href property (lines 326-333)
  • Builds filtered TLS options (lines 386-422) to avoid passing invalid properties like ALPNProtocols to the SSL parser

The filtering pattern for TLS options is particularly important - it ensures only supported properties (ca, cert, key, passphrase, rejectUnauthorized) are passed to Bun__WebSocket__parseSSLConfig, preventing potential parsing errors from agent libraries that may include extra properties.


431-433: LGTM!

The WebSocket::create calls correctly pass all proxy and TLS parameters with proper ownership semantics via WTF::move. The conditional based on rejectUnauthorized handles both the default case (-1) and explicit setting appropriately.

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

1-94: Well-structured test setup.

The test infrastructure properly:

  • Uses port: 0 throughout (lines 41, 64) per coding guidelines
  • Dynamically imports TLS certificates (line 61) to avoid circular dependencies
  • Sets up comprehensive test fixtures: HTTP proxy, authenticated proxy, ws server, wss server
  • Includes proper cleanup in afterAll

96-792: Comprehensive test coverage for WebSocket proxy functionality.

The test suite thoroughly validates:

  • API surface: proxy as string, object, with headers, with Headers class (lines 96-182)
  • Functional scenarios: ws/wss through HTTP/HTTPS proxies, authentication, custom headers (lines 184-510)
  • HttpsProxyAgent compatibility including URL objects and option precedence (lines 614-792)
  • Error handling: invalid proxy URLs, auth failures, wrong credentials

The use of Promise.withResolvers and gc() calls follows good testing practices.

Note: The static analysis warnings about ws:// protocol are false positives in test context - these tests explicitly validate proxy behavior with non-secure connections.


514-612: Intentionally disabled Docker tests with clear rationale.

The Docker squid tests are temporarily disabled (line 521) with a clear explanation of the use-after-free issue when the squid proxy closes unexpectedly. The local mock proxy tests provide good coverage in the meantime.

Consider creating a GitHub issue to track re-enabling these tests once the lifecycle issue is debugged.

The static analysis warning about the constant condition at line 521 is expected for intentionally disabled code.

Note: Would you like me to help create a tracking issue for re-enabling the Docker squid tests?

⛔ Skipped due to learnings
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.
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
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
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.
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.
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
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: 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.
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]
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.
src/bun.js/bindings/webcore/WebSocket.h (4)

72-73: LGTM!

The new create overloads cleanly extend the existing pattern with proxy and TLS support. The void* sslConfig is appropriate for passing an opaque pointer to Zig's SSLConfig.


141-142: Clean separation of connection modes.

The updated didConnect signature adds customSSLCtx for per-connection TLS contexts (e.g., custom CA certificates), while the new didConnectWithTunnel handles wss:// connections through HTTP proxies where TLS is managed by the WebSocketProxyTunnel.

This design properly separates:

  • Direct connections: TLS on socket, customSSLCtx for per-connection options
  • Tunnel connections: TLS inside proxy tunnel, managed by WebSocketProxyTunnel

165-173: LGTM!

Simple, clean accessors for the SSL config pointer. The void* type is appropriate for an opaque pointer to Zig's SSLConfig.


220-221: Well-organized proxy and TLS state.

The new helper methods (setupProxy, setExtensionsFromDeflateParams) properly extract setup logic, and the state fields are clearly documented:

  • Proxy state: URL, authorization, headers, and HTTPS flag
  • TLS state: sslConfig pointer with clear ownership comment (line 253)

The m_proxyIsHTTPS flag (line 251) is particularly important - it tracks whether the proxy connection itself is TLS, which is separate from whether the target is wss://.

Also applies to: 247-254

src/http/websocket_client/WebSocketProxyTunnel.zig (3)

77-102: LGTM - Manual certificate verification approach is well-documented.

The comment (lines 81-83) clearly explains why reject_unauthorized is set to 0 and request_cert to 1: to allow the handshake to complete so the peer certificate can be accessed for manual verification in onHandshake. The actual accept/reject decision uses this.reject_unauthorized.

This addresses the past review feedback and follows the same pattern used elsewhere in Bun's TLS handling.


212-234: Correct write buffering to maintain TLS record ordering.

The implementation properly:

  • Queues data if already buffered to maintain TLS record ordering (lines 216-218)
  • Handles write failures by buffering for retry when socket becomes writable (lines 224-226)
  • Handles partial writes by buffering remaining data (lines 230-233)

This ensures TLS records are never reordered, which would break the TLS protocol.


204-209: LGTM!

The phase transition from upgrade to connected is clean:

  • setConnectedWebSocket updates the pointer and clears the upgrade client reference
  • After transition, onData forwards decrypted data to the connected WebSocket (lines 128-132)
  • C export (lines 292-294) enables proper interop with WebSocket.cpp

Also applies to: 292-294

src/http/websocket_client/WebSocketUpgradeClient.zig (10)

46-74: Well-structured proxy and TLS state additions.

The new fields are clearly organized:

  • Proxy connection info (lines 46-51): host, port, is_https, authorization
  • Target connection info (lines 52-55): host, port, is_https (distinct from proxy)
  • TLS configuration (lines 58-64): ssl_config and custom_ssl_ctx with clear documentation

The comment on lines 61-63 effectively explains why custom_ssl_ctx is needed (per-connection options like custom CA that can't use the shared context).


171-214: Allocation failure handling is now correct.

The code properly calls client.deref() on allocation failures (lines 174, 180, 189-190, 198-200, 211) before returning null. This addresses the past review feedback about missing cleanup on early returns.

The pattern is consistent throughout: allocate → check for failure → deref client → return null.


231-283: Correct implementation of per-connection TLS contexts.

The custom SSL context creation is properly implemented:

  • Only created when ssl_config.requires_custom_request_ctx is true (line 242)
  • Configured for manual verification (lines 245-247) to match the shared context pattern
  • Socket callbacks registered on the custom context (lines 257-272)
  • Fallback to shared context on failure (lines 276-280) prevents complete connection failure
  • Ownership tracked in custom_ssl_ctx for proper cleanup

This enables custom CA certificates and other per-connection TLS options that can't be applied to the shared context.


330-366: Comprehensive cleanup with proper patterns.

The enhanced cleanup properly handles all new resources:

  • Proxy allocations (lines 331-349): host, target_host, authorization, headers, websocket_request_buf
  • Tunnel (lines 351-357): null-before-shutdown pattern prevents recursive cleanup
  • SSL config (lines 358-362): deinit and destroy
  • Custom SSL context (lines 363-366): deinit with ssl parameter

The null-before-shutdown pattern for the tunnel (lines 353-354) is particularly important - it prevents recursive cleanup if shutdown triggers callbacks that call back into clearData.


571-657: Correct proxy handshake implementation.

The proxy response handling properly:

  • Accepts both HTTP/1.1 and HTTP/1.0 200 responses (lines 582-589)
  • Maps HTTP 407 to proxy_authentication_required error (lines 610-611)
  • Branches on target protocol: TLS handshake for wss:// (line 627), direct WebSocket upgrade for ws:// (line 633)
  • Clears body buffer before WebSocket handshake (line 622) to avoid mixing proxy and WebSocket data
  • Processes any remaining data after proxy response (lines 654-656)

660-697: LGTM!

The proxy TLS handshake setup is comprehensive:

  • Creates and initializes WebSocketProxyTunnel (lines 664-666)
  • Configures SNI with target hostname (lines 669-675)
  • Transfers reject_unauthorized setting from WebSocket (lines 678-680)
  • Uses ssl_config if available, otherwise uses safe defaults (lines 683-686)
  • Handles errors by cleaning up tunnel and terminating (lines 689-693)

949-998: Correct handling of tunnel vs normal modes.

The implementation properly distinguishes two connection modes:

Tunnel mode (lines 950-976):

  • Keeps upgrade client alive to forward socket data to tunnel (comment lines 952-953)
  • Doesn't deref upgrade client when taking outgoing_websocket (line 963)
  • State transitions to .done (line 969), causing handleData to forward to tunnel (lines 501-510)
  • Tunnel forwards decrypted data to WebSocket client

Normal mode (lines 979-998):

  • Saves custom SSL context before clearData (line 981) to prevent premature destruction
  • Sets to null (line 982) so clearData doesn't destroy it
  • Transfers ownership to WebSocket via didConnect (line 998)

The distinction is crucial because tunnel mode requires the upgrade client to remain alive for the socket lifecycle.


1107-1119: LGTM!

The toHeaders helper cleanly converts NonUTF8Headers to bun.http.Headers with proper error handling and cleanup via errdefer.


1123-1169: Correct HTTP CONNECT request generation.

The buildConnectRequest helper properly formats a CONNECT request per HTTP/1.1:

  • CONNECT line with target host:port (line 1137)
  • Host header (line 1140)
  • Proxy-Connection: Keep-Alive (line 1143)
  • Proxy-Authorization if provided (lines 1146-1148)
  • Custom headers, skipping duplicate Proxy-Authorization (lines 1151-1163)
  • Blank line to end headers (line 1166)

1304-1329: Clean SSL config parsing for C++ interop.

The parseSSLConfig function properly:

  • Uses SSLConfig.fromJS for safe parsing (lines 1311-1314)
  • Returns heap-allocated pointer with transferred ownership (lines 1318-1320)
  • Returns null on error or when no options provided (line 1324)
  • Exported with correct naming convention for C++ to call (line 1328)

The ownership transfer is clearly documented (line 1323) and matches the cleanup in clearData (lines 358-362).

src/bun.js/bindings/webcore/WebSocket.cpp (8)

224-256: LGTM - Duplicate proxy setup logic successfully extracted.

The setupProxy method effectively addresses the previous review comment about duplicated proxy URL parsing and header processing. The implementation properly validates the proxy URL, computes Basic authentication, and processes proxy headers with appropriate error handling.


258-278: LGTM - Duplicate extension building logic successfully extracted.

The setExtensionsFromDeflateParams helper properly addresses the previous review comment about duplicated permessage-deflate extension string construction. The implementation correctly handles the nullptr case and efficiently builds the extension string.


324-361: LGTM - New create overloads properly handle proxy and SSL config.

The new create() overloads correctly:

  • Set m_sslConfig before connect() as noted in the comment
  • Call setupProxy() and propagate exceptions
  • Follow the established pattern of existing create() overloads

The SSL config ownership transfer flow (set in create, transferred to Zig in connect) appears correct and prevents use-after-free.


556-611: LGTM - Proxy parameter preparation and TLS client selection are correct.

The proxy parameter preparation properly:

  • Extracts proxy host, port, and auth
  • Prepares proxy header vectors
  • Transfers sslConfig ownership (lines 575-576) with appropriate nullification
  • Selects TLS client based on proxy protocol (not target protocol), correctly delegating inner TLS handling to WebSocketProxyTunnel as noted in the comment
  • Passes all necessary parameters including target security flag (is_secure) and sslConfig to Zig layer
  • Clears temporary vectors after the synchronous calls complete

The memory management pattern matches the existing header handling (lines 533-551, 610-611) and is safe assuming the Zig layer copies data during the call.


1440-1461: LGTM - didConnect properly refactored with customSSLCtx support.

The method correctly:

  • Uses the new setExtensionsFromDeflateParams helper (line 1443)
  • Selects TLS socket when target is wss:// OR proxy is HTTPS (lines 1445-1448)
  • Passes customSSLCtx to both client initialization paths
  • Maintains the existing flow by calling didConnect() at the end

1649-1677: LGTM - Excellent ordering logic with clear documentation.

The didConnectWithTunnel method demonstrates excellent defensive programming:

  • Correctly uses a plain (non-TLS) WebSocket client since the tunnel handles TLS
  • The comment at lines 1669-1673 clearly explains the critical ordering: didConnect() must be called before WebSocketProxyTunnel__setConnectedWebSocket to ensure the state is OPEN before message forwarding begins

This prevents message loss and is well-documented.


1608-1623: LGTM - Proxy error codes properly integrated.

The new proxy error cases are correctly implemented:

  • Use appropriate close code 1006 (abnormal closure) for proxy failures
  • Set CleanStatus::NotClean and isConnectionError=true to trigger error events
  • Follow the established pattern of other connection failure error codes
  • Provide clear, specific error messages for debugging

1681-1689: LGTM - Foreign function interface wrappers are correct.

The extern "C" wrappers properly:

  • Update WebSocket__didConnect signature to include customSSLCtx
  • Add new WebSocket__didConnectWithTunnel wrapper for tunnel-based connections
  • Provide straightforward forwarding to member functions for C/Zig interop

Previously, the proxy auth failure and TLS verification failure tests
would resolve their promises on any of open, error, or close events.
This meant tests would pass even if connections unexpectedly succeeded.

Now each test:
- Rejects if onopen fires (connection should NOT succeed)
- Tracks sawError flag when onerror fires
- Resolves only if sawError is true, otherwise rejects

Tests fixed:
- ws-proxy.test.ts: proxy auth failure, wrong credentials, HTTPS proxy without CA
- websocket-proxy.test.ts: proxy auth failure, wrong credentials, HTTPS proxy without CA
@cirospaciari
Copy link
Member Author

@coderabbitai review it again

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 7, 2026

@cirospaciari I'll review the changes in this PR.

✅ 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

🤖 Fix all issues with AI agents
In @test/js/web/websocket/websocket-proxy.test.ts:
- Around line 18-28: The module-level declarations tlsProxy and tlsProxyPort are
unused; remove those two declarations from the top-level variables and any
references to them, and rely on the locally-scoped httpsProxy and httpsProxyPort
used in the HTTPS proxy tests (e.g., the httpsProxy variable created around
lines 412-423) to avoid dead state; update any test teardown/cleanup that might
reference tlsProxy/tlsProxyPort to use the local httpsProxy/httpsProxyPort or
remove the redundant cleanup calls.
- Around line 532-541: Replace the dead conditional test guard with an explicit
skipped test suite: locate the block starting with the dynamic import const
dockerCompose = require("../../../docker/index.ts"); and the subsequent if
(false && isDockerEnabled()) { ... } wrapper, and change the test wrapper to use
describe.skip with the same suite name (preserving the inner test code and
references to isDockerEnabled and dockerCompose) so the tests remain present but
explicitly skipped; remove the if(...) wrapper and ensure the describe.skip call
encloses the exact same tests to preserve context for future re-enablement.
📜 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 7105189 and abc804e.

⛔ Files ignored due to path filters (1)
  • test/bun.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • src/js/thirdparty/ws.js
  • test/js/first_party/ws/ws-proxy.test.ts
  • test/js/web/websocket/websocket-proxy.test.ts
  • test/package.json
🧰 Additional context used
📓 Path-based instructions (4)
**/*.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/ws/ws-proxy.test.ts
  • test/js/web/websocket/websocket-proxy.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/ws/ws-proxy.test.ts
  • test/js/web/websocket/websocket-proxy.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/ws/ws-proxy.test.ts
  • test/js/web/websocket/websocket-proxy.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/thirdparty/ws.js
🧠 Learnings (12)
📚 Learning: 2025-11-20T19:51:32.288Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 24880
File: packages/bun-vscode/package.json:382-385
Timestamp: 2025-11-20T19:51:32.288Z
Learning: In the Bun repository, dependencies may be explicitly added to package.json files (even when not directly imported in code) to force version upgrades on transitive dependencies, particularly as part of Aikido security scanner remediation to ensure vulnerable transitive dependencies resolve to patched versions.

Applied to files:

  • test/package.json
📚 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/ws/ws-proxy.test.ts
  • test/js/web/websocket/websocket-proxy.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/ws/ws-proxy.test.ts
  • 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/ws/ws-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/first_party/ws/ws-proxy.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/ws/ws-proxy.test.ts
  • test/js/web/websocket/websocket-proxy.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/ws/ws-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/first_party/ws/ws-proxy.test.ts
  • 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) : 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/ws/ws-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) : 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/ws/ws-proxy.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/ws/ws-proxy.test.ts
  • src/js/thirdparty/ws.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/thirdparty/ws.js
🧬 Code graph analysis (3)
test/js/first_party/ws/ws-proxy.test.ts (1)
test/js/web/websocket/proxy-test-utils.ts (3)
  • createConnectProxy (18-113)
  • startProxy (190-197)
  • createTLSConnectProxy (119-185)
test/js/web/websocket/websocket-proxy.test.ts (1)
test/js/web/websocket/proxy-test-utils.ts (2)
  • createConnectProxy (18-113)
  • createTLSConnectProxy (119-185)
src/js/thirdparty/ws.js (2)
src/js/internal/util/inspect.js (1)
  • proxy (1180-1180)
test/js/bun/http/bun-websocket-cpu-fixture.js (1)
  • ws (25-25)
🪛 ast-grep (0.40.4)
test/js/first_party/ws/ws-proxy.test.ts

[warning] 95-97: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: http://127.0.0.1:${proxyPort},
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)


[warning] 103-106: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: https://127.0.0.1:${httpsProxyPort},
tls: { rejectUnauthorized: false },
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)


[warning] 112-114: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: { url: http://127.0.0.1:${proxyPort} },
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)


[warning] 120-122: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: http://user:[email protected]:${authProxyPort},
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)


[warning] 128-131: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", ["graphql-ws"], {
proxy: http://127.0.0.1:${proxyPort},
headers: { Authorization: "Bearer token" },
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)


[warning] 138-140: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: "not-a-valid-url",
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)

test/js/web/websocket/websocket-proxy.test.ts

[warning] 97-99: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: http://127.0.0.1:${proxyPort},
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)


[warning] 107-110: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: https://127.0.0.1:${proxyPort},
tls: { rejectUnauthorized: false },
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)


[warning] 126-128: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: { url: http://127.0.0.1:${proxyPort} },
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)


[warning] 134-139: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: {
url: http://127.0.0.1:${proxyPort},
headers: { "X-Custom-Header": "test-value" },
},
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)


[warning] 146-151: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: {
url: http://127.0.0.1:${proxyPort},
headers: headers,
},
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)


[warning] 157-159: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: http://user:[email protected]:${authProxyPort},
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)


[warning] 165-169: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: http://127.0.0.1:${proxyPort},
headers: { Authorization: "Bearer token" },
protocols: ["graphql-ws"],
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)


[warning] 176-178: Detected insecure WebSocket connection using 'ws://' protocol. WebSocket connections should use secure SSL/TLS connections with 'wss://' protocol to prevent man-in-the-middle attacks and ensure data confidentiality.
Context: new WebSocket("ws://example.com", {
proxy: "not-a-valid-url",
})
Note: [CWE-319] Cleartext Transmission of Sensitive Information [REFERENCES]
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
- https://cwe.mitre.org/data/definitions/319.html

(websocket-secure-connection)

🪛 Biome (2.1.2)
test/js/web/websocket/websocket-proxy.test.ts

[error] 541-541: Unexpected constant condition.

(lint/correctness/noConstantCondition)

🔇 Additional comments (13)
test/package.json (1)

54-54: LGTM!

The https-proxy-agent dependency update to ^7.0.6 is appropriate for the new WebSocket proxy tests. The caret range allows compatible patch updates.

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

92-147: Well-structured proxy and TLS extraction from agent.

The logic correctly extracts proxy configuration from agent.proxy (handling both URL objects and strings) and TLS options from agent.connectOpts or agent.options. The use of $isObject and $isCallable follows the coding guidelines for internal modules.


224-240: LGTM with minor observation.

The #createWebSocket method correctly builds wsOptions based on the presence of headers, proxy, tls, or agent. Note that method is always "GET" (initialized on line 91), so the if (method) check on line 229 will always be true when inside the conditional block. This is harmless but slightly redundant.

test/js/first_party/ws/ws-proxy.test.ts (5)

1-25: Good test setup with shared utilities.

The imports correctly use the shared proxy-test-utils module, addressing the earlier feedback about code duplication. The dynamic require for https-proxy-agent is appropriate to avoid tree-shaking issues.


26-92: Proper test infrastructure setup.

All servers correctly use port: 0 for dynamic port allocation. The afterAll cleanup properly closes all proxy servers and stops WebSocket servers with stop(true) for immediate shutdown.


215-273: Negative-path tests correctly implemented.

The sawError flag pattern ensures these tests fail if the connection unexpectedly succeeds. The onopen handler properly rejects the promise, and onclose only resolves when an error was observed. This addresses the previous review feedback.


146-178: LGTM!

Well-structured functional tests that verify actual WebSocket communication through proxies. The tests properly await message exchange and verify both the server's "connected" message and the echoed client message.


390-419: HTTPS proxy TLS failure test correctly implemented.

This test properly verifies that connecting to an HTTPS proxy without a CA certificate fails as expected. The sawError pattern ensures the test fails if the connection unexpectedly succeeds.

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

30-94: Good test setup with dynamic ports.

The beforeAll correctly uses port: 0 for all servers. The dynamic import of TLS certs works around module initialization order. Note that tlsProxy?.close() in afterAll is a no-op since tlsProxy is never assigned (the HTTPS proxy tests use a locally-scoped variable with its own cleanup).


300-358: Negative-path tests correctly implemented.

Both the "proxy auth failure" and "wrong credentials" tests use the proper sawError flag pattern. They reject if the connection opens unexpectedly and only resolve when an error was observed before close.


634-745: Comprehensive ws module integration tests.

Good coverage of the ws module's integration with the proxy functionality, including agent passthrough, TLS options, and explicit proxy precedence over agent. These tests verify that src/js/thirdparty/ws.js correctly propagates proxy configuration to the native WebSocket.


747-925: Thorough native WebSocket + HttpsProxyAgent coverage.

These tests comprehensively cover the native WebSocket API with HttpsProxyAgent, including authentication, TLS options, agent.proxy URL object handling, and explicit proxy precedence. The tests mirror the ws module tests, ensuring both APIs work consistently.


406-407: Mid-file import placement.

The import { tls as tlsCerts } from "harness" on line 407 is placed mid-file instead of at the top with other imports. This works but is unconventional. Consider moving it to the top imports section for consistency.

⛔ Skipped due to learnings
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.
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
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.
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.

cirospaciari and others added 10 commits January 7, 2026 13:41
Replace *anyopaque with type-safe alternatives in WebSocket proxy code:

- Add UpgradeClientUnion tagged union to handle HTTP/HTTPS proxy clients
  with proper dispatch methods (handleDecryptedData, terminate, etc.)
- Change upgrade_client from ?*anyopaque to UpgradeClientUnion
- Change connected_websocket from ?*anyopaque to ?*WebSocketClient
- Update register() parameter from *anyopaque to *uws.Loop
- Update connect() parameter from *anyopaque to *uws.SocketContext
- Remove unnecessary @ptrCast now that types are correct

This fixes a latent bug where the code always cast to
NewHTTPUpgradeClient(false) even for HTTPS proxy connections.
Replace getIfPropertyExists() with own-property-only access in
JSWebSocket.cpp to prevent prototype pollution attacks.

Previously, setting Object.prototype.rejectUnauthorized = false would
disable TLS verification for all WebSocket connections. Now, only
properties directly on the options object are read.

- Add getOwnPropertyIfExists() helper to ObjectBindings.h/cpp
- Replace all 19 getIfPropertyExists() calls in JSWebSocket.cpp
- Uses methodTable()->getOwnPropertySlot() for strictest security
Add helper methods to SSLConfig for client-side TLS with manual
verification, reducing code duplication across 7 locations.

New SSLConfig methods:
- asUSocketsForClientVerification(): Returns socket options with
  request_cert=1 and reject_unauthorized=0 for direct uws context
- forClientVerification(): Returns SSLConfig copy with same settings
  for SSLWrapper usage

Updated locations:
- HTTPContext.zig: Use asUSocketsForClientVerification()
- WebSocketUpgradeClient.zig: Use asUSocketsForClientVerification()
- WebSocketProxyTunnel.zig: Use forClientVerification()
- ProxyTunnel.zig: Use forClientVerification()
- PostgresSQLConnection.zig: Use asUSocketsForClientVerification()
- JSMySQLConnection.zig: Use asUSocketsForClientVerification()
Rename the field to better reflect its purpose - it's specifically used
for SNI (Server Name Indication) configuration during TLS handshakes
inside the proxy tunnel.
- Replace 10 individual proxy fields with single optional Proxy struct
- Remove unused proxy_is_https parameter from connect() signature
- Free proxy_authorization and proxy_headers immediately after building
  CONNECT request instead of holding until clearData()
- Simplify clearData() from 8 cleanup blocks to single Proxy.deinit()
- Remove unused tlsProxy/tlsProxyPort variables from tests
- Use describe.skipIf for Docker tests instead of if (false) pattern
…lbacks

Add ref/deref protection to SSLWrapper callbacks (onOpen, onData,
onHandshake, onClose) to prevent use-after-free when the tunnel is
cleaned up during callback execution.

Key changes:
- Add ref/deref pairs in all SSLWrapper callbacks to keep tunnel alive
- Reorder proxy_tunnel cleanup: set to null BEFORE shutdown to prevent
  re-entrant double cleanup
- Add isNone() check in onClose to handle already-cleaned-up state
- Fix squid healthcheck in docker-compose (pgrep instead of nc)
- Enable squid Docker proxy tests (previously disabled due to this bug)
…Config

Remove all proxy-related member fields from WebSocket class and replace
m_isSecure with a ConnectionType enum. Proxy configuration is now passed
through the call chain as a local ProxyConfig struct instead of being
stored as member fields.

Changes:
- Add ConnectionType enum (Plain, TLS, ProxyPlain, ProxyTLS) to replace
  separate m_isSecure and m_proxyIsHTTPS booleans
- Convert setupProxy() from member function to static function returning
  ExceptionOr<std::optional<ProxyConfig>>
- Add new connect() overload accepting std::optional<ProxyConfig>&&
- Remove member fields: m_proxyUrl, m_proxyAuthorization, m_proxyHeaders,
  m_proxyIsHTTPS (~105+ bytes saved per WebSocket instance)
- Update all TLS decision points to use ConnectionType enum

This reduces memory footprint for non-proxy WebSocket connections and
ensures proxy data is freed immediately after connection is established.
Simplify the tunnel public APIs by using shorter method names that
match common conventions:
- receiveData -> receive
- writeData -> write

For ProxyTunnel.zig, the internal SSLWrapper callback was renamed
from 'write' to 'writeEncrypted' to avoid naming conflict with the
new public API method.

Internal SSLWrapper method calls (wrapper.receiveData, wrapper.writeData)
remain unchanged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants