@supertokens-plugins/rownd-nodejs 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -639,12 +639,11 @@ function createLoggerConfig() {
639
639
  }
640
640
  var config = createLoggerConfig();
641
641
  var logger = common_default(config);
642
- var formatters = logger.formatters;
643
- if (formatters) {
644
- formatters.o = function(value) {
642
+ if (logger.formatters) {
643
+ logger.formatters.o = function(value) {
645
644
  return import_util.default.inspect(value, { colors: this.useColors, compact: true }).split("\n").map((line) => line.trim()).join(" ");
646
645
  };
647
- formatters.O = function(value) {
646
+ logger.formatters.O = function(value) {
648
647
  return import_util.default.inspect(value, { colors: this.useColors, compact: false });
649
648
  };
650
649
  }
@@ -866,6 +865,10 @@ var RowndPluginError = class extends Error {
866
865
  };
867
866
 
868
867
  // src/utils.ts
868
+ var ROWND_OAUTH_LOGIN_CHALLENGE_PARAM = "rownd_oauth_login_challenge";
869
+ function resolveTenantId(req) {
870
+ return req.getKeyValueFromQuery("tenantId") || PUBLIC_TENANT_ID;
871
+ }
869
872
  function rewriteLinkPath(inputUrl, targetPath, searchParams) {
870
873
  try {
871
874
  const url = new URL(inputUrl);
@@ -1066,7 +1069,8 @@ function getMagicLinkBootstrapParams(input) {
1066
1069
  ...input.appVariantId ? { appVariantId: input.appVariantId } : {},
1067
1070
  ...input.displayContext ? { displayContext: input.displayContext } : {},
1068
1071
  ...input.redirectToPath ? { redirectToPath: input.redirectToPath } : {},
1069
- ...input.clientDomainKey ? { clientDomain: input.clientDomainKey } : {}
1072
+ ...input.clientDomainKey ? { clientDomain: input.clientDomainKey } : {},
1073
+ ...input.oauthLoginChallenge ? { oauthLoginChallenge: input.oauthLoginChallenge } : {}
1070
1074
  };
1071
1075
  }
1072
1076
  function rewriteMagicLink(input) {
@@ -1092,6 +1096,10 @@ function getRequestedRedirectToPathFromRequest(req) {
1092
1096
  const redirectToPath = req.getKeyValueFromQuery("rownd_redirect_to_path");
1093
1097
  return typeof redirectToPath === "string" && redirectToPath.length > 0 ? redirectToPath : void 0;
1094
1098
  }
1099
+ function getRequestedOAuthLoginChallengeFromRequest(req) {
1100
+ const loginChallenge = req.getKeyValueFromQuery(ROWND_OAUTH_LOGIN_CHALLENGE_PARAM);
1101
+ return typeof loginChallenge === "string" && loginChallenge.length > 0 ? loginChallenge : void 0;
1102
+ }
1095
1103
 
1096
1104
  // src/config.ts
1097
1105
  var pluginConfig;
@@ -1464,6 +1472,7 @@ function buildAuthMobileConfig(authMobile) {
1464
1472
  }
1465
1473
 
1466
1474
  // src/rownd-compatibility.ts
1475
+ var import_node_crypto = require("crypto");
1467
1476
  var import_supertokens_node = __toESM(require("supertokens-node"));
1468
1477
  var import_usermetadata2 = __toESM(require("supertokens-node/recipe/usermetadata"));
1469
1478
  var IDENTITY_USER_DATA_FIELDS = /* @__PURE__ */ new Set([
@@ -1477,13 +1486,21 @@ var INTERNAL_METADATA_FIELDS = /* @__PURE__ */ new Set([
1477
1486
  "original_rownd_user",
1478
1487
  "rownd_pending_verification"
1479
1488
  ]);
1489
+ var SUPERTOKENS_FAKE_EMAIL_DOMAIN = "stfakeemail.supertokens.com";
1490
+ function isSuperTokensFakeEmail(email) {
1491
+ return typeof email === "string" && email.toLowerCase().endsWith(`@${SUPERTOKENS_FAKE_EMAIL_DOMAIN}`);
1492
+ }
1493
+ function buildSuperTokensFakeEmail(thirdPartyUserId, thirdPartyId) {
1494
+ const hash = (0, import_node_crypto.createHash)("sha256").update(`${thirdPartyId}:${thirdPartyUserId}`).digest("hex").slice(0, 32);
1495
+ return `st-${thirdPartyId}-${hash}@${SUPERTOKENS_FAKE_EMAIL_DOMAIN}`;
1496
+ }
1480
1497
  function isIdentityField(field) {
1481
1498
  return IDENTITY_USER_DATA_FIELDS.has(field);
1482
1499
  }
1483
1500
  function isInternalMetadataField(field) {
1484
1501
  return INTERNAL_METADATA_FIELDS.has(field);
1485
1502
  }
1486
- function mapRowndUserToSuperTokens(rowndUser) {
1503
+ function mapRowndUserToSuperTokens(rowndUser, tenantId) {
1487
1504
  const loginMethods = [];
1488
1505
  const rowndUserData = rowndUser.data || {};
1489
1506
  const rowndUserVerifiedData = rowndUser.verified_data || {};
@@ -1491,41 +1508,41 @@ function mapRowndUserToSuperTokens(rowndUser) {
1491
1508
  throw new Error("Rownd user has no user_id");
1492
1509
  }
1493
1510
  if (rowndUserData.google_id) {
1494
- if (!rowndUserData.email) {
1495
- throw new Error("Rownd Google user is missing email");
1496
- }
1511
+ const googleEmail = rowndUserData.email ?? buildSuperTokensFakeEmail(rowndUserData.google_id, "google");
1497
1512
  loginMethods.push({
1498
1513
  recipeId: "thirdparty",
1499
1514
  thirdPartyId: "google",
1500
1515
  thirdPartyUserId: rowndUserData.google_id,
1501
- email: rowndUserData.email,
1502
- isVerified: !!rowndUserVerifiedData.google_id
1516
+ email: googleEmail,
1517
+ isVerified: !!rowndUserData.email && !!rowndUserVerifiedData.google_id,
1518
+ ...tenantId ? { tenantIds: [tenantId] } : {}
1503
1519
  });
1504
1520
  }
1505
1521
  if (rowndUserData.apple_id) {
1506
- if (!rowndUserData.email) {
1507
- throw new Error("Rownd Apple user is missing email");
1508
- }
1522
+ const appleEmail = rowndUserData.email ?? buildSuperTokensFakeEmail(rowndUserData.apple_id, "apple");
1509
1523
  loginMethods.push({
1510
1524
  recipeId: "thirdparty",
1511
1525
  thirdPartyId: "apple",
1512
1526
  thirdPartyUserId: rowndUserData.apple_id,
1513
- email: rowndUserData.email,
1514
- isVerified: !!rowndUserVerifiedData.apple_id
1527
+ email: appleEmail,
1528
+ isVerified: !!rowndUserData.email && !!rowndUserVerifiedData.apple_id,
1529
+ ...tenantId ? { tenantIds: [tenantId] } : {}
1515
1530
  });
1516
1531
  }
1517
1532
  if (rowndUserData.phone_number) {
1518
1533
  loginMethods.push({
1519
1534
  recipeId: "passwordless",
1520
1535
  phoneNumber: rowndUserData.phone_number,
1521
- isVerified: !!rowndUserVerifiedData.phone_number
1536
+ isVerified: !!rowndUserVerifiedData.phone_number,
1537
+ ...tenantId ? { tenantIds: [tenantId] } : {}
1522
1538
  });
1523
1539
  }
1524
1540
  if (rowndUserData.email && !rowndUserData.google_id && !rowndUserData.apple_id) {
1525
1541
  loginMethods.push({
1526
1542
  recipeId: "passwordless",
1527
1543
  email: rowndUserData.email,
1528
- isVerified: !!rowndUserVerifiedData.email
1544
+ isVerified: !!rowndUserVerifiedData.email,
1545
+ ...tenantId ? { tenantIds: [tenantId] } : {}
1529
1546
  });
1530
1547
  }
1531
1548
  let authLevel = rowndUser.auth_level;
@@ -1537,7 +1554,8 @@ function mapRowndUserToSuperTokens(rowndUser) {
1537
1554
  thirdPartyId,
1538
1555
  thirdPartyUserId: rowndUserData.user_id,
1539
1556
  email: `${rowndUserData.user_id}@anonymous.local`,
1540
- isVerified: false
1557
+ isVerified: false,
1558
+ ...tenantId ? { tenantIds: [tenantId] } : {}
1541
1559
  });
1542
1560
  }
1543
1561
  const userMetadata = buildRowndUserMetadata(rowndUser);
@@ -1696,7 +1714,7 @@ async function buildStandardOAuthClaims(user, scopes) {
1696
1714
  const rowndData = isJsonRecord(metadata.original_rownd_user?.data) ? metadata.original_rownd_user.data : {};
1697
1715
  const verifiedData = isJsonRecord(metadata.original_rownd_user?.verified_data) ? metadata.original_rownd_user.verified_data : {};
1698
1716
  if (scopes.includes("email")) {
1699
- const email = firstString(rowndData.email) ?? user.emails[0];
1717
+ const email = firstRealEmail(firstString(rowndData.email), ...user.emails);
1700
1718
  if (email) {
1701
1719
  claims.email = email;
1702
1720
  claims.email_verified = isOAuthClaimVerified(
@@ -1763,6 +1781,11 @@ function firstString(value) {
1763
1781
  }
1764
1782
  return typeof value === "string" && value.length > 0 ? value : void 0;
1765
1783
  }
1784
+ function firstRealEmail(...values) {
1785
+ return values.find((entry) => {
1786
+ return typeof entry === "string" && entry.length > 0 && !isSuperTokensFakeEmail(entry);
1787
+ });
1788
+ }
1766
1789
  function isOAuthClaimVerified(value, expectedValue, fallback) {
1767
1790
  return value === true || value === expectedValue || fallback;
1768
1791
  }
@@ -2046,6 +2069,7 @@ async function createMagicLinkWithConfirmationBypass(input) {
2046
2069
  })}${getAppInfoString(stConfig.appInfo.websiteBasePath)}/verify?preAuthSessionId=${encodeURIComponent(
2047
2070
  codeInfo.preAuthSessionId
2048
2071
  )}&tenantId=${encodeURIComponent(tenantId)}#${encodeURIComponent(codeInfo.linkCode)}`;
2072
+ const oauthLoginChallenge = userContext.rowndOAuthLoginChallenge;
2049
2073
  const rewrittenUrl = new URL(rewriteMagicLink({
2050
2074
  magicLink,
2051
2075
  clientDomain,
@@ -2056,7 +2080,8 @@ async function createMagicLinkWithConfirmationBypass(input) {
2056
2080
  appVariantId,
2057
2081
  displayContext: input.displayContext,
2058
2082
  redirectToPath,
2059
- clientDomainKey: input.clientDomain
2083
+ clientDomainKey: input.clientDomain,
2084
+ oauthLoginChallenge: typeof oauthLoginChallenge === "string" ? oauthLoginChallenge : void 0
2060
2085
  })
2061
2086
  }));
2062
2087
  rewrittenUrl.searchParams.set(PASSWORDLESS_BYPASS_DEVICE_CONFIRMATION_PARAM, "true");
@@ -2076,7 +2101,7 @@ function getPendingVerifications(metadata) {
2076
2101
  function isPendingVerification(value) {
2077
2102
  return isRecord(value) && typeof value.id === "string" && typeof value.field === "string" && typeof value.value === "string" && typeof value.created_at === "string";
2078
2103
  }
2079
- async function getUserById(userId) {
2104
+ async function getUserById(userId, tenantId = PUBLIC_TENANT_ID) {
2080
2105
  const metadata = await getUserMetadata(userId);
2081
2106
  const stUser = await import_supertokens_node2.default.getUser(userId);
2082
2107
  if (!stUser) {
@@ -2105,9 +2130,12 @@ async function getUserById(userId) {
2105
2130
  const verifiedData = {
2106
2131
  ...originalRowndUser?.verified_data || {}
2107
2132
  };
2108
- for (const method of stUser.loginMethods) {
2133
+ const tenantLoginMethods = stUser.loginMethods.filter(
2134
+ (method) => method.tenantIds.includes(tenantId)
2135
+ );
2136
+ for (const method of tenantLoginMethods) {
2109
2137
  if (method.recipeId === "passwordless") {
2110
- if (method.email) {
2138
+ if (method.email && !isSuperTokensFakeEmail(method.email)) {
2111
2139
  verifiedData.email = method.email;
2112
2140
  if (data.email === void 0) data.email = method.email;
2113
2141
  }
@@ -2119,10 +2147,10 @@ async function getUserById(userId) {
2119
2147
  } else if (method.recipeId === "thirdparty") {
2120
2148
  const thirdPartyId = getThirdPartyId(method);
2121
2149
  const thirdPartyUserId = getThirdPartyUserId(method);
2122
- if (method.verified && method.email) {
2150
+ if (method.verified && method.email && !isSuperTokensFakeEmail(method.email)) {
2123
2151
  verifiedData.email = method.email;
2124
2152
  }
2125
- if (method.email && data.email === void 0) {
2153
+ if (method.email && !isSuperTokensFakeEmail(method.email) && data.email === void 0) {
2126
2154
  data.email = method.email;
2127
2155
  }
2128
2156
  if (thirdPartyId === "google" && thirdPartyUserId) {
@@ -2134,7 +2162,7 @@ async function getUserById(userId) {
2134
2162
  verifiedData.apple_id = thirdPartyUserId;
2135
2163
  }
2136
2164
  } else if (method.recipeId === "emailpassword") {
2137
- if (method.email && data.email === void 0) {
2165
+ if (method.email && !isSuperTokensFakeEmail(method.email) && data.email === void 0) {
2138
2166
  data.email = method.email;
2139
2167
  }
2140
2168
  }
@@ -2145,12 +2173,16 @@ async function getUserById(userId) {
2145
2173
  if (verifiedData.phone_number === true && typeof data.phone_number === "string") {
2146
2174
  verifiedData.phone_number = data.phone_number;
2147
2175
  }
2148
- const anonymousId = getAnonymousId(stUser.id, stUser, metadata);
2176
+ const tenantUser = {
2177
+ ...stUser,
2178
+ loginMethods: tenantLoginMethods
2179
+ };
2180
+ const anonymousId = getAnonymousId(stUser.id, tenantUser, metadata);
2149
2181
  if (anonymousId && data.anonymous_id === void 0) {
2150
2182
  data.anonymous_id = anonymousId;
2151
2183
  }
2152
2184
  const authLevel = getEffectiveAuthLevel(
2153
- stUser,
2185
+ tenantUser,
2154
2186
  originalRowndUser?.auth_level,
2155
2187
  verifiedData
2156
2188
  );
@@ -2159,15 +2191,15 @@ async function getUserById(userId) {
2159
2191
  data[key] = "";
2160
2192
  }
2161
2193
  }
2162
- const sortedByJoined = [...stUser.loginMethods].sort(
2194
+ const sortedByJoined = [...tenantLoginMethods].sort(
2163
2195
  (a, b) => a.timeJoined - b.timeJoined
2164
2196
  );
2165
- const latestSessionInfo = await getLatestSessionInfo(stUser.id);
2197
+ const latestSessionInfo = await getLatestSessionInfo(stUser.id, tenantId);
2166
2198
  const firstMethod = sortedByJoined[0];
2167
2199
  const latestSessionRecipeUserId = latestSessionInfo?.recipeUserId.getAsString();
2168
2200
  const lastMethod = latestSessionRecipeUserId ? stUser.loginMethods.find(
2169
2201
  (method) => method.recipeUserId.getAsString() === latestSessionRecipeUserId
2170
- ) : [...stUser.loginMethods].sort((a, b) => b.timeJoined - a.timeJoined)[0];
2202
+ ) : [...tenantLoginMethods].sort((a, b) => b.timeJoined - a.timeJoined)[0];
2171
2203
  const lastSignInAt = latestSessionInfo?.timeCreated ?? stUser.timeJoined;
2172
2204
  const metadataMeta = Object.fromEntries(
2173
2205
  Object.entries(metadata).filter(
@@ -2195,11 +2227,11 @@ async function getUserById(userId) {
2195
2227
  attributes: originalRowndUser?.attributes || {}
2196
2228
  };
2197
2229
  }
2198
- async function getLatestSessionInfo(userId) {
2230
+ async function getLatestSessionInfo(userId, tenantId) {
2199
2231
  const sessionHandles = await import_session.default.getAllSessionHandlesForUser(
2200
2232
  userId,
2201
2233
  true,
2202
- PUBLIC_TENANT_ID
2234
+ tenantId
2203
2235
  );
2204
2236
  const sessionInfos = await Promise.all(
2205
2237
  sessionHandles.map(
@@ -2214,21 +2246,21 @@ async function getLatestSessionInfo(userId) {
2214
2246
  }
2215
2247
  return latestSessionInfo;
2216
2248
  }
2217
- async function updateUserData(userId, inputData) {
2249
+ async function updateUserData(userId, inputData, tenantId = PUBLIC_TENANT_ID) {
2218
2250
  const metadata = await getUserMetadata(userId);
2219
2251
  const updatedMetadata = {
2220
2252
  ...metadata,
2221
2253
  ...inputData
2222
2254
  };
2223
2255
  await import_usermetadata3.default.updateUserMetadata(userId, updatedMetadata);
2224
- return getUserById(userId);
2256
+ return getUserById(userId, tenantId);
2225
2257
  }
2226
2258
  async function startPendingEmailVerification(input) {
2227
2259
  const metadata = await getUserMetadata(input.userId);
2228
- const currentEmail = (await getUserById(input.userId)).data.email;
2260
+ const currentEmail = (await getUserById(input.userId, input.tenantId)).data.email;
2229
2261
  const pendingVerifications = getPendingVerifications(metadata);
2230
2262
  const pendingEmailVerifications = pendingVerifications.filter(
2231
- (pendingVerification2) => pendingVerification2.field === "email"
2263
+ (pendingVerification2) => pendingVerification2.field === "email" && (pendingVerification2.tenantId ?? PUBLIC_TENANT_ID) === input.tenantId
2232
2264
  );
2233
2265
  if (currentEmail === input.email) {
2234
2266
  for (const pendingVerification2 of pendingEmailVerifications) {
@@ -2243,11 +2275,11 @@ async function startPendingEmailVerification(input) {
2243
2275
  await import_usermetadata3.default.updateUserMetadata(input.userId, {
2244
2276
  ...metadata,
2245
2277
  rownd_pending_verification: pendingVerifications.filter(
2246
- (pendingVerification2) => pendingVerification2.field !== "email"
2278
+ (pendingVerification2) => pendingVerification2.field !== "email" || (pendingVerification2.tenantId ?? PUBLIC_TENANT_ID) !== input.tenantId
2247
2279
  )
2248
2280
  });
2249
2281
  }
2250
- return getUserById(input.userId);
2282
+ return getUserById(input.userId, input.tenantId);
2251
2283
  }
2252
2284
  for (const pendingVerification2 of pendingEmailVerifications) {
2253
2285
  await import_emailverification.default.revokeEmailVerificationTokens(
@@ -2261,13 +2293,14 @@ async function startPendingEmailVerification(input) {
2261
2293
  id: input.pendingVerificationId,
2262
2294
  field: "email",
2263
2295
  value: input.email,
2264
- created_at: (/* @__PURE__ */ new Date()).toISOString()
2296
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
2297
+ tenantId: input.tenantId
2265
2298
  };
2266
2299
  await import_usermetadata3.default.updateUserMetadata(input.userId, {
2267
2300
  ...metadata,
2268
2301
  rownd_pending_verification: [
2269
2302
  ...pendingVerifications.filter(
2270
- (pendingVerification2) => pendingVerification2.field !== "email"
2303
+ (pendingVerification2) => pendingVerification2.field !== "email" || (pendingVerification2.tenantId ?? PUBLIC_TENANT_ID) !== input.tenantId
2271
2304
  ),
2272
2305
  pendingVerification
2273
2306
  ]
@@ -2286,12 +2319,14 @@ async function startPendingEmailVerification(input) {
2286
2319
  await completePendingEmailVerification({
2287
2320
  recipeUserId: input.recipeUserId,
2288
2321
  email: input.email,
2322
+ tenantId: input.tenantId,
2289
2323
  userContext: input.userContext
2290
2324
  });
2291
2325
  }
2292
- return getUserById(input.userId);
2326
+ return getUserById(input.userId, input.tenantId);
2293
2327
  }
2294
2328
  async function completePendingEmailVerification(input) {
2329
+ const tenantId = input.tenantId ?? PUBLIC_TENANT_ID;
2295
2330
  const user = await import_supertokens_node2.default.getUser(
2296
2331
  input.recipeUserId.getAsString(),
2297
2332
  input.userContext
@@ -2302,7 +2337,8 @@ async function completePendingEmailVerification(input) {
2302
2337
  const pendingVerification = pendingVerifications.find(
2303
2338
  (pendingVerification2) => isMatchingPendingEmailVerification(
2304
2339
  pendingVerification2,
2305
- input.email
2340
+ input.email,
2341
+ tenantId
2306
2342
  )
2307
2343
  );
2308
2344
  if (!pendingVerification) {
@@ -2310,7 +2346,12 @@ async function completePendingEmailVerification(input) {
2310
2346
  }
2311
2347
  let metadataUserId = userId;
2312
2348
  let verifiedRecipeUserId = input.recipeUserId;
2313
- const passwordlessEmailMethod = getPasswordlessEmailLoginMethod(user);
2349
+ const tenantLoginMethods = user?.loginMethods.filter(
2350
+ (method) => method.tenantIds.includes(tenantId)
2351
+ ) ?? [];
2352
+ const passwordlessEmailMethod = getPasswordlessEmailLoginMethod(
2353
+ tenantLoginMethods
2354
+ );
2314
2355
  if (passwordlessEmailMethod) {
2315
2356
  const updateResult = await import_passwordless.default.updateUser({
2316
2357
  recipeUserId: passwordlessEmailMethod.recipeUserId,
@@ -2323,9 +2364,9 @@ async function completePendingEmailVerification(input) {
2323
2364
  );
2324
2365
  }
2325
2366
  verifiedRecipeUserId = passwordlessEmailMethod.recipeUserId;
2326
- } else if (hasOnlyGuestLoginMethods(user)) {
2367
+ } else if (hasOnlyGuestLoginMethods(user ? { ...user, loginMethods: tenantLoginMethods } : user)) {
2327
2368
  const isPasswordlessSignUpAllowed = await import_accountlinking.default.isSignUpAllowed(
2328
- PUBLIC_TENANT_ID,
2369
+ tenantId,
2329
2370
  {
2330
2371
  recipeId: "passwordless",
2331
2372
  email: input.email
@@ -2339,7 +2380,7 @@ async function completePendingEmailVerification(input) {
2339
2380
  }
2340
2381
  const passwordlessUser = await import_passwordless.default.signInUp({
2341
2382
  email: input.email,
2342
- tenantId: PUBLIC_TENANT_ID,
2383
+ tenantId,
2343
2384
  userContext: input.userContext
2344
2385
  });
2345
2386
  verifiedRecipeUserId = passwordlessUser.recipeUserId;
@@ -2383,7 +2424,8 @@ async function completePendingEmailVerification(input) {
2383
2424
  rownd_pending_verification: targetPendingVerifications.filter(
2384
2425
  (verification) => !isMatchingPendingEmailVerification(
2385
2426
  verification,
2386
- input.email
2427
+ input.email,
2428
+ tenantId
2387
2429
  )
2388
2430
  )
2389
2431
  };
@@ -2393,8 +2435,8 @@ async function completePendingEmailVerification(input) {
2393
2435
  recipeUserId: verifiedRecipeUserId
2394
2436
  };
2395
2437
  }
2396
- function isMatchingPendingEmailVerification(verification, email) {
2397
- return verification.field === "email" && verification.value === email;
2438
+ function isMatchingPendingEmailVerification(verification, email, tenantId) {
2439
+ return verification.field === "email" && verification.value === email && (verification.tenantId ?? PUBLIC_TENANT_ID) === tenantId;
2398
2440
  }
2399
2441
  async function updateUserMetadata(userId, inputMeta) {
2400
2442
  const metadata = await getUserMetadata(userId);
@@ -2412,8 +2454,8 @@ async function updateUserMetadata(userId, inputMeta) {
2412
2454
  )
2413
2455
  };
2414
2456
  }
2415
- function getPasswordlessEmailLoginMethod(user) {
2416
- return user?.loginMethods.find((method) => {
2457
+ function getPasswordlessEmailLoginMethod(loginMethods) {
2458
+ return loginMethods.find((method) => {
2417
2459
  return method.recipeId === "passwordless" && !!method.email;
2418
2460
  });
2419
2461
  }
@@ -2423,6 +2465,7 @@ var import_crypto = require("crypto");
2423
2465
  var import_supertokens_node3 = __toESM(require("supertokens-node"));
2424
2466
  var import_session2 = __toESM(require("supertokens-node/recipe/session"));
2425
2467
  var import_thirdparty = __toESM(require("supertokens-node/recipe/thirdparty"));
2468
+ var import_multitenancy = __toESM(require("supertokens-node/recipe/multitenancy"));
2426
2469
  function isBodyString(body, key) {
2427
2470
  return isRecord(body) && typeof body[key] === "string" && body[key].length > 0;
2428
2471
  }
@@ -2487,7 +2530,9 @@ function handleGuestLogin(deps) {
2487
2530
  return async (req, res, _session, userContext) => {
2488
2531
  const startedAt = Date.now();
2489
2532
  const guestId = `guest_${(0, import_crypto.randomUUID)()}`;
2533
+ let tenantId;
2490
2534
  try {
2535
+ tenantId = resolveTenantId(req);
2491
2536
  const body = parseGuestBody(await getJsonBody(req));
2492
2537
  const appVariantId = getRequestedAppVariantIdFromRequest(req);
2493
2538
  assertRowndAppVariantIsConfigured(appVariantId);
@@ -2495,7 +2540,7 @@ function handleGuestLogin(deps) {
2495
2540
  const thirdPartyUserId = thirdPartyId === INSTANT_AUTH_METHOD_ID ? `anon_${(0, import_crypto.randomUUID)()}` : guestId;
2496
2541
  const authLevel = thirdPartyId === INSTANT_AUTH_METHOD_ID ? INSTANT_AUTH_METHOD_ID : GUEST_AUTH_METHOD_ID;
2497
2542
  const response = await import_thirdparty.default.manuallyCreateOrUpdateUser(
2498
- PUBLIC_TENANT_ID,
2543
+ tenantId,
2499
2544
  thirdPartyId,
2500
2545
  thirdPartyUserId,
2501
2546
  `${thirdPartyUserId}@anonymous.local`,
@@ -2511,7 +2556,7 @@ function handleGuestLogin(deps) {
2511
2556
  await import_session2.default.createNewSession(
2512
2557
  req,
2513
2558
  res,
2514
- PUBLIC_TENANT_ID,
2559
+ tenantId,
2515
2560
  response.recipeUserId,
2516
2561
  {
2517
2562
  ...buildRowndAudience({}, appVariantId),
@@ -2526,7 +2571,7 @@ function handleGuestLogin(deps) {
2526
2571
  deps.telemetryClient.recordSuccess({
2527
2572
  outcome: "success",
2528
2573
  durationMs: Date.now() - startedAt,
2529
- tenantId: PUBLIC_TENANT_ID,
2574
+ tenantId,
2530
2575
  superTokensUserId: response.user.id
2531
2576
  });
2532
2577
  return {
@@ -2538,7 +2583,7 @@ function handleGuestLogin(deps) {
2538
2583
  deps.telemetryClient.recordError({
2539
2584
  error,
2540
2585
  startedAt,
2541
- tenantId: PUBLIC_TENANT_ID
2586
+ tenantId
2542
2587
  });
2543
2588
  return {
2544
2589
  status: "ERROR",
@@ -2550,7 +2595,7 @@ function handleGuestLogin(deps) {
2550
2595
  function handleMigrate(deps) {
2551
2596
  return async (req, res, _session, userContext) => {
2552
2597
  const startedAt = Date.now();
2553
- let tenantId = PUBLIC_TENANT_ID;
2598
+ let tenantId;
2554
2599
  let rowndUserId;
2555
2600
  let superTokensUserId;
2556
2601
  let user;
@@ -2559,6 +2604,7 @@ function handleMigrate(deps) {
2559
2604
  if (!deps.stConfig.supertokens) {
2560
2605
  throw new Error("Supertokens config not found");
2561
2606
  }
2607
+ tenantId = resolveTenantId(req);
2562
2608
  const parsed = await parseRequest(req);
2563
2609
  const appVariantId = getRequestedAppVariantIdFromRequest(req);
2564
2610
  assertRowndAppVariantIsConfigured(appVariantId);
@@ -2566,13 +2612,16 @@ function handleMigrate(deps) {
2566
2612
  const rowndUser = await fetchOptionalRowndUserInfo(rowndUserId);
2567
2613
  if (!rowndUser) {
2568
2614
  logDebugMessage(
2569
- `Skipping migration because user does not exist in Rownd. tenantId: ${PUBLIC_TENANT_ID}, rowndUserId: ${rowndUserId}`
2615
+ `Skipping migration because user does not exist in Rownd. tenantId: ${tenantId}, rowndUserId: ${rowndUserId}`
2570
2616
  );
2571
2617
  return { status: "OK" };
2572
2618
  }
2573
2619
  user = await import_supertokens_node3.default.getUser(rowndUserId, userContext);
2574
2620
  if (!user) {
2575
- const stUserImport = mapRowndUserToSuperTokens(rowndUser);
2621
+ const stUserImport = mapRowndUserToSuperTokens(
2622
+ rowndUser,
2623
+ tenantId === PUBLIC_TENANT_ID ? void 0 : tenantId
2624
+ );
2576
2625
  try {
2577
2626
  await importUser(stUserImport, deps.stConfig.supertokens);
2578
2627
  clearSuperTokensCoreCallCache(userContext);
@@ -2590,29 +2639,43 @@ function handleMigrate(deps) {
2590
2639
  superTokensUserId = user.id;
2591
2640
  recipeUserId = user.loginMethods[0]?.recipeUserId;
2592
2641
  logDebugMessage(
2593
- `User already migrated (race condition). tenantId: ${PUBLIC_TENANT_ID}, rowndUserId: ${rowndUserId}`
2642
+ `User already migrated (race condition). tenantId: ${tenantId}, rowndUserId: ${rowndUserId}`
2594
2643
  );
2595
2644
  }
2596
2645
  logDebugMessage(
2597
- `User migrated successfully. tenantId: ${PUBLIC_TENANT_ID}, rowndUserId: ${rowndUserId}`
2646
+ `User migrated successfully. tenantId: ${tenantId}, rowndUserId: ${rowndUserId}`
2598
2647
  );
2599
2648
  } else {
2600
2649
  superTokensUserId = user.id;
2601
2650
  recipeUserId = user.loginMethods[0]?.recipeUserId;
2602
2651
  logDebugMessage(
2603
- `User already migrated. tenantId: ${PUBLIC_TENANT_ID}, rowndUserId: ${rowndUserId}`
2652
+ `User already migrated. tenantId: ${tenantId}, rowndUserId: ${rowndUserId}`
2604
2653
  );
2605
2654
  }
2606
2655
  if (superTokensUserId) {
2607
2656
  await recordRowndAppVariantForUser(superTokensUserId, appVariantId);
2608
2657
  }
2658
+ const tenantLoginMethod = user?.loginMethods.find(
2659
+ (method) => method.tenantIds.includes(tenantId)
2660
+ );
2661
+ recipeUserId = tenantLoginMethod?.recipeUserId ?? recipeUserId;
2609
2662
  if (!recipeUserId) {
2610
2663
  throw new Error("User not found or has no login methods");
2611
2664
  }
2665
+ if (!tenantLoginMethod) {
2666
+ const associationResult = await import_multitenancy.default.associateUserToTenant(
2667
+ tenantId,
2668
+ recipeUserId,
2669
+ userContext
2670
+ );
2671
+ if (associationResult.status !== "OK") {
2672
+ throw new Error(`Failed to associate migrated user with tenant: ${associationResult.status}`);
2673
+ }
2674
+ }
2612
2675
  await import_session2.default.createNewSession(
2613
2676
  req,
2614
2677
  res,
2615
- PUBLIC_TENANT_ID,
2678
+ tenantId,
2616
2679
  recipeUserId,
2617
2680
  {
2618
2681
  ...buildRowndAudience({}, appVariantId)
@@ -2621,7 +2684,7 @@ function handleMigrate(deps) {
2621
2684
  userContext
2622
2685
  );
2623
2686
  logDebugMessage(
2624
- `Session migrated successfully. tenantId: ${PUBLIC_TENANT_ID}, userId: ${superTokensUserId}`
2687
+ `Session migrated successfully. tenantId: ${tenantId}, userId: ${superTokensUserId}`
2625
2688
  );
2626
2689
  deps.telemetryClient.recordSuccess({
2627
2690
  outcome: "success",
@@ -2655,7 +2718,7 @@ function clearSuperTokensCoreCallCache(userContext) {
2655
2718
  }
2656
2719
  function handleGetUser() {
2657
2720
  return async (_req, _res, session) => {
2658
- const user = await getUserById(session.getUserId());
2721
+ const user = await getUserById(session.getUserId(), session.getTenantId());
2659
2722
  return {
2660
2723
  status: "OK",
2661
2724
  ...user
@@ -2681,7 +2744,11 @@ function handleUpdateUser() {
2681
2744
  return permissionError;
2682
2745
  }
2683
2746
  if (Object.keys(dataWithoutEmail).length > 0) {
2684
- await updateUserData(session.getUserId(), dataWithoutEmail);
2747
+ await updateUserData(
2748
+ session.getUserId(),
2749
+ dataWithoutEmail,
2750
+ session.getTenantId()
2751
+ );
2685
2752
  }
2686
2753
  if (hasEmailUpdate) {
2687
2754
  const pendingVerificationResult = await startPendingEmailVerification({
@@ -2697,7 +2764,7 @@ function handleUpdateUser() {
2697
2764
  ...pendingVerificationResult
2698
2765
  };
2699
2766
  }
2700
- const user = await getUserById(session.getUserId());
2767
+ const user = await getUserById(session.getUserId(), session.getTenantId());
2701
2768
  return {
2702
2769
  status: "OK",
2703
2770
  ...user
@@ -2764,7 +2831,7 @@ function handleGetUserField() {
2764
2831
  if (!field) {
2765
2832
  return missingFieldResponse();
2766
2833
  }
2767
- const user = await getUserById(session.getUserId());
2834
+ const user = await getUserById(session.getUserId(), session.getTenantId());
2768
2835
  return {
2769
2836
  status: "OK",
2770
2837
  value: user.data[field]
@@ -2798,9 +2865,11 @@ function handleUpdateUserField() {
2798
2865
  if (permissionError) {
2799
2866
  return permissionError;
2800
2867
  }
2801
- const updateUserDataResult = await updateUserData(session.getUserId(), {
2802
- [field]: payload.value
2803
- });
2868
+ const updateUserDataResult = await updateUserData(
2869
+ session.getUserId(),
2870
+ { [field]: payload.value },
2871
+ session.getTenantId()
2872
+ );
2804
2873
  return {
2805
2874
  status: "OK",
2806
2875
  ...updateUserDataResult
@@ -2839,6 +2908,7 @@ var init = createPluginInitFunction(
2839
2908
  const displayContext = input?.userContext?.rowndDisplayContext;
2840
2909
  const redirectToPath = input?.userContext?.rowndRedirectToPath;
2841
2910
  const clientDomain = input?.userContext?.rowndClientDomain;
2911
+ const oauthLoginChallenge = input?.userContext?.rowndOAuthLoginChallenge;
2842
2912
  const clientDomainKey = clientDomain ?? (displayContext === "mobile_app" ? "mobile" : "browser");
2843
2913
  const clientBaseUrl = pluginConfig2.clientDomains?.[clientDomainKey];
2844
2914
  const bootstrapParams = {
@@ -2846,7 +2916,8 @@ var init = createPluginInitFunction(
2846
2916
  ...hubBootstrapParams ?? {},
2847
2917
  ...typeof appVariantId === "string" ? { appVariantId } : {},
2848
2918
  ...typeof displayContext === "string" ? { displayContext } : {},
2849
- ...typeof redirectToPath === "string" ? { redirectToPath } : {}
2919
+ ...typeof redirectToPath === "string" ? { redirectToPath } : {},
2920
+ ...typeof oauthLoginChallenge === "string" ? { oauthLoginChallenge } : {}
2850
2921
  };
2851
2922
  const rewrittenLink = input[linkKey] ? clientBaseUrl ? rewriteLinkToBaseUrl(
2852
2923
  input[linkKey],
@@ -3132,6 +3203,12 @@ var init = createPluginInitFunction(
3132
3203
  if (appVariantId) {
3133
3204
  input.userContext.rowndAppVariantId = appVariantId;
3134
3205
  }
3206
+ const oauthLoginChallenge = getRequestedOAuthLoginChallengeFromRequest(
3207
+ input.options.req
3208
+ );
3209
+ if (oauthLoginChallenge) {
3210
+ input.userContext.rowndOAuthLoginChallenge = oauthLoginChallenge;
3211
+ }
3135
3212
  assertRowndAppVariantIsConfigured(appVariantId);
3136
3213
  return originalImplementation.createCodePOST(input);
3137
3214
  },
@@ -3275,6 +3352,7 @@ var init = createPluginInitFunction(
3275
3352
  const verificationResult = await completePendingEmailVerification({
3276
3353
  recipeUserId: response.user.recipeUserId,
3277
3354
  email: response.user.email,
3355
+ tenantId: input.tenantId,
3278
3356
  userContext: input.userContext
3279
3357
  });
3280
3358
  const session = input.session;