Skip to content

Commit db74d2f

Browse files
committed
fix(tanstackstart-react): Fail the build when a fixed tunnelRoute collides with an app route, as on develop
1 parent 75aadd3 commit db74d2f

2 files changed

Lines changed: 42 additions & 0 deletions

File tree

‎packages/tanstackstart-react/src/vite/tunnelRoute.ts‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,15 @@ export function normalizeTunnelRouteOptions(options: TunnelRouteOptions): Tunnel
5454
};
5555
}
5656

57+
// `routeTree.gen.ts` quote style follows `tsr.config.json#quoteStyle` (`single` | `double`),
58+
// so we check both forms for each route-identifying key.
59+
const ROUTE_CONFLICT_KEYS = ['fullPath', 'path', 'id'] as const;
60+
61+
function hasRouteConflict(source: string, tunnelPath: string): boolean {
62+
const literals = [`'${tunnelPath}'`, `"${tunnelPath}"`];
63+
return ROUTE_CONFLICT_KEYS.some(key => literals.some(literal => source.includes(`${key}: ${literal}`)));
64+
}
65+
5766
/**
5867
* Tells the client SDK which tunnel to use. The server entry wrapper serves it.
5968
*/
@@ -70,6 +79,17 @@ export function makeTunnelRoutePlugin(options: TunnelRouteOptions, debug?: boole
7079
config() {
7180
return { define: { __SENTRY_TANSTACKSTART_TUNNEL_ROUTE__: path ? JSON.stringify(path) : 'true' } };
7281
},
82+
// The server entry wrapper answers POSTs to a fixed path before Start's routing, so an app route on that path
83+
// would silently lose them.
84+
transform(source, id) {
85+
if (path && /[\\/]routeTree\.gen\.ts$/.test(id) && hasRouteConflict(source, path)) {
86+
throw new Error(
87+
`[@sentry/tanstackstart-react] Cannot register managed tunnel route "${path}" because an existing TanStack Start route already uses that path.`,
88+
);
89+
}
90+
91+
return null;
92+
},
7393
};
7494
}
7595

‎packages/tanstackstart-react/test/vite/tunnelRoute.test.ts‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,28 @@ describe('tunnelRoute vite plugin', () => {
4545
define: { __SENTRY_TANSTACKSTART_TUNNEL_ROUTE__: 'true' },
4646
});
4747
});
48+
49+
it('fails when a static tunnel route conflicts with an existing route', () => {
50+
const transform = (path: string, source: string): unknown =>
51+
(makeTunnelRoutePlugin(path).transform as (source: string, id: string) => unknown)(
52+
source,
53+
'/app/src/routeTree.gen.ts',
54+
);
55+
const singleQuoted = "const MonitorRoute = MonitorRouteImport.update({\n id: '/monitor',\n path: '/monitor',";
56+
const doubleQuoted = singleQuoted.replace(/'/g, '"');
57+
58+
expect(() => transform('/monitor', singleQuoted)).toThrow(
59+
'Cannot register managed tunnel route "/monitor" because an existing TanStack Start route already uses that path.',
60+
);
61+
expect(() => transform('/monitor', doubleQuoted)).toThrow('already uses that path');
62+
expect(transform('/other', singleQuoted)).toBeNull();
63+
expect(
64+
(makeTunnelRoutePlugin(true).transform as (s: string, id: string) => unknown)(
65+
singleQuoted,
66+
'/app/src/routeTree.gen.ts',
67+
),
68+
).toBeNull();
69+
});
4870
});
4971

5072
describe('server entry tunnel vite plugin', () => {

0 commit comments

Comments
 (0)