Skip to content

ref(bun): Use the shared request handler wrapper for Bun.serve - #25587

Open
isaacs wants to merge 1 commit into
isaacschlueter/js-3975-share-one-request-handler-wrapper-across-denoserve-bunservefrom
isaacschlueter/js-3975-share-one-request-handler-wrapper-across-denoserve-bunserve-b
Open

isaacs wants to merge 1 commit into
isaacschlueter/js-3975-share-one-request-handler-wrapper-across-denoserve-bunservefrom
isaacschlueter/js-3975-share-one-request-handler-wrapper-across-denoserve-bunserve-b

Conversation

@isaacs

@isaacs isaacs commented Oct 20, 2026 •

Copy link
Copy Markdown
Member

Moves Bun.serve onto wrapServerRequestHandler, which Deno.serve uses since the previous PR. Bun keeps only what is unique to it: the patches for fetch, routes and server.reload, the route template, the route parameters, and the socket address from server.requestIP(). Its copy of the stream monitor moves out, because the wrapper uses the same code from @sentry/server-utils.

The wrapper gets two optional fields for this. routeName passes the matched route to core's span helper, which sets http.route, the route source and the span name. attributes adds span attributes that only the runtime knows, here url.path.parameter.*.

Bun built its own span attributes, which did not follow the Sentry conventions for http.server spans. The conventions say that server instrumentation sets the matched route in http.route, and that url.template is for http.client spans and client-side routing. The host goes in server.address, as on Node, Deno and Cloudflare. So Bun spans change:

  • url.template becomes http.route. Routes without parameters now also get http.route and the route source.
  • url.domain becomes server.address.
  • A request to / gets the route source and the name GET /, as on the other runtimes, because the path is already low cardinality.
  • Spans also get user_agent.original and http.request.body.size.
  • Errors in OPTIONS and HEAD requests now carry the request data.

The wrapper now also keeps every Set-Cookie header of a response. Headers.forEach lists each one on its own, so a plain dict kept only the last one. This fixes Deno too, and Cloudflare once it moves.

Part of #25577
Part of JS-3975

@linear-code

linear-code Bot commented Oct 20, 2026

Copy link
Copy Markdown

JS-3975

@isaacs
isaacs added this pull request to stack #25589 October 20, 2026 22:30

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale Bugbot comment from a previous run.

Comment thread packages/server-utils/test/utils/wrapServerRequestHandler.test.ts
@github-actions

github-actions Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

size-limit report 📦

Compared: a89acfb (PR test merge using develop at fb0508a)

Against: b3e0c9e (develop) · base run #63030

⚠️ Baseline mismatch: 16 develop commit(s) in the PR build are missing from the baseline. Their size changes also affect this comparison. Compare commits. Re-run once develop's baseline build for fb0508a finishes.

Path Size % Change Change
@sentry/browser 29.91 kB - -
@sentry/browser - with treeshaking flags 28.05 kB - -
@sentry/browser - with treeshaking flags tracing without tracing 27.95 kB - -
@sentry/browser (incl. Tracing) 52.1 kB - -
@sentry/browser (incl. Tracing + Span Streaming) 52.1 kB - -
@sentry/browser (incl. Tracing, Profiling) 55.05 kB - -
@sentry/browser (incl. Tracing, Replay) 91.85 kB - -
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 80.72 kB - -
@sentry/browser (incl. Tracing, Replay with Canvas) 96.58 kB - -
@sentry/browser (incl. Tracing, Replay, Feedback) 109.52 kB - -
@sentry/browser (incl. Feedback) 47.42 kB - -
@sentry/browser (incl. sendFeedback) 34.97 kB - -
@sentry/browser (incl. FeedbackAsync) 40.07 kB - -
@sentry/browser (incl. Metrics) 30.93 kB - -
@sentry/browser (incl. Logs) 31.21 kB - -
@sentry/browser (incl. Metrics & Logs) 31.84 kB - -
@sentry/react 31.74 kB - -
@sentry/react (incl. Tracing) 54.42 kB - -
@sentry/vue 38.07 kB - -
@sentry/vue (incl. Tracing) 55.03 kB - -
@sentry/svelte 29.93 kB - -
@sentry/remix (Remix 3 client bundle) 57.11 kB - -
CDN Bundle 31.67 kB - -
CDN Bundle (incl. Tracing) 52.61 kB - -
CDN Bundle (incl. Logs, Metrics) 33.87 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) 54.55 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) 74.79 kB - -
CDN Bundle (incl. Tracing, Replay) 90.28 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 92.21 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) 96.42 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 98.37 kB - -
CDN Bundle - uncompressed 93.29 kB - -
CDN Bundle (incl. Tracing) - uncompressed 156.14 kB - -
CDN Bundle (incl. Logs, Metrics) - uncompressed 99.84 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 162.11 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 229.88 kB - -
CDN Bundle (incl. Tracing, Replay) - uncompressed 276.31 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 282.26 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 290.01 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 295.96 kB - -
@sentry/nextjs (client) 57.31 kB - -
@sentry/sveltekit (client) 52.48 kB - -
@sentry/core/server 41.85 kB - -
@sentry/core/browser 13.81 kB - -
@sentry/node 152.87 kB +0.13% +195 B 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection) 81.58 kB - -
@sentry/node - without tracing 94.4 kB +0.17% +153 B 🔺
@sentry/node - without channel injection 133.52 kB +0.13% +173 B 🔺
@sentry/aws-serverless 102.65 kB +0.17% +174 B 🔺
@sentry/cloudflare (withSentry) - minified 212.78 kB +0.8% +1.67 kB 🔺
@sentry/cloudflare (withSentry) 527.48 kB +0.7% +3.65 kB 🔺
@sentry/nextjs/cloudflare (withSentry) - minified 232.34 kB +0.7% +1.6 kB 🔺

