diff --git a/dev-packages/e2e-tests/test-applications/tanstackstart-react/tests/tunnel.test.ts b/dev-packages/e2e-tests/test-applications/tanstackstart-react/tests/tunnel.test.ts index d3f9694a6d22..2c609065912d 100644 --- a/dev-packages/e2e-tests/test-applications/tanstackstart-react/tests/tunnel.test.ts +++ b/dev-packages/e2e-tests/test-applications/tanstackstart-react/tests/tunnel.test.ts @@ -62,6 +62,15 @@ test('Sends client-side errors through the configured tunnel route', async ({ pa expect(errorEvent.transaction).toBe('/'); }); +test('Rejects non-POST requests to the managed tunnel route instead of rendering the app', async ({ request }) => { + test.skip(tunnelRouteMode !== 'static', 'Requires a known managed tunnel path'); + + const response = await request.get('/monitor'); + + expect(response.status()).toBe(405); + expect(response.headers()['allow']).toBe('POST'); +}); + function pathnameMatchesTunnelRoute(pathname: string): boolean { return typeof expectedTunnelPathMatcher === 'string' ? pathname === expectedTunnelPathMatcher diff --git a/packages/tanstackstart-react/src/vite/tunnelRoute.ts b/packages/tanstackstart-react/src/vite/tunnelRoute.ts index c7af98412461..06f3337b4e5e 100644 --- a/packages/tanstackstart-react/src/vite/tunnelRoute.ts +++ b/packages/tanstackstart-react/src/vite/tunnelRoute.ts @@ -194,6 +194,10 @@ export const Route = createFileRoute(${serializedTunnelRoute})({ const Sentry = await import('@sentry/tanstackstart-react'); return Sentry.createSentryTunnelRoute(${serializedAllowedDsns ? `{ allowedDsns: ${serializedAllowedDsns} }` : `{}`}).handlers.POST({ request }); }, + // Without a handler for a method, TanStack Start falls back to SSR-rendering the app (running root loaders). + ANY() { + return new Response(null, { status: 405, headers: { Allow: 'POST' } }); + }, }, }, }); diff --git a/packages/tanstackstart-react/test/vite/tunnelRoute.test.ts b/packages/tanstackstart-react/test/vite/tunnelRoute.test.ts index 822a01aeeeff..22b3a9be56a5 100644 --- a/packages/tanstackstart-react/test/vite/tunnelRoute.test.ts +++ b/packages/tanstackstart-react/test/vite/tunnelRoute.test.ts @@ -139,6 +139,15 @@ describe('tunnelRoute vite plugin', () => { expect(virtualRouteModule).toContain('createSentryTunnelRoute({})'); }); + it('rejects non-POST requests in the virtual managed tunnel route module', async () => { + const plugin = makeTunnelRoutePlugin('/monitor'); + + const virtualRouteModule = plugin.load && (await plugin.load('\0virtual:sentry-tanstackstart-react/tunnel-route')); + + expect(virtualRouteModule).toContain('ANY()'); + expect(virtualRouteModule).toContain("status: 405, headers: { Allow: 'POST' }"); + }); + it('treats an empty string `path` like omitted and uses a generated tunnel route', () => { const plugin = makeTunnelRoutePlugin({ path: '' });