Skip to content

ref(cloudflare): Extract one factory for the Vite provider plugins - #24535

Open
RulaKhaled wants to merge 4 commits into
developfrom
feat/cloudflare-provider-plugin-factory
Open

RulaKhaled wants to merge 4 commits into
developfrom
feat/cloudflare-provider-plugin-factory

Conversation

@RulaKhaled

@RulaKhaled RulaKhaled commented Sep 21, 2026

Copy link
Copy Markdown
Collaborator

Follow-up to #24476, where @isaacs pointed out that flueRuntime.ts and mastraObservability.ts are near-identical and drifting. Both are now a few lines over a shared createProvidedModulePlugin, so the next provider is a config object rather than a third copy.

The probe moves from createRequire().resolve() to the Rollup context's this.resolve(), which uses the same resolver and conditions as the injected import. That drops createRequire, node:path and the error-code special case, and fixes a latent Mastra bug: its bare catch { return; } only works because @mastra/observability still publishes a require condition, so an ESM-only release would have turned injection off silently, the same failure #24476 fixed for Flue. this.resolve() needs a plugin context, so the probe moves to buildStart and configResolved stays only to capture the app root. Resolution runs per environment against a shared instance, so it stops once the package is found and retries otherwise, since the worker environment may not run first.

Mastra also picks up the guards Flue gained in #24476: transform is idempotent, a resolver error injects rather than skipping, and the namespace goes behind the same lazy getter. Assigning reads the binding at injection time and stores undefined if the bundler evaluates Sentry's module first, which is not Flue-specific, so there is one shape for both and no lazy option.

cloudflare-mastra is the real check here: on workerd the injected binding is the only path loadMastraObservability can take, so a broken injection means no agent spans and a failing suite.

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

size-limit report 📦

Path Size % Change Change
@sentry/browser 29.07 kB - -
@sentry/browser - with treeshaking flags 27.34 kB - -
@sentry/browser - with treeshaking flags tracing without tracing 27.24 kB - -
@sentry/browser (incl. Tracing) 50.56 kB - -
@sentry/browser (incl. Tracing + Span Streaming) 50.58 kB - -
@sentry/browser (incl. Tracing, Profiling) 53.58 kB - -
@sentry/browser (incl. Tracing, Replay) 90.11 kB - -
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 79.2 kB - -
@sentry/browser (incl. Tracing, Replay with Canvas) 94.82 kB - -
@sentry/browser (incl. Tracing, Replay, Feedback) 107.79 kB - -
@sentry/browser (incl. Feedback) 46.6 kB - -
@sentry/browser (incl. sendFeedback) 34.13 kB - -
@sentry/browser (incl. FeedbackAsync) 39.25 kB - -
@sentry/browser (incl. Metrics) 30.08 kB - -
@sentry/browser (incl. Logs) 30.34 kB - -
@sentry/browser (incl. Metrics & Logs) 31 kB - -
@sentry/react 30.82 kB - -
@sentry/react (incl. Tracing) 52.89 kB - -
@sentry/vue 36.33 kB - -
@sentry/vue (incl. Tracing) 52.87 kB - -
@sentry/svelte 29.1 kB - -
CDN Bundle 30.77 kB - -
CDN Bundle (incl. Tracing) 51.09 kB - -
CDN Bundle (incl. Logs, Metrics) 33.02 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) 53.07 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) 73.71 kB - -
CDN Bundle (incl. Tracing, Replay) 88.63 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 90.56 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) 94.67 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 96.7 kB - -
CDN Bundle - uncompressed 91.07 kB - -
CDN Bundle (incl. Tracing) - uncompressed 152.52 kB - -
CDN Bundle (incl. Logs, Metrics) - uncompressed 97.64 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 158.48 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 227.05 kB - -
CDN Bundle (incl. Tracing, Replay) - uncompressed 272.09 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 278.03 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 285.8 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 291.73 kB - -
@sentry/nextjs (client) 55.22 kB - -
@sentry/sveltekit (client) 51.01 kB - -
@sentry/core/server 39.97 kB - -
@sentry/core/browser 13.63 kB - -
@sentry/node 133.37 kB +0.02% +20 B 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection) 82.15 kB - -
@sentry/node - without tracing 89.92 kB +0.03% +20 B 🔺
@sentry/node - without channel injection 112.16 kB +0.02% +22 B 🔺
@sentry/aws-serverless 98.19 kB +0.02% +18 B 🔺
@sentry/cloudflare (withSentry) - minified 204.67 kB - -
@sentry/cloudflare (withSentry) 509.34 kB - -

