Skip to content

Commit 43d3c3e

Browse files
chore(backend): Fix ClerkRequest helper instance check (#7431)
Co-authored-by: chris-kreidl <[email protected]>
1 parent f49e8aa commit 43d3c3e

File tree

4 files changed

+46
-2
lines changed

4 files changed

+46
-2
lines changed

.changeset/five-numbers-scream.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@clerk/backend": patch
3+
---
4+
5+
Fixed an issue where TanStack React Start middleware fails to properly handle requests.

integration/templates/tanstack-react-start/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
"@tanstack/react-start": "1.132.51",
1414
"react": "18.3.1",
1515
"react-dom": "18.3.1",
16-
"srvx": "0.8.15",
1716
"tailwind-merge": "^2.5.4"
1817
},
1918
"devDependencies": {

packages/backend/src/tokens/__tests__/clerkRequest.test.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,4 +171,39 @@ describe('createClerkRequest', () => {
171171
expect(json.cookies).toBe('{}');
172172
});
173173
});
174+
175+
describe('duck typing detection (instanceof workaround)', () => {
176+
it('should create a new ClerkRequest from a regular Request', () => {
177+
const regularRequest = new Request('http://localhost:3000');
178+
const clerkRequest = createClerkRequest(regularRequest);
179+
180+
expect(clerkRequest).not.toBe(regularRequest);
181+
expect(clerkRequest.clerkUrl).toBeDefined();
182+
expect(clerkRequest.cookies).toBeDefined();
183+
});
184+
185+
it('should return an existing ClerkRequest instance unchanged', () => {
186+
const firstClerkRequest = createClerkRequest(new Request('http://localhost:3000'));
187+
const secondClerkRequest = createClerkRequest(firstClerkRequest);
188+
189+
expect(secondClerkRequest).toBe(firstClerkRequest);
190+
});
191+
192+
it('should work correctly with bundler-scoped Request classes', () => {
193+
// Simulate bundler creating a scoped Request class (like Request$1)
194+
class RequestScoped extends Request {
195+
constructor(input: RequestInfo | URL, init?: RequestInit) {
196+
super(input, init);
197+
}
198+
}
199+
200+
const scopedRequest = new RequestScoped('http://localhost:3000');
201+
const clerkRequest = createClerkRequest(scopedRequest);
202+
203+
// Should create a new ClerkRequest even though scopedRequest is a different Request class
204+
expect(clerkRequest).not.toBe(scopedRequest);
205+
expect(clerkRequest.clerkUrl).toBeDefined();
206+
expect(clerkRequest.cookies).toBeDefined();
207+
});
208+
});
174209
});

packages/backend/src/tokens/clerkRequest.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,12 @@ class ClerkRequest extends Request {
7777
}
7878

7979
export const createClerkRequest = (...args: ConstructorParameters<typeof ClerkRequest>): ClerkRequest => {
80-
return args[0] instanceof ClerkRequest ? args[0] : new ClerkRequest(...args);
80+
// Use duck typing instead of instanceof to avoid issues with polyfilled Request classes
81+
// (e.g., in TanStack Start or other environments with multiple Request class instances)
82+
// ClerkRequest has unique properties 'clerkUrl' and 'cookies' that distinguish it from Request
83+
const isClerkRequest = args[0] && typeof args[0] === 'object' && 'clerkUrl' in args[0] && 'cookies' in args[0];
84+
85+
return isClerkRequest ? (args[0] as ClerkRequest) : new ClerkRequest(...args);
8186
};
8287

8388
export type { ClerkRequest };

0 commit comments

Comments
 (0)