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`)

未关闭
#21,901 4 条评论 0 个 reaction 已指派 1 人 已被 @JPeer264 认领 在 GitHub 查看
Astro Cloudflare Workers Feature
主要语言
TypeScript
星标
8.7k
派生
1.8k
平均合并
1 天 17 小时
30 天内合并 PR
515

描述

## 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.

贡献指南

打开贡献指南

评估

这个 Issue 还没有评估数据。

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。