@@ -15,6 +15,7 @@ import {
1515import { UserContext } from "supertokens-node/lib/build/types" ;
1616import { createMockCalendarListEntry as mockCalendarListCreate } from "@core/__tests__/helpers/gcal.factory" ;
1717import { gSchema$CalendarListEntry } from "@core/types/gcal" ;
18+ import { StringV4Schema , zObjectId } from "@core/types/type.utils" ;
1819import { UserMetadata } from "@core/types/user.types" ;
1920import { mockAndCategorizeGcalEvents } from "@backend/__tests__/mocks.gcal/factories/gcal.event.batch" ;
2021import { mockGcal } from "@backend/__tests__/mocks.gcal/factories/gcal.factory" ;
@@ -85,29 +86,39 @@ function mockSuperToken() {
8586 ? JSON . parse ( sessionString )
8687 : undefined ;
8788
88- if ( typeof session ?. userId === "string" ) {
89- req . session = {
90- getUserId ( ) {
91- return session . userId ;
92- } ,
93- getAccessTokenPayload ( ) : SupertokensAccessTokenPayload {
94- return {
95- iat : now . getMilliseconds ( ) ,
96- exp : now . getMilliseconds ( ) + 5000 ,
97- iss : req . headers . origin ?? "http://localhost" ,
98- sub : session . userId ,
99- rsub : session . userId ,
100- tId,
101- sessionHandle : session . sessionId ?? sessionHandle ,
102- refreshTokenHash1 : null ,
103- parentRefreshTokenHash1 : null ,
104- antiCsrfToken : null ,
105- } ;
106- } ,
107- } as SessionContainerInterface ;
108-
109- return next ?.( ) ;
110- }
89+ const userId = zObjectId . parse ( session ?. userId , {
90+ error : ( ) => "invalid superToken session" ,
91+ } ) ;
92+
93+ const sessionId = StringV4Schema . parse (
94+ session ?. sessionId ?? sessionHandle ,
95+ { error : ( ) => "invalid superToken session" } ,
96+ ) ;
97+
98+ req . session = {
99+ getUserId ( ) {
100+ return userId . toString ( ) ;
101+ } ,
102+ getHandle ( ) {
103+ return sessionId ;
104+ } ,
105+ getAccessTokenPayload ( ) : SupertokensAccessTokenPayload {
106+ return {
107+ iat : now . getMilliseconds ( ) ,
108+ exp : now . getMilliseconds ( ) + 5000 ,
109+ iss : req . headers . origin ?? "http://localhost" ,
110+ sub : userId . toString ( ) ,
111+ rsub : userId . toString ( ) ,
112+ tId,
113+ sessionHandle : sessionId ,
114+ refreshTokenHash1 : null ,
115+ parentRefreshTokenHash1 : null ,
116+ antiCsrfToken : null ,
117+ } ;
118+ } ,
119+ } as SessionContainerInterface ;
120+
121+ return next ?.( ) ;
111122
112123 if ( input ?. verifySessionOptions ?. sessionRequired ) {
113124 throw new Error ( "invalid superToken session" ) ;
@@ -145,6 +156,71 @@ function mockSuperToken() {
145156 } ) ;
146157 }
147158
159+ const mappings = new Map < string , string > ( ) ;
160+
161+ async function getUserIdMapping ( input : {
162+ userId : string ;
163+ userIdType ?: "SUPERTOKENS" | "EXTERNAL" | "ANY" ;
164+ userContext ?: Record < string , unknown > ;
165+ } ) : Promise <
166+ | {
167+ status : "OK" ;
168+ superTokensUserId : string ;
169+ externalUserId : string ;
170+ }
171+ | { status : "UNKNOWN_MAPPING_ERROR" }
172+ > {
173+ const superTokensUserId = mappings . get ( input . userId ) ;
174+
175+ if ( ! superTokensUserId ) {
176+ return { status : "UNKNOWN_MAPPING_ERROR" } ;
177+ }
178+
179+ return { status : "OK" , superTokensUserId, externalUserId : input . userId } ;
180+ }
181+
182+ async function createUserIdMapping ( input : {
183+ superTokensUserId : string ;
184+ externalUserId : string ;
185+ externalUserIdInfo ?: string ;
186+ userContext ?: Record < string , unknown > ;
187+ force ?: boolean ;
188+ } ) : Promise <
189+ | { status : "OK" | "UNKNOWN_SUPERTOKENS_USER_ID_ERROR" }
190+ | {
191+ status : "USER_ID_MAPPING_ALREADY_EXISTS_ERROR" ;
192+ doesSuperTokensUserIdExist : boolean ;
193+ doesExternalUserIdExist : boolean ;
194+ }
195+ > {
196+ const superTokensUserId = mappings . get ( input . externalUserId ) ;
197+ const exists = superTokensUserId === input . superTokensUserId ;
198+
199+ if ( superTokensUserId && ! input . force ) {
200+ return {
201+ status : "USER_ID_MAPPING_ALREADY_EXISTS_ERROR" ,
202+ doesSuperTokensUserIdExist : exists ,
203+ doesExternalUserIdExist : true ,
204+ } ;
205+ }
206+
207+ mappings . set ( input . externalUserId , input . superTokensUserId ) ;
208+
209+ return { status : "OK" } ;
210+ }
211+
212+ mockModule (
213+ "supertokens-node" ,
214+ ( superTokens : typeof import ( "supertokens-node" ) ) => {
215+ const superTokensModule = mergeWith ( superTokens , {
216+ getUserIdMapping : jest . fn ( getUserIdMapping ) ,
217+ createUserIdMapping : jest . fn ( createUserIdMapping ) ,
218+ } ) ;
219+
220+ return mergeWith ( superTokensModule , { default : superTokensModule } ) ;
221+ } ,
222+ ) ;
223+
148224 mockModule (
149225 "supertokens-node/recipe/session/framework/express" ,
150226 (
0 commit comments