ref(core)!: Split browser/server-only exports out of the default entrypoint - #23762
Conversation
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want reviews to match your repository better? Bugbot Learning can learn team-specific rules from PR activity. A team admin can enable Learning in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit e32bdf9. Configure here.
size-limit report 📦
|
e32bdf9 to
e787ccb
Compare
096dba7 to
8813722
Compare
…ypoint `@sentry/core` now exposes only isomorphic code. The `/browser` and `/server` entrypoints contain only their platform-specific exports instead of also re-exporting the full shared surface, and consumer packages import platform-specific symbols from the matching entrypoint. A `no-unguarded-span-apis` lint rule enforces that browser-facing code imports the span-start APIs from `@sentry/core/browser` (the guarded variant), never from `@sentry/core`/`@sentry/core/server`. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Point browser-facing tests at `@sentry/core` for isomorphic symbols (keeping only the guarded span-start APIs on `@sentry/core/browser`), and point server-facing tests at `@sentry/core/server` for the moved server-only symbols (`flushIfServerless`, `loadModule`, `isNodeEnv`, `vercelWaitUntil`, `nodeStackLineParser`, `trpcMiddleware`, `ServerRuntimeClient`, ...) so mocks and spies intercept the same binding the source imports. Update `core`'s `exports.test.ts` to the disjoint entrypoint contract: the root entry serves the plain span-start APIs and `spanStreamingIntegration`, the browser entry serves the guarded span-start variants, and the server entry re-exports neither (server code imports the isomorphic APIs from the root entry). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The postgres/postgresjs tracing scenarios imported `uuid4` from `@sentry/core/server`, which only serves server-specific exports and does not provide `uuid4` — the ESM import crashed each scenario at load. `uuid4` is isomorphic and lives on the root `@sentry/core` entry. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
8813722 to
64417fb
Compare
JPeer264
left a comment
There was a problem hiding this comment.
LGTM. Tests are failing but they seem to be flaky. I'll rerun
| * Effect `Tracer` that records Effect spans as Sentry spans on the server. | ||
| * | ||
| * Deliberately the plain `@sentry/core` variant, not `@sentry/core/browser`: the browser one guards | ||
| * Deliberately the plain `@sentry/core` variant, not `@sentry/core`: the browser one guards |
There was a problem hiding this comment.
l: This comment doesn't make sense anymore when /browser got removed. I guess this block can be removed now
There was a problem hiding this comment.
we still need the block, but the comment is wrong indeeed :D
| import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; | ||
| import { z } from 'zod'; | ||
| import { wrapMcpServerWithSentry } from '@sentry/core'; | ||
| import { wrapMcpServerWithSentry } from '@sentry/node'; |
There was a problem hiding this comment.
l: The @sentry/core dependency can then also be removed if this switches to @sentry/node
There was a problem hiding this comment.
we still use a type from this somewhere 🤔

Splits the browser- and server-only exports out of
@sentry/core's default entrypoint.@sentry/corenow exposes only isomorphic code, and the@sentry/core/browserand@sentry/core/serverentrypoints now contain only their platform-specific exports instead of also re-exporting the shared surface on top.Previously the default entrypoint re-exported everything (via
shared-exports.ts), and both/browserand/serverre-exported that shared surface plus their platform extras. That meant importing anything from@sentry/corecould drag server-only code (http server/client instrumentation, ANR, postgres/sql helpers, …) into browser bundles, and the platform entrypoints were never cleanly separable.After this change:
@sentry/core— isomorphic exports only (the formershared-exports.ts, inlined intoindex.ts).@sentry/core/browser— browser-only exports, e.g. the guardedstartSpan/startInactiveSpanvariants that installspanStreamingIntegration.@sentry/core/server— server-only exports:ServerRuntimeClient,ServerRuntimeOptions,trpcMiddleware,wrapMcpServerWithSentry, the http client/server subscription APIs,flushIfServerless,loadModule, node stack-trace helpers, postgres/sql instrumentation, and more.Consumer packages were updated to import platform-specific symbols from the matching entrypoint rather than from
@sentry/core.Root cause of the guarded-span split: the browser SDK's
init()deliberately omitsspanStreamingIntegration— referencing it would keep the whole span-streaming graph in every bundle, including error-only ones. Because the plain and guarded span-start APIs share their names, importing the plain variant in browser code compiles fine but produces spans that are then never sent. The newno-unguarded-span-apislint rule is the only thing that catches this, and enforces that browser-facing code imports the span-start APIs from@sentry/core/browser.Decisions
/browserand/serverre-export the isomorphic surface. Consumers import isomorphic code from@sentry/coreand platform code from the matching subpath — this is what makes the separation meaningful for tree-shaking and bundle size.!): symbols previously reachable from@sentry/core(e.g.trpcMiddleware,wrapMcpServerWithSentry) now live under@sentry/core/server.