View base workflow run

Base automatically changed from feat/flue-cloudflare-autoinstrument to develop September 21, 2026 09:20
@RulaKhaled
RulaKhaled force-pushed the feat/cloudflare-provider-plugin-factory branch from 5ece63b to 7ca5878 Compare September 21, 2026 09:23
`flueRuntime.ts` and `mastraObservability.ts` were near-identical, differing
only in the module specifier, the injected identifier, the target regex, how
they handled a failed resolve, and getter versus assignment. Both call sites are
now a few lines over a shared `createProvidedModulePlugin`.

Replace the `createRequire().resolve()` probe with the Rollup context's
`this.resolve()`, which answers with the same resolver and conditions the
injected import will use. That drops `createRequire`, `node:path` and the
error-code special case, and it fixes a latent bug on the Mastra side: its bare
`catch { return; }` worked only because `@mastra/observability` still publishes
a `require` condition, so an ESM-only release would have turned injection off
with no error and no log. The probe needs a plugin context, so it moves from
`configResolved` to `buildStart`. `configResolved` stays to capture the app
root.

Resolution runs per environment against a shared plugin instance, so the probe
stops once it finds the package and retries in the next environment otherwise.
Only the worker environment ever reaches `transform`, and it may not run first.

Mastra also picks up the guards Flue gained in #24476: `transform` is
idempotent, a resolver error injects rather than silently skipping, and the
namespace now goes behind the same lazy getter. Assigning reads the binding at
injection time, so it stores `undefined` whenever the bundler evaluates Sentry's
module first. That hazard is not specific to Flue, so both providers use one
shape and the `lazy` option is gone.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@RulaKhaled
RulaKhaled force-pushed the feat/cloudflare-provider-plugin-factory branch from 7ca5878 to 8b3cbd3 Compare September 21, 2026 09:43
RulaKhaled and others added 3 commits September 21, 2026 17:45
Two defects in the factory, both found reviewing it against real Vite 6.4.3.

`buildStart` runs once per environment against one shared plugin instance, and
nothing gated which environments it applied to. A two-environment build proved
the `client` environment probes first, resolves under browser conditions, and
short-circuits the worker so its resolver is never consulted. That defeats the
reason the probe moved off `createRequire` at all. `applyToEnvironment` now
gates to server consumers, matching the orchestrion plugin.

The matcher built a `RegExp` from a caller-supplied string, which needed
`escapeStringForRegex` and so put the first `@sentry/core` import into
`src/vite/`. Every other module there stays on `node:*`, `magic-string` and
`wrangler`, and the orchestrion config module documents the same rule: a
build-time plugin must not drag the SDK into the build. The pattern was
end-anchored with nothing else to match, so `endsWith` replaces it exactly and
the import is gone.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The `catch` around `this.resolve` swallowed the error and injected anyway. The
injection is the right call, since skipping is how an installed package silently
loses instrumentation, but the import error Vite raises next says nothing about
why resolution broke. Warn with the original cause.

The Flue and Mastra suites built plugin contexts with only `resolve`, which
would have thrown on the new `this.warn` call had those tests taken the catch
path. `strictBindCallApply` does not catch this through `Function.call`, so they
typechecked clean while carrying the trap.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`found` and `missing` were module-scope `vi.fn()` instances shared by four
tests, with no reset between them, so their call counts accumulated. Nothing
asserts on those counts today, but the next test that tried would pass in
isolation and fail in suite order.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@RulaKhaled
RulaKhaled marked this pull request as ready for review September 21, 2026 15:29
@RulaKhaled
RulaKhaled requested a review from a team as a code owner September 21, 2026 15:29
@RulaKhaled
RulaKhaled requested review from JPeer264 and isaacs and removed request for a team September 21, 2026 15:29

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