diff --git a/CHANGELOG.md b/CHANGELOG.md
index 581097a47..487d4922c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,104 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [unreleased]
+## [0.35.0] - 2023-09-XX
+
+### Overview
+
+#### Introducing account-linking
+
+With this release, we are introducing AccountLinking, this will let you:
+
+- link accounts automatically,
+- implement manual account linking flows.
+
+Check our [guide](https://supertokens.com/docs/thirdpartyemailpassword/common-customizations/account-linking/overview) for more information.
+
+To use this you'll need compatible versions:
+
+- Core>=7.0.0
+- supertokens-node>=16.0.0 (support is pending in other backend SDKs)
+- supertokens-website>=17.0.3
+- supertokens-web-js>=0.8.0
+- supertokens-auth-react>=0.35.0
+
+### Breaking changes
+
+- Added support for FDI 1.18 (Node SDK>= 16.0.0), but keeping support FDI version1.17 (node >= 15.0.0, golang>=0.13, python>=0.15.0)
+- User type has changed across recipes and functions: recipe specific user types have been removed and replaced by a generic one that contains more information
+- `createdNewUser` has been renamed to `createdNewRecipeUser`
+- `createCode`, `consumeCode`, `createPasswordlessCode` and `consumePasswordlessCode` can now return status: `SIGN_IN_UP_NOT_ALLOWED`
+- `signInAndUp` and `thirdPartySignInAndUp` can now return new status: `SIGN_IN_UP_NOT_ALLOWED`
+- `sendPasswordResetEmail` can now return `status: "PASSWORD_RESET_NOT_ALLOWED"`
+- `signIn` and `emailPasswordSignIn` can now return `SIGN_IN_NOT_ALLOWED`
+- `signUp` and `emailPasswordSignUp` can now return `SIGN_UP_NOT_ALLOWED`
+- The context param of `getRedirectionURL` gets an optional `user` prop (it's always defined if `createdNewRecipeUser` is set to true)
+- Added new language translation keys
+- We've added error messages for all of the above error statuses. Please see the new UI [here](https://supertokens.com/docs/thirdpartyemailpassword/common-customizations/account-linking/automatic-account-linking#support-status-codes). You can change the text using the language translation feature
+
+### Migration
+
+#### New User structure
+
+We've added a generic `User` type instead of the old recipe specific ones. The mapping of old props to new in case you are not using account-linking:
+
+- `user.id` stays `user.id`
+- `user.email` becomes `user.emails[0]`
+- `user.phoneNumber` becomes `user.phoneNumbers[0]`
+- `user.thirdParty` becomes `user.thirdParty[0]`
+- `user.timeJoined` is still `user.timeJoined`
+- `user.tenantIds` is still `user.tenantIds`
+
+#### Checking if a user signed up or signed in
+
+- When calling passwordless consumeCode / social login signinup APIs, you can check if a user signed up by:
+
+```
+ // Here res refers to the result the function/api functions mentioned above.
+ const isNewUser = res.createdNewRecipeUser && res.user.loginMethods.length === 1;
+```
+
+- When calling the emailpassword sign up API, you can check if a user signed up by:
+
+```
+ const isNewUser = res.user.loginMethods.length === 1;
+```
+
+- In `getRedirectionURL`
+
+```
+EmailPassword.init({ // This looks the same for other recipes
+ // Other config options.
+ async getRedirectionURL(context) {
+ if (context.action === "SUCCESS") {
+ if (context.isNewRecipeUser && context.user.loginMethods.length === 1) {
+ // new primary user
+ } else {
+ // only a recipe user was created
+ }
+ }
+ return undefined;
+ }
+})
+```
+
+- In `onHandleEvent`:
+
+```
+EmailPassword.init({ // This looks the same for other recipes
+ // Other config options.
+ onHandleEvent(context: EmailPasswordOnHandleEventContext) {
+ if (context.action === "SUCCESS") {
+ if (context.isNewRecipeUser && context.user.loginMethods.length === 1) {
+ // new primary user
+ } else {
+ // only a recipe user was created
+ }
+ }
+ },
+})
+```
+
## [0.34.2] - 2023-08-27
### Fixes
@@ -40,6 +138,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Only supporting FDI 1.17
- Backend SDKs have to be updated first to a version that supports multi-tenancy for thirdparty
- supertokens-node: >= 15.0.0
+ - supertokens-golang: >= 0.13.0
+ - supertokens-python: >= 0.15.0
- In ThirdParty recipe,
- Changed signatures of the functions `getAuthorisationURLWithQueryParamsAndSetState`
diff --git a/examples/for-tests-react-16/src/App.js b/examples/for-tests-react-16/src/App.js
index e69a5154e..10330bef8 100644
--- a/examples/for-tests-react-16/src/App.js
+++ b/examples/for-tests-react-16/src/App.js
@@ -605,7 +605,7 @@ function getEmailPasswordConfigs({ disableDefaultUI }) {
getRedirectionURL: async (context) => {
console.log(`ST_LOGS EMAIL_PASSWORD GET_REDIRECTION_URL ${context.action}`);
if (context.action === "SUCCESS") {
- setIsNewUserToStorage("emailpassword", context.isNewUser);
+ setIsNewUserToStorage("emailpassword", context.isNewRecipeUser);
return context.redirectToPath || "/dashboard";
}
},
@@ -653,6 +653,10 @@ function getThirdPartyPasswordlessConfigs({ staticProviderList, disableDefaultUI
name: "Auth0",
getRedirectURL: thirdPartyRedirectURL !== null ? () => thirdPartyRedirectURL : undefined,
},
+ {
+ id: "mock-provider",
+ name: "Mock Provider",
+ },
];
if (staticProviderList) {
const ids = JSON.parse(staticProviderList);
@@ -728,7 +732,7 @@ function getThirdPartyPasswordlessConfigs({ staticProviderList, disableDefaultUI
getRedirectionURL: async (context) => {
console.log(`ST_LOGS THIRDPARTYPASSWORDLESS GET_REDIRECTION_URL ${context.action}`);
if (context.action === "SUCCESS") {
- setIsNewUserToStorage("thirdpartypasswordless", context.isNewUser);
+ setIsNewUserToStorage("thirdpartypasswordless", context.isNewRecipeUser);
return context.redirectToPath || "/dashboard";
}
},
@@ -812,7 +816,7 @@ function getPasswordlessConfigs({ disableDefaultUI }) {
getRedirectionURL: async (context) => {
console.log(`ST_LOGS PASSWORDLESS GET_REDIRECTION_URL ${context.action}`);
if (context.action === "SUCCESS") {
- setIsNewUserToStorage("passwordless", context.isNewUser);
+ setIsNewUserToStorage("passwordless", context.isNewRecipeUser);
return context.redirectToPath || "/dashboard";
}
},
@@ -855,6 +859,10 @@ function getThirdPartyConfigs({ staticProviderList, disableDefaultUI, thirdParty
name: "Auth0",
getRedirectURL: thirdPartyRedirectURL !== null ? () => thirdPartyRedirectURL : undefined,
},
+ {
+ id: "mock-provider",
+ name: "Mock Provider",
+ },
];
if (staticProviderList) {
const ids = JSON.parse(staticProviderList);
@@ -874,7 +882,7 @@ function getThirdPartyConfigs({ staticProviderList, disableDefaultUI, thirdParty
getRedirectionURL: async (context) => {
console.log(`ST_LOGS THIRD_PARTY GET_REDIRECTION_URL ${context.action}`);
if (context.action === "SUCCESS") {
- setIsNewUserToStorage("thirdparty", context.isNewUser);
+ setIsNewUserToStorage("thirdparty", context.isNewRecipeUser);
return context.redirectToPath || "/dashboard";
}
},
@@ -940,6 +948,10 @@ function getThirdPartyEmailPasswordConfigs({ staticProviderList, disableDefaultU
name: "Auth0",
getRedirectURL: thirdPartyRedirectURL !== null ? () => thirdPartyRedirectURL : undefined,
},
+ {
+ id: "mock-provider",
+ name: "Mock Provider",
+ },
];
if (staticProviderList) {
const ids = JSON.parse(staticProviderList);
@@ -953,7 +965,7 @@ function getThirdPartyEmailPasswordConfigs({ staticProviderList, disableDefaultU
getRedirectionURL: async (context) => {
console.log(`ST_LOGS THIRD_PARTY_EMAIL_PASSWORD GET_REDIRECTION_URL ${context.action}`);
if (context.action === "SUCCESS") {
- setIsNewUserToStorage("thirdpartyemailpassword", context.isNewUser);
+ setIsNewUserToStorage("thirdpartyemailpassword", context.isNewRecipeUser);
return context.redirectToPath || "/dashboard";
}
},
@@ -1104,8 +1116,8 @@ function getThirdPartyEmailPasswordConfigs({ staticProviderList, disableDefaultU
});
}
-function setIsNewUserToStorage(recipeName, isNewUser) {
- localStorage.setItem("isNewUserCheck", `${recipeName}-${isNewUser}`);
+function setIsNewUserToStorage(recipeName, isNewRecipeUser) {
+ localStorage.setItem("isNewUserCheck", `${recipeName}-${isNewRecipeUser}`);
}
window.SuperTokens = SuperTokens;
diff --git a/examples/for-tests/src/App.js b/examples/for-tests/src/App.js
index a453227fe..f65dac002 100644
--- a/examples/for-tests/src/App.js
+++ b/examples/for-tests/src/App.js
@@ -610,7 +610,7 @@ function getEmailPasswordConfigs({ disableDefaultUI }) {
getRedirectionURL: async (context) => {
console.log(`ST_LOGS EMAIL_PASSWORD GET_REDIRECTION_URL ${context.action}`);
if (context.action === "SUCCESS") {
- setIsNewUserToStorage("emailpassword", context.isNewUser);
+ setIsNewUserToStorage("emailpassword", context.isNewRecipeUser);
return context.redirectToPath || "/dashboard";
}
},
@@ -658,6 +658,10 @@ function getThirdPartyPasswordlessConfigs({ staticProviderList, disableDefaultUI
name: "Auth0",
getRedirectURL: thirdPartyRedirectURL !== null ? () => thirdPartyRedirectURL : undefined,
},
+ {
+ id: "mock-provider",
+ name: "Mock Provider",
+ },
];
if (staticProviderList) {
const ids = JSON.parse(staticProviderList);
@@ -745,7 +749,7 @@ function getThirdPartyPasswordlessConfigs({ staticProviderList, disableDefaultUI
getRedirectionURL: async (context) => {
console.log(`ST_LOGS THIRDPARTYPASSWORDLESS GET_REDIRECTION_URL ${context.action}`);
if (context.action === "SUCCESS") {
- setIsNewUserToStorage("thirdpartypasswordless", context.isNewUser);
+ setIsNewUserToStorage("thirdpartypasswordless", context.isNewRecipeUser);
return context.redirectToPath || "/dashboard";
}
},
@@ -838,7 +842,7 @@ function getPasswordlessConfigs({ disableDefaultUI }) {
getRedirectionURL: async (context) => {
console.log(`ST_LOGS PASSWORDLESS GET_REDIRECTION_URL ${context.action}`);
if (context.action === "SUCCESS") {
- setIsNewUserToStorage("passwordless", context.isNewUser);
+ setIsNewUserToStorage("passwordless", context.isNewRecipeUser);
return context.redirectToPath || "/dashboard";
}
},
@@ -891,6 +895,10 @@ function getThirdPartyConfigs({ staticProviderList, disableDefaultUI, thirdParty
),
},
+ {
+ id: "mock-provider",
+ name: "Mock Provider",
+ },
];
if (staticProviderList) {
const ids = JSON.parse(staticProviderList);
@@ -922,7 +930,7 @@ function getThirdPartyConfigs({ staticProviderList, disableDefaultUI, thirdParty
getRedirectionURL: async (context) => {
console.log(`ST_LOGS THIRD_PARTY GET_REDIRECTION_URL ${context.action}`);
if (context.action === "SUCCESS") {
- setIsNewUserToStorage("thirdparty", context.isNewUser);
+ setIsNewUserToStorage("thirdparty", context.isNewRecipeUser);
return context.redirectToPath || "/dashboard";
}
},
@@ -988,6 +996,10 @@ function getThirdPartyEmailPasswordConfigs({ staticProviderList, disableDefaultU
name: "Auth0",
getRedirectURL: thirdPartyRedirectURL !== null ? () => thirdPartyRedirectURL : undefined,
},
+ {
+ id: "mock-provider",
+ name: "Mock Provider",
+ },
];
if (staticProviderList) {
const ids = JSON.parse(staticProviderList);
@@ -1014,7 +1026,7 @@ function getThirdPartyEmailPasswordConfigs({ staticProviderList, disableDefaultU
getRedirectionURL: async (context) => {
console.log(`ST_LOGS THIRD_PARTY_EMAIL_PASSWORD GET_REDIRECTION_URL ${context.action}`);
if (context.action === "SUCCESS") {
- setIsNewUserToStorage("thirdpartyemailpassword", context.isNewUser);
+ setIsNewUserToStorage("thirdpartyemailpassword", context.isNewRecipeUser);
return context.redirectToPath || "/dashboard";
}
},
@@ -1165,8 +1177,8 @@ function getThirdPartyEmailPasswordConfigs({ staticProviderList, disableDefaultU
});
}
-function setIsNewUserToStorage(recipeName, isNewUser) {
- localStorage.setItem("isNewUserCheck", `${recipeName}-${isNewUser}`);
+function setIsNewUserToStorage(recipeName, isNewRecipeUser) {
+ localStorage.setItem("isNewUserCheck", `${recipeName}-${isNewRecipeUser}`);
}
window.SuperTokens = SuperTokens;
diff --git a/examples/with-account-linking/README.md b/examples/with-account-linking/README.md
index 06201884d..cd4ab4501 100644
--- a/examples/with-account-linking/README.md
+++ b/examples/with-account-linking/README.md
@@ -1 +1,65 @@
-# Account linking is not supported yet, we are actively working on the feature.
+![SuperTokens banner](https://raw.githubusercontent.com/supertokens/supertokens-logo/master/images/Artboard%20%E2%80%93%2027%402x.png)
+
+# SuperTokens Google one tap Demo app
+
+This demo app demonstrates the following use cases:
+
+- Thirdparty Login / Sign-up
+- Email Password Login / Sign-up
+- Logout
+- Session management & Calling APIs
+- Account linking
+
+## Project setup
+
+Clone the repo, enter the directory, and use `npm` to install the project dependencies:
+
+```bash
+git clone https://github.com/supertokens/supertokens-auth-react
+cd supertokens-auth-react/examples/with-account-linking
+npm install
+cd frontend && npm install && cd ../
+cd backend && npm install && cd ../
+```
+
+## Run the demo app
+
+This compiles and serves the React app and starts the backend API server on port 3001.
+
+```bash
+npm run start
+```
+
+The app will start on `http://localhost:3000`
+
+## How it works
+
+We are adding a new (`/link`) page where the user can add new login methods to their current user, plus enabling automatic account linking.
+
+### On the frontend
+
+The demo uses the pre-built UI, but you can always build your own UI instead.
+
+- We do not need any extra configuration to enable account linking
+- To enable manual linking through a custom callback page, we add `getRedirectURL` to the configuration of the social login providers.
+- We add a custom page (`/link`) that will:
+ - Get and show the login methods belonging to the current user
+ - Show a password form (if available) that calls `/addPassword` to add an email+password login method to the current user.
+ - Show a phone number form (if available) that calls `/addPhoneNumber` to associate a phone number with the current user.
+ - Show an "Add Google account" that start a login process through Google
+- We add a custom page (`/link/tpcallback/:thirdPartyId`) that will:
+ - Call `/addThirdPartyUser` through a customized `ThirdPartyEmailPassword.thirdPartySignInAndUp` call
+
+### On the backend
+
+- We enable account linking by initializing the recipe and providing a `shouldDoAutomaticAccountLinking` implementation
+- We add `/addPassword`, `/addPhoneNumber` and `/addThirdPartyUser` to enable manual linking from the frontend
+- We add `/userInfo` so the frontend can list/show the login methods belonging to the current user.
+
+## Author
+
+Created with :heart: by the folks at supertokens.com.
+
+## License
+
+This project is licensed under the Apache 2.0 license.
diff --git a/examples/with-account-linking/backend/config.ts b/examples/with-account-linking/backend/config.ts
new file mode 100644
index 000000000..3d03ffb2d
--- /dev/null
+++ b/examples/with-account-linking/backend/config.ts
@@ -0,0 +1,100 @@
+import ThirdPartyEmailPassword from "supertokens-node/recipe/thirdpartyemailpassword";
+import Session from "supertokens-node/recipe/session";
+import Passwordless from "supertokens-node/recipe/passwordless";
+import AccountLinking from "supertokens-node/recipe/accountlinking";
+import EmailVerification from "supertokens-node/recipe/emailverification";
+import { TypeInput } from "supertokens-node/types";
+import UserMetadata from "supertokens-node/recipe/usermetadata";
+import Dashboard from "supertokens-node/recipe/dashboard";
+import { getUser } from "supertokens-node";
+
+export function getApiDomain() {
+ const apiPort = process.env.REACT_APP_API_PORT || 3001;
+ const apiUrl = process.env.REACT_APP_API_URL || `http://localhost:${apiPort}`;
+ return apiUrl;
+}
+
+export function getWebsiteDomain() {
+ const websitePort = process.env.REACT_APP_WEBSITE_PORT || 3000;
+ const websiteUrl = process.env.REACT_APP_WEBSITE_URL || `http://localhost:${websitePort}`;
+ return websiteUrl;
+}
+
+export const SuperTokensConfig: TypeInput = {
+ supertokens: {
+ // this is the location of the SuperTokens core.
+ connectionURI: "https://try.supertokens.com",
+ },
+ appInfo: {
+ appName: "SuperTokens Demo App",
+ apiDomain: getApiDomain(),
+ websiteDomain: getWebsiteDomain(),
+ },
+ // recipeList contains all the modules that you want to
+ // use from SuperTokens. See the full list here: https://supertokens.com/docs/guides
+ recipeList: [
+ EmailVerification.init({
+ mode: "REQUIRED",
+ }),
+ AccountLinking.init({
+ shouldDoAutomaticAccountLinking: async (newAccountInfo, user, _tenantId, context) => {
+ if (context.doNotLink === true) {
+ return {
+ shouldAutomaticallyLink: false,
+ };
+ }
+
+ if (newAccountInfo.recipeUserId !== undefined && user !== undefined) {
+ let userId = newAccountInfo.recipeUserId.getAsString();
+ let hasInfoAssociatedWithUserId = false; // TODO: add your own implementation here.
+ if (hasInfoAssociatedWithUserId) {
+ return {
+ // Alternatively, you can link users but then you should provide an `onAccountLinked` callback
+ // that implements merging the user of the two users.
+ shouldAutomaticallyLink: false,
+ };
+ }
+ }
+
+ return {
+ shouldAutomaticallyLink: true,
+ shouldRequireVerification: true,
+ };
+ },
+ }),
+ ThirdPartyEmailPassword.init({
+ providers: [
+ // We have provided you with development keys which you can use for testing.
+ // IMPORTANT: Please replace them with your own OAuth keys for production use.
+ {
+ config: {
+ thirdPartyId: "google",
+ clients: [
+ {
+ clientId: "1060725074195-kmeum4crr01uirfl2op9kd5acmi9jutn.apps.googleusercontent.com",
+ clientSecret: "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",
+ },
+ ],
+ },
+ },
+ {
+ config: {
+ thirdPartyId: "github",
+ clients: [
+ {
+ clientId: "467101b197249757c71f",
+ clientSecret: "e97051221f4b6426e8fe8d51486396703012f5bd",
+ },
+ ],
+ },
+ },
+ ],
+ }),
+ Passwordless.init({
+ contactMethod: "PHONE",
+ flowType: "USER_INPUT_CODE_AND_MAGIC_LINK",
+ }),
+ Session.init(),
+ Dashboard.init(),
+ ],
+};
diff --git a/examples/with-account-linking/backend/index.ts b/examples/with-account-linking/backend/index.ts
new file mode 100644
index 000000000..13b0cdf0e
--- /dev/null
+++ b/examples/with-account-linking/backend/index.ts
@@ -0,0 +1,285 @@
+import express from "express";
+import cors from "cors";
+import supertokens, { getUser, listUsersByAccountInfo } from "supertokens-node";
+import { verifySession } from "supertokens-node/recipe/session/framework/express";
+import { middleware, errorHandler, SessionRequest } from "supertokens-node/framework/express";
+import { getWebsiteDomain, SuperTokensConfig } from "./config";
+import EmailVerification from "supertokens-node/recipe/emailverification";
+import AccountLinking from "supertokens-node/recipe/accountlinking";
+import Session from "supertokens-node/recipe/session";
+import ThirdPartyEmailPassword from "supertokens-node/recipe/thirdpartyemailpassword";
+import Passwordless from "supertokens-node/recipe/passwordless";
+
+supertokens.init(SuperTokensConfig);
+
+const app = express();
+
+app.use(
+ cors({
+ origin: getWebsiteDomain(),
+ allowedHeaders: ["content-type", ...supertokens.getAllCORSHeaders()],
+ methods: ["GET", "PUT", "POST", "DELETE"],
+ credentials: true,
+ })
+);
+
+// This exposes all the APIs from SuperTokens to the client.
+app.use(middleware());
+app.use(express.json());
+
+// An example API that requires session verification
+app.get("/sessioninfo", verifySession(), async (req: SessionRequest, res) => {
+ let session = req.session;
+ res.send({
+ sessionHandle: session!.getHandle(),
+ userId: session!.getUserId(),
+ accessTokenPayload: session!.getAccessTokenPayload(),
+ });
+});
+
+app.get("/userInfo", verifySession(), async (req: SessionRequest, res) => {
+ const session = req.session!;
+ const user = await getUser(session.getRecipeUserId().getAsString());
+ if (!user) {
+ throw new Session.Error({ type: Session.Error.UNAUTHORISED, message: "user removed" });
+ }
+
+ res.json({
+ user: user.toJson(),
+ });
+});
+
+app.post("/addPassword", verifySession(), async (req: SessionRequest, res) => {
+ const session = req.session!;
+ // First we check that the current session (and the user it belongs to) can have a user linked to it.
+ const user = await getUser(session.getRecipeUserId().getAsString());
+ if (!user) {
+ throw new Session.Error({ type: Session.Error.UNAUTHORISED, message: "user removed" });
+ }
+
+ const currentLoginMethod = user.loginMethods.find(
+ (m) => m.recipeUserId.getAsString() === session.getRecipeUserId().getAsString()
+ );
+ if (!currentLoginMethod) {
+ throw new Error("This should never happen");
+ }
+
+ if (currentLoginMethod.recipeId === "emailpassword") {
+ return res.json({
+ status: "GENERAL_ERROR",
+ message: "This user already logged in using a password",
+ });
+ }
+
+ if (!currentLoginMethod.verified) {
+ return res.json({
+ status: "GENERAL_ERROR",
+ message: "You can only add a password when logged in using a verified account",
+ });
+ }
+
+ if (currentLoginMethod.email === undefined) {
+ return res.json({
+ status: "GENERAL_ERROR",
+ message: "You can only add a password to accounts associated with email addresses",
+ });
+ }
+
+ // We then "add the password" by signing up with a new user
+ let password: string = req.body.password;
+ const signUpResp = await ThirdPartyEmailPassword.emailPasswordSignUp(
+ session.getTenantId(),
+ currentLoginMethod.email,
+ password
+ );
+
+ if (signUpResp.status === "EMAIL_ALREADY_EXISTS_ERROR") {
+ // In this case the current user has an email that has already signed up
+ // If they are not linked, the other user can be deleted on the dashboard
+ // (or merged here if you provide an app specific implementation, but that is a longer/separate topic)
+ return res.json({
+ status: "GENERAL_ERROR",
+ message: "This user has already signed up using a password.",
+ });
+ }
+
+ // Here we can assume the user in signUpResp is not a primary user since it was just created
+ // Plus the linkAccounts checks anyway
+ const newRecipeUserId = signUpResp.user.loginMethods[0].recipeUserId;
+
+ const linkResp = await AccountLinking.linkAccounts(newRecipeUserId, session.getUserId());
+ if (linkResp.status !== "OK") {
+ return res.json({
+ status: "GENERAL_ERROR",
+ message: `Account linking failed (${linkResp.status})`,
+ });
+ }
+ // if the access token payload contains any information that'd change based on the new account, we'd want to update it here.
+
+ return res.json({
+ status: "OK",
+ user: linkResp.user,
+ });
+});
+
+app.post("/addThirdPartyUser", verifySession(), async (req: SessionRequest, res) => {
+ // We need this because several functions below require it
+ const userContext = {};
+ const session = req.session!;
+ // First we check that the current session (and the user it belongs to) can have a user linked to it.
+ const user = await getUser(session.getRecipeUserId().getAsString());
+ if (!user) {
+ throw new Session.Error({ type: Session.Error.UNAUTHORISED, message: "user removed" });
+ }
+ const loginMethod = user.loginMethods.find(
+ (m) => m.recipeUserId.getAsString() === session.getRecipeUserId().getAsString()
+ );
+ if (!loginMethod) {
+ throw new Error("This should never happen");
+ }
+
+ if (!loginMethod.verified) {
+ return res.json({
+ status: "GENERAL_ERROR",
+ message: "You can only add a password when logged in using a verified account",
+ });
+ }
+
+ // We then get get the user info from the third party provider
+ const provider = await ThirdPartyEmailPassword.thirdPartyGetProvider(
+ session.getTenantId(),
+ req.body.thirdPartyId,
+ req.body.clientType
+ );
+ if (provider === undefined) {
+ return res.json({
+ status: "GENERAL_ERROR",
+ message: "Unknown thirdparty provider id/client type",
+ });
+ }
+
+ let oAuthTokensToUse;
+ if ("redirectURIInfo" in req.body && req.body.redirectURIInfo !== undefined) {
+ oAuthTokensToUse = await provider.exchangeAuthCodeForOAuthTokens({
+ redirectURIInfo: req.body.redirectURIInfo,
+ userContext,
+ });
+ } else if ("oAuthTokens" in req.body && req.body.oAuthTokens !== undefined) {
+ oAuthTokensToUse = req.body.oAuthTokens;
+ } else {
+ throw Error("should never come here");
+ }
+ const tpUserInfo = await provider.getUserInfo({ oAuthTokens: oAuthTokensToUse, userContext });
+ let emailInfo = tpUserInfo.email;
+ if (emailInfo === undefined) {
+ return res.json({
+ status: "NO_EMAIL_GIVEN_BY_PROVIDER",
+ });
+ }
+
+ // In general, we require email verification before linking, but we can skip it in case if the user
+ // already verified this address in some other way
+ if (!user.emails.includes(emailInfo.id) && !emailInfo.isVerified) {
+ return res.json({
+ status: "GENERAL_ERROR",
+ message: "The email of the third-party account doesn't match the current user and is not verified",
+ });
+ }
+ // We create the new user here
+ const signUpResp = await ThirdPartyEmailPassword.thirdPartyManuallyCreateOrUpdateUser(
+ session.getTenantId(),
+ req.body.thirdPartyId,
+ tpUserInfo.thirdPartyUserId,
+ emailInfo.id,
+ emailInfo.isVerified,
+ { doNotLink: true }
+ );
+
+ if (signUpResp.status !== "OK") {
+ return res.json(signUpResp);
+ }
+
+ if (!signUpResp.createdNewRecipeUser) {
+ // In this case the third party user we tried to add has already signed up
+ // The other user can be deleted on the dashboard
+ // (or merged here if you provide an app specific implementation, but that is a longer/separate topic)
+ return res.json({
+ status: "GENERAL_ERROR",
+ message: "This user has already signed up. Please delete it first.",
+ });
+ }
+ // Now we can assume the user in signUpResp is not a primary user since it was just created
+ // Plus the linkAccounts core impl checks anyway
+ const newRecipeUserId = signUpResp.user.loginMethods[0].recipeUserId;
+
+ const linkResp = await AccountLinking.linkAccounts(newRecipeUserId, session.getUserId());
+ if (linkResp.status !== "OK") {
+ return res.json({
+ status: "GENERAL_ERROR",
+ message: `Account linking failed (${linkResp.status})`,
+ });
+ }
+ // if the access token payload contains any information that'd change based on the new account, we'd want to update it here.
+
+ return res.json({
+ status: "OK",
+ user: linkResp.user,
+ });
+});
+
+app.post("/addPhoneNumber", verifySession(), async (req: SessionRequest, res) => {
+ const session = req.session!;
+ // First we check that the current session (and the user it belongs to) can have a user linked to it.
+ const user = await getUser(session.getRecipeUserId().getAsString());
+ if (!user) {
+ throw new Session.Error({ type: Session.Error.UNAUTHORISED, message: "user removed" });
+ }
+ const loginMethod = user.loginMethods.find(
+ (m) => m.recipeUserId.getAsString() === session.getRecipeUserId().getAsString()
+ );
+ if (!loginMethod) {
+ throw new Error("This should never happen");
+ }
+
+ if (!loginMethod.verified) {
+ return res.json({
+ status: "GENERAL_ERROR",
+ message: "You can only add a phone number when logged in using a verified account",
+ });
+ }
+
+ const phoneNumber = req.body.phoneNumber;
+ const signUpResp = await Passwordless.signInUp({
+ tenantId: session.getTenantId(),
+ phoneNumber,
+ userContext: { doNotLink: true },
+ });
+
+ if (signUpResp.createdNewRecipeUser === false) {
+ return res.json({
+ status: "GENERAL_ERROR",
+ message: "You can only add a phone number to a single user",
+ });
+ }
+ const newRecipeUserId = signUpResp.user.loginMethods[0].recipeUserId;
+
+ const linkResp = await AccountLinking.linkAccounts(newRecipeUserId, session.getUserId());
+ if (linkResp.status !== "OK") {
+ return res.json({
+ status: "GENERAL_ERROR",
+ message: `Account linking failed (${linkResp.status})`,
+ });
+ }
+ // if the access token payload contains any information that'd change based on the new account, we'd want to update it here.
+
+ return res.json({
+ status: "OK",
+ user: linkResp.user,
+ });
+});
+
+// In case of session related errors, this error handler
+// returns 401 to the client.
+app.use(errorHandler());
+
+app.listen(3001, () => console.log(`API Server listening on port 3001`));
diff --git a/examples/with-account-linking/backend/package.json b/examples/with-account-linking/backend/package.json
new file mode 100644
index 000000000..59a4adeee
--- /dev/null
+++ b/examples/with-account-linking/backend/package.json
@@ -0,0 +1,30 @@
+{
+ "name": "supertokens-node",
+ "version": "0.0.1",
+ "private": true,
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "start": "npx ts-node-dev --project ./tsconfig.json ./index.ts"
+ },
+ "dependencies": {
+ "cors": "^2.8.5",
+ "express": "^4.18.1",
+ "helmet": "^5.1.0",
+ "morgan": "^1.10.0",
+ "npm-run-all": "^4.1.5",
+ "supertokens-node": "github:supertokens/supertokens-node#account-linking",
+ "ts-node-dev": "^2.0.0",
+ "typescript": "^4.7.2"
+ },
+ "devDependencies": {
+ "@types/cors": "^2.8.12",
+ "@types/express": "^4.17.17",
+ "@types/morgan": "^1.9.3",
+ "@types/node": "^16.11.38",
+ "nodemon": "^2.0.16"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "ISC"
+}
diff --git a/examples/with-account-linking/backend/tsconfig.json b/examples/with-account-linking/backend/tsconfig.json
new file mode 100644
index 000000000..8a91acaae
--- /dev/null
+++ b/examples/with-account-linking/backend/tsconfig.json
@@ -0,0 +1,62 @@
+{
+ "compilerOptions": {
+ /* Visit https://aka.ms/tsconfig.json to read more about this file */
+ /* Basic Options */
+ // "incremental": true, /* Enable incremental compilation */
+ "target": "es5" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
+ "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
+ // "lib": [], /* Specify library files to be included in the compilation. */
+ // "allowJs": true, /* Allow javascript files to be compiled. */
+ // "checkJs": true, /* Report errors in .js files. */
+ // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
+ // "declaration": true, /* Generates corresponding '.d.ts' file. */
+ // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
+ // "sourceMap": true, /* Generates corresponding '.map' file. */
+ // "outFile": "./", /* Concatenate and emit output to single file. */
+ // "outDir": "./", /* Redirect output structure to the directory. */
+ // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
+ // "composite": true, /* Enable project compilation */
+ // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
+ // "removeComments": true, /* Do not emit comments to output. */
+ // "noEmit": true, /* Do not emit outputs. */
+ // "importHelpers": true, /* Import emit helpers from 'tslib'. */
+ // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
+ // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
+ /* Strict Type-Checking Options */
+ "strict": true /* Enable all strict type-checking options. */,
+ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
+ // "strictNullChecks": true, /* Enable strict null checks. */
+ // "strictFunctionTypes": true, /* Enable strict checking of function types. */
+ // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
+ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
+ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
+ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
+ /* Additional Checks */
+ // "noUnusedLocals": true, /* Report errors on unused locals. */
+ // "noUnusedParameters": true, /* Report errors on unused parameters. */
+ // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
+ // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
+ /* Module Resolution Options */
+ // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
+ // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
+ // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
+ // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
+ // "typeRoots": [], /* List of folders to include type definitions from. */
+ // "types": [], /* Type declaration files to be included in compilation. */
+ // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
+ "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
+ // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
+ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
+ /* Source Map Options */
+ // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
+ // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
+ // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
+ // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
+ /* Experimental Options */
+ // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
+ // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
+ /* Advanced Options */
+ "skipLibCheck": true /* Skip type checking of declaration files. */,
+ "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
+ }
+}
diff --git a/examples/with-account-linking/frontend/.env b/examples/with-account-linking/frontend/.env
new file mode 100644
index 000000000..7d910f148
--- /dev/null
+++ b/examples/with-account-linking/frontend/.env
@@ -0,0 +1 @@
+SKIP_PREFLIGHT_CHECK=true
\ No newline at end of file
diff --git a/examples/with-account-linking/frontend/.gitignore b/examples/with-account-linking/frontend/.gitignore
new file mode 100644
index 000000000..4d29575de
--- /dev/null
+++ b/examples/with-account-linking/frontend/.gitignore
@@ -0,0 +1,23 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.js
+
+# testing
+/coverage
+
+# production
+/build
+
+# misc
+.DS_Store
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local
+
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
diff --git a/examples/with-account-linking/frontend/LICENSE.md b/examples/with-account-linking/frontend/LICENSE.md
new file mode 100644
index 000000000..588f27e68
--- /dev/null
+++ b/examples/with-account-linking/frontend/LICENSE.md
@@ -0,0 +1,192 @@
+Copyright (c) 2020, VRAI Labs and/or its affiliates. All rights reserved.
+
+This software is licensed under the Apache License, Version 2.0 (the
+"License") as published by the Apache Software Foundation.
+
+You may not use this software except in compliance with the License. A copy
+of the License is available below the line.
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+License for the specific language governing permissions and limitations
+under the License.
+
+---
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
diff --git a/examples/with-account-linking/frontend/package.json b/examples/with-account-linking/frontend/package.json
new file mode 100644
index 000000000..cd6e6e145
--- /dev/null
+++ b/examples/with-account-linking/frontend/package.json
@@ -0,0 +1,46 @@
+{
+ "name": "supertokens-react",
+ "version": "0.1.0",
+ "private": true,
+ "dependencies": {
+ "@testing-library/jest-dom": "^5.16.5",
+ "@testing-library/react": "^13.4.0",
+ "@testing-library/user-event": "^13.5.0",
+ "@types/jest": "^27.5.2",
+ "@types/node": "^16.11.56",
+ "@types/react": "^18.0.18",
+ "@types/react-dom": "^18.0.6",
+ "axios": "^0.21.0",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0",
+ "react-router-dom": "^6.2.1",
+ "react-scripts": "5.0.1",
+ "supertokens-auth-react": "github:supertokens/supertokens-auth-react#feat/account-linking",
+ "typescript": "^4.8.2",
+ "web-vitals": "^2.1.4"
+ },
+ "scripts": {
+ "start": "react-scripts start",
+ "build": "react-scripts build",
+ "test": "react-scripts test",
+ "eject": "react-scripts eject"
+ },
+ "eslintConfig": {
+ "extends": [
+ "react-app",
+ "react-app/jest"
+ ]
+ },
+ "browserslist": {
+ "production": [
+ ">0.2%",
+ "not dead",
+ "not op_mini all"
+ ],
+ "development": [
+ "last 1 chrome version",
+ "last 1 firefox version",
+ "last 1 safari version"
+ ]
+ }
+}
diff --git a/examples/with-account-linking/frontend/public/favicon.ico b/examples/with-account-linking/frontend/public/favicon.ico
new file mode 100644
index 000000000..a11777cc4
Binary files /dev/null and b/examples/with-account-linking/frontend/public/favicon.ico differ
diff --git a/examples/with-account-linking/frontend/public/index.html b/examples/with-account-linking/frontend/public/index.html
new file mode 100644
index 000000000..6f1f7cb51
--- /dev/null
+++ b/examples/with-account-linking/frontend/public/index.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ React App
+
+
+ You need to enable JavaScript to run this app.
+
+
+
diff --git a/examples/with-account-linking/frontend/public/manifest.json b/examples/with-account-linking/frontend/public/manifest.json
new file mode 100644
index 000000000..f01493ff0
--- /dev/null
+++ b/examples/with-account-linking/frontend/public/manifest.json
@@ -0,0 +1,25 @@
+{
+ "short_name": "React App",
+ "name": "Create React App Sample",
+ "icons": [
+ {
+ "src": "favicon.ico",
+ "sizes": "64x64 32x32 24x24 16x16",
+ "type": "image/x-icon"
+ },
+ {
+ "src": "logo192.png",
+ "type": "image/png",
+ "sizes": "192x192"
+ },
+ {
+ "src": "logo512.png",
+ "type": "image/png",
+ "sizes": "512x512"
+ }
+ ],
+ "start_url": ".",
+ "display": "standalone",
+ "theme_color": "#000000",
+ "background_color": "#ffffff"
+}
diff --git a/examples/with-account-linking/frontend/public/robots.txt b/examples/with-account-linking/frontend/public/robots.txt
new file mode 100644
index 000000000..e9e57dc4d
--- /dev/null
+++ b/examples/with-account-linking/frontend/public/robots.txt
@@ -0,0 +1,3 @@
+# https://www.robotstxt.org/robotstxt.html
+User-agent: *
+Disallow:
diff --git a/examples/with-account-linking/frontend/src/App.css b/examples/with-account-linking/frontend/src/App.css
new file mode 100644
index 000000000..8a98a2341
--- /dev/null
+++ b/examples/with-account-linking/frontend/src/App.css
@@ -0,0 +1,27 @@
+.App {
+ display: flex;
+ flex-direction: column;
+ width: 100vw;
+ height: 100vh;
+ font-family: Rubik;
+}
+
+.fill {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ flex: 1;
+}
+
+.sessionButton {
+ padding-left: 13px;
+ padding-right: 13px;
+ padding-top: 8px;
+ padding-bottom: 8px;
+ background-color: black;
+ border-radius: 10px;
+ cursor: pointer;
+ color: white;
+ font-weight: bold;
+ font-size: 17px;
+}
diff --git a/examples/with-account-linking/frontend/src/App.tsx b/examples/with-account-linking/frontend/src/App.tsx
new file mode 100644
index 000000000..6a8bcd2b7
--- /dev/null
+++ b/examples/with-account-linking/frontend/src/App.tsx
@@ -0,0 +1,60 @@
+import "./App.css";
+import SuperTokens, { SuperTokensWrapper } from "supertokens-auth-react";
+import { getSuperTokensRoutesForReactRouterDom } from "supertokens-auth-react/ui";
+import { SessionAuth } from "supertokens-auth-react/recipe/session";
+import { Routes, BrowserRouter as Router, Route } from "react-router-dom";
+import Home from "./Home";
+import { PreBuiltUIList, SuperTokensConfig } from "./config";
+import { LinkingPage } from "./LinkingPage";
+import { LinkingCallbackPage } from "./LinkingCallbackPage";
+
+SuperTokens.init(SuperTokensConfig);
+
+function App() {
+ return (
+
+
+
+
+
+ {/* This shows the login UI on "/auth" route */}
+ {getSuperTokensRoutesForReactRouterDom(require("react-router-dom"), PreBuiltUIList)}
+
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+ only if the user is logged in.
+ Else it redirects the user to "/auth" */
+
+
+
+ }
+ />
+
+
+
+
+
+ );
+}
+
+export default App;
diff --git a/examples/with-account-linking/frontend/src/Home/CallAPIView.tsx b/examples/with-account-linking/frontend/src/Home/CallAPIView.tsx
new file mode 100644
index 000000000..6a9d510d4
--- /dev/null
+++ b/examples/with-account-linking/frontend/src/Home/CallAPIView.tsx
@@ -0,0 +1,15 @@
+import axios from "axios";
+import { getApiDomain } from "../config";
+
+export default function CallAPIView() {
+ async function callAPIClicked() {
+ let response = await axios.get(getApiDomain() + "/sessioninfo");
+ window.alert("Session Information:\n" + JSON.stringify(response.data, null, 2));
+ }
+
+ return (
+
+ Call API
+
+ );
+}
diff --git a/examples/with-account-linking/frontend/src/Home/Home.css b/examples/with-account-linking/frontend/src/Home/Home.css
new file mode 100644
index 000000000..228e600d4
--- /dev/null
+++ b/examples/with-account-linking/frontend/src/Home/Home.css
@@ -0,0 +1,191 @@
+@font-face {
+ font-family: Menlo;
+ src: url("../assets/fonts/MenloRegular.ttf");
+}
+
+.app-container {
+ font-family: Rubik, sans-serif;
+}
+
+.app-container * {
+ box-sizing: border-box;
+}
+
+.bold-400 {
+ font-variation-settings: "wght" 400;
+}
+
+.bold-500 {
+ font-variation-settings: "wght" 500;
+}
+
+.bold-600 {
+ font-variation-settings: "wght" 600;
+}
+
+#home-container {
+ align-items: center;
+ min-height: 100vh;
+ background: url("../assets/images/background.png");
+ background-size: cover;
+}
+
+.bold-700 {
+ font-variation-settings: "wght" 700;
+}
+
+.app-container .main-container {
+ box-shadow: 0px 0px 60px 0px rgba(0, 0, 0, 0.16);
+ width: min(635px, calc(100% - 24px));
+ border-radius: 16px;
+ margin-block-end: 159px;
+ background-color: #ffffff;
+}
+
+.main-container .success-title {
+ line-height: 1;
+ padding-block: 26px;
+ background-color: #e7ffed;
+ text-align: center;
+ color: #3eb655;
+ display: flex;
+ justify-content: center;
+ align-items: flex-end;
+ font-size: 20px;
+}
+
+.success-title img.success-icon {
+ margin-right: 8px;
+}
+
+.main-container .inner-content {
+ padding-block: 48px;
+ text-align: center;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+.inner-content #user-id {
+ position: relative;
+ padding: 14px 17px;
+ border-image-slice: 1;
+ width: min(430px, calc(100% - 30px));
+ margin-inline: auto;
+ margin-block: 11px 23px;
+ border-radius: 9px;
+ line-height: 1;
+ font-family: Menlo, serif;
+ cursor: text;
+}
+
+.inner-content #user-id:before {
+ content: "";
+ position: absolute;
+ inset: 0;
+ border-radius: 9px;
+ padding: 2px;
+ background: linear-gradient(90.31deg, #ff9933 0.11%, #ff3f33 99.82%);
+ -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
+ -webkit-mask-composite: xor;
+ mask-composite: exclude;
+}
+
+.main-container > .top-band,
+.main-container > .bottom-band {
+ border-radius: inherit;
+}
+
+.main-container .top-band {
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
+}
+
+.main-container .bottom-band {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+}
+
+.main-container .sessionButton {
+ box-sizing: border-box;
+ background: #ff9933;
+ border: 1px solid #ff8a15;
+ box-shadow: 0px 3px 6px rgba(255, 153, 51, 0.16);
+ border-radius: 6px;
+ font-size: 16px;
+ margin: 0.5em;
+ text-decoration: none;
+}
+
+.bottom-cta-container {
+ display: flex;
+ justify-content: flex-end;
+ padding-inline: 21px;
+ background-color: #212d4f;
+}
+
+.bottom-cta-container .view-code {
+ padding-block: 11px;
+ color: #bac9f5;
+ cursor: pointer;
+ font-size: 14px;
+}
+
+.bottom-links-container {
+ display: grid;
+ grid-template-columns: repeat(4, auto);
+ margin-bottom: 22px;
+}
+
+.bottom-links-container .link {
+ display: flex;
+ align-items: center;
+ margin-inline-end: 68px;
+ cursor: pointer;
+}
+
+.bottom-links-container .link:last-child {
+ margin-right: 0;
+}
+
+.truncate {
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: nowrap;
+}
+
+.separator-line {
+ max-width: 100%;
+}
+
+.link .link-icon {
+ width: 15px;
+ margin-right: 5px;
+}
+
+@media screen and (max-width: 768px) {
+ .bottom-links-container {
+ grid-template-columns: repeat(2, 1fr);
+ column-gap: 64px;
+ row-gap: 34px;
+ }
+
+ .bottom-links-container .link {
+ margin-inline-end: 0;
+ }
+
+ .separator-line {
+ max-width: 200px;
+ }
+}
+
+@media screen and (max-width: 480px) {
+ #home-container {
+ justify-content: start;
+ padding-block-start: 25px;
+ }
+
+ .app-container .main-container {
+ margin-block-end: 90px;
+ }
+}
diff --git a/examples/with-account-linking/frontend/src/Home/SuccessView.tsx b/examples/with-account-linking/frontend/src/Home/SuccessView.tsx
new file mode 100644
index 000000000..5a5417afe
--- /dev/null
+++ b/examples/with-account-linking/frontend/src/Home/SuccessView.tsx
@@ -0,0 +1,78 @@
+import { NavLink, useNavigate } from "react-router-dom";
+import { signOut } from "supertokens-auth-react/recipe/session";
+import { recipeDetails } from "../config";
+import CallAPIView from "./CallAPIView";
+import { BlogsIcon, CelebrateIcon, GuideIcon, SeparatorLine, SignOutIcon } from "../assets/images";
+
+interface ILink {
+ name: string;
+ onClick: () => void;
+ icon: string;
+}
+
+export default function SuccessView(props: { userId: string }) {
+ let userId = props.userId;
+
+ const navigate = useNavigate();
+
+ async function logoutClicked() {
+ await signOut();
+ navigate("/auth");
+ }
+
+ function openLink(url: string) {
+ window.open(url, "_blank");
+ }
+
+ const links: ILink[] = [
+ {
+ name: "Blogs",
+ onClick: () => openLink("https://supertokens.com/blog"),
+ icon: BlogsIcon,
+ },
+ {
+ name: "Documentation",
+ onClick: () => openLink(recipeDetails.docsLink),
+ icon: GuideIcon,
+ },
+ {
+ name: "Sign Out",
+ onClick: logoutClicked,
+ icon: SignOutIcon,
+ },
+ ];
+
+ return (
+ <>
+
+
+
Login successful
+
+
+
Your userID is:
+
+ {userId}
+
+
+
+
+
+ Manage login Methods
+
+
+
+
+
+ {links.map((link) => (
+
+
+
+ {link.name}
+
+
+ ))}
+
+
+ >
+ );
+}
diff --git a/examples/with-account-linking/frontend/src/Home/index.tsx b/examples/with-account-linking/frontend/src/Home/index.tsx
new file mode 100644
index 000000000..0c3f288e8
--- /dev/null
+++ b/examples/with-account-linking/frontend/src/Home/index.tsx
@@ -0,0 +1,17 @@
+import SuccessView from "./SuccessView";
+import { useSessionContext } from "supertokens-auth-react/recipe/session";
+import "./Home.css";
+
+export default function Home() {
+ const sessionContext = useSessionContext();
+
+ if (sessionContext.loading === true) {
+ return null;
+ }
+
+ return (
+
+
+
+ );
+}
diff --git a/examples/with-account-linking/frontend/src/LinkingCallbackPage/index.tsx b/examples/with-account-linking/frontend/src/LinkingCallbackPage/index.tsx
new file mode 100644
index 000000000..581ea6fc3
--- /dev/null
+++ b/examples/with-account-linking/frontend/src/LinkingCallbackPage/index.tsx
@@ -0,0 +1,37 @@
+import ThirdPartyEmailPassword from "supertokens-auth-react/recipe/thirdpartyemailpassword";
+import React from "react";
+import { useNavigate } from "react-router-dom";
+import { useAsyncCallOnMount } from "../useAsyncCallOnMount";
+
+export const LinkingCallbackPage: React.FC = () => {
+ const navigate = useNavigate();
+
+ useAsyncCallOnMount(
+ () =>
+ ThirdPartyEmailPassword.thirdPartySignInAndUp({
+ options: {
+ preAPIHook: async (input) => {
+ const url = new URL(input.url);
+ url.pathname = "/addThirdPartyUser";
+ input.url = url.toString();
+ return input;
+ },
+ },
+ }),
+ (resp) => {
+ if (resp.status === "OK") {
+ navigate(`/link?success=${encodeURIComponent("Successfully added third-party account")}`);
+ } else if ("reason" in resp) {
+ navigate(`/link?error=${encodeURIComponent(resp.reason)}`);
+ } else {
+ navigate(`/link?error=${encodeURIComponent(resp.status)}`);
+ }
+ }
+ );
+
+ return (
+
+ Linking...
+
+ );
+};
diff --git a/examples/with-account-linking/frontend/src/LinkingPage/index.tsx b/examples/with-account-linking/frontend/src/LinkingPage/index.tsx
new file mode 100644
index 000000000..90d47a34b
--- /dev/null
+++ b/examples/with-account-linking/frontend/src/LinkingPage/index.tsx
@@ -0,0 +1,145 @@
+import React, { useCallback, useEffect, useState } from "react";
+import { NavLink, useLocation } from "react-router-dom";
+import { useSessionContext } from "supertokens-auth-react/recipe/session";
+import { redirectToThirdPartyLogin } from "supertokens-auth-react/recipe/thirdpartyemailpassword";
+
+import { getApiDomain } from "../config";
+import "./styles.css";
+
+export const LinkingPage: React.FC = () => {
+ const location = useLocation();
+ const sessionContext = useSessionContext();
+
+ const [userInfo, setUserInfo] = useState();
+
+ const [error, setError] = useState(new URLSearchParams(location.search).get("error"));
+ const [success, setSuccess] = useState(new URLSearchParams(location.search).get("success"));
+
+ const [phoneNumber, setPhoneNumber] = useState();
+ const [password, setPassword] = useState();
+
+ const loadUserInfo = useCallback(async () => {
+ const res = await fetch(`${getApiDomain()}/userInfo`);
+ setUserInfo(await res.json());
+ }, [setUserInfo]);
+
+ const addPassword = useCallback(async () => {
+ const resp = await fetch(`${getApiDomain()}/addPassword`, {
+ method: "POST",
+ headers: {
+ "content-type": "application/json",
+ },
+ body: JSON.stringify({
+ password,
+ }),
+ });
+
+ const respBody = await resp.json();
+ if (respBody.status !== "OK") {
+ setSuccess(null);
+ setError(respBody.reason ?? respBody.message ?? respBody.status);
+ } else {
+ setSuccess("Successfully added password");
+ setError(null);
+ }
+ }, [setError, setSuccess]);
+
+ const addPhoneNumber = useCallback(async () => {
+ const resp = await fetch(`${getApiDomain()}/addPhoneNumber`, {
+ method: "POST",
+ headers: {
+ "content-type": "application/json",
+ },
+ body: JSON.stringify({
+ phoneNumber,
+ }),
+ });
+
+ const respBody = await resp.json();
+ if (respBody.status !== "OK") {
+ setError(respBody.reason ?? respBody.message ?? respBody.status);
+ } else {
+ setSuccess("Successfully added password");
+ }
+ loadUserInfo();
+ }, [setError, setSuccess, loadUserInfo]);
+
+ useEffect(() => {
+ loadUserInfo();
+ }, [loadUserInfo]);
+
+ if (sessionContext.loading === true) {
+ return null;
+ }
+
+ let passwordLoginMethods = userInfo?.user.loginMethods.filter((lm: any) => lm.recipeId === "emailpassword");
+ let thirdPartyLoginMethod = userInfo?.user.loginMethods.filter((lm: any) => lm.recipeId === "thirdparty");
+ let phoneLoginMethod = userInfo?.user.loginMethods.filter((lm: any) => lm.recipeId === "passwordless");
+
+ return (
+
+
Back
+ {error &&
{error}
}
+ {success &&
{success}
}
+
+ {userInfo === undefined ? (
+
Login methods loading...
+ ) : (
+
+ {passwordLoginMethods.map((lm: any) => (
+
+ {lm.recipeId}
+ {lm.recipeUserId}
+ Email: {lm.email}
+
+ ))}
+ {thirdPartyLoginMethod.map((lm: any) => (
+
+ {lm.recipeId}
+ {lm.recipeUserId}
+
+ Provider: {lm.thirdParty.id} ({lm.thirdParty.userId}) - Email: {lm.email}
+
+
+ ))}
+ {phoneLoginMethod.map((lm: any) => (
+
+ {lm.recipeId}
+ {lm.recipeUserId}
+ Phone number: {lm.phoneNumber}
+
+ ))}
+
+ )}
+ {passwordLoginMethods?.length === 0 && (
+
+ )}
+ {phoneLoginMethod?.length === 0 && (
+
+ )}
+ {thirdPartyLoginMethod?.length === 0 && (
+
+ )}
+
+ );
+};
diff --git a/examples/with-account-linking/frontend/src/LinkingPage/styles.css b/examples/with-account-linking/frontend/src/LinkingPage/styles.css
new file mode 100644
index 000000000..643f6b4dd
--- /dev/null
+++ b/examples/with-account-linking/frontend/src/LinkingPage/styles.css
@@ -0,0 +1,62 @@
+.success-message {
+ line-height: 1;
+ padding-block: 26px;
+ background-color: #e7ffed;
+ text-align: center;
+ color: #3eb655;
+ display: flex;
+ justify-content: center;
+ align-items: flex-end;
+ font-size: 20px;
+ margin: 8px;
+ padding: 16px;
+ border-radius: 16px;
+}
+
+.error-message {
+ line-height: 1;
+ padding-block: 26px;
+ background-color: #ef9a9a;
+ text-align: center;
+ color: black;
+ display: flex;
+ justify-content: center;
+ align-items: flex-end;
+ font-size: 20px;
+ margin: 8px;
+ padding: 16px;
+ border-radius: 16px;
+}
+
+.login-method {
+ padding: 1em;
+ background-color: white;
+ margin: 1.25em;
+ display: grid;
+ grid-template-columns: 8em auto;
+ border-radius: 1em;
+}
+
+.contactInfo {
+ grid-column: 1 / 3;
+ margin-top: 0.5em;
+}
+
+.userId {
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ overflow: hidden;
+}
+
+form {
+ margin: 1.25em;
+}
+
+button {
+ box-sizing: border-box;
+ border-radius: 6px;
+ font-size: 16px;
+ margin: 0.5em;
+ border: 1px solid black;
+ text-decoration: none;
+}
diff --git a/examples/with-account-linking/frontend/src/assets/fonts/MenloRegular.ttf b/examples/with-account-linking/frontend/src/assets/fonts/MenloRegular.ttf
new file mode 100644
index 000000000..033dc6d21
Binary files /dev/null and b/examples/with-account-linking/frontend/src/assets/fonts/MenloRegular.ttf differ
diff --git a/examples/with-account-linking/frontend/src/assets/images/arrow-right-icon.svg b/examples/with-account-linking/frontend/src/assets/images/arrow-right-icon.svg
new file mode 100644
index 000000000..95aa1fec6
--- /dev/null
+++ b/examples/with-account-linking/frontend/src/assets/images/arrow-right-icon.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/examples/with-account-linking/frontend/src/assets/images/background.png b/examples/with-account-linking/frontend/src/assets/images/background.png
new file mode 100644
index 000000000..2147c15c2
Binary files /dev/null and b/examples/with-account-linking/frontend/src/assets/images/background.png differ
diff --git a/examples/with-account-linking/frontend/src/assets/images/blogs-icon.svg b/examples/with-account-linking/frontend/src/assets/images/blogs-icon.svg
new file mode 100644
index 000000000..a2fc9dd62
--- /dev/null
+++ b/examples/with-account-linking/frontend/src/assets/images/blogs-icon.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/examples/with-account-linking/frontend/src/assets/images/celebrate-icon.svg b/examples/with-account-linking/frontend/src/assets/images/celebrate-icon.svg
new file mode 100644
index 000000000..3b40b1efa
--- /dev/null
+++ b/examples/with-account-linking/frontend/src/assets/images/celebrate-icon.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/examples/with-account-linking/frontend/src/assets/images/guide-icon.svg b/examples/with-account-linking/frontend/src/assets/images/guide-icon.svg
new file mode 100644
index 000000000..bd85af72b
--- /dev/null
+++ b/examples/with-account-linking/frontend/src/assets/images/guide-icon.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/examples/with-account-linking/frontend/src/assets/images/index.ts b/examples/with-account-linking/frontend/src/assets/images/index.ts
new file mode 100644
index 000000000..7adf036c4
--- /dev/null
+++ b/examples/with-account-linking/frontend/src/assets/images/index.ts
@@ -0,0 +1,8 @@
+import SeparatorLine from "./separator-line.svg";
+import ArrowRight from "./arrow-right-icon.svg";
+import SignOutIcon from "./sign-out-icon.svg";
+import GuideIcon from "./guide-icon.svg";
+import BlogsIcon from "./blogs-icon.svg";
+import CelebrateIcon from "./celebrate-icon.svg";
+
+export { SeparatorLine, ArrowRight, SignOutIcon, GuideIcon, BlogsIcon, CelebrateIcon };
diff --git a/examples/with-account-linking/frontend/src/assets/images/separator-line.svg b/examples/with-account-linking/frontend/src/assets/images/separator-line.svg
new file mode 100644
index 000000000..7127a00dc
--- /dev/null
+++ b/examples/with-account-linking/frontend/src/assets/images/separator-line.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/with-account-linking/frontend/src/assets/images/sign-out-icon.svg b/examples/with-account-linking/frontend/src/assets/images/sign-out-icon.svg
new file mode 100644
index 000000000..6cc4f85fd
--- /dev/null
+++ b/examples/with-account-linking/frontend/src/assets/images/sign-out-icon.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/examples/with-account-linking/frontend/src/config.tsx b/examples/with-account-linking/frontend/src/config.tsx
new file mode 100644
index 000000000..1a6ba9d8a
--- /dev/null
+++ b/examples/with-account-linking/frontend/src/config.tsx
@@ -0,0 +1,61 @@
+import ThirdPartyEmailPassword, { Google, Github, Apple } from "supertokens-auth-react/recipe/thirdpartyemailpassword";
+import EmailVerification from "supertokens-auth-react/recipe/emailverification";
+import { ThirdPartyEmailPasswordPreBuiltUI } from "supertokens-auth-react/recipe/thirdpartyemailpassword/prebuiltui";
+import { EmailVerificationPreBuiltUI } from "supertokens-auth-react/recipe/emailverification/prebuiltui";
+import Session from "supertokens-auth-react/recipe/session";
+
+export function getApiDomain() {
+ const apiPort = process.env.REACT_APP_API_PORT || 3001;
+ const apiUrl = process.env.REACT_APP_API_URL || `http://localhost:${apiPort}`;
+ return apiUrl;
+}
+
+export function getWebsiteDomain() {
+ const websitePort = process.env.REACT_APP_WEBSITE_PORT || 3000;
+ const websiteUrl = process.env.REACT_APP_WEBSITE_URL || `http://localhost:${websitePort}`;
+ return websiteUrl;
+}
+
+export const SuperTokensConfig = {
+ appInfo: {
+ appName: "SuperTokens Demo App",
+ apiDomain: getApiDomain(),
+ websiteDomain: getWebsiteDomain(),
+ },
+ // recipeList contains all the modules that you want to
+ // use from SuperTokens. See the full list here: https://supertokens.com/docs/guides
+ recipeList: [
+ EmailVerification.init({
+ mode: "REQUIRED",
+ }),
+ ThirdPartyEmailPassword.init({
+ signInAndUpFeature: {
+ providers: [
+ Github.init({
+ getRedirectURL: (id) => {
+ if (window.location.pathname.startsWith("/link")) {
+ return `${getWebsiteDomain()}/link/tpcallback/${id}`;
+ }
+ return `${getWebsiteDomain()}/auth/callback/${id}`;
+ },
+ }),
+ Google.init({
+ getRedirectURL: (id) => {
+ if (window.location.pathname.startsWith("/link")) {
+ return `${getWebsiteDomain()}/link/tpcallback/${id}`;
+ }
+ return `${getWebsiteDomain()}/auth/callback/${id}`;
+ },
+ }),
+ ],
+ },
+ }),
+ Session.init(),
+ ],
+};
+
+export const recipeDetails = {
+ docsLink: "https://supertokens.com/docs/thirdpartyemailpassword/introduction",
+};
+
+export const PreBuiltUIList = [ThirdPartyEmailPasswordPreBuiltUI, EmailVerificationPreBuiltUI];
diff --git a/examples/with-account-linking/frontend/src/index.css b/examples/with-account-linking/frontend/src/index.css
new file mode 100644
index 000000000..04146b5e7
--- /dev/null
+++ b/examples/with-account-linking/frontend/src/index.css
@@ -0,0 +1,11 @@
+body {
+ margin: 0;
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans",
+ "Droid Sans", "Helvetica Neue", sans-serif;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+code {
+ font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace;
+}
diff --git a/examples/with-account-linking/frontend/src/index.tsx b/examples/with-account-linking/frontend/src/index.tsx
new file mode 100644
index 000000000..399c737cd
--- /dev/null
+++ b/examples/with-account-linking/frontend/src/index.tsx
@@ -0,0 +1,11 @@
+import React from "react";
+import ReactDOM from "react-dom/client";
+import "./index.css";
+import App from "./App";
+
+const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement);
+root.render(
+
+
+
+);
diff --git a/examples/with-account-linking/frontend/src/react-app-env.d.ts b/examples/with-account-linking/frontend/src/react-app-env.d.ts
new file mode 100644
index 000000000..6431bc5fc
--- /dev/null
+++ b/examples/with-account-linking/frontend/src/react-app-env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/examples/with-account-linking/frontend/src/useAsyncCallOnMount.ts b/examples/with-account-linking/frontend/src/useAsyncCallOnMount.ts
new file mode 100644
index 000000000..a619b8561
--- /dev/null
+++ b/examples/with-account-linking/frontend/src/useAsyncCallOnMount.ts
@@ -0,0 +1,35 @@
+import { useEffect, useRef } from "react";
+
+export const useAsyncCallOnMount = (
+ func: () => Promise,
+ handler: (res: T) => void,
+ errorHandler?: (err: any) => void
+) => {
+ const signInUpPromise = useRef | undefined>(undefined);
+
+ useEffect(() => {
+ if (signInUpPromise.current === undefined) {
+ signInUpPromise.current = func();
+ }
+ const abort = new AbortController();
+
+ signInUpPromise.current.then(
+ (resp) => {
+ if (abort.signal.aborted) {
+ return;
+ }
+ handler(resp);
+ },
+ (err) => {
+ if (abort.signal.aborted) {
+ return;
+ }
+ if (errorHandler !== undefined) {
+ errorHandler(err);
+ }
+ }
+ );
+
+ return () => abort.abort();
+ }, [handler, errorHandler]);
+};
diff --git a/examples/with-account-linking/frontend/tsconfig.json b/examples/with-account-linking/frontend/tsconfig.json
new file mode 100644
index 000000000..c0555cbc6
--- /dev/null
+++ b/examples/with-account-linking/frontend/tsconfig.json
@@ -0,0 +1,20 @@
+{
+ "compilerOptions": {
+ "target": "es5",
+ "lib": ["dom", "dom.iterable", "esnext"],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "esModuleInterop": true,
+ "allowSyntheticDefaultImports": true,
+ "strict": true,
+ "forceConsistentCasingInFileNames": true,
+ "noFallthroughCasesInSwitch": true,
+ "module": "esnext",
+ "moduleResolution": "node",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+ "jsx": "react-jsx"
+ },
+ "include": ["src"]
+}
diff --git a/examples/with-account-linking/package.json b/examples/with-account-linking/package.json
new file mode 100644
index 000000000..55d8979fe
--- /dev/null
+++ b/examples/with-account-linking/package.json
@@ -0,0 +1,20 @@
+{
+ "name": "with-account-linking",
+ "version": "0.0.1",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "start:frontend": "cd frontend && npm run start",
+ "start:frontend-live-demo-app": "cd frontend && npx serve -s build",
+ "start:backend": "cd backend && npm run start",
+ "start:backend-live-demo-app": "cd backend && ./startLiveDemoApp.sh",
+ "start": "npm-run-all --parallel start:frontend start:backend",
+ "start-live-demo-app": "npx npm-run-all --parallel start:frontend-live-demo-app start:backend-live-demo-app"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "ISC",
+ "dependencies": {
+ "npm-run-all": "^4.1.5"
+ }
+}
diff --git a/examples/with-emailpassword-vercel/test/basic.test.js b/examples/with-emailpassword-vercel/test/basic.test.js
index 48073408c..ba7efd707 100644
--- a/examples/with-emailpassword-vercel/test/basic.test.js
+++ b/examples/with-emailpassword-vercel/test/basic.test.js
@@ -90,7 +90,11 @@ describe("SuperTokens Example Basic tests", function () {
await waitForSTElement(page, "[data-supertokens~='sendVerifyEmailIcon']");
// Create a new token and use it (we don't have access to the originally sent one)
- const tokenInfo = await EmailVerification.createEmailVerificationToken("public", userId, email);
+ const tokenInfo = await EmailVerification.createEmailVerificationToken(
+ "public",
+ SuperTokensNode.convertToRecipeUserId(userId),
+ email
+ );
await page.goto(`${websiteDomain}/auth/verify-email?token=${tokenInfo.token}`);
await submitForm(page);
diff --git a/examples/with-emailverification-then-password-thirdpartyemailpassword/api-server.js b/examples/with-emailverification-then-password-thirdpartyemailpassword/api-server.js
index 0a8761bf7..da97da89e 100644
--- a/examples/with-emailverification-then-password-thirdpartyemailpassword/api-server.js
+++ b/examples/with-emailverification-then-password-thirdpartyemailpassword/api-server.js
@@ -74,7 +74,9 @@ supertokens.init({
};
}
const res = await oI.emailPasswordSignInPOST(input);
- await res.session.setClaimValue(RealPasswordClaim, true, input.userContext);
+ if (res.status === "OK") {
+ await res.session.setClaimValue(RealPasswordClaim, true, input.userContext);
+ }
return res;
},
emailPasswordSignUpPOST: async function (input) {
@@ -101,10 +103,11 @@ supertokens.init({
if (signInResponse.status === "WRONG_CREDENTIALS_ERROR") {
return response;
} else {
- await EmailVerification.unverifyEmail(signInResponse.user.id, email);
+ await EmailVerification.unverifyEmail(signInResponse.recipeUserId, email);
response = {
status: "OK",
user: signInResponse.user,
+ recipeUserId: signInResponse.recipeUserId,
};
}
}
@@ -112,23 +115,30 @@ supertokens.init({
// we have just created a user with the fake password.
// so we mark their session as unusable by the APIs
- await Session.createNewSession(
+ const newSession = await Session.createNewSession(
input.options.req,
input.options.res,
input.tenantId,
- user.id,
+ response.recipeUserId,
{
- ...RealPasswordClaim.build(user.id, input.tenantId, input.userContext),
+ ...RealPasswordClaim.build(
+ user.id,
+ response.recipeUserId,
+ input.tenantId,
+ input.userContext
+ ),
},
{}
);
return {
+ ...response,
status: "OK",
user,
+ session: newSession,
};
} else {
// session exists.. so the user is trying to change their password now
- let userId = session.getUserId();
+ let recipeUserId = session.getRecipeUserId();
let password = input.formFields.filter((f) => f.id === "password")[0].value;
if (password === FAKE_PASSWORD) {
@@ -137,16 +147,18 @@ supertokens.init({
// now we modify the user's password to the new password + change the session to set RealPasswordClaim to true
await ThirdPartyEmailPassword.updateEmailOrPassword({
- userId,
+ recipeUserId,
password,
});
await session.setClaimValue(RealPasswordClaim, true);
- let user = await ThirdPartyEmailPassword.getUserById(userId);
+ let user = await supertokens.getUser(recipeUserId.getAsString());
return {
status: "OK",
user,
+ recipeUserId,
+ session,
};
}
},
diff --git a/examples/with-emailverification-then-password-thirdpartyemailpassword/test/basic.test.js b/examples/with-emailverification-then-password-thirdpartyemailpassword/test/basic.test.js
index 7e8505be9..5e65c6b15 100644
--- a/examples/with-emailverification-then-password-thirdpartyemailpassword/test/basic.test.js
+++ b/examples/with-emailverification-then-password-thirdpartyemailpassword/test/basic.test.js
@@ -84,7 +84,11 @@ describe("SuperTokens Example Basic tests", function () {
const userId = await page.evaluate(() => window.__supertokensSessionRecipe.getUserId());
// Create a new token and use it (we don't have access to the originally sent one)
- const tokenInfo = await EmailVerification.createEmailVerificationToken("public", userId, email);
+ const tokenInfo = await EmailVerification.createEmailVerificationToken(
+ "public",
+ SuperTokensNode.convertToRecipeUserId(userId),
+ email
+ );
await page.goto(`${websiteDomain}/auth/verify-email?token=${tokenInfo.token}`);
await submitForm(page);
diff --git a/examples/with-emailverification-with-otp/api-server/server.ts b/examples/with-emailverification-with-otp/api-server/server.ts
index 4fe454064..1b2837c81 100644
--- a/examples/with-emailverification-with-otp/api-server/server.ts
+++ b/examples/with-emailverification-with-otp/api-server/server.ts
@@ -22,7 +22,7 @@ supertokens.init({
framework: "express",
supertokens: {
// TODO: This is a core hosted for demo purposes. You can use this, but make sure to change it to your core instance URI eventually.
- connectionURI: "https://try.supertokens.io",
+ connectionURI: "https://try.supertokens.com",
apiKey: "",
},
appInfo: {
diff --git a/examples/with-hasura-thirdpartyemailpassword/api-server.js b/examples/with-hasura-thirdpartyemailpassword/api-server.js
index 183af8171..8258e8f30 100644
--- a/examples/with-hasura-thirdpartyemailpassword/api-server.js
+++ b/examples/with-hasura-thirdpartyemailpassword/api-server.js
@@ -89,12 +89,12 @@ supertokens.init({
return {
...oI,
createNewSession: async function (input) {
- let userInfo = await ThirdPartyEmailPassword.getUserById(input.userId);
+ let userInfo = await supertokens.getUser(input.userId);
input.accessTokenPayload = {
...input.accessTokenPayload,
"https://hasura.io/jwt/claims": {
- "x-hasura-user-id": userInfo.email,
+ "x-hasura-user-id": userInfo.emails[0],
"x-hasura-default-role": "user",
"x-hasura-allowed-roles": ["user"],
},
diff --git a/examples/with-i18next/test/basic.test.js b/examples/with-i18next/test/basic.test.js
index 548e2824c..682fca229 100644
--- a/examples/with-i18next/test/basic.test.js
+++ b/examples/with-i18next/test/basic.test.js
@@ -97,7 +97,11 @@ describe("SuperTokens Example Basic tests", function () {
await waitForSTElement(page, "[data-supertokens~='sendVerifyEmailIcon']");
// Create a new token and use it (we don't have access to the originally sent one)
- const tokenInfo = await EmailVerification.createEmailVerificationToken("public", userId, email);
+ const tokenInfo = await EmailVerification.createEmailVerificationToken(
+ "public",
+ SuperTokensNode.convertToRecipeUserId(userId),
+ email
+ );
await page.goto(`${websiteDomain}/auth/verify-email?token=${tokenInfo.token}`);
await submitForm(page);
diff --git a/examples/with-localstorage/test/basic.test.js b/examples/with-localstorage/test/basic.test.js
index 48073408c..ba7efd707 100644
--- a/examples/with-localstorage/test/basic.test.js
+++ b/examples/with-localstorage/test/basic.test.js
@@ -90,7 +90,11 @@ describe("SuperTokens Example Basic tests", function () {
await waitForSTElement(page, "[data-supertokens~='sendVerifyEmailIcon']");
// Create a new token and use it (we don't have access to the originally sent one)
- const tokenInfo = await EmailVerification.createEmailVerificationToken("public", userId, email);
+ const tokenInfo = await EmailVerification.createEmailVerificationToken(
+ "public",
+ SuperTokensNode.convertToRecipeUserId(userId),
+ email
+ );
await page.goto(`${websiteDomain}/auth/verify-email?token=${tokenInfo.token}`);
await submitForm(page);
diff --git a/examples/with-multiple-email-sign-in/api-server/epOverride.ts b/examples/with-multiple-email-sign-in/api-server/epOverride.ts
index 3d03c4c14..b37bd0db3 100644
--- a/examples/with-multiple-email-sign-in/api-server/epOverride.ts
+++ b/examples/with-multiple-email-sign-in/api-server/epOverride.ts
@@ -1,29 +1,27 @@
-import { RecipeInterface } from "supertokens-node/recipe/emailpassword";
+import { APIInterface } from "supertokens-node/recipe/emailpassword";
import { getPrimaryEmailFromInputEmail } from "./emailLinkingMap";
-export function epOverride(oI: RecipeInterface): RecipeInterface {
+export function epOverride(oI: APIInterface): APIInterface {
return {
...oI,
- signIn: async function (input) {
- let primaryEmail = getPrimaryEmailFromInputEmail(input.email);
- if (primaryEmail !== undefined) {
- input.email = primaryEmail;
- }
- return oI.signIn(input);
- },
- signUp: async function (input) {
- let primaryEmail = getPrimaryEmailFromInputEmail(input.email);
+ signInPOST: async function (input) {
+ const emailField = input.formFields.find((f) => f.id === "email")!;
+
+ let primaryEmail = getPrimaryEmailFromInputEmail(emailField.value);
if (primaryEmail !== undefined) {
- input.email = primaryEmail;
+ emailField.value = primaryEmail;
}
- return oI.signUp(input);
+ return oI.signInPOST!(input);
},
- getUserByEmail: async function (input) {
- let primaryEmail = getPrimaryEmailFromInputEmail(input.email);
+ signUpPOST: async function (input) {
+ const emailField = input.formFields.find((f) => f.id === "email")!;
+
+ let primaryEmail = getPrimaryEmailFromInputEmail(emailField.value);
if (primaryEmail !== undefined) {
- input.email = primaryEmail;
+ emailField.value = primaryEmail;
}
- return oI.getUserByEmail(input);
+
+ return oI.signUpPOST!(input);
},
};
}
diff --git a/examples/with-multiple-email-sign-in/api-server/index.ts b/examples/with-multiple-email-sign-in/api-server/index.ts
index d92fde8d0..f33112e46 100644
--- a/examples/with-multiple-email-sign-in/api-server/index.ts
+++ b/examples/with-multiple-email-sign-in/api-server/index.ts
@@ -53,7 +53,7 @@ supertokens.init({
}),
EmailPassword.init({
override: {
- functions: (oI) => epOverride(oI),
+ apis: (oI) => epOverride(oI),
},
}),
Session.init(),
@@ -79,7 +79,7 @@ app.use(middleware());
app.post("/add-email", verifySession(), async (req: SessionRequest, res) => {
let userId = req.session!.getUserId();
let emailToAdd = req.body.email;
- let success = associateNewEmailWithPrimaryEmail(emailToAdd, (await EmailPassword.getUserById(userId))!.email);
+ let success = associateNewEmailWithPrimaryEmail(emailToAdd, (await supertokens.getUser(userId))!.emails[0]);
res.send({
status: success ? "OK" : "INPUT_EMAIL_ASSOCIATED_WITH_ANOTHER_USER",
});
diff --git a/examples/with-multiple-email-sign-in/test/basic.test.js b/examples/with-multiple-email-sign-in/test/basic.test.js
index 5f3ea42f2..dc99f268f 100644
--- a/examples/with-multiple-email-sign-in/test/basic.test.js
+++ b/examples/with-multiple-email-sign-in/test/basic.test.js
@@ -90,7 +90,11 @@ describe("SuperTokens Example Basic tests", function () {
await waitForSTElement(page, "[data-supertokens~='sendVerifyEmailIcon']");
// Create a new token and use it (we don't have access to the originally sent one)
- const tokenInfo = await EmailVerification.createEmailVerificationToken("public", userId, email);
+ const tokenInfo = await EmailVerification.createEmailVerificationToken(
+ "public",
+ SuperTokensNode.convertToRecipeUserId(userId),
+ email
+ );
await page.goto(`${websiteDomain}/auth/verify-email?token=${tokenInfo.token}`);
await waitForSTElement(page, "[data-supertokens='button']");
await submitForm(page);
@@ -121,7 +125,11 @@ describe("SuperTokens Example Basic tests", function () {
await submitForm(page);
// Redirected to email verification screen
await waitForSTElement(page, "[data-supertokens~='sendVerifyEmailIcon']");
- const tokenInfo2 = await EmailVerification.createEmailVerificationToken("public", userId, email2);
+ const tokenInfo2 = await EmailVerification.createEmailVerificationToken(
+ "public",
+ SuperTokensNode.convertToRecipeUserId(userId),
+ email2
+ );
await page.goto(`${websiteDomain}/auth/verify-email?token=${tokenInfo2.token}`);
await waitForSTElement(page, "[data-supertokens='button']");
await submitForm(page);
diff --git a/examples/with-netlify/.netlify/edge-functions-import-map.json b/examples/with-netlify/.netlify/edge-functions-import-map.json
index b2f6de6db..6ac38f509 100644
--- a/examples/with-netlify/.netlify/edge-functions-import-map.json
+++ b/examples/with-netlify/.netlify/edge-functions-import-map.json
@@ -1 +1,7 @@
-{ "imports": { "netlify:edge": "https://edge.netlify.com/v1/index.ts" } }
+{
+ "imports": {
+ "@netlify/edge-functions": "https://edge.netlify.com/v1/index.ts",
+ "netlify:edge": "https://edge.netlify.com/v1/index.ts?v=legacy"
+ },
+ "scopes": {}
+}
diff --git a/examples/with-netlify/test/basic.test.js b/examples/with-netlify/test/basic.test.js
index 664487aa9..17eee7d77 100644
--- a/examples/with-netlify/test/basic.test.js
+++ b/examples/with-netlify/test/basic.test.js
@@ -71,6 +71,7 @@ describe("SuperTokens Example Basic tests", function () {
describe("Email Password test", function () {
it("Successful signup with credentials", async function () {
+ await new Promise((res) => setTimeout(res, 1000));
await Promise.all([page.goto(websiteDomain), page.waitForNavigation({ waitUntil: "networkidle0" })]);
// redirected to /auth
diff --git a/examples/with-no-session-on-sign-up-thirdpartyemailpassword/api-server/index.js b/examples/with-no-session-on-sign-up-thirdpartyemailpassword/api-server/index.js
index 0a38e6b68..48b909fe8 100644
--- a/examples/with-no-session-on-sign-up-thirdpartyemailpassword/api-server/index.js
+++ b/examples/with-no-session-on-sign-up-thirdpartyemailpassword/api-server/index.js
@@ -77,18 +77,18 @@ supertokens.init({
thirdPartySignInUp: async function (input) {
let resp = await oI.thirdPartySignInUp(input);
if (resp.status === "OK") {
- if (resp.createdNewUser) {
+ if (resp.createdNewRecipeUser) {
// we set this context here so that
// the createNewSession recipe function can
// check this and NOT create a new session
// (since we want to disable session creation during sign up)
- input.userContext.isNewUser = true;
+ input.userContext.isNewRecipeUser = true;
}
}
return resp;
},
emailPasswordSignUp: async function (input) {
- input.userContext.isNewUser = true;
+ input.userContext.isNewRecipeUser = true;
// we set this context here so that
// the createNewSession recipe function can
// check this and NOT create a new session
@@ -105,7 +105,7 @@ supertokens.init({
return {
...oI,
createNewSession: async function (input) {
- if (input.userContext.isNewUser) {
+ if (input.userContext.isNewRecipeUser) {
// we do not want to create a session for a new user.
return {
getAccessToken: () => "",
@@ -115,6 +115,7 @@ supertokens.init({
getSessionDataFromDatabase: () => null,
getTimeCreated: () => -1,
getUserId: () => "",
+ getRecipeUserId: () => input.recipeUserId,
revokeSession: () => {},
updateSessionDataInDatabase: () => {},
attachToRequestResponse: () => {},
diff --git a/examples/with-no-session-on-sign-up-thirdpartyemailpassword/src/App.js b/examples/with-no-session-on-sign-up-thirdpartyemailpassword/src/App.js
index c89b44de5..458c9e04a 100644
--- a/examples/with-no-session-on-sign-up-thirdpartyemailpassword/src/App.js
+++ b/examples/with-no-session-on-sign-up-thirdpartyemailpassword/src/App.js
@@ -36,7 +36,7 @@ SuperTokens.init({
ThirdPartyEmailPassword.init({
onHandleEvent: (context) => {
if (context.action === "SUCCESS") {
- if (context.isNewUser) {
+ if (context.isNewRecipeUser) {
// we save info in localstorage to indicate to the UI that we should show
// a sign in message in the sign in page.
localStorage.setItem("showSignInMessage", "true");
diff --git a/examples/with-one-login-per-subdomain/test/basic.test.js b/examples/with-one-login-per-subdomain/test/basic.test.js
index e9019aa93..32412530a 100644
--- a/examples/with-one-login-per-subdomain/test/basic.test.js
+++ b/examples/with-one-login-per-subdomain/test/basic.test.js
@@ -95,7 +95,11 @@ describe("SuperTokens Example Basic tests", function () {
await waitForSTElement(page, "[data-supertokens~='sendVerifyEmailIcon']");
// Create a new token and use it (we don't have access to the originally sent one)
- const tokenInfo = await EmailVerification.createEmailVerificationToken("public", userId, email);
+ const tokenInfo = await EmailVerification.createEmailVerificationToken(
+ "public",
+ SuperTokensNode.convertToRecipeUserId(userId),
+ email
+ );
await page.goto(`${websiteDomain}/auth/verify-email?token=${tokenInfo.token}`);
await submitForm(page);
diff --git a/examples/with-phone-password/api-server/index.ts b/examples/with-phone-password/api-server/index.ts
index d0ed7f3a3..4b576262c 100644
--- a/examples/with-phone-password/api-server/index.ts
+++ b/examples/with-phone-password/api-server/index.ts
@@ -159,6 +159,7 @@ supertokens.init({
// session's payload as PhoneVerifiedClaim: true so that
// the user has access to API routes and the frontend UI
await session.setClaimValue(PhoneVerifiedClaim, true, input.userContext);
+ resp.user = (await supertokens.getUser(session.getUserId()))!;
}
return resp;
@@ -187,13 +188,18 @@ supertokens.init({
// we also get the phone number of the user and save it in the
// session so that the OTP can be sent to it directly
- let userInfo = await EmailPassword.getUserById(input.userId, input.userContext);
+ let userInfo = await supertokens.getUser(input.userId, input.userContext);
return originalImplementation.createNewSession({
...input,
accessTokenPayload: {
...input.accessTokenPayload,
- ...PhoneVerifiedClaim.build(input.userId, input.tenantId, input.userContext),
- phoneNumber: userInfo?.email,
+ ...PhoneVerifiedClaim.build(
+ input.userId,
+ input.recipeUserId,
+ input.tenantId,
+ input.userContext
+ ),
+ phoneNumber: userInfo?.emails[0],
},
});
}
diff --git a/examples/with-phone-password/test/basic.test.js b/examples/with-phone-password/test/basic.test.js
index 3d7c04159..084752781 100644
--- a/examples/with-phone-password/test/basic.test.js
+++ b/examples/with-phone-password/test/basic.test.js
@@ -68,9 +68,9 @@ describe("SuperTokens Example Basic tests", function () {
const testOTP = "test123456";
before(async function () {
- const user = await EmailPassword.getUserByEmail("public", phoneNumber);
- if (user) {
- await SuperTokensNode.deleteUser(user.id);
+ const user = await SuperTokensNode.listUsersByAccountInfo("public", { email: phoneNumber });
+ if (user.length > 0) {
+ await SuperTokensNode.deleteUser(user[0].id);
}
browser = await puppeteer.launch({
diff --git a/examples/with-supabase/config/backendConfig.ts b/examples/with-supabase/config/backendConfig.ts
index 76dadb82b..a8f4dd4f6 100644
--- a/examples/with-supabase/config/backendConfig.ts
+++ b/examples/with-supabase/config/backendConfig.ts
@@ -74,7 +74,7 @@ export let backendConfig = (): TypeInput => {
let response = await originalImplementation.thirdPartySignInUpPOST(input);
// check that there is no issue with sign up and that a new user is created
- if (response.status === "OK" && response.createdNewUser) {
+ if (response.status === "OK" && response.createdNewRecipeUser) {
// retrieve the supabase_token from the accessTokenPayload
const accessTokenPayload = response.session.getAccessTokenPayload();
diff --git a/examples/with-thirdpartyemailpassword-2fa-passwordless/api-server/index.ts b/examples/with-thirdpartyemailpassword-2fa-passwordless/api-server/index.ts
index bb8146fd5..2d3e6eef4 100644
--- a/examples/with-thirdpartyemailpassword-2fa-passwordless/api-server/index.ts
+++ b/examples/with-thirdpartyemailpassword-2fa-passwordless/api-server/index.ts
@@ -185,17 +185,22 @@ supertokens.init({
// we alreay have a phone number associated with this user,
// so we will add it to the access token payload so that
// we can send an OTP to it without asking the end user.
- let passwordlessUserInfo = await Passwordless.getUserById({
- userId: userMetadata.metadata.passwordlessUserId as string,
- userContext: input.userContext,
- });
- phoneNumber = passwordlessUserInfo?.phoneNumber;
+ let passwordlessUserInfo = await supertokens.getUser(
+ userMetadata.metadata.passwordlessUserId as string,
+ input.userContext
+ );
+ phoneNumber = passwordlessUserInfo?.phoneNumbers[0];
}
return originalImplementation.createNewSession({
...input,
accessTokenPayload: {
...input.accessTokenPayload,
- ...(await SecondFactorClaim.build(input.userId, input.tenantId, input.userContext)),
+ ...(await SecondFactorClaim.build(
+ input.userId,
+ input.recipeUserId,
+ input.tenantId,
+ input.userContext
+ )),
phoneNumber,
},
});
diff --git a/examples/with-thirdpartyemailpassword-2fa-passwordless/test/basic.test.js b/examples/with-thirdpartyemailpassword-2fa-passwordless/test/basic.test.js
index 9cce15fa1..e5760ff5a 100644
--- a/examples/with-thirdpartyemailpassword-2fa-passwordless/test/basic.test.js
+++ b/examples/with-thirdpartyemailpassword-2fa-passwordless/test/basic.test.js
@@ -139,7 +139,11 @@ describe("SuperTokens Example Basic tests", function () {
await waitForSTElement(page, "[data-supertokens~='sendVerifyEmailIcon']");
// Create a new token and use it (we don't have access to the originally sent one)
- const tokenInfo = await EmailVerification.createEmailVerificationToken("public", userId, email);
+ const tokenInfo = await EmailVerification.createEmailVerificationToken(
+ "public",
+ SuperTokensNode.convertToRecipeUserId(userId),
+ email
+ );
await page.goto(`${websiteDomain}/auth/verify-email?token=${tokenInfo.token}`);
await submitForm(page);
diff --git a/examples/with-thirdpartyemailpassword-passwordless/test/basic.test.js b/examples/with-thirdpartyemailpassword-passwordless/test/basic.test.js
index d53ab4b62..ab3cf8d03 100644
--- a/examples/with-thirdpartyemailpassword-passwordless/test/basic.test.js
+++ b/examples/with-thirdpartyemailpassword-passwordless/test/basic.test.js
@@ -100,7 +100,11 @@ describe("SuperTokens Example Basic tests", function () {
await waitForSTElement(page, "[data-supertokens~='sendVerifyEmailIcon']");
// Create a new token and use it (we don't have access to the originally sent one)
- const tokenInfo = await EmailVerification.createEmailVerificationToken("public", userId, email);
+ const tokenInfo = await EmailVerification.createEmailVerificationToken(
+ "public",
+ SuperTokensNode.convertToRecipeUserId(userId),
+ email
+ );
await page.goto(`${websiteDomain}/auth/verify-email?token=${tokenInfo.token}`);
await submitForm(page);
diff --git a/examples/with-update-email-post-verification/backend/config.ts b/examples/with-update-email-post-verification/backend/config.ts
index 3c838bca3..0ff7093f3 100644
--- a/examples/with-update-email-post-verification/backend/config.ts
+++ b/examples/with-update-email-post-verification/backend/config.ts
@@ -44,7 +44,7 @@ export const SuperTokensConfig: TypeInput = {
// This will update the email of the user to the one
// that was just marked as verified by the token.
await EmailPassword.updateEmailOrPassword({
- userId: response.user.id,
+ recipeUserId: response.user.recipeUserId,
email: response.user.email,
});
}
diff --git a/examples/with-update-email-post-verification/backend/index.ts b/examples/with-update-email-post-verification/backend/index.ts
index 34a443dfc..7938d48c8 100644
--- a/examples/with-update-email-post-verification/backend/index.ts
+++ b/examples/with-update-email-post-verification/backend/index.ts
@@ -37,12 +37,12 @@ app.get("/sessioninfo", verifySession(), async (req: SessionRequest, res) => {
app.get("/email", verifySession(), async (req: SessionRequest, res) => {
let userId = req.session!.getUserId();
- let user = await EmailPassword.getUserById(userId);
+ let user = await supertokens.getUser(userId);
if (user === undefined) {
throw new Error("Should never come here");
}
- return res.send(user.email);
+ return res.send(user.emails[0]);
});
// This API is called from the frontend when the user enters their new email.
@@ -58,7 +58,8 @@ app.post("/change-email", verifySession(), async (req: SessionRequest, res) => {
// First we check if the new email is already associated with another user.
// If it is, then we throw an error. If it's already associated with this user,
// then we return a success response with an appropriate message.
- let existingUser = await EmailPassword.getUserByEmail(session.getTenantId(), email);
+ let users = await supertokens.listUsersByAccountInfo(session.getTenantId(), { email });
+ const existingUser = users[0];
if (existingUser !== undefined) {
if (existingUser.id === session.getUserId()) {
return res.status(200).send("Email already belongs to this account");
@@ -70,13 +71,14 @@ app.post("/change-email", verifySession(), async (req: SessionRequest, res) => {
// Then, we check if the email is verified for this user ID or not.
// It is important to understand that SuperTokens stores email verification
// status based on the user ID AND the email, and not just the email.
- let isVerified = await EmailVerification.isEmailVerified(session.getUserId(), email);
+ let isVerified = await EmailVerification.isEmailVerified(session.getRecipeUserId(), email);
if (!isVerified) {
// Now we send the email verification link to the user for the new email.
const sendEmailRes = await EmailVerification.sendEmailVerificationEmail(
session.getTenantId(),
session.getUserId(),
+ session.getRecipeUserId(),
email
);
@@ -89,7 +91,7 @@ app.post("/change-email", verifySession(), async (req: SessionRequest, res) => {
// Since the email is verified, we try and do an update
let resp = await EmailPassword.updateEmailOrPassword({
- userId: session.getUserId(),
+ recipeUserId: session.getRecipeUserId(),
email: email,
});
diff --git a/examples/with-update-email-post-verification/test/basic.test.js b/examples/with-update-email-post-verification/test/basic.test.js
index 55eb0f72f..538dde75f 100644
--- a/examples/with-update-email-post-verification/test/basic.test.js
+++ b/examples/with-update-email-post-verification/test/basic.test.js
@@ -90,7 +90,11 @@ describe("SuperTokens Example Basic tests", function () {
await waitForSTElement(page, "[data-supertokens~='sendVerifyEmailIcon']");
// Create a new token and use it (we don't have access to the originally sent one)
- const tokenInfo = await EmailVerification.createEmailVerificationToken("public", userId, email);
+ const tokenInfo = await EmailVerification.createEmailVerificationToken(
+ "public",
+ SuperTokensNode.convertToRecipeUserId(userId),
+ email
+ );
await page.goto(`${websiteDomain}/auth/verify-email?token=${tokenInfo.token}`);
await submitForm(page);
@@ -131,7 +135,11 @@ describe("SuperTokens Example Basic tests", function () {
const alertText = await alertContent;
assert(alertText === "Email verification email sent");
- const tokenInfo = await EmailVerification.createEmailVerificationToken("public", userId, newEmail);
+ const tokenInfo = await EmailVerification.createEmailVerificationToken(
+ "public",
+ SuperTokensNode.convertToRecipeUserId(userId),
+ newEmail
+ );
await page.goto(`${websiteDomain}/auth/verify-email?token=${tokenInfo.token}`);
await submitForm(page);
diff --git a/frontendDriverInterfaceSupported.json b/frontendDriverInterfaceSupported.json
index 9e871c070..0e254b7bb 100644
--- a/frontendDriverInterfaceSupported.json
+++ b/frontendDriverInterfaceSupported.json
@@ -1,4 +1,4 @@
{
"_comment": "contains a list of frontend-backend interface versions that this package supports",
- "versions": ["1.17"]
+ "versions": ["1.17", "1.18"]
}
diff --git a/lib/build/SuperTokensBranding.js b/lib/build/SuperTokensBranding.js
index 3d960956f..fad0aaeab 100644
--- a/lib/build/SuperTokensBranding.js
+++ b/lib/build/SuperTokensBranding.js
@@ -45,7 +45,8 @@ var Redirector = function (props) {
rid: props.authRecipe.config.recipeId,
successRedirectContext: {
action: "SUCCESS",
- isNewUser: false,
+ isNewRecipeUser: false,
+ user: undefined,
redirectToPath: genericComponentOverrideContext.getRedirectToPathFromURL(),
},
},
diff --git a/lib/build/emailpassword-shared4.js b/lib/build/emailpassword-shared4.js
index c96bd2110..e3070936a 100644
--- a/lib/build/emailpassword-shared4.js
+++ b/lib/build/emailpassword-shared4.js
@@ -56,6 +56,10 @@ var getFunctionOverrides = function (onHandleEvent) {
if (response.status === "OK") {
onHandleEvent({
action: "RESET_PASSWORD_EMAIL_SENT",
+ email: input.formFields.find(function (_a) {
+ var id = _a.id;
+ return id === "email";
+ }).value,
userContext: input.userContext,
});
}
@@ -76,7 +80,7 @@ var getFunctionOverrides = function (onHandleEvent) {
if (response.status === "OK") {
onHandleEvent({
action: "SUCCESS",
- isNewUser: true,
+ isNewRecipeUser: true,
user: response.user,
userContext: input.userContext,
});
@@ -98,7 +102,7 @@ var getFunctionOverrides = function (onHandleEvent) {
if (response.status === "OK") {
onHandleEvent({
action: "SUCCESS",
- isNewUser: false,
+ isNewRecipeUser: false,
user: response.user,
userContext: input.userContext,
});
diff --git a/lib/build/emailpassword-shared6.js b/lib/build/emailpassword-shared6.js
index 9b9557670..86d336eb2 100644
--- a/lib/build/emailpassword-shared6.js
+++ b/lib/build/emailpassword-shared6.js
@@ -16,6 +16,7 @@ var generalError = require("./emailpassword-shared.js");
var STGeneralError = require("supertokens-web-js/utils/error");
var button = require("./emailpassword-shared2.js");
var recipe = require("./session-shared2.js");
+var STGeneralError$1 = require("supertokens-web-js/lib/build/error");
var validators = require("./emailpassword-shared5.js");
var recipe$1 = require("./emailpassword-shared4.js");
@@ -52,6 +53,7 @@ function _interopNamespace(e) {
var NormalisedURLPath__default = /*#__PURE__*/ _interopDefault(NormalisedURLPath);
var React__namespace = /*#__PURE__*/ _interopNamespace(React);
var STGeneralError__default = /*#__PURE__*/ _interopDefault(STGeneralError);
+var STGeneralError__default$1 = /*#__PURE__*/ _interopDefault(STGeneralError$1);
/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.
*
@@ -250,7 +252,7 @@ var EmailPasswordResetPasswordEmail = function (props) {
void 0,
void 0,
function () {
- var validationErrors, emailField;
+ var validationErrors, emailField, resp;
return genericComponentOverrideContext.__generator(this, function (_a) {
switch (_a.label) {
case 0:
@@ -287,7 +289,19 @@ var EmailPasswordResetPasswordEmail = function (props) {
}),
];
case 2:
- return [2 /*return*/, _a.sent()];
+ resp = _a.sent();
+ if (resp.status === "PASSWORD_RESET_NOT_ALLOWED") {
+ return [
+ 2 /*return*/,
+ {
+ status: "FIELD_ERROR",
+ formFields: [
+ { id: "email", error: resp.reason },
+ ],
+ },
+ ];
+ }
+ return [2 /*return*/, resp];
}
});
}
@@ -615,6 +629,12 @@ var defaultTranslationsEmailPassword = {
"Password must contain at least one alphabet": undefined,
"Password must contain at least one number": undefined,
"Email is invalid": undefined,
+ "Reset password link was not created because of account take over risk. Please contact support. (ERR_CODE_001)":
+ undefined,
+ "Cannot sign up due to security reasons. Please try logging in, use a different login method or contact support. (ERR_CODE_007)":
+ undefined,
+ "Cannot sign in due to security reasons. Please try resetting your password, use a different login method or contact support. (ERR_CODE_008)":
+ undefined,
}
),
};
@@ -771,6 +791,8 @@ var SignInForm = uiEntry.withOverride("EmailPasswordSignInForm", function EmailP
throw new STGeneralError__default.default(
"EMAIL_PASSWORD_SIGN_IN_WRONG_CREDENTIALS_ERROR"
);
+ } else if (response.status === "SIGN_IN_NOT_ALLOWED") {
+ throw new STGeneralError__default.default(response.reason);
} else {
return [2 /*return*/, response];
}
@@ -927,7 +949,7 @@ var SignUpForm = uiEntry.withOverride("EmailPasswordSignUpForm", function EmailP
onSuccess: props.onSuccess,
callAPI: function (formFields) {
return genericComponentOverrideContext.__awaiter(_this, void 0, void 0, function () {
- var validationErrors;
+ var validationErrors, res;
return genericComponentOverrideContext.__generator(this, function (_a) {
switch (_a.label) {
case 0:
@@ -950,12 +972,18 @@ var SignUpForm = uiEntry.withOverride("EmailPasswordSignUpForm", function EmailP
];
}
return [
- 2 /*return*/,
+ 4 /*yield*/,
props.recipeImplementation.signUp({
formFields: formFields,
userContext: userContext,
}),
];
+ case 2:
+ res = _a.sent();
+ if (res.status === "SIGN_UP_NOT_ALLOWED") {
+ throw new STGeneralError__default$1.default(res.reason);
+ }
+ return [2 /*return*/, res];
}
});
});
@@ -1149,7 +1177,7 @@ function useChildProps(recipe$1, state, dispatch, history) {
);
var userContext = uiEntry.useUserContext();
var onSignInSuccess = React.useCallback(
- function () {
+ function (response) {
return genericComponentOverrideContext.__awaiter(_this, void 0, void 0, function () {
return genericComponentOverrideContext.__generator(this, function (_a) {
return [
@@ -1159,7 +1187,8 @@ function useChildProps(recipe$1, state, dispatch, history) {
rid: recipe$1.config.recipeId,
successRedirectContext: {
action: "SUCCESS",
- isNewUser: false,
+ isNewRecipeUser: false,
+ user: response.user,
redirectToPath: genericComponentOverrideContext.getRedirectToPathFromURL(),
},
},
@@ -1173,7 +1202,7 @@ function useChildProps(recipe$1, state, dispatch, history) {
[recipe$1, userContext, history]
);
var onSignUpSuccess = React.useCallback(
- function () {
+ function (response) {
return genericComponentOverrideContext.__awaiter(_this, void 0, void 0, function () {
return genericComponentOverrideContext.__generator(this, function (_a) {
return [
@@ -1183,7 +1212,8 @@ function useChildProps(recipe$1, state, dispatch, history) {
rid: recipe$1.config.recipeId,
successRedirectContext: {
action: "SUCCESS",
- isNewUser: true,
+ isNewRecipeUser: true,
+ user: response.user,
redirectToPath: genericComponentOverrideContext.getRedirectToPathFromURL(),
},
},
diff --git a/lib/build/emailpasswordprebuiltui.js b/lib/build/emailpasswordprebuiltui.js
index 9f40e0da2..dbf36ecd1 100644
--- a/lib/build/emailpasswordprebuiltui.js
+++ b/lib/build/emailpasswordprebuiltui.js
@@ -32,6 +32,7 @@ require("./emailpassword-shared7.js");
require("supertokens-web-js/utils/error");
require("./emailpassword-shared2.js");
require("./emailpassword-shared.js");
+require("supertokens-web-js/lib/build/error");
require("supertokens-web-js/recipe/emailpassword");
require("./authRecipe-shared.js");
diff --git a/lib/build/passwordless-shared2.js b/lib/build/passwordless-shared2.js
index 979d2e6a9..06f1fa598 100644
--- a/lib/build/passwordless-shared2.js
+++ b/lib/build/passwordless-shared2.js
@@ -74,7 +74,7 @@ var getFunctionOverrides = function (onHandleEvent) {
} else if (response.status === "OK") {
onHandleEvent({
action: "SUCCESS",
- isNewUser: response.createdNewUser,
+ isNewRecipeUser: response.createdNewRecipeUser,
user: response.user,
});
}
diff --git a/lib/build/passwordless-shared3.js b/lib/build/passwordless-shared3.js
index e46e54f52..de28acb50 100644
--- a/lib/build/passwordless-shared3.js
+++ b/lib/build/passwordless-shared3.js
@@ -229,6 +229,10 @@ var defaultTranslationsPasswordless = {
"Failed to generate a one time code. Please try again": undefined,
"Phone number is invalid": undefined,
"Email is invalid": undefined,
+ "Cannot sign in / up due to security reasons. Please try a different login method or contact support. (ERR_CODE_002)":
+ undefined,
+ "Cannot sign in / up due to security reasons. Please try a different login method or contact support. (ERR_CODE_003)":
+ undefined,
}
),
};
@@ -315,6 +319,18 @@ var LinkClickedScreen = function (props) {
}),
];
}
+ if (response.status === "SIGN_IN_UP_NOT_ALLOWED") {
+ return [
+ 2 /*return*/,
+ genericComponentOverrideContext.SuperTokens.getInstanceOrThrow().redirectToAuth({
+ history: props.history,
+ queryParams: {
+ error: response.reason,
+ },
+ redirectBack: false,
+ }),
+ ];
+ }
if (!(response.status === "OK")) return [3 /*break*/, 3];
return [
4 /*yield*/,
@@ -339,7 +355,8 @@ var LinkClickedScreen = function (props) {
rid: props.recipe.config.recipeId,
successRedirectContext: {
action: "SUCCESS",
- isNewUser: response.createdNewUser,
+ isNewRecipeUser: response.createdNewRecipeUser,
+ user: response.user,
redirectToPath:
loginAttemptInfo === null || loginAttemptInfo === void 0
? void 0
@@ -599,6 +616,9 @@ var EmailForm = uiEntry.withOverride("PasswordlessEmailForm", function Passwordl
];
case 2:
response = _b.sent();
+ if (response.status === "SIGN_IN_UP_NOT_ALLOWED") {
+ throw new STGeneralError__default.default(response.reason);
+ }
return [2 /*return*/, response];
}
});
@@ -2768,6 +2788,7 @@ var EmailOrPhoneForm = uiEntry.withOverride(
response,
intPhoneNumber,
phoneValidationResAfterGuess,
+ response,
ex_1;
var _a;
return genericComponentOverrideContext.__generator(this, function (_b) {
@@ -2798,6 +2819,9 @@ var EmailOrPhoneForm = uiEntry.withOverride(
];
case 3:
response = _b.sent();
+ if (response.status === "SIGN_IN_UP_NOT_ALLOWED") {
+ throw new STGeneralError__default.default(response.reason);
+ }
return [2 /*return*/, response];
case 4:
throw new STGeneralError__default.default(emailValidationRes);
@@ -2817,6 +2841,9 @@ var EmailOrPhoneForm = uiEntry.withOverride(
];
case 8:
response = _b.sent();
+ if (response.status === "SIGN_IN_UP_NOT_ALLOWED") {
+ throw new STGeneralError__default.default(response.reason);
+ }
return [2 /*return*/, response];
case 9:
return [
@@ -2844,7 +2871,11 @@ var EmailOrPhoneForm = uiEntry.withOverride(
}),
];
case 13:
- return [2 /*return*/, _b.sent()];
+ response = _b.sent();
+ if (response.status === "SIGN_IN_UP_NOT_ALLOWED") {
+ throw new STGeneralError__default.default(response.reason);
+ }
+ return [2 /*return*/, response];
case 14:
ex_1 = _b.sent();
// General errors from the API can make createCode throw but we want to switch to the phone UI anyway
@@ -3420,6 +3451,9 @@ var PhoneForm = uiEntry.withOverride("PasswordlessPhoneForm", function Passwordl
];
case 2:
response = _b.sent();
+ if (response.status === "SIGN_IN_UP_NOT_ALLOWED") {
+ throw new STGeneralError__default.default(response.reason);
+ }
return [2 /*return*/, response];
}
});
@@ -3633,7 +3667,13 @@ var UserInputCodeForm = uiEntry.withOverride(
];
case 1:
response = _b.sent();
- if (response.status === "OK" || response.status === "RESTART_FLOW_ERROR") {
+ // We can redirect these statuses, since they all cause a redirection
+ // and we don't really want to show anything
+ if (
+ response.status === "OK" ||
+ response.status === "RESTART_FLOW_ERROR" ||
+ response.status === "SIGN_IN_UP_NOT_ALLOWED"
+ ) {
return [2 /*return*/, response];
}
if (response.status === "INCORRECT_USER_INPUT_CODE_ERROR") {
@@ -4036,7 +4076,8 @@ function useChildProps(recipe$1, dispatch, state, callingConsumeCodeRef, userCon
rid: recipe$1.config.recipeId,
successRedirectContext: {
action: "SUCCESS",
- isNewUser: result.createdNewUser,
+ isNewRecipeUser: result.createdNewRecipeUser,
+ user: result.user,
redirectToPath: genericComponentOverrideContext.getRedirectToPathFromURL(),
},
},
@@ -4241,9 +4282,9 @@ function getModifiedRecipeImplementation(originalImpl, config, dispatch, calling
case 2:
_a.sent();
dispatch({ type: "restartFlow", error: "ERROR_SIGN_IN_UP_CODE_CONSUME_RESTART_FLOW" });
- return [3 /*break*/, 5];
+ return [3 /*break*/, 7];
case 3:
- if (!(res.status === "OK")) return [3 /*break*/, 5];
+ if (!(res.status === "SIGN_IN_UP_NOT_ALLOWED")) return [3 /*break*/, 5];
return [
4 /*yield*/,
originalImpl.clearLoginAttemptInfo({
@@ -4252,8 +4293,20 @@ function getModifiedRecipeImplementation(originalImpl, config, dispatch, calling
];
case 4:
_a.sent();
- _a.label = 5;
+ dispatch({ type: "restartFlow", error: res.reason });
+ return [3 /*break*/, 7];
case 5:
+ if (!(res.status === "OK")) return [3 /*break*/, 7];
+ return [
+ 4 /*yield*/,
+ originalImpl.clearLoginAttemptInfo({
+ userContext: input.userContext,
+ }),
+ ];
+ case 6:
+ _a.sent();
+ _a.label = 7;
+ case 7:
callingConsumeCodeRef.current = false;
return [2 /*return*/, res];
}
diff --git a/lib/build/recipe/authRecipe/types.d.ts b/lib/build/recipe/authRecipe/types.d.ts
index a2cdfd0fc..9e09ed432 100644
--- a/lib/build/recipe/authRecipe/types.d.ts
+++ b/lib/build/recipe/authRecipe/types.d.ts
@@ -3,19 +3,23 @@ import type {
NormalisedConfig as NormalisedRecipeModuleConfig,
UserInput as UserInputRecipeModule,
} from "../recipeModule/types";
-export declare type User = {
- id: string;
- email: string;
- timeJoined: number;
-};
+import type { User } from "supertokens-web-js/types";
export declare type UserInput = UserInputRecipeModule;
export declare type Config = UserInput & RecipeModuleConfig;
export declare type NormalisedConfig = NormalisedRecipeModuleConfig;
-export declare type GetRedirectionURLContext = {
- action: "SUCCESS";
- isNewUser: boolean;
- redirectToPath?: string;
-};
+export declare type GetRedirectionURLContext =
+ | {
+ action: "SUCCESS";
+ isNewRecipeUser: true;
+ user: User;
+ redirectToPath?: string;
+ }
+ | {
+ action: "SUCCESS";
+ isNewRecipeUser: false;
+ user?: User;
+ redirectToPath?: string;
+ };
export declare type OnHandleEventContext = {
action: "SESSION_ALREADY_EXISTS";
};
diff --git a/lib/build/recipe/emailpassword/components/themes/signInAndUp/signIn.d.ts b/lib/build/recipe/emailpassword/components/themes/signInAndUp/signIn.d.ts
index 46dd93ed6..2b40c960b 100644
--- a/lib/build/recipe/emailpassword/components/themes/signInAndUp/signIn.d.ts
+++ b/lib/build/recipe/emailpassword/components/themes/signInAndUp/signIn.d.ts
@@ -10,6 +10,6 @@ export declare const SignIn: import("react").ComponentType<
config: import("../../../types").NormalisedConfig;
signUpClicked?: (() => void) | undefined;
forgotPasswordClick: () => void;
- onSuccess: () => void;
+ onSuccess: (result: { user: import("supertokens-web-js/types").User }) => void;
}
>;
diff --git a/lib/build/recipe/emailpassword/components/themes/signInAndUp/signInForm.d.ts b/lib/build/recipe/emailpassword/components/themes/signInAndUp/signInForm.d.ts
index 41858dc47..7dbc1321c 100644
--- a/lib/build/recipe/emailpassword/components/themes/signInAndUp/signInForm.d.ts
+++ b/lib/build/recipe/emailpassword/components/themes/signInAndUp/signInForm.d.ts
@@ -10,7 +10,7 @@ export declare const SignInForm: import("react").ComponentType<
config: import("../../../types").NormalisedConfig;
signUpClicked?: (() => void) | undefined;
forgotPasswordClick: () => void;
- onSuccess: () => void;
+ onSuccess: (result: { user: import("supertokens-web-js/types").User }) => void;
} & {
header?: JSX.Element | undefined;
footer?: JSX.Element | undefined;
diff --git a/lib/build/recipe/emailpassword/components/themes/signInAndUp/signUp.d.ts b/lib/build/recipe/emailpassword/components/themes/signInAndUp/signUp.d.ts
index 1a0268aa8..380a6e333 100644
--- a/lib/build/recipe/emailpassword/components/themes/signInAndUp/signUp.d.ts
+++ b/lib/build/recipe/emailpassword/components/themes/signInAndUp/signUp.d.ts
@@ -9,6 +9,6 @@ export declare const SignUp: import("react").ComponentType<
onError: (error: string) => void;
config: import("../../../types").NormalisedConfig;
signInClicked?: (() => void) | undefined;
- onSuccess: () => void;
+ onSuccess: (result: { user: import("supertokens-web-js/types").User }) => void;
}
>;
diff --git a/lib/build/recipe/emailpassword/components/themes/signInAndUp/signUpForm.d.ts b/lib/build/recipe/emailpassword/components/themes/signInAndUp/signUpForm.d.ts
index d57524cfe..bbe4a2eb2 100644
--- a/lib/build/recipe/emailpassword/components/themes/signInAndUp/signUpForm.d.ts
+++ b/lib/build/recipe/emailpassword/components/themes/signInAndUp/signUpForm.d.ts
@@ -9,7 +9,7 @@ export declare const SignUpForm: import("react").ComponentType<
onError: (error: string) => void;
config: import("../../../types").NormalisedConfig;
signInClicked?: (() => void) | undefined;
- onSuccess: () => void;
+ onSuccess: (result: { user: import("supertokens-web-js/types").User }) => void;
} & {
header?: JSX.Element | undefined;
footer?: JSX.Element | undefined;
diff --git a/lib/build/recipe/emailpassword/components/themes/translations.d.ts b/lib/build/recipe/emailpassword/components/themes/translations.d.ts
index e0a73064a..6cf2ec356 100644
--- a/lib/build/recipe/emailpassword/components/themes/translations.d.ts
+++ b/lib/build/recipe/emailpassword/components/themes/translations.d.ts
@@ -57,6 +57,9 @@ export declare const defaultTranslationsEmailPassword: {
"Password must contain at least one alphabet": undefined;
"Password must contain at least one number": undefined;
"Email is invalid": undefined;
+ "Reset password link was not created because of account take over risk. Please contact support. (ERR_CODE_001)": undefined;
+ "Cannot sign up due to security reasons. Please try logging in, use a different login method or contact support. (ERR_CODE_007)": undefined;
+ "Cannot sign in due to security reasons. Please try resetting your password, use a different login method or contact support. (ERR_CODE_008)": undefined;
EMAIL_VERIFICATION_RESEND_SUCCESS: string;
EMAIL_VERIFICATION_SEND_TITLE: string;
EMAIL_VERIFICATION_SEND_DESC_START: string;
diff --git a/lib/build/recipe/emailpassword/index.d.ts b/lib/build/recipe/emailpassword/index.d.ts
index b632002d1..ad2c6e085 100644
--- a/lib/build/recipe/emailpassword/index.d.ts
+++ b/lib/build/recipe/emailpassword/index.d.ts
@@ -2,8 +2,8 @@
import { RecipeInterface } from "supertokens-web-js/recipe/emailpassword";
import { UserInput } from "./types";
import { GetRedirectionURLContext, PreAPIHookContext, OnHandleEventContext } from "./types";
-import type { User } from "../authRecipe/types";
import type { RecipeFunctionOptions } from "supertokens-web-js/recipe/emailpassword";
+import type { User } from "supertokens-web-js/types";
export default class Wrapper {
static init(
config?: UserInput
@@ -23,7 +23,11 @@ export default class Wrapper {
userContext?: any;
}): Promise<
| {
- status: "OK" | "RESET_PASSWORD_INVALID_TOKEN_ERROR";
+ status: "OK";
+ fetchResponse: Response;
+ }
+ | {
+ status: "RESET_PASSWORD_INVALID_TOKEN_ERROR";
fetchResponse: Response;
}
| {
@@ -44,7 +48,7 @@ export default class Wrapper {
userContext?: any;
}): Promise<
| {
- status: "OK";
+ status: "OK" | "PASSWORD_RESET_NOT_ALLOWED";
fetchResponse: Response;
}
| {
@@ -77,6 +81,11 @@ export default class Wrapper {
}[];
fetchResponse: Response;
}
+ | {
+ status: "SIGN_UP_NOT_ALLOWED";
+ reason: string;
+ fetchResponse: Response;
+ }
>;
static signIn(input: {
formFields: {
@@ -103,6 +112,11 @@ export default class Wrapper {
status: "WRONG_CREDENTIALS_ERROR";
fetchResponse: Response;
}
+ | {
+ status: "SIGN_IN_NOT_ALLOWED";
+ reason: string;
+ fetchResponse: Response;
+ }
>;
static doesEmailExist(input: { email: string; options?: RecipeFunctionOptions; userContext?: any }): Promise<{
status: "OK";
diff --git a/lib/build/recipe/emailpassword/types.d.ts b/lib/build/recipe/emailpassword/types.d.ts
index 8c03ab29f..d819f58c8 100644
--- a/lib/build/recipe/emailpassword/types.d.ts
+++ b/lib/build/recipe/emailpassword/types.d.ts
@@ -22,7 +22,6 @@ import type {
import type {
GetRedirectionURLContext as AuthRecipeModuleGetRedirectionURLContext,
OnHandleEventContext as AuthRecipeModuleOnHandleEventContext,
- User,
Config as AuthRecipeModuleConfig,
NormalisedConfig as NormalisedAuthRecipeModuleConfig,
UserInput as AuthRecipeModuleUserInput,
@@ -31,6 +30,7 @@ import type React from "react";
import type { Dispatch } from "react";
import type { OverrideableBuilder } from "supertokens-js-override";
import type { RecipeInterface } from "supertokens-web-js/recipe/emailpassword";
+import type { User } from "supertokens-web-js/types";
export declare type ComponentOverrideMap = {
EmailPasswordSignIn_Override?: ComponentOverride;
EmailPasswordSignInFooter_Override?: ComponentOverride;
@@ -122,7 +122,7 @@ export declare type SignInThemeProps = FormThemeBaseProps & {
config: NormalisedConfig;
signUpClicked?: () => void;
forgotPasswordClick: () => void;
- onSuccess: () => void;
+ onSuccess: (result: { user: User }) => void;
};
export declare type SignUpThemeProps = FormThemeBaseProps & {
recipeImplementation: RecipeInterface;
@@ -130,7 +130,7 @@ export declare type SignUpThemeProps = FormThemeBaseProps & {
onError: (error: string) => void;
config: NormalisedConfig;
signInClicked?: () => void;
- onSuccess: () => void;
+ onSuccess: (result: { user: User }) => void;
};
export declare type SignInAndUpThemeProps = {
signInForm: SignInThemeProps;
@@ -172,16 +172,18 @@ export declare type GetRedirectionURLContext =
export declare type OnHandleEventContext =
| AuthRecipeModuleOnHandleEventContext
| {
- action: "RESET_PASSWORD_EMAIL_SENT" | "PASSWORD_RESET_SUCCESSFUL";
+ action: "RESET_PASSWORD_EMAIL_SENT";
+ email: string;
+ userContext: any;
+ }
+ | {
+ action: "PASSWORD_RESET_SUCCESSFUL";
userContext: any;
}
| {
action: "SUCCESS";
- isNewUser: boolean;
- user: {
- id: string;
- email: string;
- };
+ isNewRecipeUser: boolean;
+ user: User;
userContext: any;
};
export declare type ResetPasswordUsingTokenThemeProps = {
diff --git a/lib/build/recipe/passwordless/components/themes/translations.d.ts b/lib/build/recipe/passwordless/components/themes/translations.d.ts
index 72eb4b70a..0fed6a0d3 100644
--- a/lib/build/recipe/passwordless/components/themes/translations.d.ts
+++ b/lib/build/recipe/passwordless/components/themes/translations.d.ts
@@ -55,6 +55,8 @@ export declare const defaultTranslationsPasswordless: {
"Failed to generate a one time code. Please try again": undefined;
"Phone number is invalid": undefined;
"Email is invalid": undefined;
+ "Cannot sign in / up due to security reasons. Please try a different login method or contact support. (ERR_CODE_002)": undefined;
+ "Cannot sign in / up due to security reasons. Please try a different login method or contact support. (ERR_CODE_003)": undefined;
BRANDING_POWERED_BY_START: string;
BRANDING_POWERED_BY_END: string;
SOMETHING_WENT_WRONG_ERROR: string;
diff --git a/lib/build/recipe/passwordless/index.d.ts b/lib/build/recipe/passwordless/index.d.ts
index c8dd212ea..8e8685244 100644
--- a/lib/build/recipe/passwordless/index.d.ts
+++ b/lib/build/recipe/passwordless/index.d.ts
@@ -3,7 +3,8 @@ import { RecipeInterface } from "supertokens-web-js/recipe/passwordless";
import { UserInput } from "./types";
import { GetRedirectionURLContext, PreAPIHookContext, OnHandleEventContext } from "./types";
import type { RecipeFunctionOptions } from "supertokens-web-js/recipe/passwordless";
-import type { PasswordlessFlowType, PasswordlessUser } from "supertokens-web-js/recipe/passwordless/types";
+import type { PasswordlessFlowType } from "supertokens-web-js/recipe/passwordless/types";
+import type { User } from "supertokens-web-js/types";
export default class Wrapper {
static init(
config: UserInput
@@ -26,13 +27,19 @@ export default class Wrapper {
userContext?: any;
options?: RecipeFunctionOptions;
}
- ): Promise<{
- status: "OK";
- deviceId: string;
- preAuthSessionId: string;
- flowType: PasswordlessFlowType;
- fetchResponse: Response;
- }>;
+ ): Promise<
+ | {
+ status: "OK";
+ deviceId: string;
+ preAuthSessionId: string;
+ flowType: PasswordlessFlowType;
+ fetchResponse: Response;
+ }
+ | {
+ status: "SIGN_IN_UP_NOT_ALLOWED";
+ reason: string;
+ }
+ >;
static resendCode(input?: { userContext?: any; options?: RecipeFunctionOptions }): Promise<{
status: "OK" | "RESTART_FLOW_ERROR";
fetchResponse: Response;
@@ -51,8 +58,8 @@ export default class Wrapper {
): Promise<
| {
status: "OK";
- createdNewUser: boolean;
- user: PasswordlessUser;
+ createdNewRecipeUser: boolean;
+ user: User;
fetchResponse: Response;
}
| {
@@ -65,6 +72,11 @@ export default class Wrapper {
status: "RESTART_FLOW_ERROR";
fetchResponse: Response;
}
+ | {
+ status: "SIGN_IN_UP_NOT_ALLOWED";
+ reason: string;
+ fetchResponse: Response;
+ }
>;
static getLinkCodeFromURL(input?: { userContext?: any }): string;
static getPreAuthSessionIdFromURL(input?: { userContext?: any }): string;
diff --git a/lib/build/recipe/passwordless/types.d.ts b/lib/build/recipe/passwordless/types.d.ts
index 12caca75c..617b38663 100644
--- a/lib/build/recipe/passwordless/types.d.ts
+++ b/lib/build/recipe/passwordless/types.d.ts
@@ -20,7 +20,8 @@ import type {
} from "../authRecipe/types";
import type { Dispatch } from "react";
import type WebJSRecipe from "supertokens-web-js/recipe/passwordless";
-import type { RecipeInterface, PasswordlessUser } from "supertokens-web-js/recipe/passwordless";
+import type { RecipeInterface } from "supertokens-web-js/recipe/passwordless";
+import type { User } from "supertokens-web-js/types";
export declare type PreAndPostAPIHookAction =
| "PASSWORDLESS_CREATE_CODE"
| "PASSWORDLESS_CONSUME_CODE"
@@ -36,8 +37,8 @@ export declare type GetRedirectionURLContext = AuthRecipeModuleGetRedirectionURL
export declare type OnHandleEventContext =
| {
action: "SUCCESS";
- isNewUser: boolean;
- user: PasswordlessUser;
+ isNewRecipeUser: boolean;
+ user: User;
}
| {
action: "PASSWORDLESS_RESTART_FLOW";
@@ -123,7 +124,7 @@ export declare type UserInput = (
export declare type SignInUpProps = {
recipeImplementation: RecipeImplementation;
config: NormalisedConfig;
- onSuccess?: (result: { createdNewUser: boolean; user: PasswordlessUser }) => void;
+ onSuccess?: (result: { createdNewRecipeUser: boolean; user: User }) => void;
dispatch: Dispatch;
featureState: {
loginAttemptInfo?: LoginAttemptInfo;
@@ -187,7 +188,7 @@ export declare type SignInUpUserInputCodeFormProps = {
recipeImplementation: RecipeImplementation;
config: NormalisedConfig;
loginAttemptInfo: LoginAttemptInfo;
- onSuccess?: (result: { createdNewUser: boolean; user: PasswordlessUser }) => void;
+ onSuccess?: (result: { createdNewRecipeUser: boolean; user: User }) => void;
};
export declare type LinkClickedScreenProps = {
recipeImplementation: RecipeImplementation;
diff --git a/lib/build/recipe/thirdparty/components/themes/translations.d.ts b/lib/build/recipe/thirdparty/components/themes/translations.d.ts
index 7ba3735b6..05233577d 100644
--- a/lib/build/recipe/thirdparty/components/themes/translations.d.ts
+++ b/lib/build/recipe/thirdparty/components/themes/translations.d.ts
@@ -9,6 +9,9 @@ export declare const defaultTranslationsThirdParty: {
THIRD_PARTY_PROVIDER_DEFAULT_BTN_START: string;
THIRD_PARTY_PROVIDER_DEFAULT_BTN_END: string;
THIRD_PARTY_ERROR_NO_EMAIL: string;
+ "Cannot sign in / up due to security reasons. Please try a different login method or contact support. (ERR_CODE_004)": undefined;
+ "Cannot sign in / up because new email cannot be applied to existing account. Please contact support. (ERR_CODE_005)": undefined;
+ "Cannot sign in / up due to security reasons. Please try a different login method or contact support. (ERR_CODE_006)": undefined;
BRANDING_POWERED_BY_START: string;
BRANDING_POWERED_BY_END: string;
SOMETHING_WENT_WRONG_ERROR: string;
diff --git a/lib/build/recipe/thirdparty/index.d.ts b/lib/build/recipe/thirdparty/index.d.ts
index 1fa238f4f..043dcba42 100644
--- a/lib/build/recipe/thirdparty/index.d.ts
+++ b/lib/build/recipe/thirdparty/index.d.ts
@@ -1,5 +1,5 @@
///
-import { RecipeInterface, ThirdPartyUserType as User } from "supertokens-web-js/recipe/thirdparty";
+import { RecipeInterface } from "supertokens-web-js/recipe/thirdparty";
import ActiveDirectory from "./providers/activeDirectory";
import Apple from "./providers/apple";
import Bitbucket from "./providers/bitbucket";
@@ -16,6 +16,7 @@ import Twitter from "./providers/twitter";
import { UserInput, GetRedirectionURLContext, PreAPIHookContext, OnHandleEventContext } from "./types";
import type { StateObject } from "supertokens-web-js/recipe/thirdparty";
import type { RecipeFunctionOptions } from "supertokens-web-js/recipe/thirdpartyemailpassword";
+import type { User } from "supertokens-web-js/types";
export default class Wrapper {
static init(
config?: UserInput
@@ -43,13 +44,18 @@ export default class Wrapper {
| {
status: "OK";
user: User;
- createdNewUser: boolean;
+ createdNewRecipeUser: boolean;
fetchResponse: Response;
}
| {
status: "NO_EMAIL_GIVEN_BY_PROVIDER";
fetchResponse: Response;
}
+ | {
+ status: "SIGN_IN_UP_NOT_ALLOWED";
+ reason: string;
+ fetchResponse: Response;
+ }
>;
static Apple: typeof Apple;
static Bitbucket: typeof Bitbucket;
@@ -101,7 +107,6 @@ export {
redirectToThirdPartyLogin,
ThirdpartyComponentsOverrideProvider,
signOut,
- User,
GetRedirectionURLContext,
PreAPIHookContext,
OnHandleEventContext,
diff --git a/lib/build/recipe/thirdparty/types.d.ts b/lib/build/recipe/thirdparty/types.d.ts
index b923ceb60..0a93ccc3d 100644
--- a/lib/build/recipe/thirdparty/types.d.ts
+++ b/lib/build/recipe/thirdparty/types.d.ts
@@ -16,6 +16,7 @@ import type {
import type { OverrideableBuilder } from "supertokens-js-override";
import type ThirdPartyWebJS from "supertokens-web-js/recipe/thirdparty";
import type { StateObject as WebJsStateObject, RecipeInterface } from "supertokens-web-js/recipe/thirdparty";
+import type { User } from "supertokens-web-js/types";
export declare type ComponentOverrideMap = {
ThirdPartySignUpFooter_Override?: ComponentOverride;
ThirdPartySignInAndUpHeader_Override?: ComponentOverride;
@@ -68,11 +69,8 @@ export declare type OnHandleEventContext =
| AuthRecipeModuleOnHandleEventContext
| {
action: "SUCCESS";
- isNewUser: boolean;
- user: {
- id: string;
- email: string;
- };
+ isNewRecipeUser: boolean;
+ user: User;
userContext: any;
};
export declare type SignInAndUpThemeProps = {
diff --git a/lib/build/recipe/thirdpartyemailpassword/components/themes/translations.d.ts b/lib/build/recipe/thirdpartyemailpassword/components/themes/translations.d.ts
index bb256d116..bd164e96d 100644
--- a/lib/build/recipe/thirdpartyemailpassword/components/themes/translations.d.ts
+++ b/lib/build/recipe/thirdpartyemailpassword/components/themes/translations.d.ts
@@ -58,6 +58,7 @@ export declare const defaultTranslationsThirdPartyEmailPassword: {
"Password must contain at least one alphabet": undefined;
"Password must contain at least one number": undefined;
"Email is invalid": undefined;
+ "Reset password link was not created because of account take over risk. Please contact support. (ERR_CODE_001)": undefined;
EMAIL_VERIFICATION_RESEND_SUCCESS: string;
EMAIL_VERIFICATION_SEND_TITLE: string;
EMAIL_VERIFICATION_SEND_DESC_START: string;
@@ -86,5 +87,8 @@ export declare const defaultTranslationsThirdPartyEmailPassword: {
THIRD_PARTY_PROVIDER_DEFAULT_BTN_START: string;
THIRD_PARTY_PROVIDER_DEFAULT_BTN_END: string;
THIRD_PARTY_ERROR_NO_EMAIL: string;
+ "Cannot sign in / up due to security reasons. Please try a different login method or contact support. (ERR_CODE_004)": undefined;
+ "Cannot sign in / up because new email cannot be applied to existing account. Please contact support. (ERR_CODE_005)": undefined;
+ "Cannot sign in / up due to security reasons. Please try a different login method or contact support. (ERR_CODE_006)": undefined;
};
};
diff --git a/lib/build/recipe/thirdpartyemailpassword/index.d.ts b/lib/build/recipe/thirdpartyemailpassword/index.d.ts
index 7b1a767b2..f225db25e 100644
--- a/lib/build/recipe/thirdpartyemailpassword/index.d.ts
+++ b/lib/build/recipe/thirdpartyemailpassword/index.d.ts
@@ -1,9 +1,5 @@
///
-import {
- RecipeInterface,
- EmailPasswordUserType as UserType,
- ThirdPartyUserType,
-} from "supertokens-web-js/recipe/thirdpartyemailpassword";
+import { RecipeInterface } from "supertokens-web-js/recipe/thirdpartyemailpassword";
import {
Apple,
Google,
@@ -21,6 +17,7 @@ import {
import { UserInput, GetRedirectionURLContext, PreAPIHookContext, OnHandleEventContext } from "./types";
import type { StateObject } from "supertokens-web-js/recipe/thirdparty";
import type { RecipeFunctionOptions } from "supertokens-web-js/recipe/thirdpartyemailpassword";
+import type { User } from "supertokens-web-js/types";
export default class Wrapper {
static init(
config?: UserInput
@@ -40,7 +37,11 @@ export default class Wrapper {
userContext?: any;
}): Promise<
| {
- status: "OK" | "RESET_PASSWORD_INVALID_TOKEN_ERROR";
+ status: "OK";
+ fetchResponse: Response;
+ }
+ | {
+ status: "RESET_PASSWORD_INVALID_TOKEN_ERROR";
fetchResponse: Response;
}
| {
@@ -61,7 +62,7 @@ export default class Wrapper {
userContext?: any;
}): Promise<
| {
- status: "OK";
+ status: "OK" | "PASSWORD_RESET_NOT_ALLOWED";
fetchResponse: Response;
}
| {
@@ -83,7 +84,7 @@ export default class Wrapper {
}): Promise<
| {
status: "OK";
- user: UserType;
+ user: User;
fetchResponse: Response;
}
| {
@@ -94,6 +95,11 @@ export default class Wrapper {
}[];
fetchResponse: Response;
}
+ | {
+ status: "SIGN_UP_NOT_ALLOWED";
+ reason: string;
+ fetchResponse: Response;
+ }
>;
static emailPasswordSignIn(input: {
formFields: {
@@ -105,7 +111,7 @@ export default class Wrapper {
}): Promise<
| {
status: "OK";
- user: UserType;
+ user: User;
fetchResponse: Response;
}
| {
@@ -120,6 +126,11 @@ export default class Wrapper {
status: "WRONG_CREDENTIALS_ERROR";
fetchResponse: Response;
}
+ | {
+ status: "SIGN_IN_NOT_ALLOWED";
+ reason: string;
+ fetchResponse: Response;
+ }
>;
static doesEmailExist(input: { email: string; options?: RecipeFunctionOptions; userContext?: any }): Promise<{
status: "OK";
@@ -133,14 +144,19 @@ export default class Wrapper {
static thirdPartySignInAndUp(input?: { userContext?: any; options?: RecipeFunctionOptions }): Promise<
| {
status: "OK";
- user: ThirdPartyUserType;
- createdNewUser: boolean;
+ user: User;
+ createdNewRecipeUser: boolean;
fetchResponse: Response;
}
| {
status: "NO_EMAIL_GIVEN_BY_PROVIDER";
fetchResponse: Response;
}
+ | {
+ status: "SIGN_IN_UP_NOT_ALLOWED";
+ reason: string;
+ fetchResponse: Response;
+ }
>;
static getStateAndOtherInfoFromStorage(input?: {
userContext?: any;
@@ -218,6 +234,4 @@ export {
OnHandleEventContext,
UserInput,
RecipeInterface,
- UserType,
- ThirdPartyUserType,
};
diff --git a/lib/build/recipe/thirdpartypasswordless/components/themes/translations.d.ts b/lib/build/recipe/thirdpartypasswordless/components/themes/translations.d.ts
index dbe4e941e..b24b59e60 100644
--- a/lib/build/recipe/thirdpartypasswordless/components/themes/translations.d.ts
+++ b/lib/build/recipe/thirdpartypasswordless/components/themes/translations.d.ts
@@ -57,6 +57,8 @@ export declare const defaultTranslationsThirdPartyPasswordless: {
"Failed to generate a one time code. Please try again": undefined;
"Phone number is invalid": undefined;
"Email is invalid": undefined;
+ "Cannot sign in / up due to security reasons. Please try a different login method or contact support. (ERR_CODE_002)": undefined;
+ "Cannot sign in / up due to security reasons. Please try a different login method or contact support. (ERR_CODE_003)": undefined;
BRANDING_POWERED_BY_START: string;
BRANDING_POWERED_BY_END: string;
SOMETHING_WENT_WRONG_ERROR: string;
@@ -69,5 +71,8 @@ export declare const defaultTranslationsThirdPartyPasswordless: {
THIRD_PARTY_PROVIDER_DEFAULT_BTN_START: string;
THIRD_PARTY_PROVIDER_DEFAULT_BTN_END: string;
THIRD_PARTY_ERROR_NO_EMAIL: string;
+ "Cannot sign in / up due to security reasons. Please try a different login method or contact support. (ERR_CODE_004)": undefined;
+ "Cannot sign in / up because new email cannot be applied to existing account. Please contact support. (ERR_CODE_005)": undefined;
+ "Cannot sign in / up due to security reasons. Please try a different login method or contact support. (ERR_CODE_006)": undefined;
};
};
diff --git a/lib/build/recipe/thirdpartypasswordless/index.d.ts b/lib/build/recipe/thirdpartypasswordless/index.d.ts
index 4508e4735..db4806266 100644
--- a/lib/build/recipe/thirdpartypasswordless/index.d.ts
+++ b/lib/build/recipe/thirdpartypasswordless/index.d.ts
@@ -15,17 +15,14 @@ import {
Okta,
} from "../thirdparty/";
import { UserInput, GetRedirectionURLContext, PreAPIHookContext, OnHandleEventContext } from "./types";
-import type { StateObject, ThirdPartyUserType as UserType } from "supertokens-web-js/recipe/thirdparty";
-import type {
- PasswordlessFlowType,
- PasswordlessUser,
- RecipeFunctionOptions,
-} from "supertokens-web-js/recipe/thirdpartypasswordless";
+import type { StateObject } from "supertokens-web-js/recipe/thirdparty";
+import type { PasswordlessFlowType, RecipeFunctionOptions } from "supertokens-web-js/recipe/thirdpartypasswordless";
+import type { User } from "supertokens-web-js/types";
export default class Wrapper {
static init(
config: UserInput
): import("../../types").RecipeInitResult<
- import("../authRecipe/types").GetRedirectionURLContext,
+ GetRedirectionURLContext,
import("./types").PreAndPostAPIHookAction,
OnHandleEventContext,
import("./types").NormalisedConfig
@@ -37,14 +34,19 @@ export default class Wrapper {
static thirdPartySignInAndUp(input?: { userContext?: any; options?: RecipeFunctionOptions }): Promise<
| {
status: "OK";
- user: UserType;
- createdNewUser: boolean;
+ user: User;
+ createdNewRecipeUser: boolean;
fetchResponse: Response;
}
| {
status: "NO_EMAIL_GIVEN_BY_PROVIDER";
fetchResponse: Response;
}
+ | {
+ status: "SIGN_IN_UP_NOT_ALLOWED";
+ reason: string;
+ fetchResponse: Response;
+ }
>;
static getThirdPartyStateAndOtherInfoFromStorage(input?: {
userContext?: any;
@@ -68,13 +70,20 @@ export default class Wrapper {
userContext?: any;
options?: RecipeFunctionOptions;
}
- ): Promise<{
- status: "OK";
- deviceId: string;
- preAuthSessionId: string;
- flowType: PasswordlessFlowType;
- fetchResponse: Response;
- }>;
+ ): Promise<
+ | {
+ status: "OK";
+ deviceId: string;
+ preAuthSessionId: string;
+ flowType: PasswordlessFlowType;
+ fetchResponse: Response;
+ }
+ | {
+ status: "SIGN_IN_UP_NOT_ALLOWED";
+ reason: string;
+ fetchResponse: Response;
+ }
+ >;
static resendPasswordlessCode(input?: { userContext?: any; options?: RecipeFunctionOptions }): Promise<{
status: "OK" | "RESTART_FLOW_ERROR";
fetchResponse: Response;
@@ -93,8 +102,8 @@ export default class Wrapper {
): Promise<
| {
status: "OK";
- createdNewUser: boolean;
- user: PasswordlessUser;
+ createdNewRecipeUser: boolean;
+ user: User;
fetchResponse: Response;
}
| {
@@ -107,6 +116,11 @@ export default class Wrapper {
status: "RESTART_FLOW_ERROR";
fetchResponse: Response;
}
+ | {
+ status: "SIGN_IN_UP_NOT_ALLOWED";
+ reason: string;
+ fetchResponse: Response;
+ }
>;
static getPasswordlessLinkCodeFromURL(input?: { userContext?: any }): string;
static getPasswordlessPreAuthSessionIdFromURL(input?: { userContext?: any }): string;
diff --git a/lib/build/session-shared2.js b/lib/build/session-shared2.js
index 2415bbc17..7d78ccc90 100644
--- a/lib/build/session-shared2.js
+++ b/lib/build/session-shared2.js
@@ -295,7 +295,8 @@ var Session = /** @class */ (function (_super) {
rid: Session.RECIPE_ID,
successRedirectContext: {
action: "SUCCESS",
- isNewUser: false,
+ isNewRecipeUser: false,
+ user: undefined,
},
};
_a.label = 13;
diff --git a/lib/build/thirdparty-shared.js b/lib/build/thirdparty-shared.js
index fa9fa1e1a..9ecf3f819 100644
--- a/lib/build/thirdparty-shared.js
+++ b/lib/build/thirdparty-shared.js
@@ -1080,7 +1080,7 @@ var getFunctionOverrides = function (recipeId, onHandleEvent) {
if (response.status === "OK") {
onHandleEvent({
action: "SUCCESS",
- isNewUser: response.createdNewUser,
+ isNewRecipeUser: response.createdNewRecipeUser,
user: response.user,
userContext: input.userContext,
});
diff --git a/lib/build/thirdparty-shared2.js b/lib/build/thirdparty-shared2.js
index bf26d1480..c5f17c5db 100644
--- a/lib/build/thirdparty-shared2.js
+++ b/lib/build/thirdparty-shared2.js
@@ -287,6 +287,17 @@ var defaultTranslationsThirdParty = {
THIRD_PARTY_PROVIDER_DEFAULT_BTN_START: "Continue with ",
THIRD_PARTY_PROVIDER_DEFAULT_BTN_END: "",
THIRD_PARTY_ERROR_NO_EMAIL: "Could not retrieve email. Please try a different method.",
+ /*
+ * The following are error messages from our backend SDK.
+ * These are returned as full messages to preserver compatibilty, but they work just like the keys above.
+ * They are shown as is by default (setting the value to undefined will display the raw translation key)
+ */
+ "Cannot sign in / up due to security reasons. Please try a different login method or contact support. (ERR_CODE_004)":
+ undefined,
+ "Cannot sign in / up because new email cannot be applied to existing account. Please contact support. (ERR_CODE_005)":
+ undefined,
+ "Cannot sign in / up due to security reasons. Please try a different login method or contact support. (ERR_CODE_006)":
+ undefined,
}
),
};
@@ -507,6 +518,19 @@ var SignInAndUpCallback$1 = function (props) {
}),
];
}
+ if (response.status === "SIGN_IN_UP_NOT_ALLOWED") {
+ return [
+ 2 /*return*/,
+ genericComponentOverrideContext.SuperTokens.getInstanceOrThrow().redirectToAuth({
+ history: props.history,
+ queryParams: {
+ error: response.status,
+ message: response.reason,
+ },
+ redirectBack: false,
+ }),
+ ];
+ }
if (response.status === "OK") {
stateResponse = props.recipe.webJSRecipe.getStateAndOtherInfoFromStorage({
userContext: userContext,
@@ -519,7 +543,8 @@ var SignInAndUpCallback$1 = function (props) {
rid: props.recipe.config.recipeId,
successRedirectContext: {
action: "SUCCESS",
- isNewUser: response.createdNewUser,
+ isNewRecipeUser: response.createdNewRecipeUser,
+ user: response.user,
redirectToPath: redirectToPath,
},
},
diff --git a/lib/build/thirdpartyemailpassword-shared.js b/lib/build/thirdpartyemailpassword-shared.js
index b3322dda9..a215a9380 100644
--- a/lib/build/thirdpartyemailpassword-shared.js
+++ b/lib/build/thirdpartyemailpassword-shared.js
@@ -31,7 +31,7 @@ var getFunctionOverrides = function (recipeId, onHandleEvent) {
if (response.status === "OK") {
onHandleEvent({
action: "SUCCESS",
- isNewUser: response.createdNewUser,
+ isNewRecipeUser: response.createdNewRecipeUser,
user: response.user,
userContext: input.userContext,
});
@@ -90,6 +90,10 @@ var getFunctionOverrides = function (recipeId, onHandleEvent) {
if (response.status === "OK") {
onHandleEvent({
action: "RESET_PASSWORD_EMAIL_SENT",
+ email: input.formFields.find(function (_a) {
+ var id = _a.id;
+ return id === "email";
+ }).value,
userContext: input.userContext,
});
}
@@ -110,7 +114,7 @@ var getFunctionOverrides = function (recipeId, onHandleEvent) {
if (response.status === "OK") {
onHandleEvent({
action: "SUCCESS",
- isNewUser: true,
+ isNewRecipeUser: true,
user: response.user,
userContext: input.userContext,
});
@@ -132,7 +136,7 @@ var getFunctionOverrides = function (recipeId, onHandleEvent) {
if (response.status === "OK") {
onHandleEvent({
action: "SUCCESS",
- isNewUser: false,
+ isNewRecipeUser: false,
user: response.user,
userContext: input.userContext,
});
diff --git a/lib/build/thirdpartyemailpasswordprebuiltui.js b/lib/build/thirdpartyemailpasswordprebuiltui.js
index 66e50379f..091b64450 100644
--- a/lib/build/thirdpartyemailpasswordprebuiltui.js
+++ b/lib/build/thirdpartyemailpasswordprebuiltui.js
@@ -33,6 +33,7 @@ require("./emailpassword-shared7.js");
require("supertokens-web-js/utils/error");
require("./emailpassword-shared5.js");
require("./emailpassword-shared2.js");
+require("supertokens-web-js/lib/build/error");
require("./emailpassword-shared4.js");
require("supertokens-web-js/recipe/emailpassword");
require("./authRecipe-shared.js");
diff --git a/lib/build/thirdpartypasswordless-shared.js b/lib/build/thirdpartypasswordless-shared.js
index 299c78801..ef7d96ef0 100644
--- a/lib/build/thirdpartypasswordless-shared.js
+++ b/lib/build/thirdpartypasswordless-shared.js
@@ -31,7 +31,7 @@ var getFunctionOverrides = function (recipeId, onHandleEvent) {
if (response.status === "OK") {
onHandleEvent({
action: "SUCCESS",
- isNewUser: response.createdNewUser,
+ isNewRecipeUser: response.createdNewRecipeUser,
user: response.user,
userContext: input.userContext,
});
@@ -110,7 +110,7 @@ var getFunctionOverrides = function (recipeId, onHandleEvent) {
} else if (response.status === "OK") {
onHandleEvent({
action: "SUCCESS",
- isNewUser: response.createdNewUser,
+ isNewRecipeUser: response.createdNewRecipeUser,
user: response.user,
});
}
diff --git a/lib/build/version.d.ts b/lib/build/version.d.ts
index 2da25307c..1e2536ff4 100644
--- a/lib/build/version.d.ts
+++ b/lib/build/version.d.ts
@@ -1 +1 @@
-export declare const package_version = "0.34.2";
+export declare const package_version = "0.35.0";
diff --git a/lib/ts/recipe/authRecipe/authWidgetWrapper.tsx b/lib/ts/recipe/authRecipe/authWidgetWrapper.tsx
index 55b4be1c2..052000fe9 100644
--- a/lib/ts/recipe/authRecipe/authWidgetWrapper.tsx
+++ b/lib/ts/recipe/authRecipe/authWidgetWrapper.tsx
@@ -77,7 +77,8 @@ const Redirector = = UserInputRecipeModule;
@@ -31,11 +26,19 @@ export type Config = UserInput & RecipeModuleConfig;
export type NormalisedConfig = NormalisedRecipeModuleConfig;
-export type GetRedirectionURLContext = {
- action: "SUCCESS";
- isNewUser: boolean;
- redirectToPath?: string;
-};
+export type GetRedirectionURLContext =
+ | {
+ action: "SUCCESS";
+ isNewRecipeUser: true;
+ user: User;
+ redirectToPath?: string;
+ }
+ | {
+ action: "SUCCESS";
+ isNewRecipeUser: false;
+ user?: User;
+ redirectToPath?: string;
+ };
export type OnHandleEventContext = {
action: "SESSION_ALREADY_EXISTS";
diff --git a/lib/ts/recipe/emailpassword/components/features/signInAndUp/index.tsx b/lib/ts/recipe/emailpassword/components/features/signInAndUp/index.tsx
index fc6cb65d9..86def01ab 100644
--- a/lib/ts/recipe/emailpassword/components/features/signInAndUp/index.tsx
+++ b/lib/ts/recipe/emailpassword/components/features/signInAndUp/index.tsx
@@ -41,6 +41,7 @@ import type {
} from "../../../types";
import type { Dispatch } from "react";
import type { RecipeInterface } from "supertokens-web-js/recipe/emailpassword";
+import type { User } from "supertokens-web-js/types";
export const useFeatureReducer = (recipe: Recipe | undefined) => {
return React.useReducer(
@@ -111,35 +112,43 @@ export function useChildProps(
const recipeImplementation = useMemo(() => recipe && getModifiedRecipeImplementation(recipe.webJSRecipe), [recipe]);
const userContext = useUserContext();
- const onSignInSuccess = useCallback(async (): Promise => {
- return Session.getInstanceOrThrow().validateGlobalClaimsAndHandleSuccessRedirection(
- {
- rid: recipe!.config.recipeId,
- successRedirectContext: {
- action: "SUCCESS",
- isNewUser: false,
- redirectToPath: getRedirectToPathFromURL(),
+ const onSignInSuccess = useCallback(
+ async (response: { user: User }): Promise => {
+ return Session.getInstanceOrThrow().validateGlobalClaimsAndHandleSuccessRedirection(
+ {
+ rid: recipe!.config.recipeId,
+ successRedirectContext: {
+ action: "SUCCESS",
+ isNewRecipeUser: false,
+ user: response.user,
+ redirectToPath: getRedirectToPathFromURL(),
+ },
},
- },
- userContext,
- history
- );
- }, [recipe, userContext, history]);
+ userContext,
+ history
+ );
+ },
+ [recipe, userContext, history]
+ );
- const onSignUpSuccess = useCallback(async (): Promise => {
- return Session.getInstanceOrThrow().validateGlobalClaimsAndHandleSuccessRedirection(
- {
- rid: recipe!.config.recipeId,
- successRedirectContext: {
- action: "SUCCESS",
- isNewUser: true,
- redirectToPath: getRedirectToPathFromURL(),
+ const onSignUpSuccess = useCallback(
+ async (response: { user: User }): Promise => {
+ return Session.getInstanceOrThrow().validateGlobalClaimsAndHandleSuccessRedirection(
+ {
+ rid: recipe!.config.recipeId,
+ successRedirectContext: {
+ action: "SUCCESS",
+ isNewRecipeUser: true,
+ user: response.user,
+ redirectToPath: getRedirectToPathFromURL(),
+ },
},
- },
- userContext,
- history
- );
- }, [recipe, userContext, history]);
+ userContext,
+ history
+ );
+ },
+ [recipe, userContext, history]
+ );
return useMemo(() => {
if (recipe === undefined || recipeImplementation === undefined) {
diff --git a/lib/ts/recipe/emailpassword/components/themes/resetPasswordUsingToken/resetPasswordEmail.tsx b/lib/ts/recipe/emailpassword/components/themes/resetPasswordUsingToken/resetPasswordEmail.tsx
index bd2c3bb36..75451f204 100644
--- a/lib/ts/recipe/emailpassword/components/themes/resetPasswordUsingToken/resetPasswordEmail.tsx
+++ b/lib/ts/recipe/emailpassword/components/themes/resetPasswordUsingToken/resetPasswordEmail.tsx
@@ -105,10 +105,17 @@ const EmailPasswordResetPasswordEmail: React.FC = (props) => {
setEmailFieldValue(emailField.value);
}
- return await props.recipeImplementation.sendPasswordResetEmail({
+ const resp = await props.recipeImplementation.sendPasswordResetEmail({
formFields,
userContext,
});
+ if (resp.status === "PASSWORD_RESET_NOT_ALLOWED") {
+ return {
+ status: "FIELD_ERROR",
+ formFields: [{ id: "email", error: resp.reason }],
+ };
+ }
+ return resp;
}}
showLabels={true}
validateOnBlur={true}
diff --git a/lib/ts/recipe/emailpassword/components/themes/signInAndUp/signInForm.tsx b/lib/ts/recipe/emailpassword/components/themes/signInAndUp/signInForm.tsx
index b0cdb8f56..2f7cc2dde 100644
--- a/lib/ts/recipe/emailpassword/components/themes/signInAndUp/signInForm.tsx
+++ b/lib/ts/recipe/emailpassword/components/themes/signInAndUp/signInForm.tsx
@@ -62,6 +62,8 @@ export const SignInForm = withOverride(
});
if (response.status === "WRONG_CREDENTIALS_ERROR") {
throw new STGeneralError("EMAIL_PASSWORD_SIGN_IN_WRONG_CREDENTIALS_ERROR");
+ } else if (response.status === "SIGN_IN_NOT_ALLOWED") {
+ throw new STGeneralError(response.reason);
} else {
return response;
}
diff --git a/lib/ts/recipe/emailpassword/components/themes/signInAndUp/signUpForm.tsx b/lib/ts/recipe/emailpassword/components/themes/signInAndUp/signUpForm.tsx
index 1c69829dd..e7df1ceba 100644
--- a/lib/ts/recipe/emailpassword/components/themes/signInAndUp/signUpForm.tsx
+++ b/lib/ts/recipe/emailpassword/components/themes/signInAndUp/signUpForm.tsx
@@ -15,6 +15,8 @@
/*
* Imports.
*/
+import STGeneralError from "supertokens-web-js/lib/build/error";
+
import { withOverride } from "../../../../../components/componentOverride/withOverride";
import { useUserContext } from "../../../../../usercontext";
import { validateForm } from "../../../../../utils";
@@ -56,10 +58,15 @@ export const SignUpForm = withOverride(
};
}
- return props.recipeImplementation.signUp({
+ const res = await props.recipeImplementation.signUp({
formFields,
userContext,
});
+
+ if (res.status === "SIGN_UP_NOT_ALLOWED") {
+ throw new STGeneralError(res.reason);
+ }
+ return res;
}}
validateOnBlur={true}
showLabels={true}
diff --git a/lib/ts/recipe/emailpassword/components/themes/translations.ts b/lib/ts/recipe/emailpassword/components/themes/translations.ts
index 7d16fb5b6..048a6940a 100644
--- a/lib/ts/recipe/emailpassword/components/themes/translations.ts
+++ b/lib/ts/recipe/emailpassword/components/themes/translations.ts
@@ -80,5 +80,11 @@ export const defaultTranslationsEmailPassword = {
"Password must contain at least one alphabet": undefined,
"Password must contain at least one number": undefined,
"Email is invalid": undefined,
+ "Reset password link was not created because of account take over risk. Please contact support. (ERR_CODE_001)":
+ undefined,
+ "Cannot sign up due to security reasons. Please try logging in, use a different login method or contact support. (ERR_CODE_007)":
+ undefined,
+ "Cannot sign in due to security reasons. Please try resetting your password, use a different login method or contact support. (ERR_CODE_008)":
+ undefined,
},
};
diff --git a/lib/ts/recipe/emailpassword/functionOverrides.ts b/lib/ts/recipe/emailpassword/functionOverrides.ts
index 3e01f10ce..06227e9c0 100644
--- a/lib/ts/recipe/emailpassword/functionOverrides.ts
+++ b/lib/ts/recipe/emailpassword/functionOverrides.ts
@@ -28,6 +28,7 @@ export const getFunctionOverrides =
if (response.status === "OK") {
onHandleEvent({
action: "RESET_PASSWORD_EMAIL_SENT",
+ email: input.formFields.find(({ id }) => id === "email")!.value,
userContext: input.userContext,
});
}
@@ -40,7 +41,7 @@ export const getFunctionOverrides =
if (response.status === "OK") {
onHandleEvent({
action: "SUCCESS",
- isNewUser: true,
+ isNewRecipeUser: true,
user: response.user,
userContext: input.userContext,
});
@@ -54,7 +55,7 @@ export const getFunctionOverrides =
if (response.status === "OK") {
onHandleEvent({
action: "SUCCESS",
- isNewUser: false,
+ isNewRecipeUser: false,
user: response.user,
userContext: input.userContext,
});
diff --git a/lib/ts/recipe/emailpassword/index.ts b/lib/ts/recipe/emailpassword/index.ts
index e44cfb821..6f5423b40 100644
--- a/lib/ts/recipe/emailpassword/index.ts
+++ b/lib/ts/recipe/emailpassword/index.ts
@@ -22,8 +22,8 @@ import EmailPassword from "./recipe";
import { UserInput } from "./types";
import { GetRedirectionURLContext, PreAPIHookContext, OnHandleEventContext } from "./types";
-import type { User } from "../authRecipe/types";
import type { RecipeFunctionOptions } from "supertokens-web-js/recipe/emailpassword";
+import type { User } from "supertokens-web-js/types";
export default class Wrapper {
static init(config?: UserInput) {
@@ -45,7 +45,11 @@ export default class Wrapper {
userContext?: any;
}): Promise<
| {
- status: "OK" | "RESET_PASSWORD_INVALID_TOKEN_ERROR";
+ status: "OK";
+ fetchResponse: Response;
+ }
+ | {
+ status: "RESET_PASSWORD_INVALID_TOKEN_ERROR";
fetchResponse: Response;
}
| {
@@ -72,7 +76,7 @@ export default class Wrapper {
userContext?: any;
}): Promise<
| {
- status: "OK";
+ status: "OK" | "PASSWORD_RESET_NOT_ALLOWED";
fetchResponse: Response;
}
| {
@@ -111,6 +115,11 @@ export default class Wrapper {
}[];
fetchResponse: Response;
}
+ | {
+ status: "SIGN_UP_NOT_ALLOWED";
+ reason: string;
+ fetchResponse: Response;
+ }
> {
return EmailPassword.getInstanceOrThrow().webJSRecipe.signUp({
...input,
@@ -143,6 +152,11 @@ export default class Wrapper {
status: "WRONG_CREDENTIALS_ERROR";
fetchResponse: Response;
}
+ | {
+ status: "SIGN_IN_NOT_ALLOWED";
+ reason: string;
+ fetchResponse: Response;
+ }
> {
return EmailPassword.getInstanceOrThrow().webJSRecipe.signIn({
...input,
diff --git a/lib/ts/recipe/emailpassword/types.ts b/lib/ts/recipe/emailpassword/types.ts
index df43f112e..253329077 100644
--- a/lib/ts/recipe/emailpassword/types.ts
+++ b/lib/ts/recipe/emailpassword/types.ts
@@ -37,7 +37,6 @@ import type {
import type {
GetRedirectionURLContext as AuthRecipeModuleGetRedirectionURLContext,
OnHandleEventContext as AuthRecipeModuleOnHandleEventContext,
- User,
Config as AuthRecipeModuleConfig,
NormalisedConfig as NormalisedAuthRecipeModuleConfig,
UserInput as AuthRecipeModuleUserInput,
@@ -46,6 +45,7 @@ import type React from "react";
import type { Dispatch } from "react";
import type { OverrideableBuilder } from "supertokens-js-override";
import type { RecipeInterface } from "supertokens-web-js/recipe/emailpassword";
+import type { User } from "supertokens-web-js/types";
export type ComponentOverrideMap = {
EmailPasswordSignIn_Override?: ComponentOverride;
@@ -245,7 +245,7 @@ export type SignInThemeProps = FormThemeBaseProps & {
config: NormalisedConfig;
signUpClicked?: () => void;
forgotPasswordClick: () => void;
- onSuccess: () => void;
+ onSuccess: (result: { user: User }) => void;
};
export type SignUpThemeProps = FormThemeBaseProps & {
@@ -254,7 +254,7 @@ export type SignUpThemeProps = FormThemeBaseProps & {
onError: (error: string) => void;
config: NormalisedConfig;
signInClicked?: () => void;
- onSuccess: () => void;
+ onSuccess: (result: { user: User }) => void;
};
export type SignInAndUpThemeProps = {
@@ -342,13 +342,21 @@ export type OnHandleEventContext =
/*
* On Handle Event actions
*/
- action: "RESET_PASSWORD_EMAIL_SENT" | "PASSWORD_RESET_SUCCESSFUL";
+ action: "RESET_PASSWORD_EMAIL_SENT";
+ email: string;
+ userContext: any;
+ }
+ | {
+ /*
+ * On Handle Event actions
+ */
+ action: "PASSWORD_RESET_SUCCESSFUL";
userContext: any;
}
| {
action: "SUCCESS";
- isNewUser: boolean;
- user: { id: string; email: string };
+ isNewRecipeUser: boolean;
+ user: User;
userContext: any;
};
diff --git a/lib/ts/recipe/passwordless/components/features/linkClickedScreen/index.tsx b/lib/ts/recipe/passwordless/components/features/linkClickedScreen/index.tsx
index d79c2991c..99181dee9 100644
--- a/lib/ts/recipe/passwordless/components/features/linkClickedScreen/index.tsx
+++ b/lib/ts/recipe/passwordless/components/features/linkClickedScreen/index.tsx
@@ -86,6 +86,16 @@ const LinkClickedScreen: React.FC = (props) => {
});
}
+ if (response.status === "SIGN_IN_UP_NOT_ALLOWED") {
+ return SuperTokens.getInstanceOrThrow().redirectToAuth({
+ history: props.history,
+ queryParams: {
+ error: response.reason,
+ },
+ redirectBack: false,
+ });
+ }
+
if (response.status === "OK") {
const loginAttemptInfo =
await props.recipe.webJSRecipe.getLoginAttemptInfo({
@@ -99,7 +109,8 @@ const LinkClickedScreen: React.FC = (props) => {
rid: props.recipe.config.recipeId,
successRedirectContext: {
action: "SUCCESS",
- isNewUser: response.createdNewUser,
+ isNewRecipeUser: response.createdNewRecipeUser,
+ user: response.user,
redirectToPath: loginAttemptInfo?.redirectToPath,
},
},
diff --git a/lib/ts/recipe/passwordless/components/features/signInAndUp/index.tsx b/lib/ts/recipe/passwordless/components/features/signInAndUp/index.tsx
index 831b70a13..49eb6f92f 100644
--- a/lib/ts/recipe/passwordless/components/features/signInAndUp/index.tsx
+++ b/lib/ts/recipe/passwordless/components/features/signInAndUp/index.tsx
@@ -35,7 +35,8 @@ import type { FeatureBaseProps } from "../../../../../types";
import type Recipe from "../../../recipe";
import type { AdditionalLoginAttemptInfoProperties, ComponentOverrideMap } from "../../../types";
import type { PasswordlessSignInUpAction, SignInUpState, SignInUpChildProps, NormalisedConfig } from "../../../types";
-import type { RecipeInterface, PasswordlessUser } from "supertokens-web-js/recipe/passwordless";
+import type { RecipeInterface } from "supertokens-web-js/recipe/passwordless";
+import type { User } from "supertokens-web-js/types";
export const useSuccessInAnotherTabChecker = (
state: SignInUpState,
@@ -214,13 +215,14 @@ export function useChildProps(
return undefined;
}
return {
- onSuccess: (result: { createdNewUser: boolean; user: PasswordlessUser }) => {
+ onSuccess: (result: { createdNewRecipeUser: boolean; user: User }) => {
return SessionRecipe.getInstanceOrThrow().validateGlobalClaimsAndHandleSuccessRedirection(
{
rid: recipe.config.recipeId,
successRedirectContext: {
action: "SUCCESS",
- isNewUser: result.createdNewUser,
+ isNewRecipeUser: result.createdNewRecipeUser,
+ user: result.user,
redirectToPath: getRedirectToPathFromURL(),
},
},
@@ -367,6 +369,12 @@ function getModifiedRecipeImplementation(
});
dispatch({ type: "restartFlow", error: "ERROR_SIGN_IN_UP_CODE_CONSUME_RESTART_FLOW" });
+ } else if (res.status === "SIGN_IN_UP_NOT_ALLOWED") {
+ await originalImpl.clearLoginAttemptInfo({
+ userContext: input.userContext,
+ });
+
+ dispatch({ type: "restartFlow", error: res.reason });
} else if (res.status === "OK") {
await originalImpl.clearLoginAttemptInfo({
userContext: input.userContext,
diff --git a/lib/ts/recipe/passwordless/components/themes/signInUp/emailForm.tsx b/lib/ts/recipe/passwordless/components/themes/signInUp/emailForm.tsx
index 3055e1165..451b60535 100644
--- a/lib/ts/recipe/passwordless/components/themes/signInUp/emailForm.tsx
+++ b/lib/ts/recipe/passwordless/components/themes/signInUp/emailForm.tsx
@@ -61,6 +61,10 @@ export const EmailForm = withOverride(
userContext,
});
+ if (response.status === "SIGN_IN_UP_NOT_ALLOWED") {
+ throw new STGeneralError(response.reason);
+ }
+
return response;
}}
validateOnBlur={false}
diff --git a/lib/ts/recipe/passwordless/components/themes/signInUp/emailOrPhoneForm.tsx b/lib/ts/recipe/passwordless/components/themes/signInUp/emailOrPhoneForm.tsx
index fbade3bfc..8e7bd9cb6 100644
--- a/lib/ts/recipe/passwordless/components/themes/signInUp/emailOrPhoneForm.tsx
+++ b/lib/ts/recipe/passwordless/components/themes/signInUp/emailOrPhoneForm.tsx
@@ -83,6 +83,10 @@ export const EmailOrPhoneForm = withOverride(
userContext,
});
+ if (response.status === "SIGN_IN_UP_NOT_ALLOWED") {
+ throw new STGeneralError(response.reason);
+ }
+
return response;
} else {
throw new STGeneralError(emailValidationRes);
@@ -95,6 +99,9 @@ export const EmailOrPhoneForm = withOverride(
userContext,
});
+ if (response.status === "SIGN_IN_UP_NOT_ALLOWED") {
+ throw new STGeneralError(response.reason);
+ }
return response;
}
@@ -108,10 +115,15 @@ export const EmailOrPhoneForm = withOverride(
const phoneValidationResAfterGuess = await props.config.validatePhoneNumber(intPhoneNumber);
if (phoneValidationResAfterGuess === undefined) {
try {
- return await props.recipeImplementation.createCode({
+ const response = await props.recipeImplementation.createCode({
phoneNumber: intPhoneNumber,
userContext,
});
+
+ if (response.status === "SIGN_IN_UP_NOT_ALLOWED") {
+ throw new STGeneralError(response.reason);
+ }
+ return response;
} catch (ex) {
// General errors from the API can make createCode throw but we want to switch to the phone UI anyway
setValue("emailOrPhone", intPhoneNumber);
diff --git a/lib/ts/recipe/passwordless/components/themes/signInUp/phoneForm.tsx b/lib/ts/recipe/passwordless/components/themes/signInUp/phoneForm.tsx
index 81f75c4aa..f081908da 100644
--- a/lib/ts/recipe/passwordless/components/themes/signInUp/phoneForm.tsx
+++ b/lib/ts/recipe/passwordless/components/themes/signInUp/phoneForm.tsx
@@ -77,6 +77,10 @@ export const PhoneForm = withOverride(
userContext,
});
+ if (response.status === "SIGN_IN_UP_NOT_ALLOWED") {
+ throw new STGeneralError(response.reason);
+ }
+
return response;
}}
validateOnBlur={false}
diff --git a/lib/ts/recipe/passwordless/components/themes/signInUp/userInputCodeForm.tsx b/lib/ts/recipe/passwordless/components/themes/signInUp/userInputCodeForm.tsx
index 57c772e06..7ce45d203 100644
--- a/lib/ts/recipe/passwordless/components/themes/signInUp/userInputCodeForm.tsx
+++ b/lib/ts/recipe/passwordless/components/themes/signInUp/userInputCodeForm.tsx
@@ -137,7 +137,13 @@ export const UserInputCodeForm = withOverride(
userContext,
});
- if (response.status === "OK" || response.status === "RESTART_FLOW_ERROR") {
+ // We can redirect these statuses, since they all cause a redirection
+ // and we don't really want to show anything
+ if (
+ response.status === "OK" ||
+ response.status === "RESTART_FLOW_ERROR" ||
+ response.status === "SIGN_IN_UP_NOT_ALLOWED"
+ ) {
return response;
}
diff --git a/lib/ts/recipe/passwordless/components/themes/translations.ts b/lib/ts/recipe/passwordless/components/themes/translations.ts
index 26cc2ffdc..0fa66ae81 100644
--- a/lib/ts/recipe/passwordless/components/themes/translations.ts
+++ b/lib/ts/recipe/passwordless/components/themes/translations.ts
@@ -79,5 +79,9 @@ export const defaultTranslationsPasswordless = {
"Failed to generate a one time code. Please try again": undefined,
"Phone number is invalid": undefined,
"Email is invalid": undefined,
+ "Cannot sign in / up due to security reasons. Please try a different login method or contact support. (ERR_CODE_002)":
+ undefined,
+ "Cannot sign in / up due to security reasons. Please try a different login method or contact support. (ERR_CODE_003)":
+ undefined,
},
};
diff --git a/lib/ts/recipe/passwordless/functionOverrides.ts b/lib/ts/recipe/passwordless/functionOverrides.ts
index b5b299a12..372cf858b 100644
--- a/lib/ts/recipe/passwordless/functionOverrides.ts
+++ b/lib/ts/recipe/passwordless/functionOverrides.ts
@@ -43,7 +43,7 @@ export const getFunctionOverrides =
} else if (response.status === "OK") {
onHandleEvent({
action: "SUCCESS",
- isNewUser: response.createdNewUser,
+ isNewRecipeUser: response.createdNewRecipeUser,
user: response.user,
});
}
diff --git a/lib/ts/recipe/passwordless/index.ts b/lib/ts/recipe/passwordless/index.ts
index 93f5c8e8c..d4ae09bec 100644
--- a/lib/ts/recipe/passwordless/index.ts
+++ b/lib/ts/recipe/passwordless/index.ts
@@ -23,7 +23,8 @@ import { UserInput } from "./types";
import { GetRedirectionURLContext, PreAPIHookContext, OnHandleEventContext } from "./types";
import type { RecipeFunctionOptions } from "supertokens-web-js/recipe/passwordless";
-import type { PasswordlessFlowType, PasswordlessUser } from "supertokens-web-js/recipe/passwordless/types";
+import type { PasswordlessFlowType } from "supertokens-web-js/recipe/passwordless/types";
+import type { User } from "supertokens-web-js/types";
export default class Wrapper {
static init(config: UserInput) {
@@ -40,13 +41,19 @@ export default class Wrapper {
input:
| { email: string; userContext?: any; options?: RecipeFunctionOptions }
| { phoneNumber: string; userContext?: any; options?: RecipeFunctionOptions }
- ): Promise<{
- status: "OK";
- deviceId: string;
- preAuthSessionId: string;
- flowType: PasswordlessFlowType;
- fetchResponse: Response;
- }> {
+ ): Promise<
+ | {
+ status: "OK";
+ deviceId: string;
+ preAuthSessionId: string;
+ flowType: PasswordlessFlowType;
+ fetchResponse: Response;
+ }
+ | {
+ status: "SIGN_IN_UP_NOT_ALLOWED";
+ reason: string;
+ }
+ > {
return Passwordless.getInstanceOrThrow().webJSRecipe.createCode({
...input,
userContext: getNormalisedUserContext(input?.userContext),
@@ -77,8 +84,8 @@ export default class Wrapper {
): Promise<
| {
status: "OK";
- createdNewUser: boolean;
- user: PasswordlessUser;
+ createdNewRecipeUser: boolean;
+ user: User;
fetchResponse: Response;
}
| {
@@ -88,6 +95,7 @@ export default class Wrapper {
fetchResponse: Response;
}
| { status: "RESTART_FLOW_ERROR"; fetchResponse: Response }
+ | { status: "SIGN_IN_UP_NOT_ALLOWED"; reason: string; fetchResponse: Response }
> {
return Passwordless.getInstanceOrThrow().webJSRecipe.consumeCode({
...input,
diff --git a/lib/ts/recipe/passwordless/types.ts b/lib/ts/recipe/passwordless/types.ts
index 5598ff13b..bd78c63ce 100644
--- a/lib/ts/recipe/passwordless/types.ts
+++ b/lib/ts/recipe/passwordless/types.ts
@@ -35,7 +35,8 @@ import type {
} from "../authRecipe/types";
import type { Dispatch } from "react";
import type WebJSRecipe from "supertokens-web-js/recipe/passwordless";
-import type { RecipeInterface, PasswordlessUser } from "supertokens-web-js/recipe/passwordless";
+import type { RecipeInterface } from "supertokens-web-js/recipe/passwordless";
+import type { User } from "supertokens-web-js/types";
export type PreAndPostAPIHookAction =
| "PASSWORDLESS_CREATE_CODE"
@@ -66,8 +67,8 @@ export type GetRedirectionURLContext = AuthRecipeModuleGetRedirectionURLContext;
export type OnHandleEventContext =
| {
action: "SUCCESS";
- isNewUser: boolean;
- user: PasswordlessUser;
+ isNewRecipeUser: boolean;
+ user: User;
}
| {
action: "PASSWORDLESS_RESTART_FLOW";
@@ -187,7 +188,7 @@ export type UserInput = (
export type SignInUpProps = {
recipeImplementation: RecipeImplementation;
config: NormalisedConfig;
- onSuccess?: (result: { createdNewUser: boolean; user: PasswordlessUser }) => void;
+ onSuccess?: (result: { createdNewRecipeUser: boolean; user: User }) => void;
dispatch: Dispatch;
featureState: {
loginAttemptInfo?: LoginAttemptInfo;
@@ -257,7 +258,7 @@ export type SignInUpUserInputCodeFormProps = {
recipeImplementation: RecipeImplementation;
config: NormalisedConfig;
loginAttemptInfo: LoginAttemptInfo;
- onSuccess?: (result: { createdNewUser: boolean; user: PasswordlessUser }) => void;
+ onSuccess?: (result: { createdNewRecipeUser: boolean; user: User }) => void;
};
export type LinkClickedScreenProps = {
diff --git a/lib/ts/recipe/session/recipe.tsx b/lib/ts/recipe/session/recipe.tsx
index 81ce43874..46f1ffb96 100644
--- a/lib/ts/recipe/session/recipe.tsx
+++ b/lib/ts/recipe/session/recipe.tsx
@@ -169,7 +169,8 @@ export default class Session extends RecipeModule = (props) => {
});
}
+ if (response.status === "SIGN_IN_UP_NOT_ALLOWED") {
+ return SuperTokens.getInstanceOrThrow().redirectToAuth({
+ history: props.history,
+ queryParams: {
+ error: response.status,
+ message: response.reason,
+ },
+ redirectBack: false,
+ });
+ }
+
if (response.status === "OK") {
const stateResponse = props.recipe.webJSRecipe.getStateAndOtherInfoFromStorage({
userContext,
@@ -65,7 +76,8 @@ const SignInAndUpCallback: React.FC = (props) => {
rid: props.recipe.config.recipeId,
successRedirectContext: {
action: "SUCCESS",
- isNewUser: response.createdNewUser,
+ isNewRecipeUser: response.createdNewRecipeUser,
+ user: response.user,
redirectToPath,
},
},
diff --git a/lib/ts/recipe/thirdparty/components/themes/translations.ts b/lib/ts/recipe/thirdparty/components/themes/translations.ts
index c9ed3258e..052ac5537 100644
--- a/lib/ts/recipe/thirdparty/components/themes/translations.ts
+++ b/lib/ts/recipe/thirdparty/components/themes/translations.ts
@@ -15,5 +15,19 @@ export const defaultTranslationsThirdParty = {
THIRD_PARTY_PROVIDER_DEFAULT_BTN_END: "",
THIRD_PARTY_ERROR_NO_EMAIL: "Could not retrieve email. Please try a different method.",
+
+ /*
+ * The following are error messages from our backend SDK.
+ * These are returned as full messages to preserver compatibilty, but they work just like the keys above.
+ * They are shown as is by default (setting the value to undefined will display the raw translation key)
+ */
+
+ "Cannot sign in / up due to security reasons. Please try a different login method or contact support. (ERR_CODE_004)":
+ undefined,
+ "Cannot sign in / up because new email cannot be applied to existing account. Please contact support. (ERR_CODE_005)":
+ undefined,
+
+ "Cannot sign in / up due to security reasons. Please try a different login method or contact support. (ERR_CODE_006)":
+ undefined,
},
};
diff --git a/lib/ts/recipe/thirdparty/functionOverrides.ts b/lib/ts/recipe/thirdparty/functionOverrides.ts
index 2070af3e4..5c5637cc3 100644
--- a/lib/ts/recipe/thirdparty/functionOverrides.ts
+++ b/lib/ts/recipe/thirdparty/functionOverrides.ts
@@ -14,7 +14,7 @@ export const getFunctionOverrides =
if (response.status === "OK") {
onHandleEvent({
action: "SUCCESS",
- isNewUser: response.createdNewUser,
+ isNewRecipeUser: response.createdNewRecipeUser,
user: response.user,
userContext: input.userContext,
});
diff --git a/lib/ts/recipe/thirdparty/index.ts b/lib/ts/recipe/thirdparty/index.ts
index 996e1bece..1ca8e57da 100644
--- a/lib/ts/recipe/thirdparty/index.ts
+++ b/lib/ts/recipe/thirdparty/index.ts
@@ -18,7 +18,7 @@
*/
// /!\ ThirdParty must be imported before any of the providers to prevent circular dependencies.
-import { RecipeInterface, ThirdPartyUserType as User } from "supertokens-web-js/recipe/thirdparty";
+import { RecipeInterface } from "supertokens-web-js/recipe/thirdparty";
import { getNormalisedUserContext } from "../../utils";
@@ -42,6 +42,7 @@ import { redirectToThirdPartyLogin as UtilsRedirectToThirdPartyLogin } from "./u
import type { StateObject } from "supertokens-web-js/recipe/thirdparty";
import type { RecipeFunctionOptions } from "supertokens-web-js/recipe/thirdpartyemailpassword";
+import type { User } from "supertokens-web-js/types";
export default class Wrapper {
/*
@@ -98,13 +99,18 @@ export default class Wrapper {
| {
status: "OK";
user: User;
- createdNewUser: boolean;
+ createdNewRecipeUser: boolean;
fetchResponse: Response;
}
| {
status: "NO_EMAIL_GIVEN_BY_PROVIDER";
fetchResponse: Response;
}
+ | {
+ status: "SIGN_IN_UP_NOT_ALLOWED";
+ reason: string;
+ fetchResponse: Response;
+ }
> {
return ThirdParty.getInstanceOrThrow().webJSRecipe.signInAndUp({
...input,
@@ -159,7 +165,6 @@ export {
redirectToThirdPartyLogin,
ThirdpartyComponentsOverrideProvider,
signOut,
- User,
GetRedirectionURLContext,
PreAPIHookContext,
OnHandleEventContext,
diff --git a/lib/ts/recipe/thirdparty/types.ts b/lib/ts/recipe/thirdparty/types.ts
index cc93bb2b3..6be339670 100644
--- a/lib/ts/recipe/thirdparty/types.ts
+++ b/lib/ts/recipe/thirdparty/types.ts
@@ -31,6 +31,7 @@ import type {
import type { OverrideableBuilder } from "supertokens-js-override";
import type ThirdPartyWebJS from "supertokens-web-js/recipe/thirdparty";
import type { StateObject as WebJsStateObject, RecipeInterface } from "supertokens-web-js/recipe/thirdparty";
+import type { User } from "supertokens-web-js/types";
export type ComponentOverrideMap = {
ThirdPartySignUpFooter_Override?: ComponentOverride;
@@ -123,8 +124,8 @@ export type OnHandleEventContext =
| AuthRecipeModuleOnHandleEventContext
| {
action: "SUCCESS";
- isNewUser: boolean;
- user: { id: string; email: string };
+ isNewRecipeUser: boolean;
+ user: User;
userContext: any;
};
diff --git a/lib/ts/recipe/thirdpartyemailpassword/functionOverrides.ts b/lib/ts/recipe/thirdpartyemailpassword/functionOverrides.ts
index 66b511aa1..0a3653072 100644
--- a/lib/ts/recipe/thirdpartyemailpassword/functionOverrides.ts
+++ b/lib/ts/recipe/thirdpartyemailpassword/functionOverrides.ts
@@ -14,7 +14,7 @@ export const getFunctionOverrides =
if (response.status === "OK") {
onHandleEvent({
action: "SUCCESS",
- isNewUser: response.createdNewUser,
+ isNewRecipeUser: response.createdNewRecipeUser,
user: response.user,
userContext: input.userContext,
});
@@ -58,6 +58,7 @@ export const getFunctionOverrides =
if (response.status === "OK") {
onHandleEvent({
action: "RESET_PASSWORD_EMAIL_SENT",
+ email: input.formFields.find(({ id }) => id === "email")!.value,
userContext: input.userContext,
});
}
@@ -70,7 +71,7 @@ export const getFunctionOverrides =
if (response.status === "OK") {
onHandleEvent({
action: "SUCCESS",
- isNewUser: true,
+ isNewRecipeUser: true,
user: response.user,
userContext: input.userContext,
});
@@ -84,7 +85,7 @@ export const getFunctionOverrides =
if (response.status === "OK") {
onHandleEvent({
action: "SUCCESS",
- isNewUser: false,
+ isNewRecipeUser: false,
user: response.user,
userContext: input.userContext,
});
diff --git a/lib/ts/recipe/thirdpartyemailpassword/index.ts b/lib/ts/recipe/thirdpartyemailpassword/index.ts
index 146aac166..f352812c9 100644
--- a/lib/ts/recipe/thirdpartyemailpassword/index.ts
+++ b/lib/ts/recipe/thirdpartyemailpassword/index.ts
@@ -12,11 +12,7 @@
* License for the specific language governing permissions and limitations
* under the License.
*/
-import {
- RecipeInterface,
- EmailPasswordUserType as UserType,
- ThirdPartyUserType,
-} from "supertokens-web-js/recipe/thirdpartyemailpassword";
+import { RecipeInterface } from "supertokens-web-js/recipe/thirdpartyemailpassword";
import { getNormalisedUserContext } from "../../utils";
import {
@@ -41,6 +37,7 @@ import { UserInput, GetRedirectionURLContext, PreAPIHookContext, OnHandleEventCo
import type { StateObject } from "supertokens-web-js/recipe/thirdparty";
import type { RecipeFunctionOptions } from "supertokens-web-js/recipe/thirdpartyemailpassword";
+import type { User } from "supertokens-web-js/types";
export default class Wrapper {
static init(config?: UserInput) {
@@ -62,7 +59,11 @@ export default class Wrapper {
userContext?: any;
}): Promise<
| {
- status: "OK" | "RESET_PASSWORD_INVALID_TOKEN_ERROR";
+ status: "OK";
+ fetchResponse: Response;
+ }
+ | {
+ status: "RESET_PASSWORD_INVALID_TOKEN_ERROR";
fetchResponse: Response;
}
| {
@@ -89,7 +90,7 @@ export default class Wrapper {
userContext?: any;
}): Promise<
| {
- status: "OK";
+ status: "OK" | "PASSWORD_RESET_NOT_ALLOWED";
fetchResponse: Response;
}
| {
@@ -117,7 +118,7 @@ export default class Wrapper {
}): Promise<
| {
status: "OK";
- user: UserType;
+ user: User;
fetchResponse: Response;
}
| {
@@ -128,6 +129,11 @@ export default class Wrapper {
}[];
fetchResponse: Response;
}
+ | {
+ status: "SIGN_UP_NOT_ALLOWED";
+ reason: string;
+ fetchResponse: Response;
+ }
> {
return ThirdPartyEmailPassword.getInstanceOrThrow().webJSRecipe.emailPasswordSignUp({
...input,
@@ -145,7 +151,7 @@ export default class Wrapper {
}): Promise<
| {
status: "OK";
- user: UserType;
+ user: User;
fetchResponse: Response;
}
| {
@@ -160,6 +166,11 @@ export default class Wrapper {
status: "WRONG_CREDENTIALS_ERROR";
fetchResponse: Response;
}
+ | {
+ status: "SIGN_IN_NOT_ALLOWED";
+ reason: string;
+ fetchResponse: Response;
+ }
> {
return ThirdPartyEmailPassword.getInstanceOrThrow().webJSRecipe.emailPasswordSignIn({
...input,
@@ -208,14 +219,19 @@ export default class Wrapper {
static async thirdPartySignInAndUp(input?: { userContext?: any; options?: RecipeFunctionOptions }): Promise<
| {
status: "OK";
- user: ThirdPartyUserType;
- createdNewUser: boolean;
+ user: User;
+ createdNewRecipeUser: boolean;
fetchResponse: Response;
}
| {
status: "NO_EMAIL_GIVEN_BY_PROVIDER";
fetchResponse: Response;
}
+ | {
+ status: "SIGN_IN_UP_NOT_ALLOWED";
+ reason: string;
+ fetchResponse: Response;
+ }
> {
return ThirdPartyEmailPassword.getInstanceOrThrow().webJSRecipe.thirdPartySignInAndUp({
...input,
@@ -305,6 +321,4 @@ export {
OnHandleEventContext,
UserInput,
RecipeInterface,
- UserType,
- ThirdPartyUserType,
};
diff --git a/lib/ts/recipe/thirdpartypasswordless/functionOverrides.ts b/lib/ts/recipe/thirdpartypasswordless/functionOverrides.ts
index 62f386f12..de3737de5 100644
--- a/lib/ts/recipe/thirdpartypasswordless/functionOverrides.ts
+++ b/lib/ts/recipe/thirdpartypasswordless/functionOverrides.ts
@@ -14,7 +14,7 @@ export const getFunctionOverrides =
if (response.status === "OK") {
onHandleEvent({
action: "SUCCESS",
- isNewUser: response.createdNewUser,
+ isNewRecipeUser: response.createdNewRecipeUser,
user: response.user,
userContext: input.userContext,
});
@@ -73,7 +73,7 @@ export const getFunctionOverrides =
} else if (response.status === "OK") {
onHandleEvent({
action: "SUCCESS",
- isNewUser: response.createdNewUser,
+ isNewRecipeUser: response.createdNewRecipeUser,
user: response.user,
});
}
diff --git a/lib/ts/recipe/thirdpartypasswordless/index.ts b/lib/ts/recipe/thirdpartypasswordless/index.ts
index 6efc183cd..7cb24c69c 100644
--- a/lib/ts/recipe/thirdpartypasswordless/index.ts
+++ b/lib/ts/recipe/thirdpartypasswordless/index.ts
@@ -35,12 +35,9 @@ import { RecipeComponentsOverrideContextProvider } from "./componentOverrideCont
import ThirdPartyPasswordless from "./recipe";
import { UserInput, GetRedirectionURLContext, PreAPIHookContext, OnHandleEventContext } from "./types";
-import type { StateObject, ThirdPartyUserType as UserType } from "supertokens-web-js/recipe/thirdparty";
-import type {
- PasswordlessFlowType,
- PasswordlessUser,
- RecipeFunctionOptions,
-} from "supertokens-web-js/recipe/thirdpartypasswordless";
+import type { StateObject } from "supertokens-web-js/recipe/thirdparty";
+import type { PasswordlessFlowType, RecipeFunctionOptions } from "supertokens-web-js/recipe/thirdpartypasswordless";
+import type { User } from "supertokens-web-js/types";
export default class Wrapper {
static init(config: UserInput) {
@@ -76,14 +73,19 @@ export default class Wrapper {
static async thirdPartySignInAndUp(input?: { userContext?: any; options?: RecipeFunctionOptions }): Promise<
| {
status: "OK";
- user: UserType;
- createdNewUser: boolean;
+ user: User;
+ createdNewRecipeUser: boolean;
fetchResponse: Response;
}
| {
status: "NO_EMAIL_GIVEN_BY_PROVIDER";
fetchResponse: Response;
}
+ | {
+ status: "SIGN_IN_UP_NOT_ALLOWED";
+ reason: string;
+ fetchResponse: Response;
+ }
> {
return ThirdPartyPasswordless.getInstanceOrThrow().webJSRecipe.thirdPartySignInAndUp({
...input,
@@ -119,13 +121,20 @@ export default class Wrapper {
input:
| { email: string; userContext?: any; options?: RecipeFunctionOptions }
| { phoneNumber: string; userContext?: any; options?: RecipeFunctionOptions }
- ): Promise<{
- status: "OK";
- deviceId: string;
- preAuthSessionId: string;
- flowType: PasswordlessFlowType;
- fetchResponse: Response;
- }> {
+ ): Promise<
+ | {
+ status: "OK";
+ deviceId: string;
+ preAuthSessionId: string;
+ flowType: PasswordlessFlowType;
+ fetchResponse: Response;
+ }
+ | {
+ status: "SIGN_IN_UP_NOT_ALLOWED";
+ reason: string;
+ fetchResponse: Response;
+ }
+ > {
return ThirdPartyPasswordless.getInstanceOrThrow().webJSRecipe.createPasswordlessCode({
...input,
userContext: getNormalisedUserContext(input.userContext),
@@ -156,8 +165,8 @@ export default class Wrapper {
): Promise<
| {
status: "OK";
- createdNewUser: boolean;
- user: PasswordlessUser;
+ createdNewRecipeUser: boolean;
+ user: User;
fetchResponse: Response;
}
| {
@@ -167,6 +176,7 @@ export default class Wrapper {
fetchResponse: Response;
}
| { status: "RESTART_FLOW_ERROR"; fetchResponse: Response }
+ | { status: "SIGN_IN_UP_NOT_ALLOWED"; reason: string; fetchResponse: Response }
> {
return ThirdPartyPasswordless.getInstanceOrThrow().webJSRecipe.consumePasswordlessCode({
...input,
diff --git a/lib/ts/version.ts b/lib/ts/version.ts
index 32897ee40..6da45ed4c 100644
--- a/lib/ts/version.ts
+++ b/lib/ts/version.ts
@@ -12,4 +12,4 @@
* License for the specific language governing permissions and limitations
* under the License.
*/
-export const package_version = "0.34.2";
+export const package_version = "0.35.0";
diff --git a/package-lock.json b/package-lock.json
index 0737d9dad..2a901d8ed 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "supertokens-auth-react",
- "version": "0.34.2",
+ "version": "0.35.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "supertokens-auth-react",
- "version": "0.34.2",
+ "version": "0.35.0",
"license": "Apache-2.0",
"dependencies": {
"intl-tel-input": "^17.0.19",
@@ -52,9 +52,9 @@
"jsdom-global": "3.0.2",
"madge": "^5.0.1",
"mkdirp": "^1.0.4",
- "mocha": "6.1.4",
- "mocha-junit-reporter": "^2.0.2",
- "mocha-multi": "1.1.6",
+ "mocha": "^10.2.0",
+ "mocha-junit-reporter": "^2.2.1",
+ "mocha-multi": "^1.1.7",
"mocha-split-tests": "github:rishabhpoddar/mocha-split-tests",
"npm-run-all": "^4.1.5",
"postcss": "^8.4.19",
@@ -88,7 +88,7 @@
"peerDependencies": {
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
- "supertokens-web-js": "^0.7.2"
+ "supertokens-web-js": "github:supertokens/supertokens-web-js#0.8"
}
},
"eslint": {
@@ -4903,9 +4903,9 @@
}
},
"node_modules/ansi-colors": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz",
- "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==",
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
+ "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
"dev": true,
"engines": {
"node": ">=6"
@@ -5070,25 +5070,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/array.prototype.reduce": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.5.tgz",
- "integrity": "sha512-kDdugMl7id9COE8R7MHF5jWk7Dqt/fs4Pv+JXoICnYwqpjjjbUurz6w5fT5IG6brLdJhv6/VoHB0H7oyIBXd+Q==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.20.4",
- "es-array-method-boxes-properly": "^1.0.0",
- "is-string": "^1.0.7"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/array.prototype.tosorted": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz",
@@ -6003,15 +5984,6 @@
"integrity": "sha512-NiujjUFB4SwScJq2bwbYUtXbZhBSlY6vYzm++3Q6oC+U+injTqfPYFK8wS9COOmb2lueqp0ZRB4nK1VYeHgNyw==",
"dev": true
},
- "node_modules/code-point-at": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
- "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/collect-v8-coverage": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz",
@@ -6904,12 +6876,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/es-array-method-boxes-properly": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz",
- "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==",
- "dev": true
- },
"node_modules/es-get-iterator": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz",
@@ -8017,13 +7983,10 @@
}
},
"node_modules/flat": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.1.tgz",
- "integrity": "sha512-FmTtBsHskrU6FJ2VxCnsDb84wu9zhmO3cUX2kGFb5tuwhfXxGciiT0oRY+cck35QmG+NmGh5eLz6lLCpWTqwpA==",
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
+ "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
"dev": true,
- "dependencies": {
- "is-buffer": "~2.0.3"
- },
"bin": {
"flat": "cli.js"
}
@@ -8074,29 +8037,6 @@
"rimraf": "bin.js"
}
},
- "node_modules/flat/node_modules/is-buffer": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz",
- "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/flatted": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz",
@@ -8467,15 +8407,6 @@
"node": ">=0.6.8"
}
},
- "node_modules/growl": {
- "version": "1.10.5",
- "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
- "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==",
- "dev": true,
- "engines": {
- "node": ">=4.x"
- }
- },
"node_modules/has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
@@ -8900,15 +8831,6 @@
"resolved": "https://registry.npmjs.org/intl-tel-input/-/intl-tel-input-17.0.21.tgz",
"integrity": "sha512-TfyPxLe41QZPOf6RqBxRE2dpQ0FThB/PBD/gRbxVhGW7IuYg30QD90x/vjmEo4vkZw7j8etxpVcjIZVRcG+Otw=="
},
- "node_modules/invert-kv": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz",
- "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/is-arguments": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
@@ -9168,6 +9090,15 @@
"node": ">=0.10.0"
}
},
+ "node_modules/is-plain-obj": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
+ "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/is-potential-custom-element-name": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
@@ -11857,18 +11788,6 @@
"node": ">=6"
}
},
- "node_modules/lcid": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz",
- "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==",
- "dev": true,
- "dependencies": {
- "invert-kv": "^2.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/leven": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
@@ -11994,15 +11913,80 @@
"dev": true
},
"node_modules/log-symbols": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz",
- "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
+ "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
"dev": true,
"dependencies": {
- "chalk": "^2.0.1"
+ "chalk": "^4.1.0",
+ "is-unicode-supported": "^0.1.0"
},
"engines": {
- "node": ">=4"
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/log-symbols/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/log-symbols/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/log-symbols/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/log-symbols/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/log-symbols/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
}
},
"node_modules/loglevel": {
@@ -12216,18 +12200,6 @@
"tmpl": "1.0.5"
}
},
- "node_modules/map-age-cleaner": {
- "version": "0.1.3",
- "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz",
- "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==",
- "dev": true,
- "dependencies": {
- "p-defer": "^1.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/marked": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz",
@@ -12287,20 +12259,6 @@
"is-buffer": "~1.1.6"
}
},
- "node_modules/mem": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz",
- "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==",
- "dev": true,
- "dependencies": {
- "map-age-cleaner": "^0.1.1",
- "mimic-fn": "^2.0.0",
- "p-is-promise": "^2.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/memorystream": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz",
@@ -12417,41 +12375,43 @@
"dev": true
},
"node_modules/mocha": {
- "version": "6.1.4",
- "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.1.4.tgz",
- "integrity": "sha512-PN8CIy4RXsIoxoFJzS4QNnCH4psUCPWc4/rPrst/ecSJJbLBkubMiyGCP2Kj/9YnWbotFqAoeXyXMucj7gwCFg==",
+ "version": "10.2.0",
+ "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz",
+ "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==",
"dev": true,
"dependencies": {
- "ansi-colors": "3.2.3",
+ "ansi-colors": "4.1.1",
"browser-stdout": "1.3.1",
- "debug": "3.2.6",
- "diff": "3.5.0",
- "escape-string-regexp": "1.0.5",
- "find-up": "3.0.0",
- "glob": "7.1.3",
- "growl": "1.10.5",
+ "chokidar": "3.5.3",
+ "debug": "4.3.4",
+ "diff": "5.0.0",
+ "escape-string-regexp": "4.0.0",
+ "find-up": "5.0.0",
+ "glob": "7.2.0",
"he": "1.2.0",
- "js-yaml": "3.13.1",
- "log-symbols": "2.2.0",
- "minimatch": "3.0.4",
- "mkdirp": "0.5.1",
- "ms": "2.1.1",
- "node-environment-flags": "1.0.5",
- "object.assign": "4.1.0",
- "strip-json-comments": "2.0.1",
- "supports-color": "6.0.0",
- "which": "1.3.1",
- "wide-align": "1.1.3",
- "yargs": "13.2.2",
- "yargs-parser": "13.0.0",
- "yargs-unparser": "1.5.0"
+ "js-yaml": "4.1.0",
+ "log-symbols": "4.1.0",
+ "minimatch": "5.0.1",
+ "ms": "2.1.3",
+ "nanoid": "3.3.3",
+ "serialize-javascript": "6.0.0",
+ "strip-json-comments": "3.1.1",
+ "supports-color": "8.1.1",
+ "workerpool": "6.2.1",
+ "yargs": "16.2.0",
+ "yargs-parser": "20.2.4",
+ "yargs-unparser": "2.0.0"
},
"bin": {
"_mocha": "bin/_mocha",
- "mocha": "bin/mocha"
+ "mocha": "bin/mocha.js"
},
"engines": {
- "node": ">= 6.0.0"
+ "node": ">= 14.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mochajs"
}
},
"node_modules/mocha-junit-reporter": {
@@ -12498,9 +12458,9 @@
}
},
"node_modules/mocha-multi": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/mocha-multi/-/mocha-multi-1.1.6.tgz",
- "integrity": "sha512-hMVmd9C1h4PEiFNwHxn8aa5/EgGLg0UswdOrlrq1Y8ieKmot8hZLYaiESIgg/He3E4oxwaXPWT1V1PJ0qNJlUQ==",
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/mocha-multi/-/mocha-multi-1.1.7.tgz",
+ "integrity": "sha512-SXZRgHy0XiRTASyOp0p6fjOkdj+R62L6cqutnYyQOvIjNznJuUwzykxctypeRiOwPd+gfn4yt3NRulMQyI8Tzg==",
"dev": true,
"dependencies": {
"debug": "^4.1.1",
@@ -12513,7 +12473,7 @@
"node": ">=6.0.0"
},
"peerDependencies": {
- "mocha": ">=2.2.0 <7 || ^9"
+ "mocha": ">=2.2.0 <7 || >=9"
}
},
"node_modules/mocha-split-tests": {
@@ -12553,80 +12513,97 @@
"url": "https://github.com/sponsors/isaacs"
}
},
- "node_modules/mocha/node_modules/ansi-regex": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz",
- "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==",
+ "node_modules/mocha/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
"engines": {
- "node": ">=4"
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
+ "node_modules/mocha/node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true
+ },
"node_modules/mocha/node_modules/cliui": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz",
- "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==",
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+ "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
"dev": true,
"dependencies": {
- "string-width": "^2.1.1",
- "strip-ansi": "^4.0.0",
- "wrap-ansi": "^2.0.0"
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^7.0.0"
}
},
- "node_modules/mocha/node_modules/cliui/node_modules/string-width": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
- "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+ "node_modules/mocha/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"dependencies": {
- "is-fullwidth-code-point": "^2.0.0",
- "strip-ansi": "^4.0.0"
+ "color-name": "~1.1.4"
},
"engines": {
- "node": ">=4"
+ "node": ">=7.0.0"
}
},
- "node_modules/mocha/node_modules/debug": {
- "version": "3.2.6",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
- "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
- "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)",
- "dev": true,
- "dependencies": {
- "ms": "^2.1.1"
- }
+ "node_modules/mocha/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
},
"node_modules/mocha/node_modules/diff": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
- "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
+ "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
"dev": true,
"engines": {
"node": ">=0.3.1"
}
},
- "node_modules/mocha/node_modules/emoji-regex": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
- "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
- "dev": true
+ "node_modules/mocha/node_modules/escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
},
"node_modules/mocha/node_modules/find-up": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
- "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
"dev": true,
"dependencies": {
- "locate-path": "^3.0.0"
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
},
"engines": {
- "node": ">=6"
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/mocha/node_modules/glob": {
- "version": "7.1.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
- "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
+ "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
"dev": true,
"dependencies": {
"fs.realpath": "^1.0.0",
@@ -12638,297 +12615,173 @@
},
"engines": {
"node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
}
},
- "node_modules/mocha/node_modules/has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/mocha/node_modules/is-fullwidth-code-point": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
- "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==",
+ "node_modules/mocha/node_modules/glob/node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
"engines": {
- "node": ">=4"
+ "node": "*"
}
},
"node_modules/mocha/node_modules/js-yaml": {
- "version": "3.13.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
- "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"dev": true,
"dependencies": {
- "argparse": "^1.0.7",
- "esprima": "^4.0.0"
+ "argparse": "^2.0.1"
},
"bin": {
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/mocha/node_modules/locate-path": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
- "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
"dev": true,
"dependencies": {
- "p-locate": "^3.0.0",
- "path-exists": "^3.0.0"
+ "p-locate": "^5.0.0"
},
"engines": {
- "node": ">=6"
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/mocha/node_modules/minimatch": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
- "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz",
+ "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
"dev": true,
"dependencies": {
- "brace-expansion": "^1.1.7"
+ "brace-expansion": "^2.0.1"
},
"engines": {
- "node": "*"
+ "node": ">=10"
}
},
- "node_modules/mocha/node_modules/minimist": {
- "version": "0.0.8",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
- "integrity": "sha512-miQKw5Hv4NS1Psg2517mV4e4dYNaO3++hjAvLOAzKqZ61rH8NS1SK+vbfBWZ5PY/Me/bEWhUwqMghEW5Fb9T7Q==",
- "dev": true
- },
- "node_modules/mocha/node_modules/mkdirp": {
- "version": "0.5.1",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
- "integrity": "sha512-SknJC52obPfGQPnjIkXbmA6+5H15E+fR+E4iR2oQ3zzCLbd7/ONua69R/Gw7AgkTLsRG+r5fzksYwWe1AgTyWA==",
- "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)",
+ "node_modules/mocha/node_modules/minimatch/node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dev": true,
"dependencies": {
- "minimist": "0.0.8"
- },
- "bin": {
- "mkdirp": "bin/cmd.js"
+ "balanced-match": "^1.0.0"
}
},
"node_modules/mocha/node_modules/ms": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
- "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true
},
- "node_modules/mocha/node_modules/object.assign": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz",
- "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==",
+ "node_modules/mocha/node_modules/nanoid": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz",
+ "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==",
"dev": true,
- "dependencies": {
- "define-properties": "^1.1.2",
- "function-bind": "^1.1.1",
- "has-symbols": "^1.0.0",
- "object-keys": "^1.0.11"
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
},
"engines": {
- "node": ">= 0.4"
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
- "node_modules/mocha/node_modules/p-limit": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
- "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "node_modules/mocha/node_modules/p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
"dev": true,
"dependencies": {
- "p-try": "^2.0.0"
+ "p-limit": "^3.0.2"
},
"engines": {
- "node": ">=6"
+ "node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/mocha/node_modules/p-locate": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
- "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
- "dev": true,
- "dependencies": {
- "p-limit": "^2.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/mocha/node_modules/path-exists": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
- "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/mocha/node_modules/string-width": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
- "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
- "dev": true,
- "dependencies": {
- "emoji-regex": "^7.0.1",
- "is-fullwidth-code-point": "^2.0.0",
- "strip-ansi": "^5.1.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/mocha/node_modules/string-width/node_modules/ansi-regex": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
- "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/mocha/node_modules/string-width/node_modules/strip-ansi": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
- "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
- "dev": true,
- "dependencies": {
- "ansi-regex": "^4.1.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/mocha/node_modules/strip-ansi": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
- "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==",
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"dependencies": {
- "ansi-regex": "^3.0.0"
+ "ansi-regex": "^5.0.1"
},
"engines": {
- "node": ">=4"
- }
- },
- "node_modules/mocha/node_modules/strip-json-comments": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
- "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
+ "node": ">=8"
}
},
"node_modules/mocha/node_modules/supports-color": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz",
- "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==",
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+ "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
"dev": true,
"dependencies": {
- "has-flag": "^3.0.0"
+ "has-flag": "^4.0.0"
},
"engines": {
- "node": ">=6"
- }
- },
- "node_modules/mocha/node_modules/which": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
- "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
- "dev": true,
- "dependencies": {
- "isexe": "^2.0.0"
+ "node": ">=10"
},
- "bin": {
- "which": "bin/which"
+ "funding": {
+ "url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
"node_modules/mocha/node_modules/wrap-ansi": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
- "integrity": "sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==",
- "dev": true,
- "dependencies": {
- "string-width": "^1.0.1",
- "strip-ansi": "^3.0.1"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/mocha/node_modules/wrap-ansi/node_modules/ansi-regex": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
- "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/mocha/node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
- "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==",
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"dev": true,
"dependencies": {
- "number-is-nan": "^1.0.0"
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
},
"engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/mocha/node_modules/wrap-ansi/node_modules/string-width": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
- "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==",
- "dev": true,
- "dependencies": {
- "code-point-at": "^1.0.0",
- "is-fullwidth-code-point": "^1.0.0",
- "strip-ansi": "^3.0.0"
+ "node": ">=10"
},
- "engines": {
- "node": ">=0.10.0"
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
- "node_modules/mocha/node_modules/wrap-ansi/node_modules/strip-ansi": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
- "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==",
+ "node_modules/mocha/node_modules/y18n": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
"dev": true,
- "dependencies": {
- "ansi-regex": "^2.0.0"
- },
"engines": {
- "node": ">=0.10.0"
+ "node": ">=10"
}
},
"node_modules/mocha/node_modules/yargs": {
- "version": "13.2.2",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.2.tgz",
- "integrity": "sha512-WyEoxgyTD3w5XRpAQNYUB9ycVH/PQrToaTXdYXRdOXvEy1l19br+VJsc0vcO8PTGg5ro/l/GY7F/JMEBmI0BxA==",
+ "version": "16.2.0",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
+ "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
"dev": true,
"dependencies": {
- "cliui": "^4.0.0",
- "find-up": "^3.0.0",
- "get-caller-file": "^2.0.1",
- "os-locale": "^3.1.0",
+ "cliui": "^7.0.2",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
"require-directory": "^2.1.1",
- "require-main-filename": "^2.0.0",
- "set-blocking": "^2.0.0",
- "string-width": "^3.0.0",
- "which-module": "^2.0.0",
- "y18n": "^4.0.0",
- "yargs-parser": "^13.0.0"
+ "string-width": "^4.2.0",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^20.2.2"
+ },
+ "engines": {
+ "node": ">=10"
}
},
"node_modules/module-definition": {
@@ -13068,16 +12921,6 @@
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
"dev": true
},
- "node_modules/node-environment-flags": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz",
- "integrity": "sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==",
- "dev": true,
- "dependencies": {
- "object.getownpropertydescriptors": "^2.0.3",
- "semver": "^5.7.0"
- }
- },
"node_modules/node-fetch": {
"version": "2.6.12",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz",
@@ -13269,15 +13112,6 @@
"node": ">=8"
}
},
- "node_modules/number-is-nan": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
- "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/nwsapi": {
"version": "2.2.7",
"resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz",
@@ -13376,25 +13210,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/object.getownpropertydescriptors": {
- "version": "2.1.6",
- "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.6.tgz",
- "integrity": "sha512-lq+61g26E/BgHv0ZTFgRvi7NMEPuAxLkFU7rukXjc/AlwH4Am5xXVnIXy3un1bg/JPbXHrixRkK1itUzzPiIjQ==",
- "dev": true,
- "dependencies": {
- "array.prototype.reduce": "^1.0.5",
- "call-bind": "^1.0.2",
- "define-properties": "^1.2.0",
- "es-abstract": "^1.21.2",
- "safe-array-concat": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.8"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/object.hasown": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.2.tgz",
@@ -13555,22 +13370,6 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
- "node_modules/ora/node_modules/log-symbols": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
- "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
- "dev": true,
- "dependencies": {
- "chalk": "^4.1.0",
- "is-unicode-supported": "^0.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/ora/node_modules/strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
@@ -13595,187 +13394,37 @@
"node": ">=8"
}
},
- "node_modules/os-locale": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz",
- "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==",
+ "node_modules/os-tmpdir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+ "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
"dev": true,
- "dependencies": {
- "execa": "^1.0.0",
- "lcid": "^2.0.0",
- "mem": "^4.0.0"
- },
"engines": {
- "node": ">=6"
+ "node": ">=0.10.0"
}
},
- "node_modules/os-locale/node_modules/cross-spawn": {
- "version": "6.0.5",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
- "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
+ "node_modules/p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
"dev": true,
"dependencies": {
- "nice-try": "^1.0.4",
- "path-key": "^2.0.1",
- "semver": "^5.5.0",
- "shebang-command": "^1.2.0",
- "which": "^1.2.9"
+ "yocto-queue": "^0.1.0"
},
"engines": {
- "node": ">=4.8"
- }
- },
- "node_modules/os-locale/node_modules/execa": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
- "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
- "dev": true,
- "dependencies": {
- "cross-spawn": "^6.0.0",
- "get-stream": "^4.0.0",
- "is-stream": "^1.1.0",
- "npm-run-path": "^2.0.0",
- "p-finally": "^1.0.0",
- "signal-exit": "^3.0.0",
- "strip-eof": "^1.0.0"
+ "node": ">=10"
},
- "engines": {
- "node": ">=6"
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/os-locale/node_modules/get-stream": {
+ "node_modules/p-locate": {
"version": "4.1.0",
- "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
- "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
"dev": true,
"dependencies": {
- "pump": "^3.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/os-locale/node_modules/is-stream": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
- "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/os-locale/node_modules/npm-run-path": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
- "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==",
- "dev": true,
- "dependencies": {
- "path-key": "^2.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/os-locale/node_modules/path-key": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
- "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/os-locale/node_modules/shebang-command": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
- "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==",
- "dev": true,
- "dependencies": {
- "shebang-regex": "^1.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/os-locale/node_modules/shebang-regex": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
- "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/os-locale/node_modules/which": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
- "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
- "dev": true,
- "dependencies": {
- "isexe": "^2.0.0"
- },
- "bin": {
- "which": "bin/which"
- }
- },
- "node_modules/os-tmpdir": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
- "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/p-defer": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz",
- "integrity": "sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/p-finally": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
- "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/p-is-promise": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz",
- "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/p-limit": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
- "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
- "dev": true,
- "dependencies": {
- "yocto-queue": "^0.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/p-locate": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
- "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
- "dev": true,
- "dependencies": {
- "p-limit": "^2.2.0"
+ "p-limit": "^2.2.0"
},
"engines": {
"node": ">=8"
@@ -15163,6 +14812,15 @@
"integrity": "sha512-twwRO/ilhlG/FIgYeKGFqyHhoEhqgnKVkcmqMKi2r524gz3ZbDTcyFt38E9xjJI2vT+KbRNHVbnJ/e0I25Azwg==",
"dev": true
},
+ "node_modules/randombytes": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+ "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
+ "dev": true,
+ "dependencies": {
+ "safe-buffer": "^5.1.0"
+ }
+ },
"node_modules/rc": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
@@ -16089,6 +15747,15 @@
"semver": "bin/semver"
}
},
+ "node_modules/serialize-javascript": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
+ "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
+ "dev": true,
+ "dependencies": {
+ "randombytes": "^2.1.0"
+ }
+ },
"node_modules/set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
@@ -16515,15 +16182,6 @@
"node": ">=8"
}
},
- "node_modules/strip-eof": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
- "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/strip-final-newline": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
@@ -16585,19 +16243,19 @@
"integrity": "sha512-r0JFBjkMIdep3Lbk3JA+MpnpuOtw4RSyrlRAbrzMcxwiYco3GFWl/daimQZ5b1forOiUODpOlXbSOljP/oyurg=="
},
"node_modules/supertokens-web-js": {
- "version": "0.7.2",
- "resolved": "https://registry.npmjs.org/supertokens-web-js/-/supertokens-web-js-0.7.2.tgz",
- "integrity": "sha512-8TQFfuDzOkdbP/br7AHI8PJaslAYOVmHKT9rxb+v2cuFXYbZzHKoZeY12C1hepqHED8Cbt+rnIIVb2VUYlzd/w==",
+ "version": "0.8.0",
+ "resolved": "git+ssh://git@github.com/supertokens/supertokens-web-js.git#3f2549680195dc660326eff9df13b150ff9fcbbd",
+ "license": "Apache-2.0",
"peer": true,
"dependencies": {
"supertokens-js-override": "0.0.4",
- "supertokens-website": "^17.0.1"
+ "supertokens-website": "^17.0.3"
}
},
"node_modules/supertokens-website": {
- "version": "17.0.2",
- "resolved": "https://registry.npmjs.org/supertokens-website/-/supertokens-website-17.0.2.tgz",
- "integrity": "sha512-ki19f8Bl24iypXOtnCj/ebMA7hi0WxCe1f0fItGXkOV0fVAkRCYVqAKf7wiLQ3Lwhc+us4cgOQwRLIvctLrrUg==",
+ "version": "17.0.3",
+ "resolved": "https://registry.npmjs.org/supertokens-website/-/supertokens-website-17.0.3.tgz",
+ "integrity": "sha512-+5qMuii8mp3TEPX5HKLt48A4gzKM8cmnoYmFeoecLeylfY3mEAeL7AbAVjCp6On/s/xvvH6Q22fOEoCFf5Tu/g==",
"peer": true,
"dependencies": {
"browser-tabs-lock": "^1.3.0",
@@ -17708,58 +17366,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/wide-align": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
- "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
- "dev": true,
- "dependencies": {
- "string-width": "^1.0.2 || 2"
- }
- },
- "node_modules/wide-align/node_modules/ansi-regex": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz",
- "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/wide-align/node_modules/is-fullwidth-code-point": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
- "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/wide-align/node_modules/string-width": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
- "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
- "dev": true,
- "dependencies": {
- "is-fullwidth-code-point": "^2.0.0",
- "strip-ansi": "^4.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/wide-align/node_modules/strip-ansi": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
- "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==",
- "dev": true,
- "dependencies": {
- "ansi-regex": "^3.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/word-wrap": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz",
@@ -17769,6 +17375,12 @@
"node": ">=0.10.0"
}
},
+ "node_modules/workerpool": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz",
+ "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==",
+ "dev": true
+ },
"node_modules/wrap-ansi": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
@@ -17958,50 +17570,69 @@
}
},
"node_modules/yargs-parser": {
- "version": "13.0.0",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.0.0.tgz",
- "integrity": "sha512-w2LXjoL8oRdRQN+hOyppuXs+V/fVAYtpcrRxZuF7Kt/Oc+Jr2uAcVntaUTNT6w5ihoWfFDpNY8CPx1QskxZ/pw==",
+ "version": "20.2.4",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
+ "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==",
"dev": true,
- "dependencies": {
- "camelcase": "^5.0.0",
- "decamelize": "^1.2.0"
+ "engines": {
+ "node": ">=10"
}
},
"node_modules/yargs-unparser": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.5.0.tgz",
- "integrity": "sha512-HK25qidFTCVuj/D1VfNiEndpLIeJN78aqgR23nL3y4N0U/91cOAzqfHlF8n2BvoNDcZmJKin3ddNSvOxSr8flw==",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz",
+ "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==",
"dev": true,
"dependencies": {
- "flat": "^4.1.0",
- "lodash": "^4.17.11",
- "yargs": "^12.0.5"
+ "camelcase": "^6.0.0",
+ "decamelize": "^4.0.0",
+ "flat": "^5.0.2",
+ "is-plain-obj": "^2.1.0"
},
"engines": {
- "node": ">=6"
+ "node": ">=10"
}
},
- "node_modules/yargs-unparser/node_modules/ansi-regex": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz",
- "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==",
+ "node_modules/yargs-unparser/node_modules/camelcase": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
+ "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
"dev": true,
"engines": {
- "node": ">=4"
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/yargs-unparser/node_modules/cliui": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz",
- "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==",
+ "node_modules/yargs-unparser/node_modules/decamelize": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
+ "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
"dev": true,
- "dependencies": {
- "string-width": "^2.1.1",
- "strip-ansi": "^4.0.0",
- "wrap-ansi": "^2.0.0"
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/yargs/node_modules/ansi-regex": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
+ "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
}
},
- "node_modules/yargs-unparser/node_modules/find-up": {
+ "node_modules/yargs/node_modules/emoji-regex": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
+ "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
+ "dev": true
+ },
+ "node_modules/yargs/node_modules/find-up": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
"integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
@@ -18013,13 +17644,7 @@
"node": ">=6"
}
},
- "node_modules/yargs-unparser/node_modules/get-caller-file": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
- "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==",
- "dev": true
- },
- "node_modules/yargs-unparser/node_modules/is-fullwidth-code-point": {
+ "node_modules/yargs/node_modules/is-fullwidth-code-point": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
"integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==",
@@ -18028,7 +17653,7 @@
"node": ">=4"
}
},
- "node_modules/yargs-unparser/node_modules/locate-path": {
+ "node_modules/yargs/node_modules/locate-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
"integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
@@ -18041,7 +17666,7 @@
"node": ">=6"
}
},
- "node_modules/yargs-unparser/node_modules/p-limit": {
+ "node_modules/yargs/node_modules/p-limit": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
@@ -18056,7 +17681,7 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/yargs-unparser/node_modules/p-locate": {
+ "node_modules/yargs/node_modules/p-locate": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
"integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
@@ -18068,7 +17693,7 @@
"node": ">=6"
}
},
- "node_modules/yargs-unparser/node_modules/path-exists": {
+ "node_modules/yargs/node_modules/path-exists": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
"integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
@@ -18077,256 +17702,50 @@
"node": ">=4"
}
},
- "node_modules/yargs-unparser/node_modules/require-main-filename": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
- "integrity": "sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==",
- "dev": true
- },
- "node_modules/yargs-unparser/node_modules/string-width": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
- "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+ "node_modules/yargs/node_modules/string-width": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
+ "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
"dev": true,
"dependencies": {
+ "emoji-regex": "^7.0.1",
"is-fullwidth-code-point": "^2.0.0",
- "strip-ansi": "^4.0.0"
+ "strip-ansi": "^5.1.0"
},
"engines": {
- "node": ">=4"
+ "node": ">=6"
}
},
- "node_modules/yargs-unparser/node_modules/strip-ansi": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
- "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==",
+ "node_modules/yargs/node_modules/strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
"dev": true,
"dependencies": {
- "ansi-regex": "^3.0.0"
+ "ansi-regex": "^4.1.0"
},
"engines": {
- "node": ">=4"
+ "node": ">=6"
}
},
- "node_modules/yargs-unparser/node_modules/wrap-ansi": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
- "integrity": "sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==",
+ "node_modules/yargs/node_modules/yargs-parser": {
+ "version": "13.1.2",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
+ "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
"dev": true,
"dependencies": {
- "string-width": "^1.0.1",
- "strip-ansi": "^3.0.1"
- },
- "engines": {
- "node": ">=0.10.0"
+ "camelcase": "^5.0.0",
+ "decamelize": "^1.2.0"
}
},
- "node_modules/yargs-unparser/node_modules/wrap-ansi/node_modules/ansi-regex": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
- "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
+ "node_modules/yauzl": {
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
+ "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==",
"dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/yargs-unparser/node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
- "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==",
- "dev": true,
- "dependencies": {
- "number-is-nan": "^1.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/yargs-unparser/node_modules/wrap-ansi/node_modules/string-width": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
- "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==",
- "dev": true,
- "dependencies": {
- "code-point-at": "^1.0.0",
- "is-fullwidth-code-point": "^1.0.0",
- "strip-ansi": "^3.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/yargs-unparser/node_modules/wrap-ansi/node_modules/strip-ansi": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
- "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==",
- "dev": true,
- "dependencies": {
- "ansi-regex": "^2.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/yargs-unparser/node_modules/yargs": {
- "version": "12.0.5",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz",
- "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==",
- "dev": true,
- "dependencies": {
- "cliui": "^4.0.0",
- "decamelize": "^1.2.0",
- "find-up": "^3.0.0",
- "get-caller-file": "^1.0.1",
- "os-locale": "^3.0.0",
- "require-directory": "^2.1.1",
- "require-main-filename": "^1.0.1",
- "set-blocking": "^2.0.0",
- "string-width": "^2.0.0",
- "which-module": "^2.0.0",
- "y18n": "^3.2.1 || ^4.0.0",
- "yargs-parser": "^11.1.1"
- }
- },
- "node_modules/yargs-unparser/node_modules/yargs-parser": {
- "version": "11.1.1",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz",
- "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==",
- "dev": true,
- "dependencies": {
- "camelcase": "^5.0.0",
- "decamelize": "^1.2.0"
- }
- },
- "node_modules/yargs/node_modules/ansi-regex": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
- "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/yargs/node_modules/emoji-regex": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
- "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
- "dev": true
- },
- "node_modules/yargs/node_modules/find-up": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
- "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
- "dev": true,
- "dependencies": {
- "locate-path": "^3.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/yargs/node_modules/is-fullwidth-code-point": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
- "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/yargs/node_modules/locate-path": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
- "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
- "dev": true,
- "dependencies": {
- "p-locate": "^3.0.0",
- "path-exists": "^3.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/yargs/node_modules/p-limit": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
- "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
- "dev": true,
- "dependencies": {
- "p-try": "^2.0.0"
- },
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/yargs/node_modules/p-locate": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
- "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
- "dev": true,
- "dependencies": {
- "p-limit": "^2.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/yargs/node_modules/path-exists": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
- "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/yargs/node_modules/string-width": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
- "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
- "dev": true,
- "dependencies": {
- "emoji-regex": "^7.0.1",
- "is-fullwidth-code-point": "^2.0.0",
- "strip-ansi": "^5.1.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/yargs/node_modules/strip-ansi": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
- "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
- "dev": true,
- "dependencies": {
- "ansi-regex": "^4.1.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/yargs/node_modules/yargs-parser": {
- "version": "13.1.2",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
- "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
- "dev": true,
- "dependencies": {
- "camelcase": "^5.0.0",
- "decamelize": "^1.2.0"
- }
- },
- "node_modules/yauzl": {
- "version": "2.10.0",
- "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
- "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==",
- "dev": true,
- "dependencies": {
- "buffer-crc32": "~0.2.3",
- "fd-slicer": "~1.1.0"
+ "dependencies": {
+ "buffer-crc32": "~0.2.3",
+ "fd-slicer": "~1.1.0"
}
},
"node_modules/yocto-queue": {
@@ -21706,9 +21125,9 @@
}
},
"ansi-colors": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz",
- "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==",
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
+ "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
"dev": true
},
"ansi-escapes": {
@@ -21828,19 +21247,6 @@
"es-shim-unscopables": "^1.0.0"
}
},
- "array.prototype.reduce": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.5.tgz",
- "integrity": "sha512-kDdugMl7id9COE8R7MHF5jWk7Dqt/fs4Pv+JXoICnYwqpjjjbUurz6w5fT5IG6brLdJhv6/VoHB0H7oyIBXd+Q==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.20.4",
- "es-array-method-boxes-properly": "^1.0.0",
- "is-string": "^1.0.7"
- }
- },
"array.prototype.tosorted": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz",
@@ -22482,12 +21888,6 @@
"integrity": "sha512-NiujjUFB4SwScJq2bwbYUtXbZhBSlY6vYzm++3Q6oC+U+injTqfPYFK8wS9COOmb2lueqp0ZRB4nK1VYeHgNyw==",
"dev": true
},
- "code-point-at": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
- "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==",
- "dev": true
- },
"collect-v8-coverage": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz",
@@ -23152,12 +22552,6 @@
"which-typed-array": "^1.1.10"
}
},
- "es-array-method-boxes-properly": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz",
- "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==",
- "dev": true
- },
"es-get-iterator": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz",
@@ -24012,21 +23406,10 @@
}
},
"flat": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.1.tgz",
- "integrity": "sha512-FmTtBsHskrU6FJ2VxCnsDb84wu9zhmO3cUX2kGFb5tuwhfXxGciiT0oRY+cck35QmG+NmGh5eLz6lLCpWTqwpA==",
- "dev": true,
- "requires": {
- "is-buffer": "~2.0.3"
- },
- "dependencies": {
- "is-buffer": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz",
- "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==",
- "dev": true
- }
- }
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
+ "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
+ "dev": true
},
"flat-cache": {
"version": "2.0.1",
@@ -24339,12 +23722,6 @@
"temp": "~0.4.0"
}
},
- "growl": {
- "version": "1.10.5",
- "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
- "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==",
- "dev": true
- },
"has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
@@ -24650,12 +24027,6 @@
"resolved": "https://registry.npmjs.org/intl-tel-input/-/intl-tel-input-17.0.21.tgz",
"integrity": "sha512-TfyPxLe41QZPOf6RqBxRE2dpQ0FThB/PBD/gRbxVhGW7IuYg30QD90x/vjmEo4vkZw7j8etxpVcjIZVRcG+Otw=="
},
- "invert-kv": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz",
- "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==",
- "dev": true
- },
"is-arguments": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
@@ -24828,6 +24199,12 @@
"integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==",
"dev": true
},
+ "is-plain-obj": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
+ "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
+ "dev": true
+ },
"is-potential-custom-element-name": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
@@ -26834,15 +26211,6 @@
"integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
"dev": true
},
- "lcid": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz",
- "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==",
- "dev": true,
- "requires": {
- "invert-kv": "^2.0.0"
- }
- },
"leven": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
@@ -26946,12 +26314,58 @@
"dev": true
},
"log-symbols": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz",
- "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
+ "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
"dev": true,
"requires": {
- "chalk": "^2.0.1"
+ "chalk": "^4.1.0",
+ "is-unicode-supported": "^0.1.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ }
}
},
"loglevel": {
@@ -27113,15 +26527,6 @@
"tmpl": "1.0.5"
}
},
- "map-age-cleaner": {
- "version": "0.1.3",
- "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz",
- "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==",
- "dev": true,
- "requires": {
- "p-defer": "^1.0.0"
- }
- },
"marked": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz",
@@ -27165,17 +26570,6 @@
"is-buffer": "~1.1.6"
}
},
- "mem": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz",
- "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==",
- "dev": true,
- "requires": {
- "map-age-cleaner": "^0.1.1",
- "mimic-fn": "^2.0.0",
- "p-is-promise": "^2.0.0"
- }
- },
"memorystream": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz",
@@ -27259,99 +26653,101 @@
"dev": true
},
"mocha": {
- "version": "6.1.4",
- "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.1.4.tgz",
- "integrity": "sha512-PN8CIy4RXsIoxoFJzS4QNnCH4psUCPWc4/rPrst/ecSJJbLBkubMiyGCP2Kj/9YnWbotFqAoeXyXMucj7gwCFg==",
+ "version": "10.2.0",
+ "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz",
+ "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==",
"dev": true,
"requires": {
- "ansi-colors": "3.2.3",
+ "ansi-colors": "4.1.1",
"browser-stdout": "1.3.1",
- "debug": "3.2.6",
- "diff": "3.5.0",
- "escape-string-regexp": "1.0.5",
- "find-up": "3.0.0",
- "glob": "7.1.3",
- "growl": "1.10.5",
+ "chokidar": "3.5.3",
+ "debug": "4.3.4",
+ "diff": "5.0.0",
+ "escape-string-regexp": "4.0.0",
+ "find-up": "5.0.0",
+ "glob": "7.2.0",
"he": "1.2.0",
- "js-yaml": "3.13.1",
- "log-symbols": "2.2.0",
- "minimatch": "3.0.4",
- "mkdirp": "0.5.1",
- "ms": "2.1.1",
- "node-environment-flags": "1.0.5",
- "object.assign": "4.1.0",
- "strip-json-comments": "2.0.1",
- "supports-color": "6.0.0",
- "which": "1.3.1",
- "wide-align": "1.1.3",
- "yargs": "13.2.2",
- "yargs-parser": "13.0.0",
- "yargs-unparser": "1.5.0"
+ "js-yaml": "4.1.0",
+ "log-symbols": "4.1.0",
+ "minimatch": "5.0.1",
+ "ms": "2.1.3",
+ "nanoid": "3.3.3",
+ "serialize-javascript": "6.0.0",
+ "strip-json-comments": "3.1.1",
+ "supports-color": "8.1.1",
+ "workerpool": "6.2.1",
+ "yargs": "16.2.0",
+ "yargs-parser": "20.2.4",
+ "yargs-unparser": "2.0.0"
},
"dependencies": {
- "ansi-regex": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz",
- "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==",
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true
},
"cliui": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz",
- "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==",
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+ "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
"dev": true,
"requires": {
- "string-width": "^2.1.1",
- "strip-ansi": "^4.0.0",
- "wrap-ansi": "^2.0.0"
- },
- "dependencies": {
- "string-width": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
- "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
- "dev": true,
- "requires": {
- "is-fullwidth-code-point": "^2.0.0",
- "strip-ansi": "^4.0.0"
- }
- }
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^7.0.0"
}
},
- "debug": {
- "version": "3.2.6",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
- "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"requires": {
- "ms": "^2.1.1"
+ "color-name": "~1.1.4"
}
},
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
"diff": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
- "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
+ "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
"dev": true
},
- "emoji-regex": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
- "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
+ "escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"dev": true
},
"find-up": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
- "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
"dev": true,
"requires": {
- "locate-path": "^3.0.0"
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
}
},
"glob": {
- "version": "7.1.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
- "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
+ "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
"dev": true,
"requires": {
"fs.realpath": "^1.0.0",
@@ -27360,231 +26756,126 @@
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
+ },
+ "dependencies": {
+ "minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ }
}
},
- "has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
- "dev": true
- },
- "is-fullwidth-code-point": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
- "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==",
- "dev": true
- },
"js-yaml": {
- "version": "3.13.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
- "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"dev": true,
"requires": {
- "argparse": "^1.0.7",
- "esprima": "^4.0.0"
+ "argparse": "^2.0.1"
}
},
"locate-path": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
- "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
"dev": true,
"requires": {
- "p-locate": "^3.0.0",
- "path-exists": "^3.0.0"
+ "p-locate": "^5.0.0"
}
},
"minimatch": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
- "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
- "dev": true,
- "requires": {
- "brace-expansion": "^1.1.7"
- }
- },
- "minimist": {
- "version": "0.0.8",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
- "integrity": "sha512-miQKw5Hv4NS1Psg2517mV4e4dYNaO3++hjAvLOAzKqZ61rH8NS1SK+vbfBWZ5PY/Me/bEWhUwqMghEW5Fb9T7Q==",
- "dev": true
- },
- "mkdirp": {
- "version": "0.5.1",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
- "integrity": "sha512-SknJC52obPfGQPnjIkXbmA6+5H15E+fR+E4iR2oQ3zzCLbd7/ONua69R/Gw7AgkTLsRG+r5fzksYwWe1AgTyWA==",
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz",
+ "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
"dev": true,
"requires": {
- "minimist": "0.0.8"
+ "brace-expansion": "^2.0.1"
+ },
+ "dependencies": {
+ "brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dev": true,
+ "requires": {
+ "balanced-match": "^1.0.0"
+ }
+ }
}
},
"ms": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
- "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true
},
- "object.assign": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz",
- "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==",
- "dev": true,
- "requires": {
- "define-properties": "^1.1.2",
- "function-bind": "^1.1.1",
- "has-symbols": "^1.0.0",
- "object-keys": "^1.0.11"
- }
- },
- "p-limit": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
- "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
- "dev": true,
- "requires": {
- "p-try": "^2.0.0"
- }
- },
- "p-locate": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
- "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
- "dev": true,
- "requires": {
- "p-limit": "^2.0.0"
- }
- },
- "path-exists": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
- "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
+ "nanoid": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz",
+ "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==",
"dev": true
},
- "string-width": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
- "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+ "p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
"dev": true,
"requires": {
- "emoji-regex": "^7.0.1",
- "is-fullwidth-code-point": "^2.0.0",
- "strip-ansi": "^5.1.0"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
- "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==",
- "dev": true
- },
- "strip-ansi": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
- "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
- "dev": true,
- "requires": {
- "ansi-regex": "^4.1.0"
- }
- }
+ "p-limit": "^3.0.2"
}
},
"strip-ansi": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
- "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==",
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"requires": {
- "ansi-regex": "^3.0.0"
+ "ansi-regex": "^5.0.1"
}
},
- "strip-json-comments": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
- "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
- "dev": true
- },
"supports-color": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz",
- "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==",
- "dev": true,
- "requires": {
- "has-flag": "^3.0.0"
- }
- },
- "which": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
- "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+ "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
"dev": true,
"requires": {
- "isexe": "^2.0.0"
+ "has-flag": "^4.0.0"
}
},
"wrap-ansi": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
- "integrity": "sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==",
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"dev": true,
"requires": {
- "string-width": "^1.0.1",
- "strip-ansi": "^3.0.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
- "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
- "dev": true
- },
- "is-fullwidth-code-point": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
- "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==",
- "dev": true,
- "requires": {
- "number-is-nan": "^1.0.0"
- }
- },
- "string-width": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
- "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==",
- "dev": true,
- "requires": {
- "code-point-at": "^1.0.0",
- "is-fullwidth-code-point": "^1.0.0",
- "strip-ansi": "^3.0.0"
- }
- },
- "strip-ansi": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
- "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==",
- "dev": true,
- "requires": {
- "ansi-regex": "^2.0.0"
- }
- }
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
}
},
+ "y18n": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "dev": true
+ },
"yargs": {
- "version": "13.2.2",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.2.tgz",
- "integrity": "sha512-WyEoxgyTD3w5XRpAQNYUB9ycVH/PQrToaTXdYXRdOXvEy1l19br+VJsc0vcO8PTGg5ro/l/GY7F/JMEBmI0BxA==",
+ "version": "16.2.0",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
+ "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
"dev": true,
"requires": {
- "cliui": "^4.0.0",
- "find-up": "^3.0.0",
- "get-caller-file": "^2.0.1",
- "os-locale": "^3.1.0",
+ "cliui": "^7.0.2",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
"require-directory": "^2.1.1",
- "require-main-filename": "^2.0.0",
- "set-blocking": "^2.0.0",
- "string-width": "^3.0.0",
- "which-module": "^2.0.0",
- "y18n": "^4.0.0",
- "yargs-parser": "^13.0.0"
+ "string-width": "^4.2.0",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^20.2.2"
}
}
}
@@ -27620,9 +26911,9 @@
}
},
"mocha-multi": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/mocha-multi/-/mocha-multi-1.1.6.tgz",
- "integrity": "sha512-hMVmd9C1h4PEiFNwHxn8aa5/EgGLg0UswdOrlrq1Y8ieKmot8hZLYaiESIgg/He3E4oxwaXPWT1V1PJ0qNJlUQ==",
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/mocha-multi/-/mocha-multi-1.1.7.tgz",
+ "integrity": "sha512-SXZRgHy0XiRTASyOp0p6fjOkdj+R62L6cqutnYyQOvIjNznJuUwzykxctypeRiOwPd+gfn4yt3NRulMQyI8Tzg==",
"dev": true,
"requires": {
"debug": "^4.1.1",
@@ -27760,16 +27051,6 @@
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
"dev": true
},
- "node-environment-flags": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz",
- "integrity": "sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==",
- "dev": true,
- "requires": {
- "object.getownpropertydescriptors": "^2.0.3",
- "semver": "^5.7.0"
- }
- },
"node-fetch": {
"version": "2.6.12",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz",
@@ -27916,14 +27197,8 @@
"integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
"dev": true,
"requires": {
- "path-key": "^3.0.0"
- }
- },
- "number-is-nan": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
- "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==",
- "dev": true
+ "path-key": "^3.0.0"
+ }
},
"nwsapi": {
"version": "2.2.7",
@@ -27993,19 +27268,6 @@
"es-abstract": "^1.20.4"
}
},
- "object.getownpropertydescriptors": {
- "version": "2.1.6",
- "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.6.tgz",
- "integrity": "sha512-lq+61g26E/BgHv0ZTFgRvi7NMEPuAxLkFU7rukXjc/AlwH4Am5xXVnIXy3un1bg/JPbXHrixRkK1itUzzPiIjQ==",
- "dev": true,
- "requires": {
- "array.prototype.reduce": "^1.0.5",
- "call-bind": "^1.0.2",
- "define-properties": "^1.2.0",
- "es-abstract": "^1.21.2",
- "safe-array-concat": "^1.0.0"
- }
- },
"object.hasown": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.2.tgz",
@@ -28121,16 +27383,6 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
- "log-symbols": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
- "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
- "dev": true,
- "requires": {
- "chalk": "^4.1.0",
- "is-unicode-supported": "^0.1.0"
- }
- },
"strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
@@ -28151,125 +27403,12 @@
}
}
},
- "os-locale": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz",
- "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==",
- "dev": true,
- "requires": {
- "execa": "^1.0.0",
- "lcid": "^2.0.0",
- "mem": "^4.0.0"
- },
- "dependencies": {
- "cross-spawn": {
- "version": "6.0.5",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
- "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
- "dev": true,
- "requires": {
- "nice-try": "^1.0.4",
- "path-key": "^2.0.1",
- "semver": "^5.5.0",
- "shebang-command": "^1.2.0",
- "which": "^1.2.9"
- }
- },
- "execa": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
- "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
- "dev": true,
- "requires": {
- "cross-spawn": "^6.0.0",
- "get-stream": "^4.0.0",
- "is-stream": "^1.1.0",
- "npm-run-path": "^2.0.0",
- "p-finally": "^1.0.0",
- "signal-exit": "^3.0.0",
- "strip-eof": "^1.0.0"
- }
- },
- "get-stream": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
- "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
- "dev": true,
- "requires": {
- "pump": "^3.0.0"
- }
- },
- "is-stream": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
- "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==",
- "dev": true
- },
- "npm-run-path": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
- "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==",
- "dev": true,
- "requires": {
- "path-key": "^2.0.0"
- }
- },
- "path-key": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
- "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==",
- "dev": true
- },
- "shebang-command": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
- "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==",
- "dev": true,
- "requires": {
- "shebang-regex": "^1.0.0"
- }
- },
- "shebang-regex": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
- "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==",
- "dev": true
- },
- "which": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
- "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
- "dev": true,
- "requires": {
- "isexe": "^2.0.0"
- }
- }
- }
- },
"os-tmpdir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
"dev": true
},
- "p-defer": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz",
- "integrity": "sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==",
- "dev": true
- },
- "p-finally": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
- "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==",
- "dev": true
- },
- "p-is-promise": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz",
- "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==",
- "dev": true
- },
"p-limit": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
@@ -29196,6 +28335,15 @@
"integrity": "sha512-twwRO/ilhlG/FIgYeKGFqyHhoEhqgnKVkcmqMKi2r524gz3ZbDTcyFt38E9xjJI2vT+KbRNHVbnJ/e0I25Azwg==",
"dev": true
},
+ "randombytes": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+ "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "^5.1.0"
+ }
+ },
"rc": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
@@ -29870,6 +29018,15 @@
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true
},
+ "serialize-javascript": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
+ "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
+ "dev": true,
+ "requires": {
+ "randombytes": "^2.1.0"
+ }
+ },
"set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
@@ -30212,12 +29369,6 @@
"integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==",
"dev": true
},
- "strip-eof": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
- "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==",
- "dev": true
- },
"strip-final-newline": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
@@ -30263,19 +29414,18 @@
"integrity": "sha512-r0JFBjkMIdep3Lbk3JA+MpnpuOtw4RSyrlRAbrzMcxwiYco3GFWl/daimQZ5b1forOiUODpOlXbSOljP/oyurg=="
},
"supertokens-web-js": {
- "version": "0.7.2",
- "resolved": "https://registry.npmjs.org/supertokens-web-js/-/supertokens-web-js-0.7.2.tgz",
- "integrity": "sha512-8TQFfuDzOkdbP/br7AHI8PJaslAYOVmHKT9rxb+v2cuFXYbZzHKoZeY12C1hepqHED8Cbt+rnIIVb2VUYlzd/w==",
+ "version": "git+ssh://git@github.com/supertokens/supertokens-web-js.git#3f2549680195dc660326eff9df13b150ff9fcbbd",
+ "from": "supertokens-web-js@github:supertokens/supertokens-web-js#0.8",
"peer": true,
"requires": {
"supertokens-js-override": "0.0.4",
- "supertokens-website": "^17.0.1"
+ "supertokens-website": "^17.0.3"
}
},
"supertokens-website": {
- "version": "17.0.2",
- "resolved": "https://registry.npmjs.org/supertokens-website/-/supertokens-website-17.0.2.tgz",
- "integrity": "sha512-ki19f8Bl24iypXOtnCj/ebMA7hi0WxCe1f0fItGXkOV0fVAkRCYVqAKf7wiLQ3Lwhc+us4cgOQwRLIvctLrrUg==",
+ "version": "17.0.3",
+ "resolved": "https://registry.npmjs.org/supertokens-website/-/supertokens-website-17.0.3.tgz",
+ "integrity": "sha512-+5qMuii8mp3TEPX5HKLt48A4gzKM8cmnoYmFeoecLeylfY3mEAeL7AbAVjCp6On/s/xvvH6Q22fOEoCFf5Tu/g==",
"peer": true,
"requires": {
"browser-tabs-lock": "^1.3.0",
@@ -31119,54 +30269,18 @@
"has-tostringtag": "^1.0.0"
}
},
- "wide-align": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
- "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
- "dev": true,
- "requires": {
- "string-width": "^1.0.2 || 2"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz",
- "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==",
- "dev": true
- },
- "is-fullwidth-code-point": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
- "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==",
- "dev": true
- },
- "string-width": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
- "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
- "dev": true,
- "requires": {
- "is-fullwidth-code-point": "^2.0.0",
- "strip-ansi": "^4.0.0"
- }
- },
- "strip-ansi": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
- "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==",
- "dev": true,
- "requires": {
- "ansi-regex": "^3.0.0"
- }
- }
- }
- },
"word-wrap": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz",
"integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==",
"dev": true
},
+ "workerpool": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz",
+ "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==",
+ "dev": true
+ },
"wrap-ansi": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
@@ -31409,199 +30523,34 @@
}
},
"yargs-parser": {
- "version": "13.0.0",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.0.0.tgz",
- "integrity": "sha512-w2LXjoL8oRdRQN+hOyppuXs+V/fVAYtpcrRxZuF7Kt/Oc+Jr2uAcVntaUTNT6w5ihoWfFDpNY8CPx1QskxZ/pw==",
- "dev": true,
- "requires": {
- "camelcase": "^5.0.0",
- "decamelize": "^1.2.0"
- }
+ "version": "20.2.4",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
+ "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==",
+ "dev": true
},
"yargs-unparser": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.5.0.tgz",
- "integrity": "sha512-HK25qidFTCVuj/D1VfNiEndpLIeJN78aqgR23nL3y4N0U/91cOAzqfHlF8n2BvoNDcZmJKin3ddNSvOxSr8flw==",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz",
+ "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==",
"dev": true,
"requires": {
- "flat": "^4.1.0",
- "lodash": "^4.17.11",
- "yargs": "^12.0.5"
+ "camelcase": "^6.0.0",
+ "decamelize": "^4.0.0",
+ "flat": "^5.0.2",
+ "is-plain-obj": "^2.1.0"
},
"dependencies": {
- "ansi-regex": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz",
- "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==",
- "dev": true
- },
- "cliui": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz",
- "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==",
- "dev": true,
- "requires": {
- "string-width": "^2.1.1",
- "strip-ansi": "^4.0.0",
- "wrap-ansi": "^2.0.0"
- }
- },
- "find-up": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
- "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
- "dev": true,
- "requires": {
- "locate-path": "^3.0.0"
- }
- },
- "get-caller-file": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
- "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==",
- "dev": true
- },
- "is-fullwidth-code-point": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
- "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==",
- "dev": true
- },
- "locate-path": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
- "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
- "dev": true,
- "requires": {
- "p-locate": "^3.0.0",
- "path-exists": "^3.0.0"
- }
- },
- "p-limit": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
- "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
- "dev": true,
- "requires": {
- "p-try": "^2.0.0"
- }
- },
- "p-locate": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
- "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
- "dev": true,
- "requires": {
- "p-limit": "^2.0.0"
- }
- },
- "path-exists": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
- "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
- "dev": true
- },
- "require-main-filename": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
- "integrity": "sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==",
+ "camelcase": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
+ "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
"dev": true
},
- "string-width": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
- "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
- "dev": true,
- "requires": {
- "is-fullwidth-code-point": "^2.0.0",
- "strip-ansi": "^4.0.0"
- }
- },
- "strip-ansi": {
+ "decamelize": {
"version": "4.0.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
- "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==",
- "dev": true,
- "requires": {
- "ansi-regex": "^3.0.0"
- }
- },
- "wrap-ansi": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
- "integrity": "sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==",
- "dev": true,
- "requires": {
- "string-width": "^1.0.1",
- "strip-ansi": "^3.0.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
- "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
- "dev": true
- },
- "is-fullwidth-code-point": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
- "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==",
- "dev": true,
- "requires": {
- "number-is-nan": "^1.0.0"
- }
- },
- "string-width": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
- "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==",
- "dev": true,
- "requires": {
- "code-point-at": "^1.0.0",
- "is-fullwidth-code-point": "^1.0.0",
- "strip-ansi": "^3.0.0"
- }
- },
- "strip-ansi": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
- "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==",
- "dev": true,
- "requires": {
- "ansi-regex": "^2.0.0"
- }
- }
- }
- },
- "yargs": {
- "version": "12.0.5",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz",
- "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==",
- "dev": true,
- "requires": {
- "cliui": "^4.0.0",
- "decamelize": "^1.2.0",
- "find-up": "^3.0.0",
- "get-caller-file": "^1.0.1",
- "os-locale": "^3.0.0",
- "require-directory": "^2.1.1",
- "require-main-filename": "^1.0.1",
- "set-blocking": "^2.0.0",
- "string-width": "^2.0.0",
- "which-module": "^2.0.0",
- "y18n": "^3.2.1 || ^4.0.0",
- "yargs-parser": "^11.1.1"
- }
- },
- "yargs-parser": {
- "version": "11.1.1",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz",
- "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==",
- "dev": true,
- "requires": {
- "camelcase": "^5.0.0",
- "decamelize": "^1.2.0"
- }
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
+ "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
+ "dev": true
}
}
},
diff --git a/package.json b/package.json
index cfb235e6c..0e38373a6 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "supertokens-auth-react",
- "version": "0.34.2",
+ "version": "0.35.0",
"description": "ReactJS SDK that provides login functionality with SuperTokens.",
"main": "./index.js",
"engines": {
@@ -46,9 +46,9 @@
"jsdom-global": "3.0.2",
"madge": "^5.0.1",
"mkdirp": "^1.0.4",
- "mocha": "6.1.4",
- "mocha-junit-reporter": "^2.0.2",
- "mocha-multi": "1.1.6",
+ "mocha": "^10.2.0",
+ "mocha-junit-reporter": "^2.2.1",
+ "mocha-multi": "^1.1.7",
"mocha-split-tests": "github:rishabhpoddar/mocha-split-tests",
"npm-run-all": "^4.1.5",
"postcss": "^8.4.19",
@@ -83,7 +83,7 @@
"peerDependencies": {
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
- "supertokens-web-js": "^0.7.2"
+ "supertokens-web-js": "github:supertokens/supertokens-web-js#0.8"
},
"scripts": {
"init": "bash ./init.sh",
diff --git a/test/end-to-end/accountlinking.test.js b/test/end-to-end/accountlinking.test.js
new file mode 100644
index 000000000..9e53cf47f
--- /dev/null
+++ b/test/end-to-end/accountlinking.test.js
@@ -0,0 +1,690 @@
+/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.
+ *
+ * This software is licensed under the Apache License, Version 2.0 (the
+ * "License") as published by the Apache Software Foundation.
+ *
+ * You may not use this file except in compliance with the License. You may
+ * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*
+ * Imports
+ */
+
+import assert from "assert";
+import puppeteer from "puppeteer";
+import {
+ clearBrowserCookiesWithoutAffectingConsole,
+ clickOnProviderButton,
+ getUserIdWithFetch,
+ getLogoutButton,
+ setInputValues,
+ submitForm,
+ waitForSTElement,
+ getPasswordlessDevice,
+ setPasswordlessFlowType,
+ getFeatureFlags,
+ isReact16,
+ setAccountLinkingConfig,
+ signUp,
+ toggleSignInSignUp,
+ getInputAdornmentsSuccess,
+ getInputAdornmentsError,
+ getFieldErrors,
+ assertProviders,
+ getGeneralError,
+ getLatestURLWithToken,
+ submitFormReturnRequestAndResponse,
+ getTextByDataSupertokens,
+ sendEmailResetPasswordSuccessMessage,
+ changeEmail,
+} from "../helpers";
+import { TEST_CLIENT_BASE_URL, TEST_SERVER_BASE_URL, SIGN_IN_UP_API, RESET_PASSWORD_API } from "../constants";
+
+/*
+ * Tests.
+ */
+describe("SuperTokens Account linking", function () {
+ let browser;
+ let page;
+ let consoleLogs;
+
+ before(async function () {
+ const features = await getFeatureFlags();
+ if (!features.includes("accountlinking")) {
+ this.skip();
+ }
+ });
+
+ describe("Recipe combination tests", () => {
+ before(async function () {
+ await fetch(`${TEST_SERVER_BASE_URL}/beforeeach`, {
+ method: "POST",
+ }).catch(console.error);
+
+ await fetch(`${TEST_SERVER_BASE_URL}/startst`, {
+ method: "POST",
+ }).catch(console.error);
+
+ browser = await puppeteer.launch({
+ args: ["--no-sandbox", "--disable-setuid-sandbox"],
+ headless: true,
+ });
+ page = await browser.newPage();
+ page.on("console", (consoleObj) => {
+ const log = consoleObj.text();
+ if (log.startsWith("ST_LOGS")) {
+ consoleLogs.push(log);
+ }
+ });
+ });
+
+ after(async function () {
+ await browser.close();
+ await fetch(`${TEST_SERVER_BASE_URL}/after`, {
+ method: "POST",
+ }).catch(console.error);
+
+ await fetch(`${TEST_SERVER_BASE_URL}/stopst`, {
+ method: "POST",
+ }).catch(console.error);
+ });
+
+ beforeEach(async function () {
+ consoleLogs = [];
+ consoleLogs = await clearBrowserCookiesWithoutAffectingConsole(page, consoleLogs);
+ await setPasswordlessFlowType("EMAIL_OR_PHONE", "USER_INPUT_CODE_AND_MAGIC_LINK");
+ await Promise.all([
+ page.goto(
+ `${TEST_CLIENT_BASE_URL}/auth/?authRecipe=thirdpartypasswordless&passwordlessContactMethodType=EMAIL_OR_PHONE`
+ ),
+ page.waitForNavigation({ waitUntil: "networkidle0" }),
+ ]);
+ await page.evaluate(() => window.localStorage.removeItem("mode"));
+ });
+
+ afterEach(async function () {
+ await page.evaluate(() => localStorage.removeItem("supertokens-passwordless-loginAttemptInfo"));
+ });
+
+ describe("account consolidation", () => {
+ const loginTypes = [
+ ["passwordless", tryPasswordlessSignInUp],
+ ["thirdparty", tryThirdPartySignInUp],
+ ["emailpassword", tryEmailPasswordSignUp],
+ ];
+
+ for (const login1 of loginTypes) {
+ for (const login2 of loginTypes) {
+ if (login1 !== login2) {
+ const doLogin1 = login1[1];
+ const doLogin2 = login2[1];
+
+ it(`should work for ${login1[0]} - ${login2[0]} w/ email verification not required`, async () => {
+ const email = `test-user+${Date.now()}@supertokens.com`;
+ await setAccountLinkingConfig(true, true, false);
+ // 1. Sign up with login method 1
+ await doLogin1(page, email);
+
+ await Promise.all([
+ page.waitForSelector(".sessionInfo-user-id"),
+ page.waitForNetworkIdle(),
+ ]);
+ const userId1 = await getUserIdWithFetch(page);
+
+ // 2. Log out
+ await logOut(page);
+
+ // 3. Sign in with other login method
+ await doLogin2(page, email, true);
+ await Promise.all([
+ page.waitForSelector(".sessionInfo-user-id"),
+ page.waitForNetworkIdle(),
+ ]);
+
+ const thirdPartyUserId = await getUserIdWithFetch(page);
+
+ // 4. Compare userIds
+ assert.strictEqual(thirdPartyUserId, userId1);
+ });
+
+ if (login2[0] !== "emailpassword") {
+ it(`should work for ${login1[0]} - ${login2[0]} w/ email verification required`, async () => {
+ await page.evaluate(() => window.localStorage.setItem("mode", "REQUIRED"));
+
+ const email = `test-user+${Date.now()}@supertokens.com`;
+ await setAccountLinkingConfig(true, true, true);
+ // 1. Sign up with login method 1
+ await doLogin1(page, email);
+ if (login1[0] === "emailpassword") {
+ await waitForSTElement(page, "[data-supertokens~='sendVerifyEmailIcon']");
+ await new Promise((res) => setTimeout(res, 250));
+ const latestURLWithToken = await getLatestURLWithToken();
+ await Promise.all([
+ page.waitForNavigation({ waitUntil: "networkidle0" }),
+ page.goto(latestURLWithToken),
+ ]);
+ await Promise.all([
+ submitForm(page),
+ page.waitForNavigation({ waitUntil: "networkidle0" }),
+ ]);
+ }
+
+ await Promise.all([
+ page.waitForSelector(".sessionInfo-user-id"),
+ page.waitForNetworkIdle(),
+ ]);
+ const userId1 = await getUserIdWithFetch(page);
+
+ // 2. Log out
+ await logOut(page);
+
+ // 3. Sign in with other login method
+ await doLogin2(page, email, true);
+ await Promise.all([
+ page.waitForSelector(".sessionInfo-user-id"),
+ page.waitForNetworkIdle(),
+ ]);
+
+ const thirdPartyUserId = await getUserIdWithFetch(page);
+
+ // 4. Compare userIds
+ assert.strictEqual(thirdPartyUserId, userId1);
+ });
+ } else {
+ it(`should work for ${login1[0]} - password reset (invite link flow) w/ email verification required`, async () => {
+ await page.evaluate(() => window.localStorage.setItem("mode", "REQUIRED"));
+
+ const email = `test-user+${Date.now()}@supertokens.com`;
+ await setAccountLinkingConfig(true, true, true);
+ // 1. Sign up with login method 1
+ await doLogin1(page, email);
+ if (login1[0] === "emailpassword") {
+ await waitForSTElement(page, "[data-supertokens~='sendVerifyEmailIcon']");
+ await new Promise((res) => setTimeout(res, 250));
+ const latestURLWithToken = await getLatestURLWithToken();
+ await Promise.all([
+ page.waitForNavigation({ waitUntil: "networkidle0" }),
+ page.goto(latestURLWithToken),
+ ]);
+ await Promise.all([
+ submitForm(page),
+ page.waitForNavigation({ waitUntil: "networkidle0" }),
+ ]);
+ }
+
+ await Promise.all([
+ page.waitForSelector(".sessionInfo-user-id"),
+ page.waitForNetworkIdle(),
+ ]);
+ const userId1 = await getUserIdWithFetch(page);
+
+ // 2. Log out
+ await logOut(page);
+
+ // 3. Sign in with other login method
+ await tryEmailPasswordResetPassword(page, email);
+ await Promise.all([
+ page.waitForSelector(".sessionInfo-user-id"),
+ page.waitForNetworkIdle(),
+ ]);
+
+ const thirdPartyUserId = await getUserIdWithFetch(page);
+
+ // 4. Compare userIds
+ assert.strictEqual(thirdPartyUserId, userId1);
+ });
+ }
+ }
+ }
+ }
+ });
+
+ describe("conflicting accounts", () => {
+ it("should not allow sign up w/ emailpassword in case of conflict", async function () {
+ const email = `test-user+${Date.now()}@supertokens.com`;
+
+ await setAccountLinkingConfig(true, true, true);
+ // 1. Sign up with credentials
+ await tryPasswordlessSignInUp(page, email);
+
+ await Promise.all([page.waitForSelector(".sessionInfo-user-id"), page.waitForNetworkIdle()]);
+
+ // 2. Log out
+ await logOut(page);
+
+ await waitForSTElement(page, `input[name=emailOrPhone]`);
+
+ // 3. Try sign up with email password
+ await tryEmailPasswordSignUp(page, email);
+
+ const successAdornments = await getInputAdornmentsSuccess(page);
+ assert.strictEqual(successAdornments.length, 4);
+
+ const errorAdornments = await getInputAdornmentsError(page);
+ assert.strictEqual(errorAdornments.length, 0);
+
+ assert.strictEqual(new URL(page.url()).pathname, "/auth/");
+ assert.strictEqual(
+ await getGeneralError(page),
+ "Cannot sign up due to security reasons. Please try logging in, use a different login method or contact support. (ERR_CODE_007)"
+ );
+ });
+
+ it("should not allow sign in w/ an unverified emailpassword user in case of conflict", async function () {
+ const email = `test-user+${Date.now()}@supertokens.com`;
+
+ await setAccountLinkingConfig(true, false);
+ // 1. Sign up without account linking with an unverified tp user & log out
+ await tryEmailPasswordSignUp(page, email);
+ await logOut(page);
+
+ await setAccountLinkingConfig(true, true, false);
+ // 2. Sign up with passwordless to create a primary user
+ await tryPasswordlessSignInUp(page, email);
+
+ await Promise.all([page.waitForSelector(".sessionInfo-user-id"), page.waitForNetworkIdle()]);
+
+ // 3. Log out
+ await logOut(page);
+
+ await waitForSTElement(page, `input[name=emailOrPhone]`);
+
+ await setAccountLinkingConfig(true, true, true);
+ // 4. Try sign in with emailpassword
+
+ await Promise.all([
+ page.goto(`${TEST_CLIENT_BASE_URL}/auth/?authRecipe=emailpassword`),
+ page.waitForNavigation({ waitUntil: "networkidle0" }),
+ ]);
+ await setInputValues(page, [
+ { name: "email", value: email },
+ { name: "password", value: "Asdf12.." },
+ ]);
+
+ await submitForm(page);
+ assert.strictEqual(new URL(page.url()).pathname, "/auth/");
+ assert.strictEqual(
+ await getGeneralError(page),
+ "Cannot sign in due to security reasons. Please try resetting your password, use a different login method or contact support. (ERR_CODE_008)"
+ );
+ });
+
+ it("should not allow sign up w/ an unverified thirdparty user in case of conflict", async function () {
+ const email = `test-user+${Date.now()}@supertokens.com`;
+
+ await setAccountLinkingConfig(true, true, true);
+ // 1. Sign up with credentials
+ await tryPasswordlessSignInUp(page, email);
+
+ await Promise.all([page.waitForSelector(".sessionInfo-user-id"), page.waitForNetworkIdle()]);
+
+ // 2. Log out
+ await logOut(page);
+
+ await waitForSTElement(page, `input[name=emailOrPhone]`);
+
+ // 3. Try sign up with third party
+ await tryThirdPartySignInUp(page, email, false);
+
+ assert.strictEqual(new URL(page.url()).pathname, "/auth/");
+ assert.strictEqual(
+ await getGeneralError(page),
+ "Cannot sign in / up due to security reasons. Please try a different login method or contact support. (ERR_CODE_006)"
+ );
+ });
+
+ it("should not allow using thirdparty sign in with changed email in case of conflict", async function () {
+ const email = `test-user+${Date.now()}@supertokens.com`;
+ const email2 = `test-user-2+${Date.now()}@supertokens.com`;
+
+ await setAccountLinkingConfig(true, true, true);
+ // 1. Sign up with credentials
+
+ await tryPasswordlessSignInUp(page, email);
+
+ await Promise.all([page.waitForSelector(".sessionInfo-user-id"), page.waitForNetworkIdle()]);
+
+ // 2. Log out
+ await logOut(page);
+
+ await waitForSTElement(page, `input[name=emailOrPhone]`);
+
+ // 3. Sign up with third party
+ await tryThirdPartySignInUp(page, email2, false);
+ await Promise.all([page.waitForSelector(".sessionInfo-user-id"), page.waitForNetworkIdle()]);
+
+ // 4. Log out
+ await logOut(page);
+
+ // 5. Sign in with changed email address (thirdPartyUserId matching the previous sign in)
+
+ await tryThirdPartySignInUp(page, email, false, email2);
+
+ assert.strictEqual(new URL(page.url()).pathname, "/auth/");
+ assert.strictEqual(
+ await getGeneralError(page),
+ "Cannot sign in / up because new email cannot be applied to existing account. Please contact support. (ERR_CODE_005)"
+ );
+ });
+
+ it("should not allow sign in w/ an unverified thirdparty user in case of conflict", async function () {
+ const email = `test-user+${Date.now()}@supertokens.com`;
+
+ await setAccountLinkingConfig(true, false);
+ // 1. Sign up without account linking with an unverified tp user & log out
+ await tryThirdPartySignInUp(page, email, false);
+ await logOut(page);
+
+ await setAccountLinkingConfig(true, true, false);
+ // 2. Sign up with passwordless to create a primary user
+ await tryPasswordlessSignInUp(page, email);
+
+ await Promise.all([page.waitForSelector(".sessionInfo-user-id"), page.waitForNetworkIdle()]);
+
+ // 3. Log out
+ await logOut(page);
+
+ await waitForSTElement(page, `input[name=emailOrPhone]`);
+
+ await setAccountLinkingConfig(true, true, true);
+ // 4. Try sign in with third party
+ await tryThirdPartySignInUp(page, email, false);
+
+ assert.strictEqual(new URL(page.url()).pathname, "/auth/");
+ assert.strictEqual(
+ await getGeneralError(page),
+ "Cannot sign in / up due to security reasons. Please try a different login method or contact support. (ERR_CODE_004)"
+ );
+ });
+
+ it("should not allow sign up w/ passwordless if it conflicts with an unverified user", async function () {
+ const email = `test-user+${Date.now()}@supertokens.com`;
+
+ await setAccountLinkingConfig(true, false);
+ // 1. Sign up without account linking with an unverified tp user & log out
+ await tryEmailPasswordSignUp(page, email);
+ await logOut(page);
+
+ await setAccountLinkingConfig(true, true, true);
+ // 2. Sign up with passwordless
+ await page.evaluate(() => localStorage.removeItem("supertokens-passwordless-loginAttemptInfo"));
+ await Promise.all([
+ page.goto(`${TEST_CLIENT_BASE_URL}/auth/?authRecipe=passwordless`),
+ page.waitForNavigation({ waitUntil: "networkidle0" }),
+ ]);
+
+ await setInputValues(page, [{ name: "emailOrPhone", value: email }]);
+ await submitForm(page);
+
+ assert.strictEqual(
+ await getGeneralError(page),
+ "Cannot sign in / up due to security reasons. Please try a different login method or contact support. (ERR_CODE_002)"
+ );
+ assert.strictEqual(new URL(page.url()).pathname, "/auth/");
+ });
+
+ it("should not allow sign up w/ passwordless after changing the email if it conflicts with an unverified user", async function () {
+ const email = `test-user+${Date.now()}@supertokens.com`;
+ const email2 = `test-user-2+${Date.now()}@supertokens.com`;
+
+ await setAccountLinkingConfig(true, false);
+ // 1. Sign up without account linking with an unverified tp user & log out
+ await tryEmailPasswordSignUp(page, email);
+ await logOut(page);
+
+ // 2. Sign up with passwordless
+ await tryPasswordlessSignInUp(page, email2);
+ await Promise.all([page.waitForSelector(".sessionInfo-user-id"), page.waitForNetworkIdle()]);
+ const accessTokenPayload = await page.evaluate(() =>
+ window.__supertokensSessionRecipe.getAccessTokenPayloadSecurely()
+ );
+ const userId = accessTokenPayload.sub;
+ await logOut(page);
+
+ await page.evaluate(() => localStorage.removeItem("supertokens-passwordless-loginAttemptInfo"));
+ await Promise.all([
+ page.goto(`${TEST_CLIENT_BASE_URL}/auth/?authRecipe=passwordless`),
+ page.waitForNavigation({ waitUntil: "networkidle0" }),
+ ]);
+ await changeEmail("passwordless", userId, email);
+ await setAccountLinkingConfig(true, true, true);
+
+ await setInputValues(page, [{ name: "emailOrPhone", value: email }]);
+ await submitForm(page);
+
+ assert.strictEqual(
+ await getGeneralError(page),
+ "Cannot sign in / up due to security reasons. Please try a different login method or contact support. (ERR_CODE_003)"
+ );
+ assert.strictEqual(new URL(page.url()).pathname, "/auth/");
+ });
+
+ it("should not allow sign up w/ passwordless if it conflicts with an unverified user", async function () {
+ const email = `test-user+${Date.now()}@supertokens.com`;
+
+ await setAccountLinkingConfig(true, false);
+ // 1. Sign up without account linking with an unverified tp user & log out
+ await tryEmailPasswordSignUp(page, email);
+ await logOut(page);
+
+ await setAccountLinkingConfig(true, true, true);
+ // 2. Sign in with passwordless
+ await page.evaluate(() => localStorage.removeItem("supertokens-passwordless-loginAttemptInfo"));
+ await Promise.all([
+ page.goto(`${TEST_CLIENT_BASE_URL}/auth/?authRecipe=passwordless`),
+ page.waitForNavigation({ waitUntil: "networkidle0" }),
+ ]);
+
+ await setInputValues(page, [{ name: "emailOrPhone", value: email }]);
+ await submitForm(page);
+
+ assert.strictEqual(
+ await getGeneralError(page),
+ "Cannot sign in / up due to security reasons. Please try a different login method or contact support. (ERR_CODE_002)"
+ );
+ assert.strictEqual(new URL(page.url()).pathname, "/auth/");
+ });
+
+ it("should not allow password reset if it conflicts with an unverified user", async function () {
+ const email = `test-user+${Date.now()}@supertokens.com`;
+ const email2 = `test-user2+${Date.now()}@supertokens.com`;
+
+ await setAccountLinkingConfig(true, true, false);
+ // 1. Sign up without account linking with an unverified tp user & log out
+ await tryThirdPartySignInUp(page, email2, false);
+ await logOut(page);
+
+ // 2. Sign up with an EP user that will be linked to the first one
+ await tryEmailPasswordSignUp(page, email2);
+ await logOut(page);
+
+ // 3. Change the email of the initial tp user
+ await tryThirdPartySignInUp(page, email, false, email2);
+ await logOut(page);
+
+ await setAccountLinkingConfig(true, false, false);
+ // 4. Add a recipe level user
+ await tryEmailPasswordSignUp(page, email);
+ await logOut(page);
+
+ await setAccountLinkingConfig(true, true, true);
+ // 5. Try resetting the password of the recipe leve user
+ await Promise.all([
+ page.goto(`${TEST_CLIENT_BASE_URL}/auth/reset-password?authRecipe=emailpassword`),
+ page.waitForNavigation({ waitUntil: "networkidle0" }),
+ ]);
+
+ await setInputValues(page, [{ name: "email", value: email }]);
+
+ await submitForm(page);
+
+ await new Promise((res) => setTimeout(res, 200));
+ assert.deepStrictEqual(await getFieldErrors(page), [
+ "Reset password link was not created because of account take over risk. Please contact support. (ERR_CODE_001)",
+ ]);
+ assert.strictEqual(new URL(page.url()).pathname, "/auth/reset-password");
+ });
+
+ it("should allow sign in w/ a verified emailpassword user in case of conflict", async function () {
+ const email = `test-user+${Date.now()}@supertokens.com`;
+ await page.evaluate(() => window.localStorage.setItem("mode", "REQUIRED"));
+
+ await setAccountLinkingConfig(true, false);
+ // 1. Sign up without account linking with an unverified tp user & log out
+ await tryEmailPasswordSignUp(page, email);
+ await waitForSTElement(page, "[data-supertokens~='sendVerifyEmailIcon']");
+
+ await new Promise((res) => setTimeout(res, 250));
+ const latestURLWithToken = await getLatestURLWithToken();
+ await Promise.all([
+ page.waitForNavigation({ waitUntil: "networkidle0" }),
+ page.goto(latestURLWithToken),
+ ]);
+ await Promise.all([submitForm(page), page.waitForNavigation({ waitUntil: "networkidle0" })]);
+
+ await logOut(page);
+
+ await setAccountLinkingConfig(true, true, false);
+ // 2. Sign up with passwordless to create a primary user
+ await tryPasswordlessSignInUp(page, email);
+
+ await Promise.all([page.waitForSelector(".sessionInfo-user-id"), page.waitForNetworkIdle()]);
+
+ // 3. Log out
+ await logOut(page);
+
+ await waitForSTElement(page, `input[name=emailOrPhone]`);
+
+ await setAccountLinkingConfig(true, true, true);
+ // 4. Try sign in with emailpassword
+
+ await Promise.all([
+ page.goto(`${TEST_CLIENT_BASE_URL}/auth/?authRecipe=emailpassword`),
+ page.waitForNavigation({ waitUntil: "networkidle0" }),
+ ]);
+ await setInputValues(page, [
+ { name: "email", value: email },
+ { name: "password", value: "Asdf12.." },
+ ]);
+
+ await submitForm(page);
+ await Promise.all([page.waitForSelector(".sessionInfo-user-id"), page.waitForNetworkIdle()]);
+ });
+ });
+ });
+});
+
+async function tryEmailPasswordSignUp(page, email) {
+ await Promise.all([
+ page.goto(`${TEST_CLIENT_BASE_URL}/auth/?authRecipe=emailpassword`),
+ page.waitForNavigation({ waitUntil: "networkidle0" }),
+ ]);
+
+ await toggleSignInSignUp(page);
+
+ await setInputValues(page, [
+ { name: "email", value: email },
+ { name: "password", value: "Asdf12.." },
+ { name: "name", value: "asdf" },
+ { name: "age", value: "20" },
+ ]);
+
+ await submitForm(page);
+ await new Promise((res) => setTimeout(res, 250));
+}
+
+async function tryPasswordlessSignInUp(page, email) {
+ await page.evaluate(() => localStorage.removeItem("supertokens-passwordless-loginAttemptInfo"));
+ await Promise.all([
+ page.goto(`${TEST_CLIENT_BASE_URL}/auth/?authRecipe=passwordless`),
+ page.waitForNavigation({ waitUntil: "networkidle0" }),
+ ]);
+
+ await setInputValues(page, [{ name: "emailOrPhone", value: email }]);
+ await submitForm(page);
+
+ await waitForSTElement(page, "[data-supertokens~=input][name=userInputCode]");
+
+ const loginAttemptInfo = JSON.parse(
+ await page.evaluate(() => localStorage.getItem("supertokens-passwordless-loginAttemptInfo"))
+ );
+ const device = await getPasswordlessDevice(loginAttemptInfo);
+ await setInputValues(page, [{ name: "userInputCode", value: device.codes[0].userInputCode }]);
+ await submitForm(page);
+}
+
+async function tryThirdPartySignInUp(page, email, isVerified = true, userId = email) {
+ await Promise.all([
+ page.goto(`${TEST_CLIENT_BASE_URL}/auth/?authRecipe=thirdparty`),
+ page.waitForNavigation({ waitUntil: "networkidle0" }),
+ ]);
+
+ await assertProviders(page);
+
+ await clickOnProviderButton(page, "Mock Provider");
+ const url = new URL(page.url());
+ assert.strictEqual(url.pathname, `/mockProvider/auth`);
+ assert.ok(url.searchParams.get("state"));
+
+ await Promise.all([
+ page.goto(
+ `${TEST_CLIENT_BASE_URL}/auth/callback/mock-provider?code=asdf&email=${encodeURIComponent(
+ email
+ )}&userId=${encodeURIComponent(userId)}&isVerified=${isVerified}&state=${url.searchParams.get("state")}`
+ ),
+ page.waitForNavigation({ waitUntil: "networkidle0" }),
+ ]);
+}
+
+async function tryEmailPasswordResetPassword(page, email) {
+ await Promise.all([
+ page.goto(`${TEST_CLIENT_BASE_URL}/auth/reset-password?authRecipe=emailpassword`),
+ page.waitForNavigation({ waitUntil: "networkidle0" }),
+ ]);
+
+ await setInputValues(page, [{ name: "email", value: email }]);
+
+ await submitForm(page);
+ const successMessage = await sendEmailResetPasswordSuccessMessage(page);
+
+ assert.deepStrictEqual(
+ successMessage,
+ `A password reset email has been sent to ${email}, if it exists in our system. Resend or change email`
+ );
+ // Get valid token.
+ const latestURLWithToken = await getLatestURLWithToken();
+ await page.goto(latestURLWithToken);
+
+ // Submit new password
+ await setInputValues(page, [
+ { name: "password", value: "Asdf12.." },
+ { name: "confirm-password", value: "Asdf12.." },
+ ]);
+ await submitFormReturnRequestAndResponse(page, RESET_PASSWORD_API);
+
+ const title = await getTextByDataSupertokens(page, "headerTitle");
+ assert.deepStrictEqual(title, "Success!");
+ await Promise.all([submitForm(page), page.waitForNavigation({ waitUntil: "networkidle0" })]);
+
+ await setInputValues(page, [
+ { name: "email", value: email },
+ { name: "password", value: "Asdf12.." },
+ ]);
+
+ await submitForm(page);
+ await new Promise((res) => setTimeout(res, 250));
+}
+
+async function logOut(page) {
+ await Promise.all([page.waitForSelector(".sessionInfo-user-id"), page.waitForNetworkIdle()]);
+ const logoutButton = await getLogoutButton(page);
+ await Promise.all([logoutButton.click(), page.waitForNavigation({ waitUntil: "networkidle0" })]);
+ await waitForSTElement(page);
+}
diff --git a/test/end-to-end/emailverification.test.js b/test/end-to-end/emailverification.test.js
index 551ad4781..66746fa05 100644
--- a/test/end-to-end/emailverification.test.js
+++ b/test/end-to-end/emailverification.test.js
@@ -17,8 +17,6 @@
* Imports
*/
-/* https://github.com/babel/babel/issues/9849#issuecomment-487040428 */
-import regeneratorRuntime from "regenerator-runtime";
import assert from "assert";
import puppeteer from "puppeteer";
import fetch from "isomorphic-fetch";
@@ -52,15 +50,14 @@ import {
waitForSTElement,
isGeneralErrorSupported,
setGeneralErrorToLocalStorage,
+ isAccountLinkingSupported,
} from "../helpers";
-// Run the tests in a DOM environment.
-require("jsdom-global")();
-
describe("SuperTokens Email Verification", function () {
let browser;
let page;
let consoleLogs;
+ let accountLinkingSupported;
before(async function () {
await fetch(`${TEST_SERVER_BASE_URL}/beforeeach`, {
@@ -73,6 +70,8 @@ describe("SuperTokens Email Verification", function () {
args: ["--no-sandbox", "--disable-setuid-sandbox"],
headless: true,
});
+ accountLinkingSupported = await isAccountLinkingSupported();
+
page = await browser.newPage();
await Promise.all([
page.goto(`${TEST_CLIENT_BASE_URL}/auth?mode=REQUIRED`),
@@ -126,7 +125,7 @@ describe("SuperTokens Email Verification", function () {
]);
await waitForSTElement(page, "[data-supertokens~='sendVerifyEmailIcon']");
- await fetch(`${TEST_SERVER_BASE_URL}/deleteUser`, {
+ await fetch(`${TEST_APPLICATION_SERVER_BASE_URL}/deleteUser`, {
method: "POST",
headers: [["content-type", "application/json"]],
body: JSON.stringify({
@@ -183,7 +182,7 @@ describe("SuperTokens Email Verification", function () {
let pathname = await page.evaluate(() => window.location.pathname);
assert.deepStrictEqual(pathname, "/auth/verify-email");
- await fetch(`${TEST_SERVER_BASE_URL}/deleteUser`, {
+ await fetch(`${TEST_APPLICATION_SERVER_BASE_URL}/deleteUser`, {
method: "POST",
headers: [["content-type", "application/json"]],
body: JSON.stringify({
@@ -257,9 +256,13 @@ describe("SuperTokens Email Verification", function () {
"ST_LOGS SESSION OVERRIDE GET_USER_ID",
"ST_LOGS EMAIL_VERIFICATION OVERRIDE IS_EMAIL_VERIFIED",
"ST_LOGS EMAIL_VERIFICATION PRE_API_HOOKS IS_EMAIL_VERIFIED",
- "ST_LOGS SESSION ON_HANDLE_EVENT ACCESS_TOKEN_PAYLOAD_UPDATED",
- "ST_LOGS SESSION OVERRIDE GET_USER_ID",
- "ST_LOGS SESSION OVERRIDE GET_JWT_PAYLOAD_SECURELY",
+ ...(accountLinkingSupported
+ ? []
+ : [
+ "ST_LOGS SESSION ON_HANDLE_EVENT ACCESS_TOKEN_PAYLOAD_UPDATED",
+ "ST_LOGS SESSION OVERRIDE GET_USER_ID",
+ "ST_LOGS SESSION OVERRIDE GET_JWT_PAYLOAD_SECURELY",
+ ]),
"ST_LOGS EMAIL_VERIFICATION OVERRIDE SEND_VERIFICATION_EMAIL",
"ST_LOGS EMAIL_VERIFICATION PRE_API_HOOKS SEND_VERIFY_EMAIL",
"ST_LOGS EMAIL_VERIFICATION ON_HANDLE_EVENT VERIFY_EMAIL_SENT",
@@ -343,9 +346,13 @@ describe("SuperTokens Email Verification", function () {
"ST_LOGS SESSION OVERRIDE GET_USER_ID",
"ST_LOGS EMAIL_VERIFICATION OVERRIDE IS_EMAIL_VERIFIED",
"ST_LOGS EMAIL_VERIFICATION PRE_API_HOOKS IS_EMAIL_VERIFIED",
- "ST_LOGS SESSION ON_HANDLE_EVENT ACCESS_TOKEN_PAYLOAD_UPDATED",
- "ST_LOGS SESSION OVERRIDE GET_USER_ID",
- "ST_LOGS SESSION OVERRIDE GET_JWT_PAYLOAD_SECURELY",
+ ...(accountLinkingSupported
+ ? []
+ : [
+ "ST_LOGS SESSION ON_HANDLE_EVENT ACCESS_TOKEN_PAYLOAD_UPDATED",
+ "ST_LOGS SESSION OVERRIDE GET_USER_ID",
+ "ST_LOGS SESSION OVERRIDE GET_JWT_PAYLOAD_SECURELY",
+ ]),
"ST_LOGS EMAIL_VERIFICATION OVERRIDE SEND_VERIFICATION_EMAIL",
"ST_LOGS EMAIL_VERIFICATION PRE_API_HOOKS SEND_VERIFY_EMAIL",
"ST_LOGS EMAIL_VERIFICATION ON_HANDLE_EVENT VERIFY_EMAIL_SENT",
@@ -489,9 +496,13 @@ describe("SuperTokens Email Verification", function () {
"ST_LOGS SESSION OVERRIDE GET_USER_ID",
"ST_LOGS EMAIL_VERIFICATION OVERRIDE IS_EMAIL_VERIFIED",
"ST_LOGS EMAIL_VERIFICATION PRE_API_HOOKS IS_EMAIL_VERIFIED",
- "ST_LOGS SESSION ON_HANDLE_EVENT ACCESS_TOKEN_PAYLOAD_UPDATED",
- "ST_LOGS SESSION OVERRIDE GET_USER_ID",
- "ST_LOGS SESSION OVERRIDE GET_JWT_PAYLOAD_SECURELY",
+ ...(accountLinkingSupported
+ ? []
+ : [
+ "ST_LOGS SESSION ON_HANDLE_EVENT ACCESS_TOKEN_PAYLOAD_UPDATED",
+ "ST_LOGS SESSION OVERRIDE GET_USER_ID",
+ "ST_LOGS SESSION OVERRIDE GET_JWT_PAYLOAD_SECURELY",
+ ]),
"ST_LOGS EMAIL_VERIFICATION OVERRIDE SEND_VERIFICATION_EMAIL",
"ST_LOGS EMAIL_VERIFICATION PRE_API_HOOKS SEND_VERIFY_EMAIL",
"ST_LOGS EMAIL_VERIFICATION ON_HANDLE_EVENT VERIFY_EMAIL_SENT",
diff --git a/test/end-to-end/generalerror.test.js b/test/end-to-end/generalerror.test.js
index c9acfbadf..31ae80548 100644
--- a/test/end-to-end/generalerror.test.js
+++ b/test/end-to-end/generalerror.test.js
@@ -42,8 +42,6 @@ import {
setGeneralErrorToLocalStorage,
} from "../helpers";
-// Run the tests in a DOM environment.
-require("jsdom-global")();
import {
TEST_SERVER_BASE_URL,
SIGN_UP_API,
diff --git a/test/end-to-end/getRedirectionURL.test.js b/test/end-to-end/getRedirectionURL.test.js
index 2f2cdf656..735fa3556 100644
--- a/test/end-to-end/getRedirectionURL.test.js
+++ b/test/end-to-end/getRedirectionURL.test.js
@@ -17,8 +17,7 @@ import {
isPasswordlessSupported,
isThirdPartyPasswordlessSupported,
} from "../helpers";
-// Run the tests in a DOM environment.
-require("jsdom-global")();
+
import {
TEST_CLIENT_BASE_URL,
TEST_SERVER_BASE_URL,
@@ -27,7 +26,7 @@ import {
} from "../constants";
describe("getRedirectionURL Tests", function () {
- describe("Test that isNewUser is passed correctly", function () {
+ describe("Test that isNewRecipeUser is passed correctly", function () {
describe("Email Password Recipe", function () {
let browser;
let page;
@@ -70,7 +69,7 @@ describe("getRedirectionURL Tests", function () {
await clearBrowserCookiesWithoutAffectingConsole(page, []);
});
- it("Test that isNewUser is true when signing up", async function () {
+ it("Test that isNewRecipeUser is true when signing up", async function () {
await toggleSignInSignUp(page);
await defaultSignUp(page);
const newUserCheck = await page.evaluate(() => localStorage.getItem("isNewUserCheck"));
@@ -117,7 +116,7 @@ describe("getRedirectionURL Tests", function () {
await page.evaluate(() => localStorage.removeItem("isNewUserCheck"));
});
- it("Test that isNewUser works correctly", async function () {
+ it("Test that isNewRecipeUser works correctly", async function () {
await Promise.all([
page.goto(`${TEST_CLIENT_BASE_URL}/auth`),
page.waitForNavigation({ waitUntil: "networkidle0" }),
@@ -175,14 +174,14 @@ describe("getRedirectionURL Tests", function () {
await page.evaluate(() => localStorage.removeItem("isNewUserCheck"));
});
- it("Test that isNewUser is true when signing up with email", async function () {
+ it("Test that isNewRecipeUser is true when signing up with email", async function () {
await toggleSignInSignUp(page);
await defaultSignUp(page, "thirdpartyemailpassword");
const newUserCheck = await page.evaluate(() => localStorage.getItem("isNewUserCheck"));
assert.equal(newUserCheck, "thirdpartyemailpassword-true");
});
- it("Test that isNewUser works correctly when signing up with auth 0", async function () {
+ it("Test that isNewRecipeUser works correctly when signing up with auth 0", async function () {
await assertProviders(page);
await clickOnProviderButton(page, "Auth0");
await Promise.all([
@@ -220,10 +219,10 @@ describe("getRedirectionURL Tests", function () {
method: "POST",
headers: [["content-type", "application/json"]],
body: JSON.stringify({
- configUpdates: [
- { key: "passwordless_code_lifetime", value: 4000 },
- { key: "passwordless_max_code_input_attempts", value: 3 },
- ],
+ coreConfig: {
+ passwordless_code_lifetime: 4000,
+ passwordless_max_code_input_attempts: 3,
+ },
}),
}).catch(console.error);
@@ -264,7 +263,7 @@ describe("getRedirectionURL Tests", function () {
await page.evaluate(() => localStorage.removeItem("isNewUserCheck"));
});
- it("Test that isNewUser is passed correctly", async function () {
+ it("Test that isNewRecipeUser is passed correctly", async function () {
await Promise.all([
page.goto(`${TEST_CLIENT_BASE_URL}/auth`),
page.waitForNavigation({ waitUntil: "networkidle0" }),
@@ -309,10 +308,10 @@ describe("getRedirectionURL Tests", function () {
method: "POST",
headers: [["content-type", "application/json"]],
body: JSON.stringify({
- configUpdates: [
- { key: "passwordless_code_lifetime", value: 4000 },
- { key: "passwordless_max_code_input_attempts", value: 3 },
- ],
+ coreConfig: {
+ passwordless_code_lifetime: 4000,
+ passwordless_max_code_input_attempts: 3,
+ },
}),
}).catch(console.error);
@@ -354,7 +353,7 @@ describe("getRedirectionURL Tests", function () {
await page.evaluate(() => localStorage.removeItem("isNewUserCheck"));
});
- it("Test that isNewUser is passed correctly", async function () {
+ it("Test that isNewRecipeUser is passed correctly", async function () {
await Promise.all([
page.goto(`${TEST_CLIENT_BASE_URL}/auth`),
page.waitForNavigation({ waitUntil: "networkidle0" }),
@@ -375,7 +374,7 @@ describe("getRedirectionURL Tests", function () {
assert.equal(newUserCheck, "thirdpartypasswordless-true");
});
- it("Test that isNewUser works correctly when signing up with auth 0", async function () {
+ it("Test that isNewRecipeUser works correctly when signing up with auth 0", async function () {
await Promise.all([
page.goto(`${TEST_CLIENT_BASE_URL}/auth`),
page.waitForNavigation({ waitUntil: "networkidle0" }),
diff --git a/test/end-to-end/multitenancy.dynamic_login_methods.test.js b/test/end-to-end/multitenancy.dynamic_login_methods.test.js
index ee811fe7d..04ded6bf8 100644
--- a/test/end-to-end/multitenancy.dynamic_login_methods.test.js
+++ b/test/end-to-end/multitenancy.dynamic_login_methods.test.js
@@ -17,8 +17,6 @@
* Imports
*/
-/* https://github.com/babel/babel/issues/9849#issuecomment-487040428 */
-import regeneratorRuntime from "regenerator-runtime";
import assert from "assert";
import puppeteer from "puppeteer";
import fetch from "isomorphic-fetch";
@@ -38,6 +36,9 @@ import {
clickOnProviderButton,
loginWithAuth0,
isMultitenancySupported,
+ isAccountLinkingSupported,
+ isMultitenancyManagementEndpointsSupported,
+ setupTenant,
} from "../helpers";
import {
TEST_CLIENT_BASE_URL,
@@ -48,9 +49,7 @@ import {
SOMETHING_WENT_WRONG_ERROR,
} from "../constants";
-// Run the tests in a DOM environment.
-require("jsdom-global")();
-
+let connectionURI;
/*
* Tests.
*/
@@ -60,7 +59,7 @@ describe("SuperTokens Multitenancy dynamic login methods", function () {
let pageCrashed;
before(async function () {
- const isSupported = await isMultitenancySupported();
+ const isSupported = (await isMultitenancySupported()) && (await isMultitenancyManagementEndpointsSupported());
if (!isSupported) {
this.skip();
}
@@ -71,10 +70,13 @@ describe("SuperTokens Multitenancy dynamic login methods", function () {
method: "POST",
}).catch(console.error);
- await fetch(`${TEST_SERVER_BASE_URL}/startst`, {
+ const startSTResp = await fetch(`${TEST_SERVER_BASE_URL}/startst`, {
method: "POST",
}).catch(console.error);
+ assert.strictEqual(startSTResp.status, 200);
+ connectionURI = await startSTResp.text();
+
page = await browser.newPage();
pageCrashed = false;
page.on("console", (c) => {
@@ -112,7 +114,9 @@ describe("SuperTokens Multitenancy dynamic login methods", function () {
});
after(async function () {
- await browser.close();
+ if (browser !== undefined) {
+ await browser.close();
+ }
});
it("Renders correct signup form with emailpassword when core list of providers is empty", async function () {
@@ -129,12 +133,18 @@ describe("SuperTokens Multitenancy dynamic login methods", function () {
page.waitForNavigation({ waitUntil: "networkidle0" }),
]);
const providers = await getProvidersLabels(page);
- compareArrayContents(providers, [
- "Continue with Github",
- "Continue with Google",
- "Continue with Facebook",
- "Continue with Auth0",
- ]);
+ compareArrayContents(
+ providers,
+ (await isAccountLinkingSupported())
+ ? [
+ "Continue with Github",
+ "Continue with Google",
+ "Continue with Facebook",
+ "Continue with Auth0",
+ "Continue with Mock Provider",
+ ]
+ : ["Continue with Github", "Continue with Google", "Continue with Facebook", "Continue with Auth0"]
+ );
const inputNames = await getInputNames(page);
assert.deepStrictEqual(inputNames, ["email", "password"]);
});
@@ -370,12 +380,18 @@ describe("SuperTokens Multitenancy dynamic login methods", function () {
]);
const providers = await getProvidersLabels(page);
- compareArrayContents(providers, [
- "Continue with Github",
- "Continue with Google",
- "Continue with Facebook",
- "Continue with Auth0",
- ]);
+ compareArrayContents(
+ providers,
+ (await isAccountLinkingSupported())
+ ? [
+ "Continue with Github",
+ "Continue with Google",
+ "Continue with Facebook",
+ "Continue with Auth0",
+ "Continue with Mock Provider",
+ ]
+ : ["Continue with Github", "Continue with Google", "Continue with Facebook", "Continue with Auth0"]
+ );
assert.strictEqual(await getProviderLogoCount(page), 3);
});
@@ -951,42 +967,8 @@ function clearDynamicLoginMethodsSettings(page) {
});
}
-export async function enableDynamicLoginMethods(page, mockLoginMethods, tenantId = "public", app = "public") {
- let coreResp = await fetch(`http://localhost:9000/appid-${app}/recipe/multitenancy/tenant`, {
- method: "PUT",
- headers: new Headers([
- ["content-type", "application/json"],
- ["rid", "multitenancy"],
- ]),
- body: JSON.stringify({
- tenantId,
- emailPasswordEnabled: mockLoginMethods.emailPassword?.enabled === true,
- thirdPartyEnabled: mockLoginMethods.thirdParty?.enabled === true,
- passwordlessEnabled: mockLoginMethods.passwordless?.enabled === true,
- coreConfig: {},
- }),
- });
- assert.strictEqual(coreResp.status, 200);
-
- for (const provider of mockLoginMethods["thirdParty"]?.providers) {
- coreResp = await fetch(`http://localhost:9000/appid-${app}/${tenantId}/recipe/multitenancy/config/thirdparty`, {
- method: "PUT",
- headers: new Headers([
- ["content-type", "application/json"],
- ["rid", "multitenancy"],
- ]),
- body: JSON.stringify({
- skipValidation: true,
- config: {
- ...providerConfigs[provider.id.split("-")[0]],
- thirdPartyId: provider.id,
- name: provider.name,
- },
- }),
- });
-
- assert.strictEqual(coreResp.status, 200);
- }
+export async function enableDynamicLoginMethods(page, mockLoginMethods, tenantId = "public") {
+ await setupTenant(tenantId, mockLoginMethods);
return page.evaluate(() => {
window.localStorage.setItem("usesDynamicLoginMethods", "true");
@@ -1002,66 +984,3 @@ export async function enableDynamicLoginMethods(page, mockLoginMethods, tenantId
function compareArrayContents(actual, expected) {
return assert.deepStrictEqual(actual.sort(), expected.sort());
}
-
-const providerConfigs = {
- apple: {
- clients: [
- {
- clientId: "4398792-io.supertokens.example.service",
- additionalConfig: {
- keyId: "7M48Y4RYDL",
- privateKey:
- "-----BEGIN PRIVATE KEY-----\nMIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgu8gXs+XYkqXD6Ala9Sf/iJXzhbwcoG5dMh1OonpdJUmgCgYIKoZIzj0DAQehRANCAASfrvlFbFCYqn3I2zeknYXLwtH30JuOKestDbSfZYxZNMqhF/OzdZFTV0zc5u5s3eN+oCWbnvl0hM+9IW0UlkdA\n-----END PRIVATE KEY-----",
- teamId: "YWQCXGJRJL",
- },
- },
- ],
- },
- github: {
- clients: [
- {
- clientSecret: "e97051221f4b6426e8fe8d51486396703012f5bd",
- clientId: "467101b197249757c71f",
- },
- ],
- },
- google: {
- clients: [
- {
- clientId: "1060725074195-kmeum4crr01uirfl2op9kd5acmi9jutn.apps.googleusercontent.com",
- clientSecret: "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",
- },
- ],
- },
- auth0: {
- // this contains info about forming the authorisation redirect URL without the state params and without the redirect_uri param
- authorizationEndpoint: `https://${process.env.AUTH0_DOMAIN}/authorize`,
- authorizationEndpointQueryParams: {
- scope: "openid profile email email_verified",
- },
- jwksURI: `https://${process.env.AUTH0_DOMAIN}/.well-known/jwks.json`,
- tokenEndpoint: `https://${process.env.AUTH0_DOMAIN}/oauth/token`,
- clients: [
- {
- clientId: process.env.AUTH0_CLIENT_ID,
- clientSecret: process.env.AUTH0_CLIENT_SECRET,
- },
- ],
- userInfoMap: {
- fromIdTokenPayload: {
- userId: "sub",
- email: "email",
- emailVerified: "email_verified",
- },
- },
- },
- test: {
- // We add a client since it's required
- clients: [
- {
- clientId: "1060725074195-kmeum4crr01uirfl2op9kd5acmi9jutn.apps.googleusercontent.com",
- clientSecret: "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",
- },
- ],
- },
-};
diff --git a/test/end-to-end/multitenancy.mock.test.js b/test/end-to-end/multitenancy.mock.test.js
index 83b132d50..5783342e7 100644
--- a/test/end-to-end/multitenancy.mock.test.js
+++ b/test/end-to-end/multitenancy.mock.test.js
@@ -17,8 +17,6 @@
* Imports
*/
-/* https://github.com/babel/babel/issues/9849#issuecomment-487040428 */
-import regeneratorRuntime from "regenerator-runtime";
import assert from "assert";
import puppeteer from "puppeteer";
import fetch from "isomorphic-fetch";
@@ -34,9 +32,6 @@ import {
import { TEST_CLIENT_BASE_URL, DEFAULT_WEBSITE_BASE_PATH, ST_ROOT_SELECTOR } from "../constants";
import { before } from "mocha";
-// Run the tests in a DOM environment.
-require("jsdom-global")();
-
/*
* Tests.
*/
diff --git a/test/end-to-end/multitenancy.tenant_interactions.test.js b/test/end-to-end/multitenancy.tenant_interactions.test.js
index e384e3e70..ab6958e6e 100644
--- a/test/end-to-end/multitenancy.tenant_interactions.test.js
+++ b/test/end-to-end/multitenancy.tenant_interactions.test.js
@@ -40,6 +40,11 @@ import {
getTextByDataSupertokens,
getVerificationEmailErrorTitle,
isMultitenancySupported,
+ isMultitenancyManagementEndpointsSupported,
+ setupTenant,
+ addUserToTenant,
+ removeUserFromTenant,
+ removeTenant,
} from "../helpers";
import {
TEST_CLIENT_BASE_URL,
@@ -50,9 +55,6 @@ import {
TEST_APPLICATION_SERVER_BASE_URL,
} from "../constants";
-// Run the tests in a DOM environment.
-require("jsdom-global")();
-
/*
* Tests.
*/
@@ -62,7 +64,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
let pageCrashed;
before(async function () {
- const isSupported = await isMultitenancySupported();
+ const isSupported = (await isMultitenancySupported()) && (await isMultitenancyManagementEndpointsSupported());
if (!isSupported) {
this.skip();
}
@@ -122,13 +124,15 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
});
after(async function () {
- await browser.close();
+ if (browser !== undefined) {
+ await browser.close();
+ }
});
describe("without user sharing", () => {
it("should not allow sign into user created on public when using a custom tenants", async function () {
await setEnabledRecipes(page, ["emailpassword"]);
- await setupTenant("public", "public", {
+ await setupTenant("public", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -136,7 +140,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
providers: [],
},
});
- await setupTenant("public", "customer1", {
+ await setupTenant("customer1", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -166,7 +170,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
it("should not allow sign into user created on custom tenant when using public", async function () {
await setEnabledRecipes(page, ["emailpassword"]);
- await setupTenant("public", "public", {
+ await setupTenant("public", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -174,7 +178,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
providers: [],
},
});
- await setupTenant("public", "customer1", {
+ await setupTenant("customer1", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -204,7 +208,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
it("should allow sign up on custom tenant after signing up on public", async function () {
await setEnabledRecipes(page, ["emailpassword"]);
- await setupTenant("public", "public", {
+ await setupTenant("public", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -212,7 +216,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
providers: [],
},
});
- await setupTenant("public", "customer1", {
+ await setupTenant("customer1", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -241,7 +245,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
it("should allow sign up on public tenant after signing up on a custom", async function () {
await setEnabledRecipes(page, ["emailpassword"]);
- await setupTenant("public", "public", {
+ await setupTenant("public", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -249,7 +253,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
providers: [],
},
});
- await setupTenant("public", "customer1", {
+ await setupTenant("customer1", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -281,7 +285,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
describe("with user sharing", () => {
it("should allow sign into user created on public when using a custom tenants", async function () {
await setEnabledRecipes(page, ["emailpassword"]);
- await setupTenant("public", "public", {
+ await setupTenant("public", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -289,7 +293,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
providers: [],
},
});
- await setupTenant("public", "customer1", {
+ await setupTenant("customer1", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -305,7 +309,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
const email = await epSignUp(page);
const userId = await getUserIdWithFetch(page);
- addUserToTenant("public", "customer1", userId);
+ addUserToTenant("customer1", userId);
await clearBrowserCookiesWithoutAffectingConsole(page, []);
await setTenantId(page, "customer1");
@@ -320,7 +324,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
it("should allow sign into user created on custom tenant when using public", async function () {
await setEnabledRecipes(page, ["emailpassword"]);
- await setupTenant("public", "public", {
+ await setupTenant("public", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -328,7 +332,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
providers: [],
},
});
- await setupTenant("public", "customer1", {
+ await setupTenant("customer1", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -345,7 +349,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
const email = await epSignUp(page);
const userId = await getUserIdWithFetch(page);
- addUserToTenant("public", "public", userId);
+ addUserToTenant("public", userId);
await clearBrowserCookiesWithoutAffectingConsole(page, []);
await setTenantId(page, "public");
@@ -360,7 +364,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
it("should not allow sign up on custom tenant after signing up on public", async function () {
await setEnabledRecipes(page, ["emailpassword"]);
- await setupTenant("public", "public", {
+ await setupTenant("public", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -368,7 +372,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
providers: [],
},
});
- await setupTenant("public", "customer1", {
+ await setupTenant("customer1", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -383,7 +387,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
]);
const email = await epSignUp(page);
const userId = await getUserIdWithFetch(page);
- addUserToTenant("public", "customer1", userId);
+ addUserToTenant("customer1", userId);
await clearBrowserCookiesWithoutAffectingConsole(page, []);
@@ -399,7 +403,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
it("should not allow sign up on public tenant after signing up on a custom", async function () {
await setEnabledRecipes(page, ["emailpassword"]);
- await setupTenant("public", "public", {
+ await setupTenant("public", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -407,7 +411,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
providers: [],
},
});
- await setupTenant("public", "customer1", {
+ await setupTenant("customer1", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -425,7 +429,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
let pathname = await page.evaluate(() => window.location.pathname);
assert.deepStrictEqual(pathname, "/dashboard");
const userId = await getUserIdWithFetch(page);
- addUserToTenant("public", "public", userId);
+ addUserToTenant("public", userId);
await clearBrowserCookiesWithoutAffectingConsole(page, []);
@@ -443,7 +447,15 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
describe("with removed user", () => {
it("should not allow sign in", async function () {
await setEnabledRecipes(page, ["emailpassword"]);
- await setupTenant("public", "public", {
+ await setupTenant("public", {
+ emailPassword: { enabled: true },
+ passwordless: { enabled: false },
+ thirdParty: {
+ enabled: true,
+ providers: [],
+ },
+ });
+ await setupTenant("customer1", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -460,7 +472,8 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
const email = await epSignUp(page);
const userId = await getUserIdWithFetch(page);
- removeUserFromTenant("public", "public", userId);
+ await addUserToTenant("customer1", userId);
+ await removeUserFromTenant("public", userId);
await clearBrowserCookiesWithoutAffectingConsole(page, []);
@@ -474,7 +487,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
it("should allow sign up", async function () {
await setEnabledRecipes(page, ["emailpassword"]);
- await setupTenant("public", "public", {
+ await setupTenant("public", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -482,7 +495,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
providers: [],
},
});
- await setupTenant("public", "customer1", {
+ await setupTenant("customer1", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -498,7 +511,8 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
const email = await epSignUp(page);
const userId = await getUserIdWithFetch(page);
- removeUserFromTenant("public", "public", userId);
+ await addUserToTenant("customer1", userId);
+ await removeUserFromTenant("public", userId);
await clearBrowserCookiesWithoutAffectingConsole(page, []);
await Promise.all([
@@ -513,7 +527,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
it("should log out on refresh", async function () {
await setEnabledRecipes(page, ["emailpassword"]);
- await setupTenant("public", "public", {
+ await setupTenant("public", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -521,7 +535,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
providers: [],
},
});
- await setupTenant("public", "customer1", {
+ await setupTenant("customer1", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -537,7 +551,8 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
await epSignUp(page);
const userId = await getUserIdWithFetch(page);
- removeUserFromTenant("public", "public", userId);
+ await addUserToTenant("customer1", userId);
+ await removeUserFromTenant("public", userId);
await Promise.all([
page.goto(`${TEST_CLIENT_BASE_URL}/dashboard`),
@@ -553,7 +568,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
describe("with removed tenant", () => {
it("should not allow sign in", async function () {
await setEnabledRecipes(page, ["emailpassword"]);
- await setupTenant("public", "customer1", {
+ await setupTenant("customer1", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -576,13 +591,13 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
page.waitForNavigation({ waitUntil: "networkidle0" }),
]);
- await removeTenant("public", "customer1");
+ await removeTenant("customer1");
await epSignIn(page, email, SOMETHING_WENT_WRONG_ERROR);
});
it("should not allow sign up", async function () {
await setEnabledRecipes(page, ["emailpassword"]);
- await setupTenant("public", "customer1", {
+ await setupTenant("customer1", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -596,13 +611,13 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
page.goto(`${TEST_CLIENT_BASE_URL}${DEFAULT_WEBSITE_BASE_PATH}`),
page.waitForNavigation({ waitUntil: "networkidle0" }),
]);
- await removeTenant("public", "customer1");
+ await removeTenant("customer1");
await epSignUp(page, undefined, [], SOMETHING_WENT_WRONG_ERROR);
});
it("should crash if dynamic login methods is enabled", async function () {
await setEnabledRecipes(page, ["emailpassword"]);
- await setupTenant("public", "customer1", {
+ await setupTenant("customer1", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -613,7 +628,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
await enableDynamicLoginMethods(page);
await setTenantId(page, "customer1");
- await removeTenant("public", "customer1");
+ await removeTenant("customer1");
await Promise.all([
page.goto(`${TEST_CLIENT_BASE_URL}${DEFAULT_WEBSITE_BASE_PATH}`),
@@ -627,7 +642,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
it("should keep the session active if even if dynamic login methods is enabled", async function () {
await setEnabledRecipes(page, ["emailpassword"]);
- await setupTenant("public", "customer1", {
+ await setupTenant("customer1", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -644,7 +659,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
]);
await epSignUp(page);
- await removeTenant("public", "customer1");
+ await removeTenant("customer1");
let getDynamicLoginMethodsCalled = false;
await page.setRequestInterception(true);
@@ -676,10 +691,10 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
}
});
- it.skip("should revoke magic links on removed tenants", async function () {
+ it("should revoke magic links on removed tenants", async function () {
await setPasswordlessFlowType("EMAIL_OR_PHONE", "USER_INPUT_CODE_AND_MAGIC_LINK");
await setEnabledRecipes(page, ["passwordless"]);
- await setupTenant("public", "customer1", {
+ await setupTenant("customer1", {
emailPassword: { enabled: false },
passwordless: { enabled: true },
thirdParty: {
@@ -706,13 +721,15 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
);
const device = await getPasswordlessDevice(loginAttemptInfo);
- await removeTenant("public", "customer1");
+ await removeTenant("customer1");
await setTenantId(page, "public");
- await page.goto(device.codes[0].urlWithLinkCode);
+ await Promise.all([
+ page.goto(device.codes[0].urlWithLinkCode),
+ page.waitForNavigation({ waitUntil: "networkidle0" }),
+ ]);
assert.strictEqual(await getGeneralError(page), SOMETHING_WENT_WRONG_ERROR);
- await waitForSTElement(page, "[data-supertokens~=input][name=emailOrPhone]");
});
});
@@ -723,7 +740,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
it("should work using OTP on the public tenants", async function () {
await setEnabledRecipes(page, ["passwordless"]);
- await setupTenant("public", "public", {
+ await setupTenant("public", {
emailPassword: { enabled: false },
passwordless: { enabled: true },
thirdParty: {
@@ -756,7 +773,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
it("should work using magic links on the public tenants", async function () {
await setEnabledRecipes(page, ["passwordless"]);
- await setupTenant("public", "public", {
+ await setupTenant("public", {
emailPassword: { enabled: false },
passwordless: { enabled: true },
thirdParty: {
@@ -788,7 +805,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
it("should work using OTP on a custom tenants", async function () {
await setEnabledRecipes(page, ["passwordless"]);
- await setupTenant("public", "customer1", {
+ await setupTenant("customer1", {
emailPassword: { enabled: false },
passwordless: { enabled: true },
thirdParty: {
@@ -822,7 +839,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
it("should work using magic links on a custom tenants", async function () {
await setEnabledRecipes(page, ["passwordless"]);
- await setupTenant("public", "customer1", {
+ await setupTenant("customer1", {
emailPassword: { enabled: false },
passwordless: { enabled: true },
thirdParty: {
@@ -855,7 +872,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
it("should work using magic links on a custom tenants even if the current app has the wrong tenant id", async function () {
await setEnabledRecipes(page, ["passwordless"]);
- await setupTenant("public", "customer1", {
+ await setupTenant("customer1", {
emailPassword: { enabled: false },
passwordless: { enabled: true },
thirdParty: {
@@ -889,7 +906,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
it("should work using OTP on a custom tenants even if the current app has the wrong tenant id", async function () {
await setEnabledRecipes(page, ["passwordless"]);
- await setupTenant("public", "customer1", {
+ await setupTenant("customer1", {
emailPassword: { enabled: false },
passwordless: { enabled: true },
thirdParty: {
@@ -933,7 +950,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
describe("password reset links", () => {
it("should reset password only on the tenant the link was created customer1 -> public", async function () {
await setEnabledRecipes(page, ["emailpassword"]);
- await setupTenant("public", "public", {
+ await setupTenant("public", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -941,7 +958,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
providers: [],
},
});
- await setupTenant("public", "customer1", {
+ await setupTenant("customer1", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -985,7 +1002,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
it("should reset password only on the tenant the link was created", async function () {
await setEnabledRecipes(page, ["emailpassword"]);
- await setupTenant("public", "public", {
+ await setupTenant("public", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -993,7 +1010,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
providers: [],
},
});
- await setupTenant("public", "customer1", {
+ await setupTenant("customer1", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -1035,9 +1052,9 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
await epSignIn(page, email);
});
- it("should be revoked when removing tenants", async function () {
+ it.skip("should be revoked when removing tenants", async function () {
await setEnabledRecipes(page, ["emailpassword"]);
- await setupTenant("public", "public", {
+ await setupTenant("public", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -1045,7 +1062,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
providers: [],
},
});
- await setupTenant("public", "customer1", {
+ await setupTenant("customer1", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -1068,7 +1085,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
await submitForm(page);
await sendEmailResetPasswordSuccessMessage(page);
const latestURLWithToken = await getLatestURLWithToken();
- await removeTenant("public", "customer1");
+ await removeTenant("customer1");
await page.goto(latestURLWithToken);
const newPassword = "NEW_Str0ngP@ssw0rd";
@@ -1077,14 +1094,14 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
{ name: "confirm-password", value: newPassword },
]);
await submitForm(page);
- assert.strictEqual(await getGeneralError(page), SOMETHING_WENT_WRONG_ERROR);
+ assert.strictEqual(await getGeneralError(page), "Invalid password reset token");
});
});
describe("email verification links", () => {
it("should verify email only on the tenant in the link", async function () {
await setEnabledRecipes(page, ["emailpassword"]);
- await setupTenant("public", "public", {
+ await setupTenant("public", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -1092,7 +1109,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
providers: [],
},
});
- await setupTenant("public", "customer1", {
+ await setupTenant("customer1", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -1145,7 +1162,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
it("should be revoked when removing tenants", async function () {
await setEnabledRecipes(page, ["emailpassword"]);
- await setupTenant("public", "public", {
+ await setupTenant("public", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -1153,7 +1170,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
providers: [],
},
});
- await setupTenant("public", "customer1", {
+ await setupTenant("customer1", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -1171,7 +1188,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
await new Promise((res) => setTimeout(res, 1000));
const latestURLWithToken = await getLatestURLWithToken();
- await removeTenant("public", "customer1");
+ await removeTenant("customer1");
await page.goto(latestURLWithToken);
assert.strictEqual(await getVerificationEmailErrorTitle(page), "!\nSomething went wrong");
@@ -1181,7 +1198,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
describe("AllowedDomainsClaim", () => {
it("should return the right value on a custom tenant", async function () {
await setEnabledRecipes(page, ["emailpassword"]);
- await setupTenant("public", "customer1", {
+ await setupTenant("customer1", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -1220,7 +1237,7 @@ describe("SuperTokens Multitenancy tenant interactions", function () {
it("should return the right value on the default tenant", async function () {
await setEnabledRecipes(page, ["emailpassword"]);
- await setupTenant("public", "public", {
+ await setupTenant("public", {
emailPassword: { enabled: true },
passwordless: { enabled: false },
thirdParty: {
@@ -1310,66 +1327,6 @@ export async function enableDynamicLoginMethods(page) {
});
}
-async function setupTenant(appId, tenantId, mockLoginMethods) {
- let coreResp = await fetch(`http://localhost:9000/appid-${appId}/recipe/multitenancy/tenant`, {
- method: "PUT",
- headers: new Headers([
- ["content-type", "application/json"],
- ["rid", "multitenancy"],
- ]),
- body: JSON.stringify({
- tenantId,
- emailPasswordEnabled: mockLoginMethods.emailPassword?.enabled === true,
- thirdPartyEnabled: mockLoginMethods.thirdParty?.enabled === true,
- passwordlessEnabled: mockLoginMethods.passwordless?.enabled === true,
- coreConfig: {},
- }),
- });
- assert.strictEqual(coreResp.status, 200);
-}
-
-async function addUserToTenant(appId, tenantId, userId) {
- let coreResp = await fetch(`http://localhost:9000/appid-${appId}/${tenantId}/recipe/multitenancy/tenant/user`, {
- method: "POST",
- headers: new Headers([
- ["content-type", "application/json"],
- ["rid", "multitenancy"],
- ]),
- body: JSON.stringify({
- userId,
- }),
- });
- assert.strictEqual(coreResp.status, 200);
-}
-
-async function removeUserFromTenant(appId, tenantId, userId) {
- let coreResp = await fetch(
- `http://localhost:9000/appid-${appId}/${tenantId}/recipe/multitenancy/tenant/user/remove`,
- {
- method: "POST",
- headers: new Headers([
- ["content-type", "application/json"],
- ["rid", "multitenancy"],
- ]),
- body: JSON.stringify({
- userId,
- }),
- }
- );
- assert.strictEqual(coreResp.status, 200);
-}
-
-async function removeTenant(appId, tenantId) {
- let coreResp = await fetch(`http://localhost:9000/appid-${appId}/recipe/multitenancy/tenant/remove`, {
- method: "POST",
- headers: new Headers([["rid", "multitenancy"]]),
- body: JSON.stringify({
- tenantId,
- }),
- });
- assert.strictEqual(coreResp.status, 200);
-}
-
async function epSignUp(page, email, fieldErrors, generalError, emailVerificationRequired) {
const link = await getSignInOrSignUpSwitchLink(page);
const linkText = await link.evaluate((e) => e.textContent);
diff --git a/test/end-to-end/passwordless.test.js b/test/end-to-end/passwordless.test.js
index ef7f55efc..401542fb3 100644
--- a/test/end-to-end/passwordless.test.js
+++ b/test/end-to-end/passwordless.test.js
@@ -17,8 +17,6 @@
* Imports
*/
-/* https://github.com/babel/babel/issues/9849#issuecomment-487040428 */
-import regeneratorRuntime from "regenerator-runtime";
import assert from "assert";
import puppeteer from "puppeteer";
import fetch from "isomorphic-fetch";
@@ -37,10 +35,9 @@ import {
isGeneralErrorSupported,
setGeneralErrorToLocalStorage,
getInputField,
+ isAccountLinkingSupported,
} from "../helpers";
-// Run the tests in a DOM environment.
-require("jsdom-global")();
import {
TEST_CLIENT_BASE_URL,
TEST_SERVER_BASE_URL,
@@ -535,10 +532,12 @@ export function getPasswordlessTestCases({ authRecipe, logId, generalErrorRecipe
});
function getTestCases(contactMethod, inputName, contactInfo) {
+ let accountLinkingSupported;
describe(`UserInputCode`, function () {
before(async function () {
({ browser, page } = await initBrowser(contactMethod, consoleLogs, authRecipe));
await setPasswordlessFlowType(contactMethod, "USER_INPUT_CODE");
+ accountLinkingSupported = await isAccountLinkingSupported();
});
after(async function () {
@@ -1039,6 +1038,7 @@ export function getPasswordlessTestCases({ authRecipe, logId, generalErrorRecipe
before(async function () {
({ browser, page } = await initBrowser(contactMethod, consoleLogs, authRecipe));
await setPasswordlessFlowType(contactMethod, "MAGIC_LINK");
+ accountLinkingSupported = await isAccountLinkingSupported();
});
after(async function () {
@@ -1470,6 +1470,7 @@ export function getPasswordlessTestCases({ authRecipe, logId, generalErrorRecipe
`ST_LOGS ${logId} OVERRIDE GET_LOGIN_ATTEMPT_INFO`,
`ST_LOGS ${logId} OVERRIDE CONSUME_CODE`,
`ST_LOGS ${logId} PRE_API_HOOKS PASSWORDLESS_CONSUME_CODE`,
+ ...(accountLinkingSupported ? [`ST_LOGS ${logId} ON_HANDLE_EVENT PASSWORDLESS_RESTART_FLOW`] : []),
`ST_LOGS SUPERTOKENS GET_REDIRECTION_URL TO_AUTH`,
...signInUpPageLoadLogs,
]);
@@ -1545,6 +1546,7 @@ export function getPasswordlessTestCases({ authRecipe, logId, generalErrorRecipe
before(async function () {
({ browser, page } = await initBrowser(contactMethod, consoleLogs, authRecipe));
await setPasswordlessFlowType(contactMethod, "USER_INPUT_CODE_AND_MAGIC_LINK");
+ accountLinkingSupported = await isAccountLinkingSupported();
});
after(async function () {
@@ -2130,10 +2132,10 @@ async function initBrowser(contactMethod, consoleLogs, authRecipe, { defaultCoun
method: "POST",
headers: [["content-type", "application/json"]],
body: JSON.stringify({
- configUpdates: [
- { key: "passwordless_code_lifetime", value: 4000 },
- { key: "passwordless_max_code_input_attempts", value: 3 },
- ],
+ coreConfig: {
+ passwordless_code_lifetime: 4000,
+ passwordless_max_code_input_attempts: 3,
+ },
}),
}).catch(console.error);
diff --git a/test/end-to-end/refresherrors.test.js b/test/end-to-end/refresherrors.test.js
index d36000842..06909e4cf 100644
--- a/test/end-to-end/refresherrors.test.js
+++ b/test/end-to-end/refresherrors.test.js
@@ -21,8 +21,6 @@ import puppeteer from "puppeteer";
import { clearBrowserCookiesWithoutAffectingConsole, getTextInDashboardNoAuth, screenshotOnFailure } from "../helpers";
-// Run the tests in a DOM environment.
-require("jsdom-global")();
import { TEST_CLIENT_BASE_URL } from "../constants";
describe("Refresh errors", function () {
diff --git a/test/end-to-end/resetpasswordusingtoken.test.js b/test/end-to-end/resetpasswordusingtoken.test.js
index 1bb1d6813..0d5b14dc1 100644
--- a/test/end-to-end/resetpasswordusingtoken.test.js
+++ b/test/end-to-end/resetpasswordusingtoken.test.js
@@ -17,8 +17,6 @@
* Imports
*/
-/* https://github.com/babel/babel/issues/9849#issuecomment-487040428 */
-import regeneratorRuntime from "regenerator-runtime";
import assert from "assert";
import puppeteer from "puppeteer";
import fetch from "isomorphic-fetch";
@@ -56,9 +54,6 @@ import {
getResetPasswordSuccessBackToSignInButton,
} from "../helpers";
-// Run the tests in a DOM environment.
-require("jsdom-global")();
-
/*
* Tests.
*/
diff --git a/test/end-to-end/routing.test.js b/test/end-to-end/routing.test.js
index 1aee0aadc..55c4e3fea 100644
--- a/test/end-to-end/routing.test.js
+++ b/test/end-to-end/routing.test.js
@@ -17,15 +17,10 @@
* Imports
*/
-/* https://github.com/babel/babel/issues/9849#issuecomment-487040428 */
-import regeneratorRuntime from "regenerator-runtime";
import assert from "assert";
import { spawn } from "child_process";
import puppeteer from "puppeteer";
-// Run the tests in a DOM environment.
-require("jsdom-global")();
-
import { TEST_CLIENT_BASE_URL, DEFAULT_WEBSITE_BASE_PATH } from "../constants";
import {
getSubmitFormButtonLabel,
diff --git a/test/end-to-end/signin-rrdv5.test.js b/test/end-to-end/signin-rrdv5.test.js
index 83c1f6a22..5a5b441df 100644
--- a/test/end-to-end/signin-rrdv5.test.js
+++ b/test/end-to-end/signin-rrdv5.test.js
@@ -17,8 +17,6 @@
* Imports
*/
-/* https://github.com/babel/babel/issues/9849#issuecomment-487040428 */
-import regeneratorRuntime from "regenerator-runtime";
import assert from "assert";
import puppeteer from "puppeteer";
import {
@@ -55,9 +53,6 @@ import {
import fetch from "isomorphic-fetch";
import { SOMETHING_WENT_WRONG_ERROR } from "../constants";
-// Run the tests in a DOM environment.
-require("jsdom-global")();
-
import { EMAIL_EXISTS_API, SIGN_IN_API, TEST_CLIENT_BASE_URL, TEST_SERVER_BASE_URL, SIGN_OUT_API } from "../constants";
/*
diff --git a/test/end-to-end/signin-rrdv6.test.js b/test/end-to-end/signin-rrdv6.test.js
index 978f4ba63..51c22c61f 100644
--- a/test/end-to-end/signin-rrdv6.test.js
+++ b/test/end-to-end/signin-rrdv6.test.js
@@ -17,8 +17,6 @@
* Imports
*/
-/* https://github.com/babel/babel/issues/9849#issuecomment-487040428 */
-import regeneratorRuntime from "regenerator-runtime";
import assert from "assert";
import puppeteer from "puppeteer";
import {
@@ -55,9 +53,6 @@ import {
import fetch from "isomorphic-fetch";
import { SOMETHING_WENT_WRONG_ERROR } from "../constants";
-// Run the tests in a DOM environment.
-require("jsdom-global")();
-
import { EMAIL_EXISTS_API, SIGN_IN_API, TEST_CLIENT_BASE_URL, TEST_SERVER_BASE_URL, SIGN_OUT_API } from "../constants";
/*
diff --git a/test/end-to-end/signin.test.js b/test/end-to-end/signin.test.js
index 1ed83048a..e5b00ecab 100644
--- a/test/end-to-end/signin.test.js
+++ b/test/end-to-end/signin.test.js
@@ -17,8 +17,6 @@
* Imports
*/
-/* https://github.com/babel/babel/issues/9849#issuecomment-487040428 */
-import regeneratorRuntime from "regenerator-runtime";
import assert from "assert";
import puppeteer from "puppeteer";
import {
@@ -58,9 +56,6 @@ import {
import fetch from "isomorphic-fetch";
import { SOMETHING_WENT_WRONG_ERROR } from "../constants";
-// Run the tests in a DOM environment.
-require("jsdom-global")();
-
import { EMAIL_EXISTS_API, SIGN_IN_API, TEST_CLIENT_BASE_URL, TEST_SERVER_BASE_URL, SIGN_OUT_API } from "../constants";
/*
diff --git a/test/end-to-end/signup.test.js b/test/end-to-end/signup.test.js
index 117458a14..3804da90c 100644
--- a/test/end-to-end/signup.test.js
+++ b/test/end-to-end/signup.test.js
@@ -17,8 +17,6 @@
* Imports
*/
-/* https://github.com/babel/babel/issues/9849#issuecomment-487040428 */
-import regeneratorRuntime from "regenerator-runtime";
import assert from "assert";
import fetch from "isomorphic-fetch";
import puppeteer from "puppeteer";
@@ -42,8 +40,6 @@ import {
waitForSTElement,
} from "../helpers";
-// Run the tests in a DOM environment.
-require("jsdom-global")();
import {
EMAIL_EXISTS_API,
SIGN_UP_API,
diff --git a/test/end-to-end/thirdparty.test.js b/test/end-to-end/thirdparty.test.js
index 5489a04e4..c1d176566 100644
--- a/test/end-to-end/thirdparty.test.js
+++ b/test/end-to-end/thirdparty.test.js
@@ -17,8 +17,6 @@
* Imports
*/
-/* https://github.com/babel/babel/issues/9849#issuecomment-487040428 */
-import regeneratorRuntime from "regenerator-runtime";
import assert from "assert";
import fetch from "isomorphic-fetch";
import puppeteer from "puppeteer";
@@ -35,8 +33,6 @@ import {
clickOnProviderButtonWithoutWaiting,
} from "../helpers";
-// Run the tests in a DOM environment.
-require("jsdom-global")();
import { TEST_CLIENT_BASE_URL, TEST_SERVER_BASE_URL, SIGN_IN_UP_API, GET_AUTH_URL_API } from "../constants";
describe("SuperTokens Third Party", function () {
diff --git a/test/end-to-end/thirdpartyemailpassword.test.js b/test/end-to-end/thirdpartyemailpassword.test.js
index 2411fba07..798908687 100644
--- a/test/end-to-end/thirdpartyemailpassword.test.js
+++ b/test/end-to-end/thirdpartyemailpassword.test.js
@@ -17,8 +17,6 @@
* Imports
*/
-/* https://github.com/babel/babel/issues/9849#issuecomment-487040428 */
-import regeneratorRuntime from "regenerator-runtime";
import assert from "assert";
import fetch from "isomorphic-fetch";
import puppeteer from "puppeteer";
@@ -43,6 +41,8 @@ import {
waitFor,
getFieldErrors,
clickOnProviderButtonWithoutWaiting,
+ getFeatureFlags,
+ setEnabledRecipes,
} from "../helpers";
import {
TEST_CLIENT_BASE_URL,
@@ -54,9 +54,6 @@ import {
GET_AUTH_URL_API,
} from "../constants";
-// Run the tests in a DOM environment.
-require("jsdom-global")();
-
/*
* Tests.
*/
@@ -371,6 +368,22 @@ describe("SuperTokens Third Party Email Password", function () {
const url = new URL(res[0].url());
assert.strictEqual(url.searchParams.get("clientType"), "test-web");
});
+
+ it("should handle no providers enabled on the backend", async function () {
+ if (!(await getFeatureFlags()).includes("recipeConfig")) {
+ this.skip();
+ }
+ await assertProviders(page);
+ await setEnabledRecipes(["thirdpartyemailpassword"], []);
+
+ await Promise.all([
+ page.waitForResponse(
+ (response) => response.url().startsWith(GET_AUTH_URL_API) && response.status() === 400
+ ),
+ clickOnProviderButtonWithoutWaiting(page, "Auth0"),
+ ]);
+ assert.strictEqual(await getGeneralError(page), "Something went wrong. Please try again.");
+ });
});
describe("Third Party callback error tests", function () {
diff --git a/test/end-to-end/thirdpartypasswordless.test.js b/test/end-to-end/thirdpartypasswordless.test.js
index be53d2cf5..9474ba8ba 100644
--- a/test/end-to-end/thirdpartypasswordless.test.js
+++ b/test/end-to-end/thirdpartypasswordless.test.js
@@ -17,8 +17,6 @@
* Imports
*/
-/* https://github.com/babel/babel/issues/9849#issuecomment-487040428 */
-import regeneratorRuntime from "regenerator-runtime";
import assert from "assert";
import puppeteer from "puppeteer";
import {
@@ -34,14 +32,15 @@ import {
setPasswordlessFlowType,
getFeatureFlags,
isReact16,
+ assertProviders,
+ setEnabledRecipes,
+ clickOnProviderButtonWithoutWaiting,
+ getGeneralError,
} from "../helpers";
-import { TEST_CLIENT_BASE_URL, TEST_SERVER_BASE_URL, SIGN_IN_UP_API } from "../constants";
+import { TEST_CLIENT_BASE_URL, TEST_SERVER_BASE_URL, SIGN_IN_UP_API, GET_AUTH_URL_API } from "../constants";
import { getThirdPartyTestCases } from "./thirdparty.test";
import { getPasswordlessTestCases } from "./passwordless.test";
-// Run the tests in a DOM environment.
-require("jsdom-global")();
-
/*
* Tests.
*/
@@ -210,6 +209,22 @@ describe("SuperTokens Third Party Passwordless", function () {
"ST_LOGS SESSION OVERRIDE GET_USER_ID",
]);
});
+
+ it("should handle no providers enabled on the backend", async function () {
+ if (!(await getFeatureFlags()).includes("recipeConfig")) {
+ this.skip();
+ }
+ await assertProviders(page);
+ await setEnabledRecipes(["thirdpartypasswordless"], []);
+
+ await Promise.all([
+ page.waitForResponse(
+ (response) => response.url().startsWith(GET_AUTH_URL_API) && response.status() === 400
+ ),
+ clickOnProviderButtonWithoutWaiting(page, "Auth0"),
+ ]);
+ assert.strictEqual(await getGeneralError(page), "Something went wrong. Please try again.");
+ });
});
describe("Third Party specific", function () {
diff --git a/test/end-to-end/userContext.test.js b/test/end-to-end/userContext.test.js
index fe1ee8c92..9bd66287d 100644
--- a/test/end-to-end/userContext.test.js
+++ b/test/end-to-end/userContext.test.js
@@ -12,8 +12,7 @@
* License for the specific language governing permissions and limitations
* under the License.
*/
-/* https://github.com/babel/babel/issues/9849#issuecomment-487040428 */
-import regeneratorRuntime from "regenerator-runtime";
+
import puppeteer from "puppeteer";
import {
clearBrowserCookiesWithoutAffectingConsole,
@@ -35,9 +34,6 @@ import {
} from "../constants";
import assert from "assert";
-// Run the tests in a DOM environment.
-require("jsdom-global")();
-
describe("SuperTokens userContext with UI components test", function () {
let browser;
let page;
diff --git a/test/end-to-end/userroles.test.js b/test/end-to-end/userroles.test.js
index 607d08ab1..f4ac7b811 100644
--- a/test/end-to-end/userroles.test.js
+++ b/test/end-to-end/userroles.test.js
@@ -32,8 +32,6 @@ import {
waitForText,
} from "../helpers";
-// Run the tests in a DOM environment.
-require("jsdom-global")();
import { TEST_APPLICATION_SERVER_BASE_URL, TEST_CLIENT_BASE_URL, TEST_SERVER_BASE_URL } from "../constants";
describe("User Roles in the frontend", function () {
diff --git a/test/helpers.js b/test/helpers.js
index 925b5d4b2..8274127f6 100644
--- a/test/helpers.js
+++ b/test/helpers.js
@@ -254,7 +254,7 @@ export async function getInputAdornmentsError(page) {
document
.querySelector(ST_ROOT_SELECTOR)
.shadowRoot.querySelectorAll("[data-supertokens~='inputAdornmentError']"),
- (i) => i.name
+ (i) => i.textContent
),
{ ST_ROOT_SELECTOR }
);
@@ -509,6 +509,7 @@ export async function assertProviders(page) {
"Continue with Apple",
"Continue with Custom",
"Continue with Auth0",
+ "Continue with Mock Provider",
]);
}
@@ -593,11 +594,7 @@ export async function defaultSignUp(page, rid = "emailpassword") {
rid
);
}
-export async function signUp(page, fields, postValues, rid = "emailpassword") {
- if (postValues === undefined) {
- postValues = JSON.stringify({ formFields: fields.map((v) => ({ id: v.name, value: v.value })) });
- }
-
+export async function signUp(page, fields, postValues = undefined, rid = "emailpassword") {
// Set values.
await setInputValues(page, fields);
const successAdornments = await getInputAdornmentsSuccess(page);
@@ -614,7 +611,9 @@ export async function signUp(page, fields, postValues, rid = "emailpassword") {
assert.strictEqual(hasEmailExistMethodBeenCalled, false);
assert.strictEqual(request.headers().rid, rid);
- assert.strictEqual(request.postData(), postValues);
+ if (postValues !== undefined) {
+ assert.strictEqual(request.postData(), postValues);
+ }
assert.strictEqual(response.status, "OK");
await page.setRequestInterception(false);
@@ -704,12 +703,12 @@ export async function screenshotOnFailure(ctx, browser) {
continue;
}
- const title = ctx.currentTest
+ let title = ctx.currentTest
.fullTitle()
.split(/\W/)
.filter((a) => a.length !== 0)
- .join("_")
- .substring(0, 20);
+ .join("_");
+ title = title.substring(title.length - 30);
await pages[i].screenshot({
path: path.join(screenshotRoot, testFileName, `${title}-tab_${i}-${Date.now()}.png`),
});
@@ -744,6 +743,44 @@ export function setPasswordlessFlowType(contactMethod, flowType) {
});
}
+export function setAccountLinkingConfig(enabled, shouldAutomaticallyLink, shouldRequireVerification) {
+ return fetch(`${TEST_APPLICATION_SERVER_BASE_URL}/test/setAccountLinkingConfig`, {
+ method: "POST",
+ headers: [["content-type", "application/json"]],
+ body: JSON.stringify({
+ enabled,
+ shouldAutoLink: {
+ shouldAutomaticallyLink,
+ shouldRequireVerification,
+ },
+ }),
+ });
+}
+
+export function changeEmail(rid, recipeUserId, email, phoneNumber) {
+ return fetch(`${TEST_APPLICATION_SERVER_BASE_URL}/changeEmail`, {
+ method: "POST",
+ headers: [["content-type", "application/json"]],
+ body: JSON.stringify({
+ rid,
+ recipeUserId,
+ email,
+ phoneNumber,
+ }),
+ });
+}
+
+export function setEnabledRecipes(enabledRecipes, enabledProviders) {
+ return fetch(`${TEST_APPLICATION_SERVER_BASE_URL}/test/setEnabledRecipes`, {
+ method: "POST",
+ headers: [["content-type", "application/json"]],
+ body: JSON.stringify({
+ enabledRecipes,
+ enabledProviders,
+ }),
+ });
+}
+
export function isReact16() {
return process.env.IS_REACT_16 === "true";
}
@@ -807,6 +844,24 @@ export async function isMultitenancySupported() {
return true;
}
+export async function isMultitenancyManagementEndpointsSupported() {
+ const features = await getFeatureFlags();
+ if (!features.includes("multitenancyManagementEndpoints")) {
+ return false;
+ }
+
+ return true;
+}
+
+export async function isAccountLinkingSupported() {
+ const features = await getFeatureFlags();
+ if (!features.includes("accountlinking")) {
+ return false;
+ }
+
+ return true;
+}
+
/**
* For example setGeneralErrorToLocalStorage("EMAIL_PASSWORD", "EMAIL_PASSWORD_SIGN_UP", page) to
* set for signUp in email password
@@ -821,3 +876,121 @@ export async function setGeneralErrorToLocalStorage(recipeName, action, page) {
export async function getTestEmail() {
return `john.doe+${Date.now()}@supertokens.io`;
}
+
+export async function setupTenant(tenantId, loginMethods) {
+ const body = {
+ tenantId,
+ loginMethods,
+ };
+ if (loginMethods.thirdParty?.providers) {
+ body.loginMethods.thirdParty.providers = loginMethods.thirdParty.providers.map((provider) => ({
+ ...testProviderConfigs[provider.id.split("-")[0]],
+ thirdPartyId: provider.id,
+ name: provider.name,
+ }));
+ }
+ let coreResp = await fetch(`${TEST_APPLICATION_SERVER_BASE_URL}/setupTenant`, {
+ method: "POST",
+ headers: new Headers([["content-type", "application/json"]]),
+ body: JSON.stringify(body),
+ });
+ assert.strictEqual(coreResp.status, 200);
+}
+
+export async function addUserToTenant(tenantId, recipeUserId) {
+ let coreResp = await fetch(`${TEST_APPLICATION_SERVER_BASE_URL}/addUserToTenant`, {
+ method: "POST",
+ headers: new Headers([["content-type", "application/json"]]),
+ body: JSON.stringify({
+ tenantId,
+ recipeUserId,
+ }),
+ });
+ assert.strictEqual(coreResp.status, 200);
+}
+
+export async function removeUserFromTenant(tenantId, recipeUserId) {
+ let coreResp = await fetch(`${TEST_APPLICATION_SERVER_BASE_URL}/removeUserFromTenant`, {
+ method: "POST",
+ headers: new Headers([["content-type", "application/json"]]),
+ body: JSON.stringify({
+ tenantId,
+ recipeUserId,
+ }),
+ });
+ assert.strictEqual(coreResp.status, 200);
+}
+
+export async function removeTenant(tenantId) {
+ let coreResp = await fetch(`${TEST_APPLICATION_SERVER_BASE_URL}/removeTenant`, {
+ method: "POST",
+ headers: new Headers([["content-type", "application/json"]]),
+ body: JSON.stringify({
+ tenantId,
+ }),
+ });
+ assert.strictEqual(coreResp.status, 200);
+}
+
+const testProviderConfigs = {
+ apple: {
+ clients: [
+ {
+ clientId: "4398792-io.supertokens.example.service",
+ additionalConfig: {
+ keyId: "7M48Y4RYDL",
+ privateKey:
+ "-----BEGIN PRIVATE KEY-----\nMIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgu8gXs+XYkqXD6Ala9Sf/iJXzhbwcoG5dMh1OonpdJUmgCgYIKoZIzj0DAQehRANCAASfrvlFbFCYqn3I2zeknYXLwtH30JuOKestDbSfZYxZNMqhF/OzdZFTV0zc5u5s3eN+oCWbnvl0hM+9IW0UlkdA\n-----END PRIVATE KEY-----",
+ teamId: "YWQCXGJRJL",
+ },
+ },
+ ],
+ },
+ github: {
+ clients: [
+ {
+ clientSecret: "e97051221f4b6426e8fe8d51486396703012f5bd",
+ clientId: "467101b197249757c71f",
+ },
+ ],
+ },
+ google: {
+ clients: [
+ {
+ clientId: "1060725074195-kmeum4crr01uirfl2op9kd5acmi9jutn.apps.googleusercontent.com",
+ clientSecret: "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",
+ },
+ ],
+ },
+ auth0: {
+ // this contains info about forming the authorisation redirect URL without the state params and without the redirect_uri param
+ authorizationEndpoint: `https://${process.env.AUTH0_DOMAIN}/authorize`,
+ authorizationEndpointQueryParams: {
+ scope: "openid profile email email_verified",
+ },
+ jwksURI: `https://${process.env.AUTH0_DOMAIN}/.well-known/jwks.json`,
+ tokenEndpoint: `https://${process.env.AUTH0_DOMAIN}/oauth/token`,
+ clients: [
+ {
+ clientId: process.env.AUTH0_CLIENT_ID,
+ clientSecret: process.env.AUTH0_CLIENT_SECRET,
+ },
+ ],
+ userInfoMap: {
+ fromIdTokenPayload: {
+ userId: "sub",
+ email: "email",
+ emailVerified: "email_verified",
+ },
+ },
+ },
+ test: {
+ // We add a client since it's required
+ clients: [
+ {
+ clientId: "1060725074195-kmeum4crr01uirfl2op9kd5acmi9jutn.apps.googleusercontent.com",
+ clientSecret: "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",
+ },
+ ],
+ },
+};
diff --git a/test/server/index.js b/test/server/index.js
index 1b2c45409..e05e753d1 100644
--- a/test/server/index.js
+++ b/test/server/index.js
@@ -44,6 +44,7 @@ let {
customAuth0Provider,
maxVersion,
stopST,
+ mockThirdPartyProvider,
} = require("./utils");
let { version: nodeSDKVersion } = require("supertokens-node/lib/build/version");
const fetch = require("isomorphic-fetch");
@@ -89,6 +90,15 @@ try {
multitenancySupported = false;
}
+let AccountLinking, AccountLinkingRaw, accountLinkingSupported;
+try {
+ AccountLinkingRaw = require("supertokens-node/lib/build/recipe/accountlinking/recipe").default;
+ AccountLinking = require("supertokens-node/recipe/accountlinking");
+ accountLinkingSupported = true;
+} catch (ex) {
+ accountLinkingSupported = false;
+}
+
let generalErrorSupported;
if (maxVersion(nodeSDKVersion, "9.9.9") === "9.9.9") {
@@ -98,7 +108,7 @@ if (maxVersion(nodeSDKVersion, "9.9.9") === "9.9.9") {
generalErrorSupported = true;
}
-const providers = [
+const fullProviderList = [
{
config: {
thirdPartyId: "google",
@@ -133,18 +143,34 @@ const providers = [
},
},
customAuth0Provider(),
+ mockThirdPartyProvider,
];
let urlencodedParser = bodyParser.urlencoded({ limit: "20mb", extended: true, parameterLimit: 20000 });
let jsonParser = bodyParser.json({ limit: "20mb" });
let app = express();
+
+const originalSend = app.response.send;
+app.response.send = function sendOverWrite(body) {
+ originalSend.call(this, body);
+ this.__custombody__ = body;
+};
+
morgan.token("body", function (req, res) {
- return JSON.stringify(req.body && req.body["formFields"]);
+ return JSON.stringify(req.body);
+});
+
+morgan.token("res-body", function (req, res) {
+ return typeof res.__custombody__ ? res.__custombody__ : JSON.stringify(res.__custombody__);
});
-app.use(morgan("[:date[iso]] :url :method :status :response-time ms - :res[content-length] - :body"));
+
app.use(urlencodedParser);
app.use(jsonParser);
+
+app.use(morgan("[:date[iso]] :url :method :body", { immediate: true }));
+app.use(morgan("[:date[iso]] :url :method :status :response-time ms - :res[content-length] :res-body"));
+
app.use(cookieParser());
const WEB_PORT = process.env.WEB_PORT || 3031;
@@ -184,6 +210,13 @@ const formFields = (process.env.MIN_FIELDS && []) || [
optional: true,
},
];
+
+let connectionURI = "http://localhost:9000";
+let passwordlessConfig = {};
+let accountLinkingConfig = {};
+let enabledProviders = undefined;
+let enabledRecipes = undefined;
+
initST();
app.use(
@@ -202,30 +235,37 @@ app.get("/ping", async (req, res) => {
});
app.post("/startst", async (req, res) => {
- if (req.body && req.body.configUpdates) {
- for (const update of req.body.configUpdates) {
- await setKeyValueInConfig(update.key, update.value);
- }
+ try {
+ connectionURI = await startST(req.body);
+ console.log("Connection URI: " + connectionURI);
+ const OPAQUE_KEY_WITH_ALL_FEATURES_ENABLED =
+ "N2yITHflaFS4BPm7n0bnfFCjP4sJoTERmP0J=kXQ5YONtALeGnfOOe2rf2QZ0mfOh0aO3pBqfF-S0jb0ABpat6pySluTpJO6jieD6tzUOR1HrGjJO=50Ob3mHi21tQHJ";
+
+ await fetch(`${connectionURI}/ee/license`, {
+ method: "PUT",
+ headers: {
+ "content-type": "application/json; charset=utf-8",
+ },
+ body: JSON.stringify({
+ licenseKey: OPAQUE_KEY_WITH_ALL_FEATURES_ENABLED,
+ }),
+ });
+ initST();
+ res.send(connectionURI + "");
+ } catch (err) {
+ console.log(err);
+ res.status(500).send(err.toString());
}
- let pid = await startST();
- const OPAQUE_KEY_WITH_MULTITENANCY_FEATURE =
- "ijaleljUd2kU9XXWLiqFYv5br8nutTxbyBqWypQdv2N-BocoNriPrnYQd0NXPm8rVkeEocN9ayq0B7c3Pv-BTBIhAZSclXMlgyfXtlwAOJk=9BfESEleW6LyTov47dXu";
-
- await fetch(`http://localhost:9000/ee/license`, {
- method: "PUT",
- headers: {
- "content-type": "application/json; charset=utf-8",
- },
- body: JSON.stringify({
- licenseKey: OPAQUE_KEY_WITH_MULTITENANCY_FEATURE,
- }),
- });
- res.send(pid + "");
});
app.post("/beforeeach", async (req, res) => {
deviceStore = new Map();
+ accountLinkingConfig = {};
+ passwordlessConfig = {};
+ enabledProviders = undefined;
+ enabledRecipes = undefined;
+
await killAllST();
await setupST();
res.send();
@@ -255,6 +295,7 @@ app.get("/sessioninfo", verifySession(), async (req, res, next) => {
res.send({
sessionHandle: session.getHandle(),
userId: session.getUserId(),
+ recipeUserId: accountLinkingSupported ? session.getRecipeUserId().getAsString() : session.getUserId(),
accessTokenPayload,
sessionData,
});
@@ -264,16 +305,46 @@ app.get("/sessioninfo", verifySession(), async (req, res, next) => {
});
app.post("/deleteUser", async (req, res) => {
- if (req.body.rid !== "emailpassword") {
- res.status(400).send({ message: "Not implemented" });
+ if (!accountLinkingSupported) {
+ const user = await EmailPassword.getUserByEmail("public", req.body.email);
+ return res.send(await SuperTokens.deleteUser(user.id));
+ }
+
+ const users = await SuperTokens.listUsersByAccountInfo("public", req.body);
+ res.send(await SuperTokens.deleteUser(users[0].id));
+});
+
+app.post("/changeEmail", async (req, res) => {
+ let resp;
+ if (req.body.rid === "emailpassword") {
+ resp = await EmailPassword.updateEmailOrPassword({
+ recipeUserId: convertToRecipeUserIdIfAvailable(req.body.recipeUserId),
+ email: req.body.email,
+ tenantIdForPasswordPolicy: req.body.tenantId,
+ });
+ } else if (req.body.rid === "thirdparty") {
+ const user = await SuperTokens.getUser({ userId: req.body.recipeUserId });
+ const loginMethod = user.loginMethod.find((lm) => lm.recipeUserId.getAsString() === req.body.recipeUserId);
+ resp = await ThirdParty.manuallyCreateOrUpdateUser(
+ req.body.tenantId,
+ loginMethod.thirdParty.id,
+ loginMethod.thirdParty.userId,
+ req.body.email,
+ false
+ );
+ } else if (req.body.rid === "passwordless") {
+ resp = await Passwordless.updateUser({
+ recipeUserId: convertToRecipeUserIdIfAvailable(req.body.recipeUserId),
+ email: req.body.email,
+ phoneNumber: req.body.phoneNumber,
+ });
}
- const user = await EmailPassword.getUserByEmail("public", req.body.email);
- res.send(await SuperTokens.deleteUser(user.id));
+ res.json(resp);
});
app.get("/unverifyEmail", verifySession(), async (req, res) => {
let session = req.session;
- await EmailVerification.unverifyEmail(session.getUserId());
+ await EmailVerification.unverifyEmail(accountLinkingSupported ? session.getRecipeUserId() : session.getUserId());
await session.fetchAndSetClaim(EmailVerification.EmailVerificationClaim);
res.send({ status: "OK" });
});
@@ -316,30 +387,82 @@ app.get("/token", async (_, res) => {
});
});
+app.post("/setupTenant", async (req, res) => {
+ const { tenantId, loginMethods, coreConfig } = req.body;
+ let coreResp = await Multitenancy.createOrUpdateTenant(tenantId, {
+ emailPasswordEnabled: loginMethods.emailPassword?.enabled === true,
+ thirdPartyEnabled: loginMethods.thirdParty?.enabled === true,
+ passwordlessEnabled: loginMethods.passwordless?.enabled === true,
+ coreConfig,
+ });
+
+ if (loginMethods.thirdParty.providers !== undefined) {
+ for (const provider of loginMethods.thirdParty.providers) {
+ await Multitenancy.createOrUpdateThirdPartyConfig(tenantId, provider);
+ }
+ }
+ res.send(coreResp);
+});
+
+app.post("/addUserToTenant", async (req, res) => {
+ const { tenantId, recipeUserId } = req.body;
+ let coreResp = await Multitenancy.associateUserToTenant(tenantId, convertToRecipeUserIdIfAvailable(recipeUserId));
+ res.send(coreResp);
+});
+
+app.post("/removeUserFromTenant", async (req, res) => {
+ const { tenantId, recipeUserId } = req.body;
+ let coreResp = await Multitenancy.disassociateUserFromTenant(
+ tenantId,
+ convertToRecipeUserIdIfAvailable(recipeUserId)
+ );
+ res.send(coreResp);
+});
+
+app.post("/removeTenant", async (req, res) => {
+ const { tenantId } = req.body;
+ let coreResp = await Multitenancy.deleteTenant(tenantId);
+ res.send(coreResp);
+});
+
app.post("/test/setFlow", (req, res) => {
- initST({
- passwordlessConfig: {
- contactMethod: req.body.contactMethod,
- flowType: req.body.flowType,
-
- emailDelivery: {
- override: (oI) => {
- return {
- ...oI,
- sendEmail: saveCode,
- };
- },
+ passwordlessConfig = {
+ contactMethod: req.body.contactMethod,
+ flowType: req.body.flowType,
+
+ emailDelivery: {
+ override: (oI) => {
+ return {
+ ...oI,
+ sendEmail: saveCode,
+ };
},
- smsDelivery: {
- override: (oI) => {
- return {
- ...oI,
- sendSms: saveCode,
- };
- },
+ },
+ smsDelivery: {
+ override: (oI) => {
+ return {
+ ...oI,
+ sendSms: saveCode,
+ };
},
},
- });
+ };
+ initST();
+ res.sendStatus(200);
+});
+
+app.post("/test/setAccountLinkingConfig", (req, res) => {
+ accountLinkingConfig = {
+ ...req.body,
+ };
+ initST();
+ res.sendStatus(200);
+});
+
+app.post("/test/setEnabledRecipes", (req, res) => {
+ enabledRecipes = req.body.enabledRecipes;
+ enabledProviders = req.body.enabledProviders;
+ initST();
res.sendStatus(200);
});
@@ -368,8 +491,15 @@ app.get("/test/featureFlags", (req, res) => {
if (multitenancySupported) {
available.push("multitenancy");
+ available.push("multitenancyManagementEndpoints");
}
+ if (accountLinkingSupported) {
+ available.push("accountlinking");
+ }
+
+ available.push("recipeConfig");
+
res.send({
available,
});
@@ -402,13 +532,12 @@ server.listen(process.env.NODE_PORT === undefined ? 8080 : process.env.NODE_PORT
} catch (e) {}
await setupST();
- const pid = await startST();
- console.log(`Application started on http://localhost:${process.env.NODE_PORT | 8080}`);
- console.log(`processId: ${pid}`);
+ connectionURI = await startST();
+ console.log("Connection URI: " + connectionURI);
}
})(process.env.START === "true");
-function initST({ passwordlessConfig } = {}) {
+function initST() {
if (process.env.TEST_MODE) {
if (userRolesSupported) {
UserRolesRaw.reset();
@@ -426,6 +555,10 @@ function initST({ passwordlessConfig } = {}) {
MultitenancyRaw.reset();
}
+ if (accountLinkingSupported) {
+ AccountLinkingRaw.reset();
+ }
+
EmailVerificationRaw.reset();
EmailPasswordRaw.reset();
ThirdPartyRaw.reset();
@@ -436,276 +569,296 @@ function initST({ passwordlessConfig } = {}) {
}
const recipeList = [
- EmailVerification.init({
- mode: "OPTIONAL",
- emailDelivery: {
- override: (oI) => {
- return {
- ...oI,
- sendEmail: async (input) => {
- console.log(input.emailVerifyLink);
- latestURLWithToken = input.emailVerifyLink;
- },
- };
+ [
+ "emailverification",
+ EmailVerification.init({
+ mode: "OPTIONAL",
+ emailDelivery: {
+ override: (oI) => {
+ return {
+ ...oI,
+ sendEmail: async (input) => {
+ latestURLWithToken = input.emailVerifyLink;
+ },
+ };
+ },
},
- },
- override: {
- apis: (oI) => {
- return {
- ...oI,
- generateEmailVerifyTokenPOST: async function (input) {
- let body = await input.options.req.getJSONBody();
- if (body.generalError === true) {
- return {
- status: "GENERAL_ERROR",
- message: "general error from API email verification code",
- };
- }
- return oI.generateEmailVerifyTokenPOST(input);
- },
- verifyEmailPOST: async function (input) {
- let body = await input.options.req.getJSONBody();
- if (body.generalError === true) {
- return {
- status: "GENERAL_ERROR",
- message: "general error from API email verify",
- };
- }
- return oI.verifyEmailPOST(input);
- },
- };
+ override: {
+ apis: (oI) => {
+ return {
+ ...oI,
+ generateEmailVerifyTokenPOST: async function (input) {
+ let body = await input.options.req.getJSONBody();
+ if (body.generalError === true) {
+ return {
+ status: "GENERAL_ERROR",
+ message: "general error from API email verification code",
+ };
+ }
+ return oI.generateEmailVerifyTokenPOST(input);
+ },
+ verifyEmailPOST: async function (input) {
+ let body = await input.options.req.getJSONBody();
+ if (body.generalError === true) {
+ return {
+ status: "GENERAL_ERROR",
+ message: "general error from API email verify",
+ };
+ }
+ return oI.verifyEmailPOST(input);
+ },
+ };
+ },
},
- },
- }),
- EmailPassword.init({
- override: {
- apis: (oI) => {
- return {
- ...oI,
- passwordResetPOST: async function (input) {
- let body = await input.options.req.getJSONBody();
- if (body.generalError === true) {
- return {
- status: "GENERAL_ERROR",
- message: "general error from API reset password consume",
- };
- }
- return oI.passwordResetPOST(input);
- },
- generatePasswordResetTokenPOST: async function (input) {
- let body = await input.options.req.getJSONBody();
- if (body.generalError === true) {
- return {
- status: "GENERAL_ERROR",
- message: "general error from API reset password",
- };
- }
- return oI.generatePasswordResetTokenPOST(input);
- },
- emailExistsGET: async function (input) {
- let generalError = input.options.req.getKeyValueFromQuery("generalError");
- if (generalError === "true") {
- return {
- status: "GENERAL_ERROR",
- message: "general error from API email exists",
- };
- }
- return oI.emailExistsGET(input);
- },
- signUpPOST: async function (input) {
- let body = await input.options.req.getJSONBody();
- if (body.generalError === true) {
- return {
- status: "GENERAL_ERROR",
- message: "general error from API sign up",
- };
- }
- return oI.signUpPOST(input);
- },
- signInPOST: async function (input) {
- let body = await input.options.req.getJSONBody();
- if (body.generalError === true) {
- let message = "general error from API sign in";
-
- if (body.generalErrorMessage !== undefined) {
- message = body.generalErrorMessage;
+ }),
+ ],
+ [
+ "emailpassword",
+ EmailPassword.init({
+ override: {
+ apis: (oI) => {
+ return {
+ ...oI,
+ passwordResetPOST: async function (input) {
+ let body = await input.options.req.getJSONBody();
+ if (body.generalError === true) {
+ return {
+ status: "GENERAL_ERROR",
+ message: "general error from API reset password consume",
+ };
}
+ return oI.passwordResetPOST(input);
+ },
+ generatePasswordResetTokenPOST: async function (input) {
+ let body = await input.options.req.getJSONBody();
+ if (body.generalError === true) {
+ return {
+ status: "GENERAL_ERROR",
+ message: "general error from API reset password",
+ };
+ }
+ return oI.generatePasswordResetTokenPOST(input);
+ },
+ emailExistsGET: async function (input) {
+ let generalError = input.options.req.getKeyValueFromQuery("generalError");
+ if (generalError === "true") {
+ return {
+ status: "GENERAL_ERROR",
+ message: "general error from API email exists",
+ };
+ }
+ return oI.emailExistsGET(input);
+ },
+ signUpPOST: async function (input) {
+ let body = await input.options.req.getJSONBody();
+ if (body.generalError === true) {
+ return {
+ status: "GENERAL_ERROR",
+ message: "general error from API sign up",
+ };
+ }
+ return oI.signUpPOST(input);
+ },
+ signInPOST: async function (input) {
+ let body = await input.options.req.getJSONBody();
+ if (body.generalError === true) {
+ let message = "general error from API sign in";
- return {
- status: "GENERAL_ERROR",
- message,
- };
- }
- return oI.signInPOST(input);
- },
- };
+ if (body.generalErrorMessage !== undefined) {
+ message = body.generalErrorMessage;
+ }
+
+ return {
+ status: "GENERAL_ERROR",
+ message,
+ };
+ }
+ return oI.signInPOST(input);
+ },
+ };
+ },
},
- },
- signUpFeature: {
- formFields,
- },
- emailDelivery: {
- override: (oI) => {
- return {
- ...oI,
- sendEmail: async (input) => {
- console.log(input.passwordResetLink);
- latestURLWithToken = input.passwordResetLink;
- },
- };
+ signUpFeature: {
+ formFields,
},
- },
- }),
- ThirdParty.init({
- signInAndUpFeature: {
- providers,
- },
- override: {
- apis: (originalImplementation) => {
- return {
- ...originalImplementation,
- authorisationUrlGET: async function (input) {
- let generalErrorFromQuery = input.options.req.getKeyValueFromQuery("generalError");
- if (generalErrorFromQuery === "true") {
- return {
- status: "GENERAL_ERROR",
- message: "general error from API authorisation url get",
- };
- }
-
- return originalImplementation.authorisationUrlGET(input);
- },
- signInUpPOST: async function (input) {
- let body = await input.options.req.getJSONBody();
- if (body.generalError === true) {
- return {
- status: "GENERAL_ERROR",
- message: "general error from API sign in up",
- };
- }
-
- return originalImplementation.signInUpPOST(input);
- },
- };
+ emailDelivery: {
+ override: (oI) => {
+ return {
+ ...oI,
+ sendEmail: async (input) => {
+ console.log(input.passwordResetLink);
+ latestURLWithToken = input.passwordResetLink;
+ },
+ };
+ },
},
- },
- }),
- ThirdPartyEmailPassword.init({
- signUpFeature: {
- formFields,
- },
- emailDelivery: {
- override: (oI) => {
- return {
- ...oI,
- sendEmail: async (input) => {
- console.log(input.passwordResetLink);
- latestURLWithToken = input.passwordResetLink;
- },
- };
+ }),
+ ],
+ [
+ "thirdparty",
+ ThirdParty.init({
+ signInAndUpFeature: {
+ providers:
+ enabledProviders !== undefined
+ ? fullProviderList.filter(({ config }) => enabledProviders.includes(config.thirdPartyId))
+ : fullProviderList,
},
- },
- providers,
- override: {
- apis: (originalImplementation) => {
- return {
- ...originalImplementation,
- emailPasswordSignUpPOST: async function (input) {
- let body = await input.options.req.getJSONBody();
- if (body.generalError === true) {
- return {
- status: "GENERAL_ERROR",
- message: "general error from API sign up",
- };
- }
-
- return originalImplementation.emailPasswordSignUpPOST(input);
- },
- passwordResetPOST: async function (input) {
- let body = await input.options.req.getJSONBody();
- if (body.generalError === true) {
- return {
- status: "GENERAL_ERROR",
- message: "general error from API reset password consume",
- };
- }
- return originalImplementation.passwordResetPOST(input);
- },
- generatePasswordResetTokenPOST: async function (input) {
- let body = await input.options.req.getJSONBody();
- if (body.generalError === true) {
- return {
- status: "GENERAL_ERROR",
- message: "general error from API reset password",
- };
- }
- return originalImplementation.generatePasswordResetTokenPOST(input);
- },
- emailPasswordEmailExistsGET: async function (input) {
- let generalError = input.options.req.getKeyValueFromQuery("generalError");
- if (generalError === "true") {
- return {
- status: "GENERAL_ERROR",
- message: "general error from API email exists",
- };
- }
- return originalImplementation.emailPasswordEmailExistsGET(input);
- },
- emailPasswordSignInPOST: async function (input) {
- let body = await input.options.req.getJSONBody();
- if (body.generalError === true) {
- return {
- status: "GENERAL_ERROR",
- message: "general error from API sign in",
- };
- }
- return originalImplementation.emailPasswordSignInPOST(input);
- },
- authorisationUrlGET: async function (input) {
- let generalErrorFromQuery = input.options.req.getKeyValueFromQuery("generalError");
- if (generalErrorFromQuery === "true") {
- return {
- status: "GENERAL_ERROR",
- message: "general error from API authorisation url get",
- };
- }
-
- return originalImplementation.authorisationUrlGET(input);
- },
- thirdPartySignInUpPOST: async function (input) {
- let body = await input.options.req.getJSONBody();
- if (body.generalError === true) {
- return {
- status: "GENERAL_ERROR",
- message: "general error from API sign in up",
- };
- }
-
- return originalImplementation.thirdPartySignInUpPOST(input);
- },
- };
+ override: {
+ apis: (originalImplementation) => {
+ return {
+ ...originalImplementation,
+ authorisationUrlGET: async function (input) {
+ let generalErrorFromQuery = input.options.req.getKeyValueFromQuery("generalError");
+ if (generalErrorFromQuery === "true") {
+ return {
+ status: "GENERAL_ERROR",
+ message: "general error from API authorisation url get",
+ };
+ }
+
+ return originalImplementation.authorisationUrlGET(input);
+ },
+ signInUpPOST: async function (input) {
+ let body = await input.options.req.getJSONBody();
+ if (body.generalError === true) {
+ return {
+ status: "GENERAL_ERROR",
+ message: "general error from API sign in up",
+ };
+ }
+
+ return originalImplementation.signInUpPOST(input);
+ },
+ };
+ },
},
- },
- }),
- Session.init({
- override: {
- apis: function (originalImplementation) {
- return {
- ...originalImplementation,
- signOutPOST: async (input) => {
- let body = await input.options.req.getJSONBody();
- if (body.generalError === true) {
- return {
- status: "GENERAL_ERROR",
- message: "general error from signout API",
- };
- }
- return originalImplementation.signOutPOST(input);
- },
- };
+ }),
+ ],
+ [
+ "thirdpartyemailpassword",
+ ThirdPartyEmailPassword.init({
+ signUpFeature: {
+ formFields,
},
- },
- }),
+ emailDelivery: {
+ override: (oI) => {
+ return {
+ ...oI,
+ sendEmail: async (input) => {
+ console.log(input.passwordResetLink);
+ latestURLWithToken = input.passwordResetLink;
+ },
+ };
+ },
+ },
+ providers:
+ enabledProviders !== undefined
+ ? fullProviderList.filter((config) => enabledProviders.includes(config.config))
+ : fullProviderList,
+ override: {
+ apis: (originalImplementation) => {
+ return {
+ ...originalImplementation,
+ emailPasswordSignUpPOST: async function (input) {
+ let body = await input.options.req.getJSONBody();
+ if (body.generalError === true) {
+ return {
+ status: "GENERAL_ERROR",
+ message: "general error from API sign up",
+ };
+ }
+
+ return originalImplementation.emailPasswordSignUpPOST(input);
+ },
+ passwordResetPOST: async function (input) {
+ let body = await input.options.req.getJSONBody();
+ if (body.generalError === true) {
+ return {
+ status: "GENERAL_ERROR",
+ message: "general error from API reset password consume",
+ };
+ }
+ return originalImplementation.passwordResetPOST(input);
+ },
+ generatePasswordResetTokenPOST: async function (input) {
+ let body = await input.options.req.getJSONBody();
+ if (body.generalError === true) {
+ return {
+ status: "GENERAL_ERROR",
+ message: "general error from API reset password",
+ };
+ }
+ return originalImplementation.generatePasswordResetTokenPOST(input);
+ },
+ emailPasswordEmailExistsGET: async function (input) {
+ let generalError = input.options.req.getKeyValueFromQuery("generalError");
+ if (generalError === "true") {
+ return {
+ status: "GENERAL_ERROR",
+ message: "general error from API email exists",
+ };
+ }
+ return originalImplementation.emailPasswordEmailExistsGET(input);
+ },
+ emailPasswordSignInPOST: async function (input) {
+ let body = await input.options.req.getJSONBody();
+ if (body.generalError === true) {
+ return {
+ status: "GENERAL_ERROR",
+ message: "general error from API sign in",
+ };
+ }
+ return originalImplementation.emailPasswordSignInPOST(input);
+ },
+ authorisationUrlGET: async function (input) {
+ let generalErrorFromQuery = input.options.req.getKeyValueFromQuery("generalError");
+ if (generalErrorFromQuery === "true") {
+ return {
+ status: "GENERAL_ERROR",
+ message: "general error from API authorisation url get",
+ };
+ }
+
+ return originalImplementation.authorisationUrlGET(input);
+ },
+ thirdPartySignInUpPOST: async function (input) {
+ let body = await input.options.req.getJSONBody();
+ if (body.generalError === true) {
+ return {
+ status: "GENERAL_ERROR",
+ message: "general error from API sign in up",
+ };
+ }
+
+ return originalImplementation.thirdPartySignInUpPOST(input);
+ },
+ };
+ },
+ },
+ }),
+ ],
+ [
+ "session",
+ Session.init({
+ override: {
+ apis: function (originalImplementation) {
+ return {
+ ...originalImplementation,
+ signOutPOST: async (input) => {
+ let body = await input.options.req.getJSONBody();
+ if (body.generalError === true) {
+ return {
+ status: "GENERAL_ERROR",
+ message: "general error from signout API",
+ };
+ }
+ return originalImplementation.signOutPOST(input);
+ },
+ };
+ },
+ },
+ }),
+ ],
];
passwordlessConfig = {
@@ -730,7 +883,8 @@ function initST({ passwordlessConfig } = {}) {
...passwordlessConfig,
};
if (passwordlessSupported) {
- recipeList.push(
+ recipeList.push([
+ "passwordless",
Passwordless.init({
...passwordlessConfig,
override: {
@@ -770,15 +924,19 @@ function initST({ passwordlessConfig } = {}) {
};
},
},
- })
- );
+ }),
+ ]);
}
if (thirdPartyPasswordlessSupported) {
- recipeList.push(
+ recipeList.push([
+ "thirdpartypasswordless",
ThirdPartyPasswordless.init({
...passwordlessConfig,
- providers,
+ providers:
+ enabledProviders !== undefined
+ ? fullProviderList.filter((config) => enabledProviders.includes(config.config))
+ : fullProviderList,
override: {
apis: (originalImplementation) => {
return {
@@ -838,23 +996,46 @@ function initST({ passwordlessConfig } = {}) {
};
},
},
- })
- );
+ }),
+ ]);
}
if (userRolesSupported) {
- recipeList.push(UserRoles.init());
+ recipeList.push(["userroles", UserRoles.init()]);
}
if (multitenancySupported) {
- recipeList.push(
+ recipeList.push([
+ "multitenancy",
Multitenancy.init({
getAllowedDomainsForTenantId: (tenantId) => [
`${tenantId}.example.com`,
websiteDomain.replace(/https?:\/\/([^:\/]*).*/, "$1"),
],
- })
- );
+ }),
+ ]);
+ }
+
+ accountLinkingConfig = {
+ enabled: false,
+ shouldAutoLink: {
+ ...accountLinkingConfig?.shouldAutoLink,
+ shouldAutomaticallyLink: true,
+ shouldRequireVerification: true,
+ },
+ ...accountLinkingConfig,
+ };
+ if (accountLinkingSupported) {
+ if (accountLinkingConfig.enabled) {
+ recipeList.push([
+ "accountlinking",
+ AccountLinking.init({
+ shouldDoAutomaticAccountLinking: () => ({
+ ...accountLinkingConfig.shouldAutoLink,
+ }),
+ }),
+ ]);
+ }
}
SuperTokens.init({
@@ -864,8 +1045,18 @@ function initST({ passwordlessConfig } = {}) {
websiteDomain,
},
supertokens: {
- connectionURI: "http://localhost:9000",
+ connectionURI,
},
- recipeList,
+ recipeList:
+ enabledRecipes !== undefined
+ ? recipeList.filter(([key]) => enabledRecipes.includes(key)).map(([_key, recipeFunc]) => recipeFunc)
+ : recipeList.map(([_key, recipeFunc]) => recipeFunc),
});
}
+
+function convertToRecipeUserIdIfAvailable(id) {
+ if (SuperTokens.convertToRecipeUserId !== undefined) {
+ return SuperTokens.convertToRecipeUserId(id);
+ }
+ return id;
+}
diff --git a/test/server/package-lock.json b/test/server/package-lock.json
index 0da214688..3eeeb3944 100644
--- a/test/server/package-lock.json
+++ b/test/server/package-lock.json
@@ -15,100 +15,7 @@
"dotenv": "^8.2.0",
"express": "4.17.1",
"morgan": "^1.10.0",
- "supertokens-node": "latest"
- }
- },
- "node_modules/@panva/asn1.js": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/@panva/asn1.js/-/asn1.js-1.0.0.tgz",
- "integrity": "sha512-UdkG3mLEqXgnlKsWanWcgb6dOjUzJ+XC5f+aWw30qrtjxeNUSfKX1cd5FBzOaXQumoe9nIqeZUvrRJS03HCCtw==",
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/@types/body-parser": {
- "version": "1.19.2",
- "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz",
- "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==",
- "dependencies": {
- "@types/connect": "*",
- "@types/node": "*"
- }
- },
- "node_modules/@types/connect": {
- "version": "3.4.35",
- "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz",
- "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==",
- "dependencies": {
- "@types/node": "*"
- }
- },
- "node_modules/@types/express": {
- "version": "4.17.17",
- "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz",
- "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==",
- "dependencies": {
- "@types/body-parser": "*",
- "@types/express-serve-static-core": "^4.17.33",
- "@types/qs": "*",
- "@types/serve-static": "*"
- }
- },
- "node_modules/@types/express-serve-static-core": {
- "version": "4.17.34",
- "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.34.tgz",
- "integrity": "sha512-fvr49XlCGoUj2Pp730AItckfjat4WNb0lb3kfrLWffd+RLeoGAMsq7UOy04PAPtoL01uKwcp6u8nhzpgpDYr3w==",
- "dependencies": {
- "@types/node": "*",
- "@types/qs": "*",
- "@types/range-parser": "*",
- "@types/send": "*"
- }
- },
- "node_modules/@types/jsonwebtoken": {
- "version": "8.5.9",
- "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.9.tgz",
- "integrity": "sha512-272FMnFGzAVMGtu9tkr29hRL6bZj4Zs1KZNeHLnKqAvp06tAIcarTMwOh8/8bz4FmKRcMxZhZNeUAQsNLoiPhg==",
- "dependencies": {
- "@types/node": "*"
- }
- },
- "node_modules/@types/mime": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
- "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw=="
- },
- "node_modules/@types/node": {
- "version": "18.16.3",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.3.tgz",
- "integrity": "sha512-OPs5WnnT1xkCBiuQrZA4+YAV4HEJejmHneyraIaxsbev5yCEr6KMwINNFP9wQeFIw8FWcoTqF3vQsa5CDaI+8Q=="
- },
- "node_modules/@types/qs": {
- "version": "6.9.7",
- "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
- "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw=="
- },
- "node_modules/@types/range-parser": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz",
- "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw=="
- },
- "node_modules/@types/send": {
- "version": "0.17.1",
- "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz",
- "integrity": "sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==",
- "dependencies": {
- "@types/mime": "^1",
- "@types/node": "*"
- }
- },
- "node_modules/@types/serve-static": {
- "version": "1.15.1",
- "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz",
- "integrity": "sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==",
- "dependencies": {
- "@types/mime": "*",
- "@types/node": "*"
+ "supertokens-node": "^15.2.0"
}
},
"node_modules/accepts": {
@@ -224,17 +131,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/co-body": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/co-body/-/co-body-6.1.0.tgz",
- "integrity": "sha512-m7pOT6CdLN7FuXUcpuz/8lfQ/L77x8SchHCF4G0RBTJO20Wzmhn5Sp4/5WsKy8OSpifBSUrmg83qEqaDHdyFuQ==",
- "dependencies": {
- "inflation": "^2.0.0",
- "qs": "^6.5.2",
- "raw-body": "^2.3.3",
- "type-is": "^1.6.16"
- }
- },
"node_modules/content-disposition": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
@@ -247,9 +143,9 @@
}
},
"node_modules/content-type": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
- "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
"engines": {
"node": ">= 0.6"
}
@@ -291,6 +187,19 @@
"node": ">= 0.10"
}
},
+ "node_modules/cross-fetch": {
+ "version": "3.1.8",
+ "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz",
+ "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==",
+ "dependencies": {
+ "node-fetch": "^2.6.12"
+ }
+ },
+ "node_modules/crypto-js": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz",
+ "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw=="
+ },
"node_modules/dayjs": {
"version": "1.11.7",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz",
@@ -579,20 +488,6 @@
"node": ">= 0.10"
}
},
- "node_modules/jose": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/jose/-/jose-2.0.6.tgz",
- "integrity": "sha512-FVoPY7SflDodE4lknJmbAHSUjLCzE2H1F6MS0RYKMQ8SR+lNccpMf8R4eqkNYyyUjR5qZReOzZo5C5YiHOCjjg==",
- "dependencies": {
- "@panva/asn1.js": "^1.0.0"
- },
- "engines": {
- "node": ">=10.13.0 < 13 || >=13.7.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/panva"
- }
- },
"node_modules/jsonwebtoken": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz",
@@ -623,43 +518,6 @@
"safe-buffer": "^5.0.1"
}
},
- "node_modules/jwks-rsa": {
- "version": "2.1.5",
- "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-2.1.5.tgz",
- "integrity": "sha512-IODtn1SwEm7n6GQZnQLY0oxKDrMh7n/jRH1MzE8mlxWMrh2NnMyOsXTebu8vJ1qCpmuTJcL4DdiE0E4h8jnwsA==",
- "dependencies": {
- "@types/express": "^4.17.14",
- "@types/jsonwebtoken": "^8.5.9",
- "debug": "^4.3.4",
- "jose": "^2.0.6",
- "limiter": "^1.1.5",
- "lru-memoizer": "^2.1.4"
- },
- "engines": {
- "node": ">=10 < 13 || >=14"
- }
- },
- "node_modules/jwks-rsa/node_modules/debug": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
- "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
- "dependencies": {
- "ms": "2.1.2"
- },
- "engines": {
- "node": ">=6.0"
- },
- "peerDependenciesMeta": {
- "supports-color": {
- "optional": true
- }
- }
- },
- "node_modules/jwks-rsa/node_modules/ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
- },
"node_modules/jws": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
@@ -674,39 +532,11 @@
"resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.13.tgz",
"integrity": "sha512-b74iyWmwb4GprAUPjPkJ11GTC7KX4Pd3onpJfKxYyY8y9Rbb4ERY47LvCMEDM09WD3thiLDMXtkfDK/AX+zT7Q=="
},
- "node_modules/limiter": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz",
- "integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA=="
- },
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
- "node_modules/lodash.clonedeep": {
- "version": "4.5.0",
- "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
- "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ=="
- },
- "node_modules/lru-cache": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz",
- "integrity": "sha512-uQw9OqphAGiZhkuPlpFGmdTU2tEuhxTourM/19qGJrxBPHAr/f8BT1a0i/lOclESnGatdJG/UCkP9kZB/Lh1iw==",
- "dependencies": {
- "pseudomap": "^1.0.1",
- "yallist": "^2.0.0"
- }
- },
- "node_modules/lru-memoizer": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.2.0.tgz",
- "integrity": "sha512-QfOZ6jNkxCcM/BkIPnFsqDhtrazLRsghi9mBwFAzol5GCvj4EkFT899Za3+QwikCg5sRX8JstioBDwOxEyzaNw==",
- "dependencies": {
- "lodash.clonedeep": "^4.5.0",
- "lru-cache": "~4.0.0"
- }
- },
"node_modules/media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@@ -794,6 +624,25 @@
"node": ">= 0.6"
}
},
+ "node_modules/node-fetch": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
+ "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
+ "dependencies": {
+ "whatwg-url": "^5.0.0"
+ },
+ "engines": {
+ "node": "4.x || >=6.0.0"
+ },
+ "peerDependencies": {
+ "encoding": "^0.1.0"
+ },
+ "peerDependenciesMeta": {
+ "encoding": {
+ "optional": true
+ }
+ }
+ },
"node_modules/nodemailer": {
"version": "6.7.8",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.7.8.tgz",
@@ -850,6 +699,14 @@
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
},
+ "node_modules/pkce-challenge": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-3.1.0.tgz",
+ "integrity": "sha512-bQ/0XPZZ7eX+cdAkd61uYWpfMhakH3NeteUF1R8GNa+LMqX8QFAkbCLqq+AYAns1/ueACBu/BMWhrlKGrdvGZg==",
+ "dependencies": {
+ "crypto-js": "^4.1.1"
+ }
+ },
"node_modules/proxy-addr": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
@@ -862,11 +719,6 @@
"node": ">= 0.10"
}
},
- "node_modules/pseudomap": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
- "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ=="
- },
"node_modules/psl": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
@@ -1031,76 +883,22 @@
"integrity": "sha512-r0JFBjkMIdep3Lbk3JA+MpnpuOtw4RSyrlRAbrzMcxwiYco3GFWl/daimQZ5b1forOiUODpOlXbSOljP/oyurg=="
},
"node_modules/supertokens-node": {
- "version": "14.1.1",
- "resolved": "https://registry.npmjs.org/supertokens-node/-/supertokens-node-14.1.1.tgz",
- "integrity": "sha512-BFcKyZs0pPe8GyKaSIcBzwJ25bU2jvVB/JKP+C1TZy8ngFNd/stETbQWVQ5sszsUb0GuxkKduDzkgxw5AYtfTA==",
+ "version": "15.2.0",
+ "resolved": "https://registry.npmjs.org/supertokens-node/-/supertokens-node-15.2.0.tgz",
+ "integrity": "sha512-lsiO77FHIiSP3gmS07YFVYRctNVchoW4+JkDfaiTdfSpSBoX+VDWCHwl7mbH47nuodIGz1JzYQuXEiaO26o7HA==",
"dependencies": {
- "axios": "0.21.4",
- "body-parser": "1.20.1",
- "co-body": "6.1.0",
+ "content-type": "^1.0.5",
"cookie": "0.4.0",
+ "cross-fetch": "^3.1.6",
"debug": "^4.3.3",
+ "inflation": "^2.0.0",
"jose": "^4.13.1",
- "jsonwebtoken": "^9.0.0",
- "jwks-rsa": "^2.0.5",
"libphonenumber-js": "^1.9.44",
"nodemailer": "^6.7.2",
+ "pkce-challenge": "^3.0.0",
"psl": "1.8.0",
"supertokens-js-override": "^0.0.4",
- "twilio": "^4.7.2",
- "verify-apple-id-token": "^3.0.1"
- }
- },
- "node_modules/supertokens-node/node_modules/axios": {
- "version": "0.21.4",
- "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
- "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
- "dependencies": {
- "follow-redirects": "^1.14.0"
- }
- },
- "node_modules/supertokens-node/node_modules/body-parser": {
- "version": "1.20.1",
- "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
- "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
- "dependencies": {
- "bytes": "3.1.2",
- "content-type": "~1.0.4",
- "debug": "2.6.9",
- "depd": "2.0.0",
- "destroy": "1.2.0",
- "http-errors": "2.0.0",
- "iconv-lite": "0.4.24",
- "on-finished": "2.4.1",
- "qs": "6.11.0",
- "raw-body": "2.5.1",
- "type-is": "~1.6.18",
- "unpipe": "1.0.0"
- },
- "engines": {
- "node": ">= 0.8",
- "npm": "1.2.8000 || >= 1.4.16"
- }
- },
- "node_modules/supertokens-node/node_modules/body-parser/node_modules/debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dependencies": {
- "ms": "2.0.0"
- }
- },
- "node_modules/supertokens-node/node_modules/body-parser/node_modules/ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
- },
- "node_modules/supertokens-node/node_modules/bytes": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
- "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
- "engines": {
- "node": ">= 0.8"
+ "twilio": "^4.7.2"
}
},
"node_modules/supertokens-node/node_modules/cookie": {
@@ -1127,43 +925,6 @@
}
}
},
- "node_modules/supertokens-node/node_modules/depd": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
- "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/supertokens-node/node_modules/destroy": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
- "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
- "engines": {
- "node": ">= 0.8",
- "npm": "1.2.8000 || >= 1.4.16"
- }
- },
- "node_modules/supertokens-node/node_modules/http-errors": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
- "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
- "dependencies": {
- "depd": "2.0.0",
- "inherits": "2.0.4",
- "setprototypeof": "1.2.0",
- "statuses": "2.0.1",
- "toidentifier": "1.0.1"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/supertokens-node/node_modules/inherits": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
- },
"node_modules/supertokens-node/node_modules/jose": {
"version": "4.14.4",
"resolved": "https://registry.npmjs.org/jose/-/jose-4.14.4.tgz",
@@ -1177,66 +938,6 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
- "node_modules/supertokens-node/node_modules/on-finished": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
- "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
- "dependencies": {
- "ee-first": "1.1.1"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/supertokens-node/node_modules/qs": {
- "version": "6.11.0",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
- "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
- "dependencies": {
- "side-channel": "^1.0.4"
- },
- "engines": {
- "node": ">=0.6"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/supertokens-node/node_modules/raw-body": {
- "version": "2.5.1",
- "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
- "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
- "dependencies": {
- "bytes": "3.1.2",
- "http-errors": "2.0.0",
- "iconv-lite": "0.4.24",
- "unpipe": "1.0.0"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/supertokens-node/node_modules/setprototypeof": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
- "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
- },
- "node_modules/supertokens-node/node_modules/statuses": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
- "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/supertokens-node/node_modules/toidentifier": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
- "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
- "engines": {
- "node": ">=0.6"
- }
- },
"node_modules/toidentifier": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
@@ -1245,6 +946,11 @@
"node": ">=0.6"
}
},
+ "node_modules/tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
+ },
"node_modules/twilio": {
"version": "4.10.0",
"resolved": "https://registry.npmjs.org/twilio/-/twilio-4.10.0.tgz",
@@ -1330,68 +1036,20 @@
"node": ">= 0.8"
}
},
- "node_modules/verify-apple-id-token": {
+ "node_modules/webidl-conversions": {
"version": "3.0.1",
- "resolved": "https://registry.npmjs.org/verify-apple-id-token/-/verify-apple-id-token-3.0.1.tgz",
- "integrity": "sha512-q91pG1e52TpEzXldMirWYNWcSQC4WuzgG0y/ZnBhzjfk0pSxi4YlGh5OTVRlodBenayGHfSDn5VseG9QDuqOew==",
- "dependencies": {
- "jsonwebtoken": "^9.0.0",
- "jwks-rsa": "^3.0.0"
- }
- },
- "node_modules/verify-apple-id-token/node_modules/@types/jsonwebtoken": {
- "version": "9.0.2",
- "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
- "integrity": "sha512-drE6uz7QBKq1fYqqoFKTDRdFCPHd5TCub75BM+D+cMx7NU9hUz7SESLfC2fSCXVFMO5Yj8sOWHuGqPgjc+fz0Q==",
- "dependencies": {
- "@types/node": "*"
- }
- },
- "node_modules/verify-apple-id-token/node_modules/debug": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
- "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
- "dependencies": {
- "ms": "2.1.2"
- },
- "engines": {
- "node": ">=6.0"
- },
- "peerDependenciesMeta": {
- "supports-color": {
- "optional": true
- }
- }
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
- "node_modules/verify-apple-id-token/node_modules/jose": {
- "version": "4.14.4",
- "resolved": "https://registry.npmjs.org/jose/-/jose-4.14.4.tgz",
- "integrity": "sha512-j8GhLiKmUAh+dsFXlX1aJCbt5KMibuKb+d7j1JaOJG6s2UjX1PQlW+OKB/sD4a/5ZYF4RcmYmLSndOoU3Lt/3g==",
- "funding": {
- "url": "https://github.com/sponsors/panva"
- }
- },
- "node_modules/verify-apple-id-token/node_modules/jwks-rsa": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-3.0.1.tgz",
- "integrity": "sha512-UUOZ0CVReK1QVU3rbi9bC7N5/le8ziUj0A2ef1Q0M7OPD2KvjEYizptqIxGIo6fSLYDkqBrazILS18tYuRc8gw==",
+ "node_modules/whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"dependencies": {
- "@types/express": "^4.17.14",
- "@types/jsonwebtoken": "^9.0.0",
- "debug": "^4.3.4",
- "jose": "^4.10.4",
- "limiter": "^1.1.5",
- "lru-memoizer": "^2.1.4"
- },
- "engines": {
- "node": ">=14"
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
}
},
- "node_modules/verify-apple-id-token/node_modules/ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
- },
"node_modules/xmlbuilder": {
"version": "13.0.2",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-13.0.2.tgz",
@@ -1399,104 +1057,9 @@
"engines": {
"node": ">=6.0"
}
- },
- "node_modules/yallist": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
- "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A=="
}
},
"dependencies": {
- "@panva/asn1.js": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/@panva/asn1.js/-/asn1.js-1.0.0.tgz",
- "integrity": "sha512-UdkG3mLEqXgnlKsWanWcgb6dOjUzJ+XC5f+aWw30qrtjxeNUSfKX1cd5FBzOaXQumoe9nIqeZUvrRJS03HCCtw=="
- },
- "@types/body-parser": {
- "version": "1.19.2",
- "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz",
- "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==",
- "requires": {
- "@types/connect": "*",
- "@types/node": "*"
- }
- },
- "@types/connect": {
- "version": "3.4.35",
- "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz",
- "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==",
- "requires": {
- "@types/node": "*"
- }
- },
- "@types/express": {
- "version": "4.17.17",
- "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz",
- "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==",
- "requires": {
- "@types/body-parser": "*",
- "@types/express-serve-static-core": "^4.17.33",
- "@types/qs": "*",
- "@types/serve-static": "*"
- }
- },
- "@types/express-serve-static-core": {
- "version": "4.17.34",
- "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.34.tgz",
- "integrity": "sha512-fvr49XlCGoUj2Pp730AItckfjat4WNb0lb3kfrLWffd+RLeoGAMsq7UOy04PAPtoL01uKwcp6u8nhzpgpDYr3w==",
- "requires": {
- "@types/node": "*",
- "@types/qs": "*",
- "@types/range-parser": "*",
- "@types/send": "*"
- }
- },
- "@types/jsonwebtoken": {
- "version": "8.5.9",
- "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.9.tgz",
- "integrity": "sha512-272FMnFGzAVMGtu9tkr29hRL6bZj4Zs1KZNeHLnKqAvp06tAIcarTMwOh8/8bz4FmKRcMxZhZNeUAQsNLoiPhg==",
- "requires": {
- "@types/node": "*"
- }
- },
- "@types/mime": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
- "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw=="
- },
- "@types/node": {
- "version": "18.16.3",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.3.tgz",
- "integrity": "sha512-OPs5WnnT1xkCBiuQrZA4+YAV4HEJejmHneyraIaxsbev5yCEr6KMwINNFP9wQeFIw8FWcoTqF3vQsa5CDaI+8Q=="
- },
- "@types/qs": {
- "version": "6.9.7",
- "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
- "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw=="
- },
- "@types/range-parser": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz",
- "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw=="
- },
- "@types/send": {
- "version": "0.17.1",
- "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz",
- "integrity": "sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==",
- "requires": {
- "@types/mime": "^1",
- "@types/node": "*"
- }
- },
- "@types/serve-static": {
- "version": "1.15.1",
- "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz",
- "integrity": "sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==",
- "requires": {
- "@types/mime": "*",
- "@types/node": "*"
- }
- },
"accepts": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
@@ -1586,17 +1149,6 @@
"get-intrinsic": "^1.0.2"
}
},
- "co-body": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/co-body/-/co-body-6.1.0.tgz",
- "integrity": "sha512-m7pOT6CdLN7FuXUcpuz/8lfQ/L77x8SchHCF4G0RBTJO20Wzmhn5Sp4/5WsKy8OSpifBSUrmg83qEqaDHdyFuQ==",
- "requires": {
- "inflation": "^2.0.0",
- "qs": "^6.5.2",
- "raw-body": "^2.3.3",
- "type-is": "^1.6.16"
- }
- },
"content-disposition": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
@@ -1606,9 +1158,9 @@
}
},
"content-type": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
- "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="
},
"cookie": {
"version": "0.3.1",
@@ -1638,6 +1190,19 @@
"vary": "^1"
}
},
+ "cross-fetch": {
+ "version": "3.1.8",
+ "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz",
+ "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==",
+ "requires": {
+ "node-fetch": "^2.6.12"
+ }
+ },
+ "crypto-js": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz",
+ "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw=="
+ },
"dayjs": {
"version": "1.11.7",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz",
@@ -1854,14 +1419,6 @@
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
},
- "jose": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/jose/-/jose-2.0.6.tgz",
- "integrity": "sha512-FVoPY7SflDodE4lknJmbAHSUjLCzE2H1F6MS0RYKMQ8SR+lNccpMf8R4eqkNYyyUjR5qZReOzZo5C5YiHOCjjg==",
- "requires": {
- "@panva/asn1.js": "^1.0.0"
- }
- },
"jsonwebtoken": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz",
@@ -1890,34 +1447,6 @@
"safe-buffer": "^5.0.1"
}
},
- "jwks-rsa": {
- "version": "2.1.5",
- "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-2.1.5.tgz",
- "integrity": "sha512-IODtn1SwEm7n6GQZnQLY0oxKDrMh7n/jRH1MzE8mlxWMrh2NnMyOsXTebu8vJ1qCpmuTJcL4DdiE0E4h8jnwsA==",
- "requires": {
- "@types/express": "^4.17.14",
- "@types/jsonwebtoken": "^8.5.9",
- "debug": "^4.3.4",
- "jose": "^2.0.6",
- "limiter": "^1.1.5",
- "lru-memoizer": "^2.1.4"
- },
- "dependencies": {
- "debug": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
- "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
- "requires": {
- "ms": "2.1.2"
- }
- },
- "ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
- }
- }
- },
"jws": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
@@ -1932,39 +1461,11 @@
"resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.13.tgz",
"integrity": "sha512-b74iyWmwb4GprAUPjPkJ11GTC7KX4Pd3onpJfKxYyY8y9Rbb4ERY47LvCMEDM09WD3thiLDMXtkfDK/AX+zT7Q=="
},
- "limiter": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz",
- "integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA=="
- },
"lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
- "lodash.clonedeep": {
- "version": "4.5.0",
- "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
- "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ=="
- },
- "lru-cache": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz",
- "integrity": "sha512-uQw9OqphAGiZhkuPlpFGmdTU2tEuhxTourM/19qGJrxBPHAr/f8BT1a0i/lOclESnGatdJG/UCkP9kZB/Lh1iw==",
- "requires": {
- "pseudomap": "^1.0.1",
- "yallist": "^2.0.0"
- }
- },
- "lru-memoizer": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.2.0.tgz",
- "integrity": "sha512-QfOZ6jNkxCcM/BkIPnFsqDhtrazLRsghi9mBwFAzol5GCvj4EkFT899Za3+QwikCg5sRX8JstioBDwOxEyzaNw==",
- "requires": {
- "lodash.clonedeep": "^4.5.0",
- "lru-cache": "~4.0.0"
- }
- },
"media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@@ -2027,6 +1528,14 @@
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
"integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="
},
+ "node-fetch": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
+ "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
+ "requires": {
+ "whatwg-url": "^5.0.0"
+ }
+ },
"nodemailer": {
"version": "6.7.8",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.7.8.tgz",
@@ -2065,6 +1574,14 @@
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
},
+ "pkce-challenge": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-3.1.0.tgz",
+ "integrity": "sha512-bQ/0XPZZ7eX+cdAkd61uYWpfMhakH3NeteUF1R8GNa+LMqX8QFAkbCLqq+AYAns1/ueACBu/BMWhrlKGrdvGZg==",
+ "requires": {
+ "crypto-js": "^4.1.1"
+ }
+ },
"proxy-addr": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
@@ -2074,11 +1591,6 @@
"ipaddr.js": "1.9.1"
}
},
- "pseudomap": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
- "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ=="
- },
"psl": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
@@ -2217,73 +1729,24 @@
"integrity": "sha512-r0JFBjkMIdep3Lbk3JA+MpnpuOtw4RSyrlRAbrzMcxwiYco3GFWl/daimQZ5b1forOiUODpOlXbSOljP/oyurg=="
},
"supertokens-node": {
- "version": "14.1.1",
- "resolved": "https://registry.npmjs.org/supertokens-node/-/supertokens-node-14.1.1.tgz",
- "integrity": "sha512-BFcKyZs0pPe8GyKaSIcBzwJ25bU2jvVB/JKP+C1TZy8ngFNd/stETbQWVQ5sszsUb0GuxkKduDzkgxw5AYtfTA==",
+ "version": "15.2.0",
+ "resolved": "https://registry.npmjs.org/supertokens-node/-/supertokens-node-15.2.0.tgz",
+ "integrity": "sha512-lsiO77FHIiSP3gmS07YFVYRctNVchoW4+JkDfaiTdfSpSBoX+VDWCHwl7mbH47nuodIGz1JzYQuXEiaO26o7HA==",
"requires": {
- "axios": "0.21.4",
- "body-parser": "1.20.1",
- "co-body": "6.1.0",
+ "content-type": "^1.0.5",
"cookie": "0.4.0",
+ "cross-fetch": "^3.1.6",
"debug": "^4.3.3",
+ "inflation": "^2.0.0",
"jose": "^4.13.1",
- "jsonwebtoken": "^9.0.0",
- "jwks-rsa": "^2.0.5",
"libphonenumber-js": "^1.9.44",
"nodemailer": "^6.7.2",
+ "pkce-challenge": "^3.0.0",
"psl": "1.8.0",
"supertokens-js-override": "^0.0.4",
- "twilio": "^4.7.2",
- "verify-apple-id-token": "^3.0.1"
+ "twilio": "^4.7.2"
},
"dependencies": {
- "axios": {
- "version": "0.21.4",
- "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
- "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
- "requires": {
- "follow-redirects": "^1.14.0"
- }
- },
- "body-parser": {
- "version": "1.20.1",
- "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
- "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
- "requires": {
- "bytes": "3.1.2",
- "content-type": "~1.0.4",
- "debug": "2.6.9",
- "depd": "2.0.0",
- "destroy": "1.2.0",
- "http-errors": "2.0.0",
- "iconv-lite": "0.4.24",
- "on-finished": "2.4.1",
- "qs": "6.11.0",
- "raw-body": "2.5.1",
- "type-is": "~1.6.18",
- "unpipe": "1.0.0"
- },
- "dependencies": {
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "requires": {
- "ms": "2.0.0"
- }
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
- }
- }
- },
- "bytes": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
- "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="
- },
"cookie": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
@@ -2297,33 +1760,6 @@
"ms": "2.1.2"
}
},
- "depd": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
- "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
- },
- "destroy": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
- "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="
- },
- "http-errors": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
- "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
- "requires": {
- "depd": "2.0.0",
- "inherits": "2.0.4",
- "setprototypeof": "1.2.0",
- "statuses": "2.0.1",
- "toidentifier": "1.0.1"
- }
- },
- "inherits": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
- },
"jose": {
"version": "4.14.4",
"resolved": "https://registry.npmjs.org/jose/-/jose-4.14.4.tgz",
@@ -2333,48 +1769,6 @@
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
- },
- "on-finished": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
- "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
- "requires": {
- "ee-first": "1.1.1"
- }
- },
- "qs": {
- "version": "6.11.0",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
- "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
- "requires": {
- "side-channel": "^1.0.4"
- }
- },
- "raw-body": {
- "version": "2.5.1",
- "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
- "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
- "requires": {
- "bytes": "3.1.2",
- "http-errors": "2.0.0",
- "iconv-lite": "0.4.24",
- "unpipe": "1.0.0"
- }
- },
- "setprototypeof": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
- "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
- },
- "statuses": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
- "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
- },
- "toidentifier": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
- "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
}
}
},
@@ -2383,6 +1777,11 @@
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
"integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
},
+ "tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
+ },
"twilio": {
"version": "4.10.0",
"resolved": "https://registry.npmjs.org/twilio/-/twilio-4.10.0.tgz",
@@ -2449,65 +1848,24 @@
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="
},
- "verify-apple-id-token": {
+ "webidl-conversions": {
"version": "3.0.1",
- "resolved": "https://registry.npmjs.org/verify-apple-id-token/-/verify-apple-id-token-3.0.1.tgz",
- "integrity": "sha512-q91pG1e52TpEzXldMirWYNWcSQC4WuzgG0y/ZnBhzjfk0pSxi4YlGh5OTVRlodBenayGHfSDn5VseG9QDuqOew==",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
+ },
+ "whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"requires": {
- "jsonwebtoken": "^9.0.0",
- "jwks-rsa": "^3.0.0"
- },
- "dependencies": {
- "@types/jsonwebtoken": {
- "version": "9.0.2",
- "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
- "integrity": "sha512-drE6uz7QBKq1fYqqoFKTDRdFCPHd5TCub75BM+D+cMx7NU9hUz7SESLfC2fSCXVFMO5Yj8sOWHuGqPgjc+fz0Q==",
- "requires": {
- "@types/node": "*"
- }
- },
- "debug": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
- "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
- "requires": {
- "ms": "2.1.2"
- }
- },
- "jose": {
- "version": "4.14.4",
- "resolved": "https://registry.npmjs.org/jose/-/jose-4.14.4.tgz",
- "integrity": "sha512-j8GhLiKmUAh+dsFXlX1aJCbt5KMibuKb+d7j1JaOJG6s2UjX1PQlW+OKB/sD4a/5ZYF4RcmYmLSndOoU3Lt/3g=="
- },
- "jwks-rsa": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-3.0.1.tgz",
- "integrity": "sha512-UUOZ0CVReK1QVU3rbi9bC7N5/le8ziUj0A2ef1Q0M7OPD2KvjEYizptqIxGIo6fSLYDkqBrazILS18tYuRc8gw==",
- "requires": {
- "@types/express": "^4.17.14",
- "@types/jsonwebtoken": "^9.0.0",
- "debug": "^4.3.4",
- "jose": "^4.10.4",
- "limiter": "^1.1.5",
- "lru-memoizer": "^2.1.4"
- }
- },
- "ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
- }
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
}
},
"xmlbuilder": {
"version": "13.0.2",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-13.0.2.tgz",
"integrity": "sha512-Eux0i2QdDYKbdbA6AM6xE4m6ZTZr4G4xF9kahI2ukSEMCzwce2eX9WlTI5J3s+NU7hpasFsr8hWIONae7LluAQ=="
- },
- "yallist": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
- "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A=="
}
}
}
diff --git a/test/server/package.json b/test/server/package.json
index 67b48cf74..a529f9e0d 100644
--- a/test/server/package.json
+++ b/test/server/package.json
@@ -15,6 +15,6 @@
"dotenv": "^8.2.0",
"express": "4.17.1",
"morgan": "^1.10.0",
- "supertokens-node": "latest"
+ "supertokens-node": "^15.2.0"
}
}
diff --git a/test/server/utils.js b/test/server/utils.js
index 12b53b78a..c80268199 100644
--- a/test/server/utils.js
+++ b/test/server/utils.js
@@ -14,6 +14,7 @@
*/
const { exec } = require("child_process");
let fs = require("fs");
+let assert = require("assert");
let axios = require("axios").default;
module.exports.executeCommand = async function (cmd) {
@@ -94,7 +95,18 @@ module.exports.killAllST = async function () {
}
};
-module.exports.startST = async function (host = "localhost", port = 9000) {
+module.exports.startST = async function (config = {}) {
+ const host = config.host ?? "localhost";
+ const port = config.port ?? 9000;
+
+ const notUsingTestApp =
+ process.env.REAL_DB_TEST !== "true" || host !== "localhost" || port !== 9000 || config.noApp === true;
+ if (config.coreConfig && notUsingTestApp) {
+ for (const [k, v] of Object.entries(config.coreConfig)) {
+ await module.exports.setKeyValueInConfig(k, v);
+ }
+ }
+
return new Promise(async (resolve, reject) => {
let installationPath = process.env.INSTALL_PATH;
let pidsBefore = await getListOfPids();
@@ -106,7 +118,8 @@ module.exports.startST = async function (host = "localhost", port = 9000) {
` && java -Djava.security.egd=file:/dev/urandom -classpath "./core/*:./plugin-interface/*" io.supertokens.Main ./ DEV host=` +
host +
" port=" +
- port
+ port +
+ " test_mode"
)
.catch((err) => {
if (!returned) {
@@ -130,7 +143,53 @@ module.exports.startST = async function (host = "localhost", port = 9000) {
} else {
if (!returned) {
returned = true;
- resolve(nonIntersection[0]);
+ console.log(`Application started on http://localhost:${process.env.NODE_PORT | 8080}`);
+ console.log(`processId: ${nonIntersection[0]}`);
+
+ if (notUsingTestApp) {
+ return resolve(`http://${host}:${port}`);
+ }
+
+ try {
+ // Math.random is an unsafe random but it doesn't actually matter here
+ // const appId = configs.appId ?? `testapp-${Date.now()}-${Math.floor(Math.random() * 1000)}`;
+ const appId = config.appId ?? `testapp`;
+
+ await module.exports.removeAppAndTenants(host, port, appId);
+
+ const OPAQUE_KEY_WITH_MULTITENANCY_FEATURE =
+ "ijaleljUd2kU9XXWLiqFYv5br8nutTxbyBqWypQdv2N-BocoNriPrnYQd0NXPm8rVkeEocN9ayq0B7c3Pv-BTBIhAZSclXMlgyfXtlwAOJk=9BfESEleW6LyTov47dXu";
+
+ await fetch(`http://${host}:${port}/ee/license`, {
+ method: "PUT",
+ headers: {
+ "content-type": "application/json; charset=utf-8",
+ },
+ body: JSON.stringify({
+ licenseKey: OPAQUE_KEY_WITH_MULTITENANCY_FEATURE,
+ }),
+ });
+
+ // Create app
+ const createAppResp = await fetch(`http://${host}:${port}/recipe/multitenancy/app`, {
+ method: "PUT",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ appId,
+ emailPasswordEnabled: true,
+ thirdPartyEnabled: true,
+ passwordlessEnabled: true,
+ coreConfig: config.coreConfig,
+ }),
+ });
+ const respBody = await createAppResp.json();
+ assert.strictEqual(respBody.status, "OK");
+ resolve(`http://${host}:${port}/appid-${appId}`);
+ } catch (err) {
+ reject(err);
+ }
}
}
}
@@ -141,6 +200,81 @@ module.exports.startST = async function (host = "localhost", port = 9000) {
});
};
+module.exports.removeAppAndTenants = async function (host, port, appId) {
+ const tenantsResp = await fetch(`http://${host}:${port}/appid-${appId}/recipe/multitenancy/tenant/list`);
+ if (tenantsResp.status === 401) {
+ const updateAppResp = await fetch(`http://${host}:${port}/recipe/multitenancy/app`, {
+ method: "PUT",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ appId,
+ coreConfig: { api_keys: null },
+ }),
+ });
+ assert.strictEqual(updateAppResp.status, 200);
+ await module.exports.removeAppAndTenants(host, port, appId);
+ } else if (tenantsResp.status === 200) {
+ const tenants = (await tenantsResp.json()).tenants;
+ for (const t of tenants) {
+ if (t.tenantId !== "public") {
+ await fetch(`http://${host}:${port}/appid-${appId}/recipe/multitenancy/tenant/remove`, {
+ method: "POST",
+ headers: {
+ "content-type": "application/json; charset=utf-8",
+ },
+ body: JSON.stringify({
+ tenantId: t.tenantId,
+ }),
+ });
+ }
+ }
+
+ const removeResp = await fetch(`http://${host}:${port}/recipe/multitenancy/app/remove`, {
+ method: "POST",
+ headers: {
+ "content-type": "application/json; charset=utf-8",
+ },
+ body: JSON.stringify({
+ appId,
+ }),
+ });
+ const removeRespBody = await removeResp.json();
+ assert.strictEqual(removeRespBody.status, "OK");
+ }
+};
+
+const WEB_PORT = process.env.WEB_PORT || 3031;
+const websiteDomain = `http://localhost:${WEB_PORT}`;
+module.exports.mockThirdPartyProvider = {
+ config: {
+ name: "Mock Provider",
+ thirdPartyId: "mock-provider",
+ authorizationEndpoint: `${websiteDomain}/mockProvider/auth`,
+ tokenEndpoint: `${websiteDomain}/mockProvider/token`,
+ clients: [
+ {
+ clientId: "supertokens",
+ clientSecret: "",
+ },
+ ],
+ },
+ override: (oI) => ({
+ ...oI,
+ exchangeAuthCodeForOAuthTokens: ({ redirectURIInfo }) => redirectURIInfo.redirectURIQueryParams,
+ getUserInfo: ({ oAuthTokens }) => {
+ return {
+ thirdPartyUserId: oAuthTokens.userId ?? "user",
+ email: {
+ id: oAuthTokens.email ?? "email@test.com",
+ isVerified: oAuthTokens.isVerified !== "false",
+ },
+ rawUserInfoFromProvider: {},
+ };
+ },
+ }),
+};
/**
*
* @returns {import("supertokens-node/lib/build/recipe/thirdparty/types").ProviderConfig}
diff --git a/test/unit/recipe/emailpassword/signInUp.test.tsx b/test/unit/recipe/emailpassword/signInUp.test.tsx
index 20e1b12ea..f2d5d5a29 100644
--- a/test/unit/recipe/emailpassword/signInUp.test.tsx
+++ b/test/unit/recipe/emailpassword/signInUp.test.tsx
@@ -73,7 +73,7 @@ describe("EmailPassword.SignInAndUp", () => {
expect(MockSession.validateGlobalClaimsAndHandleSuccessRedirection).toHaveBeenCalledWith(
{
rid: "emailpassword",
- successRedirectContext: { action: "SUCCESS", isNewUser: false, redirectToPath: undefined },
+ successRedirectContext: { action: "SUCCESS", isNewRecipeUser: false, redirectToPath: undefined },
},
{},
undefined
diff --git a/test/unit/recipe/passwordless/signInUp.test.tsx b/test/unit/recipe/passwordless/signInUp.test.tsx
index 0192e9c72..f5cb153b5 100644
--- a/test/unit/recipe/passwordless/signInUp.test.tsx
+++ b/test/unit/recipe/passwordless/signInUp.test.tsx
@@ -74,7 +74,7 @@ describe("Passwordless.SingInUp", () => {
expect(MockSession.validateGlobalClaimsAndHandleSuccessRedirection).toHaveBeenCalledWith(
{
rid: "passwordless",
- successRedirectContext: { action: "SUCCESS", isNewUser: false, redirectToPath: undefined },
+ successRedirectContext: { action: "SUCCESS", isNewRecipeUser: false, redirectToPath: undefined },
},
{},
undefined
diff --git a/test/unit/recipe/thirdparty/signInUp.test.tsx b/test/unit/recipe/thirdparty/signInUp.test.tsx
index 1e500a4b7..165450be8 100644
--- a/test/unit/recipe/thirdparty/signInUp.test.tsx
+++ b/test/unit/recipe/thirdparty/signInUp.test.tsx
@@ -78,7 +78,7 @@ describe("ThirdParty.SignInAndUp", () => {
expect(MockSession.validateGlobalClaimsAndHandleSuccessRedirection).toHaveBeenCalledWith(
{
rid: "thirdparty",
- successRedirectContext: { action: "SUCCESS", isNewUser: false, redirectToPath: undefined },
+ successRedirectContext: { action: "SUCCESS", isNewRecipeUser: false, redirectToPath: undefined },
},
{},
undefined
diff --git a/test/unit/recipe/thirdpartyemailpassword/signInUp.test.tsx b/test/unit/recipe/thirdpartyemailpassword/signInUp.test.tsx
index ff563c285..f3783cb97 100644
--- a/test/unit/recipe/thirdpartyemailpassword/signInUp.test.tsx
+++ b/test/unit/recipe/thirdpartyemailpassword/signInUp.test.tsx
@@ -73,7 +73,7 @@ describe("ThirdPartyEmailPassword.SignInAndUp", () => {
expect(MockSession.validateGlobalClaimsAndHandleSuccessRedirection).toHaveBeenCalledWith(
{
rid: "thirdpartyemailpassword",
- successRedirectContext: { action: "SUCCESS", isNewUser: false, redirectToPath: undefined },
+ successRedirectContext: { action: "SUCCESS", isNewRecipeUser: false, redirectToPath: undefined },
},
{},
undefined
diff --git a/test/unit/recipe/thirdpartypasswordless/signInUp.test.tsx b/test/unit/recipe/thirdpartypasswordless/signInUp.test.tsx
index a2a4e5ba2..807150958 100644
--- a/test/unit/recipe/thirdpartypasswordless/signInUp.test.tsx
+++ b/test/unit/recipe/thirdpartypasswordless/signInUp.test.tsx
@@ -74,7 +74,7 @@ describe("ThirdPartyPasswordless.SignInAndUp", () => {
expect(MockSession.validateGlobalClaimsAndHandleSuccessRedirection).toHaveBeenCalledWith(
{
rid: "thirdpartypasswordless",
- successRedirectContext: { action: "SUCCESS", isNewUser: false, redirectToPath: undefined },
+ successRedirectContext: { action: "SUCCESS", isNewRecipeUser: false, redirectToPath: undefined },
},
{},
undefined
diff --git a/test/visual/basic.test.js b/test/visual/basic.test.js
index 9e209d1df..c6b778a4c 100644
--- a/test/visual/basic.test.js
+++ b/test/visual/basic.test.js
@@ -17,8 +17,6 @@
* Imports
*/
-/* https://github.com/babel/babel/issues/9849#issuecomment-487040428 */
-import regeneratorRuntime from "regenerator-runtime";
import assert from "assert";
import puppeteer from "puppeteer";
import fetch from "isomorphic-fetch";
diff --git a/test/with-typescript/src/App.tsx b/test/with-typescript/src/App.tsx
index 523586b13..5a3113718 100644
--- a/test/with-typescript/src/App.tsx
+++ b/test/with-typescript/src/App.tsx
@@ -377,13 +377,28 @@ function getEmailPasswordConfigs() {
},
},
- onHandleEvent(context: EmailPasswordOnHandleEventContext) {},
+ onHandleEvent(context: EmailPasswordOnHandleEventContext) {
+ if (context.action === "SUCCESS") {
+ if (context.isNewRecipeUser && context.user.loginMethods.length === 1) {
+ // new primary user
+ } else {
+ // only a recipe user was created
+ }
+ }
+ },
async preAPIHook(context: EmailPasswordPreAPIHookContext) {
return context;
},
async getRedirectionURL(context: EmailPasswordGetRedirectionURLContext) {
+ if (context.action === "SUCCESS") {
+ if (context.isNewRecipeUser && context.user.loginMethods.length === 1) {
+ // new primary user
+ } else {
+ // only a recipe user was created
+ }
+ }
return undefined;
},
override: {
@@ -518,7 +533,7 @@ Passwordless.init({
// in this case, they are usually redirected to the main app
} else if (context.action === "SUCCESS") {
let user = context.user;
- if (context.isNewUser) {
+ if (context.isNewRecipeUser) {
// sign up success
} else {
// sign in success