@@ -259,6 +259,102 @@ describe('Session', () => {
259
259
body : { organizationId : 'newActiveOrganization' } ,
260
260
} ) ;
261
261
} ) ;
262
+
263
+ it ( 'deduplicates concurrent getToken calls to prevent multiple API requests' , async ( ) => {
264
+ BaseResource . clerk = clerkMock ( ) as any ;
265
+
266
+ const session = new Session ( {
267
+ status : 'active' ,
268
+ id : 'session_1' ,
269
+ object : 'session' ,
270
+ user : createUser ( { } ) ,
271
+ last_active_organization_id : null ,
272
+ actor : null ,
273
+ created_at : new Date ( ) . getTime ( ) ,
274
+ updated_at : new Date ( ) . getTime ( ) ,
275
+ } as SessionJSON ) ;
276
+
277
+ const requestSpy = BaseResource . clerk . getFapiClient ( ) . request as Mock < any > ;
278
+ requestSpy . mockClear ( ) ;
279
+
280
+ const [ token1 , token2 , token3 ] = await Promise . all ( [ session . getToken ( ) , session . getToken ( ) , session . getToken ( ) ] ) ;
281
+
282
+ expect ( requestSpy ) . toHaveBeenCalledTimes ( 1 ) ;
283
+ expect ( token1 ) . toEqual ( mockJwt ) ;
284
+ expect ( token2 ) . toEqual ( mockJwt ) ;
285
+ expect ( token3 ) . toEqual ( mockJwt ) ;
286
+ } ) ;
287
+
288
+ it ( 'deduplicates concurrent getToken calls with same template' , async ( ) => {
289
+ BaseResource . clerk = clerkMock ( ) as any ;
290
+
291
+ const session = new Session ( {
292
+ status : 'active' ,
293
+ id : 'session_1' ,
294
+ object : 'session' ,
295
+ user : createUser ( { } ) ,
296
+ last_active_organization_id : null ,
297
+ actor : null ,
298
+ created_at : new Date ( ) . getTime ( ) ,
299
+ updated_at : new Date ( ) . getTime ( ) ,
300
+ } as SessionJSON ) ;
301
+
302
+ const requestSpy = BaseResource . clerk . getFapiClient ( ) . request as Mock < any > ;
303
+ requestSpy . mockClear ( ) ;
304
+
305
+ const [ token1 , token2 ] = await Promise . all ( [
306
+ session . getToken ( { template : 'custom-template' } ) ,
307
+ session . getToken ( { template : 'custom-template' } ) ,
308
+ ] ) ;
309
+
310
+ expect ( requestSpy ) . toHaveBeenCalledTimes ( 1 ) ;
311
+ expect ( token1 ) . toEqual ( mockJwt ) ;
312
+ expect ( token2 ) . toEqual ( mockJwt ) ;
313
+ } ) ;
314
+
315
+ it ( 'does not deduplicate getToken calls with different templates' , async ( ) => {
316
+ BaseResource . clerk = clerkMock ( ) as any ;
317
+
318
+ const session = new Session ( {
319
+ status : 'active' ,
320
+ id : 'session_1' ,
321
+ object : 'session' ,
322
+ user : createUser ( { } ) ,
323
+ last_active_organization_id : null ,
324
+ actor : null ,
325
+ created_at : new Date ( ) . getTime ( ) ,
326
+ updated_at : new Date ( ) . getTime ( ) ,
327
+ } as SessionJSON ) ;
328
+
329
+ const requestSpy = BaseResource . clerk . getFapiClient ( ) . request as Mock < any > ;
330
+ requestSpy . mockClear ( ) ;
331
+
332
+ await Promise . all ( [ session . getToken ( { template : 'template1' } ) , session . getToken ( { template : 'template2' } ) ] ) ;
333
+
334
+ expect ( requestSpy ) . toHaveBeenCalledTimes ( 2 ) ;
335
+ } ) ;
336
+
337
+ it ( 'does not deduplicate getToken calls with different organization IDs' , async ( ) => {
338
+ BaseResource . clerk = clerkMock ( ) as any ;
339
+
340
+ const session = new Session ( {
341
+ status : 'active' ,
342
+ id : 'session_1' ,
343
+ object : 'session' ,
344
+ user : createUser ( { } ) ,
345
+ last_active_organization_id : null ,
346
+ actor : null ,
347
+ created_at : new Date ( ) . getTime ( ) ,
348
+ updated_at : new Date ( ) . getTime ( ) ,
349
+ } as SessionJSON ) ;
350
+
351
+ const requestSpy = BaseResource . clerk . getFapiClient ( ) . request as Mock < any > ;
352
+ requestSpy . mockClear ( ) ;
353
+
354
+ await Promise . all ( [ session . getToken ( { organizationId : 'org_1' } ) , session . getToken ( { organizationId : 'org_2' } ) ] ) ;
355
+
356
+ expect ( requestSpy ) . toHaveBeenCalledTimes ( 2 ) ;
357
+ } ) ;
262
358
} ) ;
263
359
264
360
describe ( 'touch()' , ( ) => {
0 commit comments