View base workflow run

@isaacs
isaacs force-pushed the isaacschlueter/js-3975-share-one-request-handler-wrapper-across-denoserve-bunserve-b branch from 429f84b to 7b98f66 Compare October 21, 2026 00:54
@isaacs
isaacs marked this pull request as ready for review October 21, 2026 00:55
@isaacs
isaacs requested a review from a team as a code owner October 21, 2026 00:55
@isaacs
isaacs requested review from JPeer264 and andreiborza and removed request for a team October 21, 2026 00:55
@isaacs
isaacs force-pushed the isaacschlueter/js-3975-share-one-request-handler-wrapper-across-denoserve-bunserve-b branch from 7b98f66 to 2d4292b Compare October 21, 2026 01:07
@isaacs
isaacs requested a review from a team as a code owner October 21, 2026 01:13
@isaacs
isaacs requested review from nicohrubec and s1gr1d and removed request for a team October 21, 2026 01:13
@isaacs
isaacs force-pushed the isaacschlueter/js-3975-share-one-request-handler-wrapper-across-denoserve-bunserve-b branch from 2d4292b to 65c97e6 Compare October 21, 2026 01:13
@isaacs
isaacs force-pushed the isaacschlueter/js-3975-share-one-request-handler-wrapper-across-denoserve-bunserve-b branch 3 times, most recently from 339b64f to c2a1219 Compare October 21, 2026 04:14

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit c2a1219. Configure here.

Comment thread packages/bun/src/integrations/bunserver.ts Outdated
@isaacs
isaacs force-pushed the isaacschlueter/js-3975-share-one-request-handler-wrapper-across-denoserve-bunserve-b branch from c2a1219 to 7e1f64d Compare October 21, 2026 14:16
@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Optional E2E tests

Some optional checks were not successful. They do not block the merge. 18 failing, 41 successful. See the run.

