mirror of
https://github.com/supabase/supabase.git
synced 2026-09-06 09:59:03 +08:00
Stacked on #47666 (base `alaister/tanstack-sentry-init`; retarget to `master` when that merges). **Supersedes #47721** (the manual `@sentry/node` wrapper). Client stays on #47666's `@sentry/react` setup. Adopts the official `@sentry/tanstackstart-react` SDK **on the server only**, after a spike (#47723) evaluating the full unified client+server SDK. The spike found the SDK's **browser** `tanstackRouterBrowserTracingIntegration` is a broken no-op stub at 10.59.0/10.64.0 — so the client stays on `@sentry/react` (whose equivalent integration is a real, working implementation, already shipped in #47666). The **server** exports, however, are a clear upgrade and slot in cleanly. ### What this adds (server-side, TanStack build only) - **`instrument.server.mjs`** — `Sentry.init` from `@sentry/tanstackstart-react`, mirroring `sentry.server.config.ts` + `release: VERCEL_GIT_COMMIT_SHA`. - **`start.ts`** — `sentryGlobalRequestMiddleware` + `sentryGlobalFunctionMiddleware` at the front of the existing `createStart(...)` middleware. **This is the win**: it captures request- and server-function errors *including the ones swallowed into 500s* — the exact class the manual wrapper (and the Next server SDK) miss. - **`api/server.js` / `scripts/serve.js`** — gated (`STUDIO_FRAMEWORK==='tanstack'`) instrument init + `wrapFetchWithSentry` on the handler. - **`vite.config.ts`** — `sentryTanstackStart({ …, autoInstrumentMiddleware: false })` as the last plugin: source-map upload + release injection (skips gracefully without an auth token). Middleware is wired explicitly rather than via the plugin's string-rewrite. ### Guarantees - **Client untouched** — the `@sentry/nextjs`→`@sentry/react` alias and #47666's client init are unchanged. - **Next untouched** — `instrumentation.ts` / `sentry.server.config.ts` etc. stay as-is; all new code is TanStack-gated. - **No server SDK in the client bundle** — verified after build: no `@sentry/node` / server middleware / `wrapFetchWithSentry` in `dist/client/assets` (`start.ts`'s server import is tree-shaken out). ### Verified TanStack build exit 0 (past `assertNoChunkCycles`), post-build server boot served `/api/get-utc-time → 200`, `tsc --noEmit` clean, prettier/eslint clean. Node smoke: no-DSN init is a clean no-op; wrapped handler returns 200. ### To test (deploy with a server DSN) Throw a server error from an `/api/*` route (or a `/_serverFn/*`) — including one that gets turned into a 500 without rethrowing — and confirm a server event in Sentry with `release` = the deploy SHA. Compared to #47721, the swallowed-500 case should now be captured via the middleware. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added Sentry integration for the Studio app’s TanStack Start runtime, including request and server-function instrumentation. * Wrapped server request handling to capture errors reliably, with tracing enabled. * Updated build tooling to conditionally upload source maps when credentials are present. * **Bug Fixes** * Improved resilience by safely falling back to a no-op Sentry setup if instrumentation cannot be loaded. * Ensured existing request protection remains enabled while adding observability middleware. * **Chores / Config** * Added `SKIP_ASSET_UPLOAD` to the build environment list to control cache/build behavior. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com> Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
47 lines
2.1 KiB
TypeScript
47 lines
2.1 KiB
TypeScript
import {
|
|
sentryGlobalFunctionMiddleware,
|
|
sentryGlobalRequestMiddleware,
|
|
} from '@sentry/tanstackstart-react'
|
|
import { createMiddleware, createStart } from '@tanstack/react-start'
|
|
|
|
import { BASE_PATH, IS_PLATFORM } from '@/lib/constants'
|
|
import { isHostedSupportedApiPath } from '@/lib/hosted-api-allowlist'
|
|
|
|
// Self-hosted-only API routes must 404 in platform (hosted) mode. Under the
|
|
// Next pages router this lives in middleware (proxy.ts), but TanStack Start
|
|
// has no middleware runtime, so the guard is migrated here as a global
|
|
// request middleware sharing the same allowlist (lib/hosted-api-allowlist.ts).
|
|
// On Vercel our `/api/*` (and `/_serverFn/*`) requests are rewritten to the
|
|
// api/server.js function which runs the Start handler, so createStartHandler
|
|
// runs this server-side for every API request — even though pages are served
|
|
// as a static SPA shell. The guard therefore covers all API routes from a
|
|
// single place.
|
|
|
|
const platformApiGuard = createMiddleware({ type: 'request' }).server(({ request, next }) => {
|
|
const { pathname } = new URL(request.url)
|
|
// Path relative to the configured basePath — mirrors Next's basePath-
|
|
// relative middleware matcher.
|
|
const relativePath =
|
|
BASE_PATH && pathname.startsWith(BASE_PATH) ? pathname.slice(BASE_PATH.length) : pathname
|
|
|
|
if (IS_PLATFORM && relativePath.startsWith('/api/') && !isHostedSupportedApiPath(relativePath)) {
|
|
return Response.json(
|
|
{ success: false, message: 'Endpoint not supported on hosted' },
|
|
{ status: 404 }
|
|
)
|
|
}
|
|
|
|
return next()
|
|
})
|
|
|
|
// Sentry's global middlewares go at the FRONT so they wrap the whole request /
|
|
// server-function lifecycle — including errors that downstream code swallows
|
|
// into a 500, which the manual `@sentry/nextjs` approach never sees. The SDK's
|
|
// Vite plugin can auto-wrap these arrays instead, but we disable that
|
|
// (`autoInstrumentMiddleware: false` in vite.config.ts) and wire them
|
|
// explicitly so the instrumentation is visible in source.
|
|
export const startInstance = createStart(() => ({
|
|
requestMiddleware: [sentryGlobalRequestMiddleware, platformApiGuard],
|
|
functionMiddleware: [sentryGlobalFunctionMiddleware],
|
|
}))
|