getsentry / getsentry/sentry-javascript
@sentry/astro: Cloudflare Worker server wrap not applied with @astrojs/cloudflare v14 (transform targets `astrojs-ssr-virtual-entry`, adapter now emits `virtual:cloudflare/worker-entry`)
- Vorherrschende Sprache
- TypeScript
- Sterne
- 8.7k
- Forks
- 1.8k
- Ø Merge
- 1 T. 17 Std.
- Gemergte PRs (30 T.)
- 515
Beschreibung
## Summary
With `@astrojs/cloudflare` v14, `@sentry/astro`'s server-side init is never applied to the deployed Cloudflare Worker. The Worker's default export is left un-wrapped by `withSentry`, so server-side error/log capture does not initialize at the fetch boundary — server-side Sentry silently does nothing.
## Versions
- `@sentry/astro` 10.62.0
- `@sentry/cloudflare` 10.62.0
- `@astrojs/cloudflare` 14.0.1
- `astro` 7.0.3
- `output: 'server'`, Cloudflare **Workers** (not Pages)
## Root cause
`sentryCloudflareVitePlugin` (`packages/astro/src/integration/cloudflare.ts`) wraps the Worker by transforming the module whose id contains `astrojs-ssr-virtual-entry`:
```js
transform(code, id) {
if (!id.includes("astrojs-ssr-virtual-entry")) {
return undefined;
}
// ...rewrites `export default X;` -> `export default withSentry(() => undefined, X);`
}
```
`@astrojs/cloudflare` v14 builds the Worker through `@cloudflare/vite-plugin`, whose entry virtual module id is `virtual:cloudflare/worker-entry` (its generated body ends with `export default mod.default ?? {};`). The old `astrojs-ssr-virtual-entry` id is no longer produced, so the `transform` guard always returns early and the entry is never wrapped.
## Effect
With an app configured per the [Astro + Cloudflare docs](https://docs.sentry.io/platforms/javascript/guides/cloudflare/frameworks/astro/) (the `sentry()` integration in `astro.config` plus a `sentry.server.config.ts` doing `export default Sentry.withSentry((env) => ({ ... }), handler)`), the generated `dist/server/entry.mjs` default export is the **raw** Astro handler. Grepping all of `dist/server` for `withSentry(() =>` finds no match — the plugin's wrap never ran.
The only remaining server wiring is the injected `import "sentry.server.config.(ts|js)"` (`injectScript("page-ssr", ...)`). That runs lazily during a page render, so it doesn't deterministically instrument the Worker's fetch entry:
- errors on the first request (before any page module has evaluated the config) aren't captured;
- routes that don't pull the page-ssr module graph (e.g. API endpoints) aren't covered;
- for a Worker whose first traffic is an API route, `Sentry.init` may never run at all.
## Repro
1. Scaffold an Astro app with `output: 'server'` and the `@astrojs/cloudflare` v14 adapter (Workers, not Pages).
2. `npm i @sentry/astro @sentry/cloudflare`; add `sentry()` to `integrations`; create `sentry.server.config.ts` per the docs:
```ts
import * as Sentry from '@sentry/cloudflare'
import handler from '@astrojs/cloudflare/entrypoints/server'
export default Sentry.withSentry((env) => ({ dsn: env.SENTRY_DSN, enableLogs: true }), handler)
```
3. `astro build`.
4. Inspect `dist/server/entry.mjs`: the default export is the un-wrapped Astro handler, and `grep -r "withSentry(() =>" dist/server` returns nothing.
## Suggested fix
Have `sentryCloudflareVitePlugin`'s `transform` also match the `@cloudflare/vite-plugin` entry id `virtual:cloudflare/worker-entry` (whose default-export expression is `mod.default ?? {}`), in addition to `astrojs-ssr-virtual-entry`, so the wrap applies on `@astrojs/cloudflare` v14+.
## Workaround
For anyone hitting this before a fix lands: a tiny build-only Vite plugin that transforms the `virtual:cloudflare/worker-entry` module and wraps its `export default mod.default ?? {};` with your own `withSentry(optionsCallback, handler)` restores deterministic, eager wrapping of the Worker entry.
Beitragsleitfaden
Bewertung
Dieses Issue wurde noch nicht bewertet.