Check Status
❌ CI: Optional E2E Tests / E2E nextjs-16 (vinext, bun) Test (optional) Failing after 21s Details
❌ CI: Optional E2E Tests / E2E node-pi-durable (latest) Test (optional) Failing after 19s Details
❌ CI: Optional E2E Tests / E2E react-router-7-framework-instrumentation Test (optional) Failing after 2m Details
❌ CI: Optional E2E Tests / E2E debug-id-sourcemaps Test (optional) Failing after 1m Details
❌ CI: Optional E2E Tests / E2E node-pi-durable Test (optional) Failing after 20s Details
❌ CI: Optional E2E Tests / E2E nextjs-16-tunnel (cloudflare) Test (optional) Failing after 23s Details
❌ CI: Optional E2E Tests / E2E nextjs-16 (cloudflare, latest) Test (optional) Failing after 1m Details
❌ CI: Optional E2E Tests / E2E cloudflare-workers-send-to-sentry Test (optional) Failing after 7m Details
❌ CI: Optional E2E Tests / E2E node-anthropic-send-to-sentry (latest) Test (optional) Failing after 1m Details
❌ CI: Optional E2E Tests / E2E nextjs-16 (deno) Test (optional) Failing after 31s Details
❌ CI: Optional E2E Tests / E2E cloudflare-pi-durable Test (optional) Failing after 16s Details
❌ CI: Optional E2E Tests / E2E cloudflare-flue-send-to-sentry Test (optional) Failing after 19s Details
❌ CI: Optional E2E Tests / E2E cloudflare-pi-durable (latest) Test (optional) Failing after 18s Details
❌ CI: Optional E2E Tests / E2E nextjs-16 (canary, turbopack) Test (optional) Failing after 13s Details
❌ CI: Optional E2E Tests / E2E nextjs-16 (vinext) Test (optional) Failing after 16s Details
❌ CI: Optional E2E Tests / E2E node-flue (latest) Test (optional) Failing after 1m Details
❌ CI: Optional E2E Tests / E2E nextjs-16 (canary, webpack) Test (optional) Failing after 22s Details
❌ CI: Optional E2E Tests / E2E node-flue Test (optional) Failing after 29s Details
Successful checks
Check Status
✅ CI: Optional E2E Tests / E2E gen-ai-libraries Test (optional) Successful in 1m Details
✅ CI: Optional E2E Tests / E2E astro-7-static Test (optional) Successful in 3m Details
✅ CI: Optional E2E Tests / E2E node-express-mcp-v2 Test (optional) Successful in 36s Details
✅ CI: Optional E2E Tests / E2E node-openai-send-to-sentry Test (optional) Successful in 3m Details
✅ CI: Optional E2E Tests / E2E nextjs-14 (latest) Test (optional) Successful in 1m Details
✅ CI: Optional E2E Tests / E2E deno (latest) Test (optional) Successful in 1m Details
✅ CI: Optional E2E Tests / E2E nuxt-3 (canary) Test (optional) Successful in 1m Details
✅ CI: Optional E2E Tests / E2E node-eve (orchestrion) Test (optional) Successful in 3m Details
✅ CI: Optional E2E Tests / E2E nuxt-5-sourcemaps Test (optional) Successful in 2m Details
✅ CI: Optional E2E Tests / E2E cloudflare-agent Test (optional) Successful in 1m Details
✅ CI: Optional E2E Tests / E2E cloudflare-think Test (optional) Successful in 1m Details
✅ CI: Optional E2E Tests / E2E node-anthropic-send-to-sentry Test (optional) Successful in 1m Details
✅ CI: Optional E2E Tests / E2E nextjs-16-standalone (canary, turbopack) Test (optional) Successful in 4m Details
✅ CI: Optional E2E Tests / E2E cloudflare-think (ai v6) Test (optional) Successful in 1m Details
✅ CI: Optional E2E Tests / E2E supabase-nextjs Test (optional) Successful in 1m Details
✅ CI: Optional E2E Tests / E2E node-mastra (latest) Test (optional) Successful in 2m Details
✅ CI: Optional E2E Tests / E2E node-express-send-to-sentry Test (optional) Successful in 2m Details
✅ CI: Optional E2E Tests / E2E node-eve (latest) Test (optional) Successful in 2m Details
✅ CI: Optional E2E Tests / E2E nextjs-14 (canary) Test (optional) Successful in 2m Details
✅ CI: Optional E2E Tests / E2E nuxt-5-sourcemaps (client source maps kept) Test (optional) Successful in 58s Details
✅ CI: Optional E2E Tests / E2E node-express-send-to-sentry-static Test (optional) Successful in 1m Details
✅ CI: Optional E2E Tests / E2E node-openai-decisions-send-to-sentry Test (optional) Successful in 1m Details
✅ CI: Optional E2E Tests / E2E nuxt-5-sourcemaps (static / nuxt generate) Test (optional) Successful in 43s Details
✅ CI: Optional E2E Tests / E2E gen-ai-libraries (cloudflare) Test (optional) Successful in 1m Details
✅ CI: Optional E2E Tests / E2E astro-7 Test (optional) Successful in 1m Details
✅ CI: Optional E2E Tests / E2E nuxt-5 Test (optional) Successful in 2m Details
✅ CI: Optional E2E Tests / E2E node-eve Test (optional) Successful in 47s Details
✅ CI: Optional E2E Tests / E2E nextjs-orpc Test (optional) Successful in 1m Details
✅ CI: Optional E2E Tests / E2E tanstackstart-react-cloudflare Test (optional) Successful in 1m Details
✅ CI: Optional E2E Tests / E2E nextjs-15 (latest) Test (optional) Successful in 4m Details
✅ CI: Optional E2E Tests / E2E cloudflare-mastra Test (optional) Successful in 2m Details
✅ CI: Optional E2E Tests / E2E node-fastify-6 Test (optional) Successful in 26s Details
✅ CI: Optional E2E Tests / E2E nuxt-4-static (canary) Test (optional) Successful in 3m Details
✅ CI: Optional E2E Tests / E2E solidstart-2 Test (optional) Successful in 1m Details
✅ CI: Optional E2E Tests / E2E nuxt-4 (canary) Test (optional) Successful in 5m Details
✅ CI: Optional E2E Tests / E2E node-mastra Test (optional) Successful in 1m Details
✅ CI: Optional E2E Tests / E2E node-openai-decisions-send-to-sentry (latest) Test (optional) Successful in 2m Details
✅ CI: Optional E2E Tests / E2E node-fastify-6 (tracer provider) Test (optional) Successful in 27s Details
✅ CI: Optional E2E Tests / E2E node-openai-send-to-sentry (latest) Test (optional) Successful in 2m Details
✅ CI: Optional E2E Tests / E2E node-express-mcp-v1 Test (optional) Successful in 22s Details
✅ CI: Optional E2E Tests / E2E nextjs-15 (turbo) Test (optional) Successful in 3m Details

