Tunnel route helper + Dynamic tunnel route generator for TanStack Start React#20264
Tunnel route helper + Dynamic tunnel route generator for TanStack Start React#20264nikolovlazar wants to merge 15 commits intodevelopfrom
Conversation
Semver Impact of This PR⚪ None (no version bump detected) 📋 Changelog PreviewThis is how your changes will appear in the changelog. New Features ✨Cloudflare
Core
Deps
Other
Bug Fixes 🐛Deno
Other
Internal Changes 🔧Ci
Deps
Other
Other
🤖 This preview updates automatically when you update the PR. |
There was a problem hiding this comment.
Pull request overview
Adds a TanStack Start server-route helper in @sentry/tanstackstart-react to make setting up a Sentry tunnel endpoint a one-liner, with unit tests to validate the POST-only route shape and forwarding behavior.
Changes:
- Introduce
createSentryTunnelRoutewhich wraps@sentry/core’shandleTunnelRequestfor TanStack Start server routes. - Export the helper from the package’s server entrypoint.
- Add unit tests covering the POST-only handler shape and correct request/options forwarding.
Reviewed changes
Copilot reviewed 3 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| yarn.lock | Lockfile updates (not directly related to the new tunnel helper). |
| packages/tanstackstart-react/src/server/tunnelRoute.ts | Adds createSentryTunnelRoute helper wrapping the core tunnel handler. |
| packages/tanstackstart-react/src/server/index.ts | Re-exports createSentryTunnelRoute from the server entrypoint. |
| packages/tanstackstart-react/test/server/tunnelRoute.test.ts | Adds focused unit tests for handler shape and forwarding behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Autofix Details
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Missing integration or E2E test for new feature
- Added E2E test file (tunnel.test.ts) and tunnel route (api.tunnel.ts) to verify createSentryTunnelRoute functionality in the tanstackstart-react E2E test application.
Or push these changes by commenting:
@cursor push b1fe0b60b9
Preview (b1fe0b60b9)
diff --git a/dev-packages/e2e-tests/test-applications/tanstackstart-react/src/routes/api.tunnel.ts b/dev-packages/e2e-tests/test-applications/tanstackstart-react/src/routes/api.tunnel.ts
new file mode 100644
--- /dev/null
+++ b/dev-packages/e2e-tests/test-applications/tanstackstart-react/src/routes/api.tunnel.ts
@@ -1,0 +1,8 @@
+import { createFileRoute } from '@tanstack/react-router';
+import { createSentryTunnelRoute } from '@sentry/tanstackstart-react';
+
+export const Route = createFileRoute('/api/tunnel')({
+ server: createSentryTunnelRoute({
+ allowedDsns: [process.env.E2E_TEST_DSN || ''],
+ }),
+});
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
new file mode 100644
--- /dev/null
+++ b/dev-packages/e2e-tests/test-applications/tanstackstart-react/tests/tunnel.test.ts
@@ -1,0 +1,66 @@
+import { expect, test } from '@playwright/test';
+import { waitForError } from '@sentry-internal/test-utils';
+
+test('Tunnel route forwards envelopes to Sentry', async ({ baseURL }) => {
+ const errorEventPromise = waitForError('tanstackstart-react', errorEvent => {
+ return errorEvent?.exception?.values?.[0]?.value === 'Test error for tunnel route';
+ });
+
+ const dsn = process.env.E2E_TEST_DSN || '';
+ const [protocol, rest] = dsn.split('://');
+ const [auth, hostAndPath] = rest.split('@');
+ const [publicKey] = auth.split(':');
+ const [host, ...pathParts] = hostAndPath.split('/');
+ const projectId = pathParts[pathParts.length - 1];
+
+ const envelope = [
+ JSON.stringify({ event_id: crypto.randomUUID(), sent_at: new Date().toISOString() }),
+ JSON.stringify({
+ type: 'event',
+ length: 0,
+ }),
+ JSON.stringify({
+ exception: {
+ values: [
+ {
+ type: 'Error',
+ value: 'Test error for tunnel route',
+ },
+ ],
+ },
+ platform: 'javascript',
+ sdk: {
+ name: 'sentry.javascript.tanstackstart-react',
+ version: '0.0.0',
+ },
+ timestamp: Date.now() / 1000,
+ }),
+ ].join('\n');
+
+ const tunnelUrl = `${baseURL}/api/tunnel`;
+ const sentryUrl = `${protocol}://${host}/api/${projectId}/envelope/`;
+
+ const response = await fetch(tunnelUrl, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/x-sentry-envelope',
+ 'X-Sentry-Auth': `Sentry sentry_key=${publicKey}, sentry_version=7`,
+ },
+ body: `${sentryUrl}\n${envelope}`,
+ });
+
+ expect(response.status).toBe(200);
+
+ const errorEvent = await errorEventPromise;
+
+ expect(errorEvent).toMatchObject({
+ exception: {
+ values: [
+ {
+ type: 'Error',
+ value: 'Test error for tunnel route',
+ },
+ ],
+ },
+ });
+});This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.
size-limit report 📦
|
logaretm
left a comment
There was a problem hiding this comment.
I think it is worth adding an e2e test case for this in one of the tanstack test applications we have.
It will also act as a live way to show how to set it up in an application, I think dev-packages/e2e-tests/test-applications/tanstackstart-react can be a good place for it or maybe a new application if you come across conflicts with pre-existing tests.
yes I did try that, but I needed to rip out the local tunnel that was defined at this file. In order not to risk breaking existing testing functionality, I didn't push the code. Should I create a different tanstack start app instead, @logaretm? |
|
@nikolovlazar Yep that works, or if you feel extra fancy check my comment here. |
…github.com:getsentry/sentry-javascript into lazarnikolov/js-2140-tanstack-start-tunnel-adapter
logaretm
left a comment
There was a problem hiding this comment.
Some ideas and some linting issues to go through but I think this is looking good and would be very valuable once its out.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 4390705. Configure here.
| validateStaticPath(path); | ||
| } | ||
|
|
||
| return { resolvedPath: resolveTunnelRoute(path ?? true), allowedDsns }; |
There was a problem hiding this comment.
Empty string path bypasses validation but gets used
Low Severity
In normalizeTunnelRouteOptions, the truthiness check if (path) skips validateStaticPath for empty strings, but path ?? true on the next line still passes the empty string through to resolveTunnelRoute('') (since nullish coalescing only checks null/undefined). This results in an invalid empty route path that bypasses the validation designed to catch it. The guard and the fallback use incompatible emptiness semantics — one treats '' as absent, the other treats it as present.
Reviewed by Cursor Bugbot for commit 4390705. Configure here.
There was a problem hiding this comment.
this is also valid, empty paths would cause the tunnel to send stuff to the root page. We should treat '' as undefined, user must specify an actual path.
It's a bit of a can of worms, but we should also make sure they always have a / in there if they provide it, basically we want to avoid relative and empty paths because they resolve to the current page.
So we can throw if they do provide a path/string and if it doesn't start with /.
| tunnel: '/monitor', | ||
| }, | ||
| sourcemaps: { disable: true }, | ||
| }); |
There was a problem hiding this comment.
Tests use wrong property name after API rename
Low Severity
The managed tunnel route tests pass tunnel: '/monitor' in the tunnelRoute options object, but the TunnelRouteOptions type defines the property as path, not tunnel. Since makeTunnelRoutePlugin is mocked, the tests pass despite the wrong property name. This means the tests don't actually verify that the path option is correctly propagated — they only confirm an object with an unrecognized extra property is forwarded. This appears to be a leftover from the tunnel → path rename discussed in PR review.
Additional Locations (1)
Triggered by project rule: PR Review Guidelines for Cursor Bot
Reviewed by Cursor Bugbot for commit 4390705. Configure here.
There was a problem hiding this comment.
This is valid since we changed that 👍



Summary
createSentryTunnelRouteto@sentry/tanstackstart-reactas a one-line server route adapter around the core tunnel handlersentryTanstackStart()(the existing Vite integration) with a newtunnelRouteoption which can automatically register a same-origin tunnel route and set the clienttunneloption to point to ittunnelRoutevariants:tunnel: true, default): generates an opaque route path once per dev session / production build so ad blockers can’t reliably target it by a known pathtunnel: '/custom-path'): uses an explicit fixed tunnel route pathNotes
yarn.lockcontains unrelated changes and should be reviewed separatelyTesting
cd packages/tanstackstart-react && yarn test/monitorreturns200and forwards envelopes to a real Sentry project. I also made sure session replays are being handled correctly. Screenshots from my Sentry org's usage indicating the events were received:Examples
createSentryTunnelRoute(manual server route)sentryTanstackStart({ tunnelRoute })(managed tunnel route via Vite plugin)