@supertokens-plugins/rownd-nodejs 0.3.0-beta.5 → 0.3.0-beta.7

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
@@ -267,12 +267,13 @@ var require_supports_color = __commonJS({
267
267
  // src/index.ts
268
268
  var index_exports = {};
269
269
  __export(index_exports, {
270
- ANONYMOUS_AUTH_METHOD_ID: () => ANONYMOUS_AUTH_METHOD_ID,
271
270
  DEFAULT_ROWND_SCHEMA: () => DEFAULT_ROWND_SCHEMA,
272
271
  GUEST_AUTH_METHOD_ID: () => GUEST_AUTH_METHOD_ID,
273
272
  HANDLE_BASE_PATH: () => HANDLE_BASE_PATH,
274
273
  HUB_LOGIN_PAGE_PATH: () => HUB_LOGIN_PAGE_PATH,
275
274
  HUB_VERIFY_EMAIL_PAGE_PATH: () => HUB_VERIFY_EMAIL_PAGE_PATH,
275
+ INSTANT_AUTH_METHOD_ID: () => INSTANT_AUTH_METHOD_ID,
276
+ PASSWORDLESS_BYPASS_DEVICE_CONFIRMATION_PARAM: () => PASSWORDLESS_BYPASS_DEVICE_CONFIRMATION_PARAM,
276
277
  PLUGIN_ID: () => PLUGIN_ID,
277
278
  PLUGIN_SDK_VERSION: () => PLUGIN_SDK_VERSION,
278
279
  PLUGIN_VERSION: () => PLUGIN_VERSION,
@@ -280,6 +281,7 @@ __export(index_exports, {
280
281
  ROWND_JWT_CLAIMS: () => ROWND_JWT_CLAIMS,
281
282
  ROWND_PLUGIN_ERROR_MESSAGES: () => ROWND_PLUGIN_ERROR_MESSAGES,
282
283
  RowndPluginError: () => RowndPluginError,
284
+ createMagicLinkWithConfirmationBypass: () => createMagicLinkWithConfirmationBypass,
283
285
  default: () => index_default,
284
286
  getRowndClient: () => getRowndClient,
285
287
  init: () => init,
@@ -690,7 +692,7 @@ var PLUGIN_SDK_VERSION = ["23.0.0", "23.0.1", ">=23.0.1"];
690
692
  var HANDLE_BASE_PATH = "/plugin/rownd";
691
693
  var PUBLIC_TENANT_ID = "public";
692
694
  var GUEST_AUTH_METHOD_ID = "guest";
693
- var ANONYMOUS_AUTH_METHOD_ID = "anonymous";
695
+ var INSTANT_AUTH_METHOD_ID = "instant";
694
696
  var ROWND_JWT_CLAIMS = {
695
697
  AppUserId: "https://auth.rownd.io/app_user_id",
696
698
  IsVerifiedUser: "https://auth.rownd.io/is_verified_user",
@@ -724,6 +726,7 @@ var DEFAULT_ROWND_SCHEMA = {
724
726
  };
725
727
  var HUB_LOGIN_PAGE_PATH = "/account/login";
726
728
  var HUB_VERIFY_EMAIL_PAGE_PATH = "/account/verify-email";
729
+ var PASSWORDLESS_BYPASS_DEVICE_CONFIRMATION_PARAM = "bypassDeviceConfirmation";
727
730
 
728
731
  // src/logger.ts
729
732
  var { logDebugMessage, enableDebugLogs } = buildLogger(
@@ -966,6 +969,109 @@ function getStringList(value) {
966
969
  function getErrorMessage(error) {
967
970
  return error instanceof Error ? error.message : "Unknown error";
968
971
  }
972
+ function getAppInfoString(value) {
973
+ return value.getAsStringDangerous();
974
+ }
975
+ function getWebsiteDomain(input) {
976
+ return getAppInfoString(input.stConfig.appInfo.getOrigin({
977
+ request: input.request,
978
+ userContext: input.userContext ?? {}
979
+ }));
980
+ }
981
+ function normalizeClientDomain(value) {
982
+ if (value.endsWith("://")) {
983
+ return value;
984
+ }
985
+ const parsed = new URL(value);
986
+ if (parsed.protocol === "http:" || parsed.protocol === "https:") {
987
+ return parsed.origin;
988
+ }
989
+ return `${parsed.protocol}//${parsed.host}`;
990
+ }
991
+ function resolveClientDomain(input) {
992
+ if (!input.clientDomain) {
993
+ return input.websiteDomain;
994
+ }
995
+ const resolved = input.pluginConfig.clientDomains?.[input.clientDomain];
996
+ if (!resolved) {
997
+ throw new Error(`Unknown clientDomain key: ${input.clientDomain}`);
998
+ }
999
+ return resolved;
1000
+ }
1001
+ function resolveAllowedClientDomain(input) {
1002
+ const websiteDomain = getWebsiteDomain(input);
1003
+ const resolvedClientDomain = resolveClientDomain({
1004
+ clientDomain: input.clientDomain,
1005
+ pluginConfig: input.pluginConfig,
1006
+ websiteDomain
1007
+ });
1008
+ const normalizedClientDomain = normalizeClientDomain(resolvedClientDomain);
1009
+ const allowed = [
1010
+ websiteDomain,
1011
+ ...Object.values(input.pluginConfig.clientDomains ?? {})
1012
+ ].map(normalizeClientDomain);
1013
+ if (!allowed.includes(normalizedClientDomain)) {
1014
+ throw new Error(`clientDomain is not allowed: ${resolvedClientDomain}`);
1015
+ }
1016
+ return normalizedClientDomain;
1017
+ }
1018
+ function normalizeRedirectToPathForClientDomain(redirectToPath, clientDomain) {
1019
+ if (!redirectToPath) {
1020
+ return void 0;
1021
+ }
1022
+ if (redirectToPath === "NATIVE_APP") {
1023
+ return redirectToPath;
1024
+ }
1025
+ if (redirectToPath.startsWith("//")) {
1026
+ throw new Error("redirectToPath cannot be schemaless");
1027
+ }
1028
+ const normalizedClientDomain = normalizeClientDomain(clientDomain);
1029
+ const redirectUrl = new URL(
1030
+ redirectToPath,
1031
+ normalizedClientDomain.endsWith("://") ? "http://localhost" : normalizedClientDomain
1032
+ );
1033
+ const hasExplicitScheme = /^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(redirectToPath);
1034
+ if (hasExplicitScheme) {
1035
+ if (redirectUrl.protocol !== "http:" && redirectUrl.protocol !== "https:") {
1036
+ throw new Error("redirectToPath must be http(s) or relative");
1037
+ }
1038
+ if (redirectUrl.origin !== normalizedClientDomain) {
1039
+ throw new Error("redirectToPath must match clientDomain");
1040
+ }
1041
+ }
1042
+ return `${redirectUrl.pathname}${redirectUrl.search}${redirectUrl.hash}`;
1043
+ }
1044
+ function assertAllowedBypassRedirectPath(pluginConfig2, redirectToPath) {
1045
+ if (!redirectToPath) {
1046
+ throw new Error("redirectToPath is required for confirmation bypass magic links");
1047
+ }
1048
+ const allowedRedirectPaths = pluginConfig2.crossDeviceConfirmationBypass?.allowedRedirectPaths ?? [];
1049
+ if (allowedRedirectPaths.length === 0) {
1050
+ throw new Error("crossDeviceConfirmationBypass.allowedRedirectPaths must be configured");
1051
+ }
1052
+ if (!allowedRedirectPaths.includes(redirectToPath)) {
1053
+ throw new Error(`redirectToPath is not allowed for confirmation bypass: ${redirectToPath}`);
1054
+ }
1055
+ }
1056
+ function getMagicLinkBootstrapParams(input) {
1057
+ return {
1058
+ appKey: input.appKey,
1059
+ apiDomain: input.apiDomain,
1060
+ apiBasePath: input.apiBasePath,
1061
+ ...input.appVariantId ? { appVariantId: input.appVariantId } : {},
1062
+ ...input.displayContext ? { displayContext: input.displayContext } : {},
1063
+ ...input.redirectToPath ? { redirectToPath: input.redirectToPath } : {},
1064
+ ...input.clientDomainKey ? { clientDomain: input.clientDomainKey } : {}
1065
+ };
1066
+ }
1067
+ function rewriteMagicLink(input) {
1068
+ return rewriteLinkToBaseUrl(
1069
+ input.magicLink,
1070
+ HUB_LOGIN_PAGE_PATH,
1071
+ input.clientDomain,
1072
+ input.bootstrapParams
1073
+ );
1074
+ }
969
1075
  function getRequestedAppVariantIdFromRequest(req) {
970
1076
  return req.getKeyValueFromQuery("app_variant_id");
971
1077
  }
@@ -984,12 +1090,19 @@ function getRequestedRedirectToPathFromRequest(req) {
984
1090
 
985
1091
  // src/config.ts
986
1092
  var pluginConfig;
1093
+ var superTokensConfig;
987
1094
  function setPluginConfig(config2) {
988
1095
  pluginConfig = config2;
989
1096
  }
990
1097
  function getPluginConfig() {
991
1098
  return pluginConfig;
992
1099
  }
1100
+ function setSuperTokensConfig(config2) {
1101
+ superTokensConfig = config2;
1102
+ }
1103
+ function getSuperTokensConfig() {
1104
+ return superTokensConfig;
1105
+ }
993
1106
  function assertRowndAppVariantIsConfigured(appVariantId) {
994
1107
  if (!appVariantId) {
995
1108
  return;
@@ -1070,7 +1183,10 @@ function buildSignInMethodsConfig(methodsArray) {
1070
1183
  },
1071
1184
  apple: {
1072
1185
  enabled: !!appleMethod,
1073
- client_id: getStringMethodProperty(appleMethod, "clientId") ?? ""
1186
+ client_id: getStringMethodProperty(appleMethod, "clientId") ?? "",
1187
+ ...getStringMethodProperty(appleMethod, "webClientType") !== void 0 ? { web_client_type: getStringMethodProperty(appleMethod, "webClientType") } : {},
1188
+ ...getStringMethodProperty(appleMethod, "iosClientType") !== void 0 ? { ios_client_type: getStringMethodProperty(appleMethod, "iosClientType") } : {},
1189
+ ...getStringMethodProperty(appleMethod, "androidClientType") !== void 0 ? { android_client_type: getStringMethodProperty(appleMethod, "androidClientType") } : {}
1074
1190
  },
1075
1191
  anonymous: {
1076
1192
  enabled: !!anonymousMethod && anonymousType !== "instant",
@@ -1344,6 +1460,7 @@ function buildAuthMobileConfig(authMobile) {
1344
1460
 
1345
1461
  // src/rownd-compatibility.ts
1346
1462
  var import_supertokens_node = __toESM(require("supertokens-node"));
1463
+ var import_usermetadata2 = __toESM(require("supertokens-node/recipe/usermetadata"));
1347
1464
  var IDENTITY_USER_DATA_FIELDS = /* @__PURE__ */ new Set([
1348
1465
  "user_id",
1349
1466
  "email",
@@ -1408,7 +1525,7 @@ function mapRowndUserToSuperTokens(rowndUser) {
1408
1525
  }
1409
1526
  let authLevel = rowndUser.auth_level;
1410
1527
  if (loginMethods.length === 0) {
1411
- const thirdPartyId = authLevel === GUEST_AUTH_METHOD_ID ? GUEST_AUTH_METHOD_ID : ANONYMOUS_AUTH_METHOD_ID;
1528
+ const thirdPartyId = authLevel === GUEST_AUTH_METHOD_ID ? GUEST_AUTH_METHOD_ID : INSTANT_AUTH_METHOD_ID;
1412
1529
  if (!authLevel) authLevel = thirdPartyId;
1413
1530
  loginMethods.push({
1414
1531
  recipeId: "thirdparty",
@@ -1480,11 +1597,10 @@ function getAnonymousId(userId, user, metadata) {
1480
1597
  if (typeof originalAnonymousId === "string") {
1481
1598
  return originalAnonymousId;
1482
1599
  }
1483
- const anonymousMethod = user?.loginMethods.find((loginMethod) => {
1484
- return loginMethod.recipeId === "thirdparty" && getThirdPartyId(loginMethod) === ANONYMOUS_AUTH_METHOD_ID;
1600
+ const guestMethod = user?.loginMethods.find((loginMethod) => {
1601
+ return loginMethod.recipeId === "thirdparty" && getThirdPartyId(loginMethod) === GUEST_AUTH_METHOD_ID;
1485
1602
  });
1486
- const thirdPartyUserId = anonymousMethod ? getThirdPartyUserId(anonymousMethod) : void 0;
1487
- return thirdPartyUserId || (hasAnonymousLoginMethod(user) ? `anon_${userId}` : void 0);
1603
+ return guestMethod ? `anon_${user?.id || userId}` : void 0;
1488
1604
  }
1489
1605
  function buildRowndSessionClaimPayload(input) {
1490
1606
  const currentPayload = input.currentPayload ?? {};
@@ -1501,7 +1617,7 @@ function buildRowndSessionClaimPayload(input) {
1501
1617
  currentPayload,
1502
1618
  input.metadata
1503
1619
  );
1504
- const isAnonymous = currentPayload.is_anonymous === true || authLevel === GUEST_AUTH_METHOD_ID || authLevel === ANONYMOUS_AUTH_METHOD_ID;
1620
+ const isAnonymous = currentPayload.is_anonymous === true || [GUEST_AUTH_METHOD_ID, INSTANT_AUTH_METHOD_ID].includes(authLevel);
1505
1621
  const anonymousId = getAnonymousId(input.userId, input.user, input.metadata);
1506
1622
  const isVerifiedUser = authLevel !== "unverified";
1507
1623
  const audience = buildRowndAudience(currentPayload, input.appVariantId);
@@ -1515,10 +1631,144 @@ function buildRowndSessionClaimPayload(input) {
1515
1631
  [ROWND_JWT_CLAIMS.AppUserId]: appUserId,
1516
1632
  [ROWND_JWT_CLAIMS.AuthLevel]: authLevel,
1517
1633
  [ROWND_JWT_CLAIMS.IsVerifiedUser]: isVerifiedUser,
1518
- [ROWND_JWT_CLAIMS.IsAnonymous]: isAnonymous,
1634
+ ...isAnonymous ? { [ROWND_JWT_CLAIMS.IsAnonymous]: true } : {},
1519
1635
  ...anonymousId ? { anonymous_id: anonymousId } : {}
1520
1636
  };
1521
1637
  }
1638
+ function normalizeRowndOAuthScopes(scopes) {
1639
+ return [...new Set(scopes.filter((scope) => scope.length > 0))];
1640
+ }
1641
+ function getRowndOAuthAudience(input) {
1642
+ const requested = input.requestedResource ?? input.requestedAudience;
1643
+ if (requested?.startsWith("app:")) {
1644
+ return requested;
1645
+ }
1646
+ return void 0;
1647
+ }
1648
+ function applyRowndOAuthResourceParams(input) {
1649
+ const resource = firstString(input.params.resource);
1650
+ const audience = firstString(input.params.audience);
1651
+ const rowndAudience = getRowndOAuthAudience({
1652
+ requestedResource: resource,
1653
+ requestedAudience: audience
1654
+ });
1655
+ if (!rowndAudience) {
1656
+ return;
1657
+ }
1658
+ input.userContext.rowndOAuthAudience = rowndAudience;
1659
+ input.params.audience = audience ?? rowndAudience;
1660
+ delete input.params.resource;
1661
+ }
1662
+ async function buildRowndOAuthPayload(input) {
1663
+ const currentPayload = input.currentPayload ?? {};
1664
+ const standardClaims = input.user ? await buildStandardOAuthClaims(input.user, input.scopes) : {};
1665
+ const rowndClaims = input.user ? await buildRowndOAuthSessionClaims(input.user, currentPayload) : {};
1666
+ const audience = getRowndOAuthAudience({
1667
+ requestedAudience: typeof input.userContext?.rowndOAuthAudience === "string" ? input.userContext.rowndOAuthAudience : void 0
1668
+ });
1669
+ return {
1670
+ ...currentPayload,
1671
+ ...standardClaims,
1672
+ ...rowndClaims,
1673
+ ...audience ? { aud: audience } : {}
1674
+ };
1675
+ }
1676
+ async function buildRowndOAuthUserInfo(input) {
1677
+ const standardClaims = await buildStandardOAuthClaims(
1678
+ input.user,
1679
+ input.scopes
1680
+ );
1681
+ const rowndClaims = pickOAuthUserInfoRowndClaims(input.accessTokenPayload);
1682
+ return {
1683
+ ...input.currentPayload,
1684
+ ...standardClaims,
1685
+ ...rowndClaims
1686
+ };
1687
+ }
1688
+ async function buildStandardOAuthClaims(user, scopes) {
1689
+ const claims = {};
1690
+ const metadata = await getRowndMetadata(user.id);
1691
+ const rowndData = isJsonRecord(metadata.original_rownd_user?.data) ? metadata.original_rownd_user.data : {};
1692
+ const verifiedData = isJsonRecord(metadata.original_rownd_user?.verified_data) ? metadata.original_rownd_user.verified_data : {};
1693
+ if (scopes.includes("email")) {
1694
+ const email = firstString(rowndData.email) ?? user.emails[0];
1695
+ if (email) {
1696
+ claims.email = email;
1697
+ claims.email_verified = isOAuthClaimVerified(
1698
+ verifiedData.email,
1699
+ email,
1700
+ user.loginMethods.some(
1701
+ (method) => method.hasSameEmailAs(email) && method.verified
1702
+ )
1703
+ );
1704
+ }
1705
+ }
1706
+ if (scopes.includes("phone")) {
1707
+ const phoneNumber = firstString(rowndData.phone_number) ?? user.phoneNumbers[0];
1708
+ if (phoneNumber) {
1709
+ claims.phone_number = phoneNumber;
1710
+ claims.phone_number_verified = isOAuthClaimVerified(
1711
+ verifiedData.phone_number,
1712
+ phoneNumber,
1713
+ user.loginMethods.some(
1714
+ (method) => method.hasSamePhoneNumberAs(phoneNumber) && method.verified
1715
+ )
1716
+ );
1717
+ }
1718
+ }
1719
+ if (scopes.includes("profile")) {
1720
+ const givenName = firstString(rowndData.first_name);
1721
+ const familyName = firstString(rowndData.last_name);
1722
+ const name = [givenName, familyName].filter(Boolean).join(" ");
1723
+ if (name) claims.name = name;
1724
+ if (givenName) claims.given_name = givenName;
1725
+ if (familyName) claims.family_name = familyName;
1726
+ if (typeof metadata.original_rownd_user?.data?.updated_at === "string") {
1727
+ claims.updated_at = metadata.original_rownd_user.data.updated_at;
1728
+ }
1729
+ }
1730
+ return claims;
1731
+ }
1732
+ async function getRowndMetadata(userId) {
1733
+ const metadata = await import_usermetadata2.default.getUserMetadata(userId);
1734
+ return metadata.metadata || {};
1735
+ }
1736
+ function pickOAuthUserInfoRowndClaims(payload) {
1737
+ const claims = {};
1738
+ for (const key of [
1739
+ "app_user_id",
1740
+ "auth_level",
1741
+ "is_verified_user",
1742
+ "is_anonymous",
1743
+ "anonymous_id",
1744
+ "https://auth.rownd.io/app_user_id",
1745
+ "https://auth.rownd.io/auth_level",
1746
+ "https://auth.rownd.io/is_verified_user",
1747
+ "https://auth.rownd.io/is_anonymous"
1748
+ ]) {
1749
+ if (payload[key] !== void 0) {
1750
+ claims[key] = payload[key];
1751
+ }
1752
+ }
1753
+ return claims;
1754
+ }
1755
+ function firstString(value) {
1756
+ if (Array.isArray(value)) {
1757
+ return value.find((entry) => typeof entry === "string");
1758
+ }
1759
+ return typeof value === "string" && value.length > 0 ? value : void 0;
1760
+ }
1761
+ function isOAuthClaimVerified(value, expectedValue, fallback) {
1762
+ return value === true || value === expectedValue || fallback;
1763
+ }
1764
+ async function buildRowndOAuthSessionClaims(user, currentPayload) {
1765
+ return buildRowndSessionClaimPayload({
1766
+ userId: user.id,
1767
+ user,
1768
+ metadata: await getRowndMetadata(user.id),
1769
+ currentPayload
1770
+ });
1771
+ }
1522
1772
  async function shouldLinkRowndAccounts(input) {
1523
1773
  const [newAccountInfo, , session] = input;
1524
1774
  if (!session) {
@@ -1561,23 +1811,26 @@ function getThirdPartyUserId(method) {
1561
1811
  return method.thirdParty?.userId;
1562
1812
  }
1563
1813
  function getGuestAuthLevel(user) {
1564
- const guestMethod = user?.loginMethods.find(isGuestLoginMethod);
1565
- return guestMethod ? GUEST_AUTH_METHOD_ID : void 0;
1566
- }
1567
- function hasAnonymousLoginMethod(user) {
1568
- return !!user?.loginMethods.some((loginMethod) => {
1569
- return loginMethod.recipeId === "thirdparty" && getThirdPartyId(loginMethod) === ANONYMOUS_AUTH_METHOD_ID;
1814
+ const guestMethod = user?.loginMethods.find((method) => {
1815
+ return method.recipeId === "thirdparty" && getThirdPartyId(method) === GUEST_AUTH_METHOD_ID;
1570
1816
  });
1817
+ if (guestMethod) {
1818
+ return GUEST_AUTH_METHOD_ID;
1819
+ }
1820
+ const instantMethod = user?.loginMethods.find((method) => {
1821
+ return method.recipeId === "thirdparty" && getThirdPartyId(method) === INSTANT_AUTH_METHOD_ID;
1822
+ });
1823
+ return instantMethod ? INSTANT_AUTH_METHOD_ID : void 0;
1571
1824
  }
1572
1825
  function hasOnlyGuestLoginMethods(user) {
1573
1826
  return !!user?.loginMethods.length && user.loginMethods.every(isGuestLoginMethod);
1574
1827
  }
1575
1828
  function isGuestLoginMethod(method) {
1576
1829
  const thirdPartyId = getThirdPartyId(method);
1577
- return method.recipeId === "thirdparty" && (thirdPartyId === GUEST_AUTH_METHOD_ID || thirdPartyId === ANONYMOUS_AUTH_METHOD_ID);
1830
+ return method.recipeId === "thirdparty" && (thirdPartyId === GUEST_AUTH_METHOD_ID || thirdPartyId === INSTANT_AUTH_METHOD_ID);
1578
1831
  }
1579
1832
  function isGuestAccountInfo(input) {
1580
- return input?.recipeId === "thirdparty" && (input.thirdParty?.id === GUEST_AUTH_METHOD_ID || input.thirdParty?.id === ANONYMOUS_AUTH_METHOD_ID);
1833
+ return input?.recipeId === "thirdparty" && (input.thirdParty?.id === GUEST_AUTH_METHOD_ID || input.thirdParty?.id === INSTANT_AUTH_METHOD_ID);
1581
1834
  }
1582
1835
  function doesAccountInfoMatchAuthMethod(user, accountInfo) {
1583
1836
  if (!user) {
@@ -1617,8 +1870,8 @@ function hasVerifiedRealLoginMethod(user) {
1617
1870
  });
1618
1871
  }
1619
1872
  function getEffectiveAuthLevel(user, originalAuthLevel, verifiedData) {
1620
- if (originalAuthLevel === ANONYMOUS_AUTH_METHOD_ID) {
1621
- return ANONYMOUS_AUTH_METHOD_ID;
1873
+ if (originalAuthLevel === INSTANT_AUTH_METHOD_ID) {
1874
+ return INSTANT_AUTH_METHOD_ID;
1622
1875
  }
1623
1876
  if (hasVerifiedRealLoginMethod(user)) {
1624
1877
  return "verified";
@@ -1663,7 +1916,7 @@ var import_emailverification = __toESM(require("supertokens-node/recipe/emailver
1663
1916
  var import_passwordless = __toESM(require("supertokens-node/recipe/passwordless"));
1664
1917
  var import_session = __toESM(require("supertokens-node/recipe/session"));
1665
1918
  var import_claims = require("supertokens-node/recipe/session/claims");
1666
- var import_usermetadata2 = __toESM(require("supertokens-node/recipe/usermetadata"));
1919
+ var import_usermetadata3 = __toESM(require("supertokens-node/recipe/usermetadata"));
1667
1920
  async function importUser(stUser, config2) {
1668
1921
  const headers = {
1669
1922
  "Content-Type": "application/json"
@@ -1702,7 +1955,7 @@ async function recordRowndAppVariantForUser(userId, appVariantId) {
1702
1955
  if (appVariants.includes(appVariantId)) {
1703
1956
  return;
1704
1957
  }
1705
- await import_usermetadata2.default.updateUserMetadata(userId, {
1958
+ await import_usermetadata3.default.updateUserMetadata(userId, {
1706
1959
  ...metadata,
1707
1960
  original_rownd_user: {
1708
1961
  ...originalRowndUser,
@@ -1720,7 +1973,7 @@ var RowndIsAnonymousClaim = new import_claims.BooleanClaim({
1720
1973
  fetchValue: async (userId) => {
1721
1974
  const user = await import_supertokens_node2.default.getUser(userId);
1722
1975
  const effectiveAuthLevel = getEffectiveAuthLevel(user);
1723
- return effectiveAuthLevel === GUEST_AUTH_METHOD_ID;
1976
+ return [GUEST_AUTH_METHOD_ID, INSTANT_AUTH_METHOD_ID].includes(effectiveAuthLevel);
1724
1977
  }
1725
1978
  });
1726
1979
  async function buildRowndSessionClaims(userId, currentPayload = {}, appVariantId) {
@@ -1734,8 +1987,78 @@ async function buildRowndSessionClaims(userId, currentPayload = {}, appVariantId
1734
1987
  appVariantId
1735
1988
  });
1736
1989
  }
1990
+ async function createMagicLinkWithConfirmationBypass(input) {
1991
+ const hasEmail = typeof input.email === "string" && input.email.length > 0;
1992
+ const hasPhoneNumber = typeof input.phoneNumber === "string" && input.phoneNumber.length > 0;
1993
+ if (hasEmail === hasPhoneNumber) {
1994
+ throw new Error("Exactly one of email or phoneNumber is required");
1995
+ }
1996
+ const stConfig = getSuperTokensConfig();
1997
+ if (!stConfig) {
1998
+ throw new Error("SuperTokens config is not initialized");
1999
+ }
2000
+ const pluginConfig2 = getPluginConfig();
2001
+ if (!pluginConfig2) {
2002
+ throw new Error("Rownd plugin config is not initialized");
2003
+ }
2004
+ const tenantId = input.tenantId ?? PUBLIC_TENANT_ID;
2005
+ const appVariantId = input.appVariantId;
2006
+ assertRowndAppVariantIsConfigured(appVariantId);
2007
+ const clientDomain = resolveAllowedClientDomain({
2008
+ clientDomain: input.clientDomain,
2009
+ pluginConfig: pluginConfig2,
2010
+ stConfig,
2011
+ request: input.request,
2012
+ userContext: input.userContext
2013
+ });
2014
+ const redirectToPath = normalizeRedirectToPathForClientDomain(input.redirectToPath, clientDomain);
2015
+ assertAllowedBypassRedirectPath(pluginConfig2, redirectToPath);
2016
+ const userContext = {
2017
+ ...input.userContext ?? {},
2018
+ ...input.displayContext ? { rowndDisplayContext: input.displayContext } : {},
2019
+ rowndRedirectToPath: redirectToPath,
2020
+ ...input.clientDomain ? { rowndClientDomain: input.clientDomain } : {},
2021
+ ...appVariantId ? { rowndAppVariantId: appVariantId } : {}
2022
+ };
2023
+ const codeInfo = hasEmail ? await import_passwordless.default.createCode({
2024
+ email: input.email,
2025
+ tenantId,
2026
+ session: input.session,
2027
+ userContext
2028
+ }) : await import_passwordless.default.createCode({
2029
+ phoneNumber: input.phoneNumber,
2030
+ tenantId,
2031
+ session: input.session,
2032
+ userContext
2033
+ });
2034
+ if (codeInfo.status !== "OK") {
2035
+ throw new Error("Failed to create magic link");
2036
+ }
2037
+ const magicLink = `${getWebsiteDomain({
2038
+ stConfig,
2039
+ request: input.request,
2040
+ userContext
2041
+ })}${getAppInfoString(stConfig.appInfo.websiteBasePath)}/verify?preAuthSessionId=${encodeURIComponent(
2042
+ codeInfo.preAuthSessionId
2043
+ )}&tenantId=${encodeURIComponent(tenantId)}#${encodeURIComponent(codeInfo.linkCode)}`;
2044
+ const rewrittenUrl = new URL(rewriteMagicLink({
2045
+ magicLink,
2046
+ clientDomain,
2047
+ bootstrapParams: getMagicLinkBootstrapParams({
2048
+ appKey: pluginConfig2.rowndAppKey,
2049
+ apiDomain: getAppInfoString(stConfig.appInfo.apiDomain),
2050
+ apiBasePath: getAppInfoString(stConfig.appInfo.apiBasePath),
2051
+ appVariantId,
2052
+ displayContext: input.displayContext,
2053
+ redirectToPath,
2054
+ clientDomainKey: input.clientDomain
2055
+ })
2056
+ }));
2057
+ rewrittenUrl.searchParams.set(PASSWORDLESS_BYPASS_DEVICE_CONFIRMATION_PARAM, "true");
2058
+ return rewrittenUrl.toString();
2059
+ }
1737
2060
  async function getUserMetadata(userId) {
1738
- const metadata = await import_usermetadata2.default.getUserMetadata(userId);
2061
+ const metadata = await import_usermetadata3.default.getUserMetadata(userId);
1739
2062
  return metadata.metadata || {};
1740
2063
  }
1741
2064
  function getPendingVerifications(metadata) {
@@ -1892,7 +2215,7 @@ async function updateUserData(userId, inputData) {
1892
2215
  ...metadata,
1893
2216
  ...inputData
1894
2217
  };
1895
- await import_usermetadata2.default.updateUserMetadata(userId, updatedMetadata);
2218
+ await import_usermetadata3.default.updateUserMetadata(userId, updatedMetadata);
1896
2219
  return getUserById(userId);
1897
2220
  }
1898
2221
  async function startPendingEmailVerification(input) {
@@ -1912,7 +2235,7 @@ async function startPendingEmailVerification(input) {
1912
2235
  );
1913
2236
  }
1914
2237
  if (pendingEmailVerifications.length > 0) {
1915
- await import_usermetadata2.default.updateUserMetadata(input.userId, {
2238
+ await import_usermetadata3.default.updateUserMetadata(input.userId, {
1916
2239
  ...metadata,
1917
2240
  rownd_pending_verification: pendingVerifications.filter(
1918
2241
  (pendingVerification2) => pendingVerification2.field !== "email"
@@ -1935,7 +2258,7 @@ async function startPendingEmailVerification(input) {
1935
2258
  value: input.email,
1936
2259
  created_at: (/* @__PURE__ */ new Date()).toISOString()
1937
2260
  };
1938
- await import_usermetadata2.default.updateUserMetadata(input.userId, {
2261
+ await import_usermetadata3.default.updateUserMetadata(input.userId, {
1939
2262
  ...metadata,
1940
2263
  rownd_pending_verification: [
1941
2264
  ...pendingVerifications.filter(
@@ -2056,7 +2379,7 @@ async function completePendingEmailVerification(input) {
2056
2379
  )
2057
2380
  )
2058
2381
  };
2059
- await import_usermetadata2.default.updateUserMetadata(metadataUserId, updatedMetadata);
2382
+ await import_usermetadata3.default.updateUserMetadata(metadataUserId, updatedMetadata);
2060
2383
  }
2061
2384
  function isMatchingPendingEmailVerification(verification, email) {
2062
2385
  return verification.field === "email" && verification.value === email;
@@ -2067,7 +2390,7 @@ async function updateUserMetadata(userId, inputMeta) {
2067
2390
  ...metadata,
2068
2391
  ...inputMeta
2069
2392
  };
2070
- await import_usermetadata2.default.updateUserMetadata(userId, updatedMetadata);
2393
+ await import_usermetadata3.default.updateUserMetadata(userId, updatedMetadata);
2071
2394
  return {
2072
2395
  id: userId,
2073
2396
  meta: Object.fromEntries(
@@ -2088,6 +2411,9 @@ var import_crypto = require("crypto");
2088
2411
  var import_supertokens_node3 = __toESM(require("supertokens-node"));
2089
2412
  var import_session2 = __toESM(require("supertokens-node/recipe/session"));
2090
2413
  var import_thirdparty = __toESM(require("supertokens-node/recipe/thirdparty"));
2414
+ function isBodyString(body, key) {
2415
+ return isRecord(body) && typeof body[key] === "string" && body[key].length > 0;
2416
+ }
2091
2417
  function handleGetAppConfig(deps) {
2092
2418
  return async (req) => {
2093
2419
  const appVariantId = getRequestedAppVariantIdFromRequest(req);
@@ -2108,6 +2434,43 @@ function handleGetAppConfig(deps) {
2108
2434
  };
2109
2435
  };
2110
2436
  }
2437
+ function handleValidatePasswordlessConfirmationBypass(deps) {
2438
+ return async (req) => {
2439
+ try {
2440
+ const body = await getJsonBody(req);
2441
+ const clientDomain = isBodyString(body, "clientDomain") ? body.clientDomain : void 0;
2442
+ const redirectToPath = isBodyString(body, "redirectToPath") ? body.redirectToPath : void 0;
2443
+ const appVariantId = isBodyString(body, "appVariantId") ? body.appVariantId : void 0;
2444
+ assertRowndAppVariantIsConfigured(appVariantId);
2445
+ const resolvedClientDomain = resolveAllowedClientDomain({
2446
+ clientDomain,
2447
+ pluginConfig: deps.pluginConfig,
2448
+ stConfig: deps.stConfig,
2449
+ request: req
2450
+ });
2451
+ const normalizedRedirectToPath = normalizeRedirectToPathForClientDomain(
2452
+ redirectToPath,
2453
+ resolvedClientDomain
2454
+ );
2455
+ assertAllowedBypassRedirectPath(
2456
+ deps.pluginConfig,
2457
+ normalizedRedirectToPath
2458
+ );
2459
+ return {
2460
+ status: "OK",
2461
+ bypass: true
2462
+ };
2463
+ } catch (error) {
2464
+ logDebugMessage(
2465
+ `Passwordless confirmation bypass validation failed. Error: ${getErrorMessage(error)}`
2466
+ );
2467
+ return {
2468
+ status: "ERROR",
2469
+ bypass: false
2470
+ };
2471
+ }
2472
+ };
2473
+ }
2111
2474
  function handleGuestLogin(deps) {
2112
2475
  return async (req, res, _session, userContext) => {
2113
2476
  const startedAt = Date.now();
@@ -2116,9 +2479,9 @@ function handleGuestLogin(deps) {
2116
2479
  const body = parseGuestBody(await getJsonBody(req));
2117
2480
  const appVariantId = getRequestedAppVariantIdFromRequest(req);
2118
2481
  assertRowndAppVariantIsConfigured(appVariantId);
2119
- const thirdPartyId = body.authLevel === ANONYMOUS_AUTH_METHOD_ID ? ANONYMOUS_AUTH_METHOD_ID : GUEST_AUTH_METHOD_ID;
2120
- const thirdPartyUserId = thirdPartyId === ANONYMOUS_AUTH_METHOD_ID ? `anon_${(0, import_crypto.randomUUID)()}` : guestId;
2121
- const authLevel = thirdPartyId === ANONYMOUS_AUTH_METHOD_ID ? ANONYMOUS_AUTH_METHOD_ID : GUEST_AUTH_METHOD_ID;
2482
+ const thirdPartyId = body.authLevel === INSTANT_AUTH_METHOD_ID ? INSTANT_AUTH_METHOD_ID : GUEST_AUTH_METHOD_ID;
2483
+ const thirdPartyUserId = thirdPartyId === INSTANT_AUTH_METHOD_ID ? `anon_${(0, import_crypto.randomUUID)()}` : guestId;
2484
+ const authLevel = thirdPartyId === INSTANT_AUTH_METHOD_ID ? INSTANT_AUTH_METHOD_ID : GUEST_AUTH_METHOD_ID;
2122
2485
  const response = await import_thirdparty.default.manuallyCreateOrUpdateUser(
2123
2486
  PUBLIC_TENANT_ID,
2124
2487
  thirdPartyId,
@@ -2141,7 +2504,7 @@ function handleGuestLogin(deps) {
2141
2504
  {
2142
2505
  ...buildRowndAudience({}, appVariantId),
2143
2506
  auth_level: authLevel,
2144
- is_anonymous: true,
2507
+ ...[GUEST_AUTH_METHOD_ID, INSTANT_AUTH_METHOD_ID].includes(authLevel) ? { is_anonymous: true } : {},
2145
2508
  app_user_id: response.user.id
2146
2509
  },
2147
2510
  {},
@@ -2505,6 +2868,7 @@ var init = createPluginInitFunction(
2505
2868
  }
2506
2869
  },
2507
2870
  routeHandlers(stConfig) {
2871
+ setSuperTokensConfig(stConfig);
2508
2872
  const apiBasePath = stConfig.appInfo.apiBasePath.getAsStringDangerous();
2509
2873
  hubBootstrapParams = {
2510
2874
  apiDomain: stConfig.appInfo.apiDomain.getAsStringDangerous(),
@@ -2535,6 +2899,13 @@ var init = createPluginInitFunction(
2535
2899
  method: "post",
2536
2900
  handler: withRequestHandler(handleMigrate(routeHandlerDeps))
2537
2901
  },
2902
+ {
2903
+ path: `${apiBasePath}/plugin/passwordless-cross-device-confirmation/validate`,
2904
+ method: "post",
2905
+ handler: withRequestHandler(
2906
+ handleValidatePasswordlessConfirmationBypass(routeHandlerDeps)
2907
+ )
2908
+ },
2538
2909
  {
2539
2910
  path: `${apiBasePath}/plugin/migrate-session`,
2540
2911
  method: "post",
@@ -2595,6 +2966,74 @@ var init = createPluginInitFunction(
2595
2966
  };
2596
2967
  },
2597
2968
  overrideMap: {
2969
+ oauth2provider: {
2970
+ recipeInitRequired: false,
2971
+ functions: (originalImplementation) => ({
2972
+ ...originalImplementation,
2973
+ getRequestedScopes: async (input) => {
2974
+ const scopes = await originalImplementation.getRequestedScopes(
2975
+ input
2976
+ );
2977
+ return normalizeRowndOAuthScopes(scopes);
2978
+ },
2979
+ buildAccessTokenPayload: async (input) => {
2980
+ const payload = await originalImplementation.buildAccessTokenPayload(
2981
+ input
2982
+ );
2983
+ return buildRowndOAuthPayload({
2984
+ user: input.user,
2985
+ client: input.client,
2986
+ scopes: input.scopes,
2987
+ currentPayload: payload,
2988
+ userContext: input.userContext
2989
+ });
2990
+ },
2991
+ buildIdTokenPayload: async (input) => {
2992
+ const payload = await originalImplementation.buildIdTokenPayload(
2993
+ input
2994
+ );
2995
+ return buildRowndOAuthPayload({
2996
+ user: input.user,
2997
+ client: input.client,
2998
+ scopes: input.scopes,
2999
+ currentPayload: payload,
3000
+ userContext: input.userContext
3001
+ });
3002
+ },
3003
+ buildUserInfo: async (input) => {
3004
+ const payload = await originalImplementation.buildUserInfo(input);
3005
+ return buildRowndOAuthUserInfo({
3006
+ user: input.user,
3007
+ accessTokenPayload: input.accessTokenPayload,
3008
+ scopes: input.scopes,
3009
+ currentPayload: payload
3010
+ });
3011
+ }
3012
+ }),
3013
+ apis: (originalImplementation) => ({
3014
+ ...originalImplementation,
3015
+ authGET: async (input) => {
3016
+ if (originalImplementation.authGET === void 0) {
3017
+ throw new Error("OAuth2Provider authGET is unavailable");
3018
+ }
3019
+ applyRowndOAuthResourceParams({
3020
+ params: input.params,
3021
+ userContext: input.userContext
3022
+ });
3023
+ return originalImplementation.authGET(input);
3024
+ },
3025
+ tokenPOST: async (input) => {
3026
+ if (originalImplementation.tokenPOST === void 0) {
3027
+ throw new Error("OAuth2Provider tokenPOST is unavailable");
3028
+ }
3029
+ applyRowndOAuthResourceParams({
3030
+ params: input.body,
3031
+ userContext: input.userContext
3032
+ });
3033
+ return originalImplementation.tokenPOST(input);
3034
+ }
3035
+ })
3036
+ },
2598
3037
  passwordless: {
2599
3038
  config: (config2) => {
2600
3039
  const originalEmailDeliveryOverride = config2.emailDelivery?.override;
@@ -2857,6 +3296,7 @@ var init = createPluginInitFunction(
2857
3296
  rowndAppSecret: config2.rowndAppSecret,
2858
3297
  enableDebugLogs: config2.enableDebugLogs,
2859
3298
  clientDomains: config2.clientDomains,
3299
+ crossDeviceConfirmationBypass: config2.crossDeviceConfirmationBypass,
2860
3300
  telemetry: config2.telemetry,
2861
3301
  schema: config2.schema,
2862
3302
  appConfig: config2.appConfig,
@@ -2879,12 +3319,13 @@ function validateClientDomainUrl(key, value) {
2879
3319
  var index_default = { init };
2880
3320
  // Annotate the CommonJS export names for ESM import in node:
2881
3321
  0 && (module.exports = {
2882
- ANONYMOUS_AUTH_METHOD_ID,
2883
3322
  DEFAULT_ROWND_SCHEMA,
2884
3323
  GUEST_AUTH_METHOD_ID,
2885
3324
  HANDLE_BASE_PATH,
2886
3325
  HUB_LOGIN_PAGE_PATH,
2887
3326
  HUB_VERIFY_EMAIL_PAGE_PATH,
3327
+ INSTANT_AUTH_METHOD_ID,
3328
+ PASSWORDLESS_BYPASS_DEVICE_CONFIRMATION_PARAM,
2888
3329
  PLUGIN_ID,
2889
3330
  PLUGIN_SDK_VERSION,
2890
3331
  PLUGIN_VERSION,
@@ -2892,6 +3333,7 @@ var index_default = { init };
2892
3333
  ROWND_JWT_CLAIMS,
2893
3334
  ROWND_PLUGIN_ERROR_MESSAGES,
2894
3335
  RowndPluginError,
3336
+ createMagicLinkWithConfirmationBypass,
2895
3337
  getRowndClient,
2896
3338
  init,
2897
3339
  setRowndClient