@isaacs
isaacs force-pushed the isaacschlueter/js-3975-share-one-request-handler-wrapper-across-denoserve-bunserve-b branch from 7e1f64d to c8a8ff5 Compare October 21, 2026 17:13
@isaacs
isaacs force-pushed the isaacschlueter/js-3975-share-one-request-handler-wrapper-across-denoserve-bunserve-b branch from c8a8ff5 to 9a24fd9 Compare October 21, 2026 17:28
@isaacs
isaacs force-pushed the isaacschlueter/js-3975-share-one-request-handler-wrapper-across-denoserve-bunserve-b branch from 7dda93e to bcab37f Compare October 21, 2026 18:28
@isaacs
isaacs force-pushed the isaacschlueter/js-3975-share-one-request-handler-wrapper-across-denoserve-bunserve-b branch from bcab37f to e6dcb2a Compare October 21, 2026 18:37
Moves `Bun.serve` onto `wrapServerRequestHandler`, which `Deno.serve`
uses since the previous PR. Bun keeps only what is unique to it: the
patches for `fetch`, `routes` and `server.reload`, the route template,
the route parameters, and the socket address from `server.requestIP()`.
Its copy of the stream monitor moves out, because the wrapper uses the
same code from `@sentry/server-utils`.

The wrapper gets two optional fields for this. `routeName` passes the
matched route to core's span helper, which sets `http.route`, the
`route` source and the span name. `attributes` adds span attributes
that only the runtime knows, here `url.path.parameter.*`.

Bun built its own span attributes, which did not follow the Sentry
conventions for `http.server` spans. The conventions say that server
instrumentation sets the matched route in `http.route`, and that
`url.template` is for `http.client` spans and client-side routing. The
host goes in `server.address`, as on Node, Deno and Cloudflare. So Bun
spans change:

- `url.template` becomes `http.route`. Routes without parameters now
  also get `http.route` and the `route` source.
- `url.domain` becomes `server.address`.
- A request to `/` gets the `route` source and the name `GET /`, as on
  the other runtimes, because the path is already low cardinality.
- Spans also get `user_agent.original` and `http.request.body.size`.
- Errors in `OPTIONS` and `HEAD` requests now carry the request data.

The wrapper now also keeps every `Set-Cookie` header of a response.
`Headers.forEach` lists each one on its own, so a plain dict kept only
the last one. This fixes Deno too, and Cloudflare once it moves.

Part of #25577
Part of JS-3975

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@isaacs
isaacs force-pushed the isaacschlueter/js-3975-share-one-request-handler-wrapper-across-denoserve-bunserve-b branch from e6dcb2a to 7c3ad11 Compare October 21, 2026 18:40

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant