From cbd157b9e4b9f949185e6e0ea0cfe1fdff43790c Mon Sep 17 00:00:00 2001 From: rishabhpoddar Date: Mon, 28 Oct 2024 10:45:13 +0530 Subject: [PATCH 01/11] initial commit for changelog copied from node sdk --- CHANGELOG.md | 620 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 614 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8f65c52..c21d65d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,13 +11,621 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.25.0] - 2024-09-18 +### Overview + +- Enable smooth switching between `useDynamicAccessTokenSigningKey` settings by allowing refresh calls to change the signing key type of a session +- Added a core call cache that should reduce traffic to your SuperTokens core instances +- Refactored sign in/up API codes to reduce code duplication +- Added MFA related information to dashboard APIs +- Added a cache to reduce the number of requests made to the core. This can be disabled using the `disableCoreCallCache: true`, in the config. +- Added new `overwriteSessionDuringSignInUp` configuration option to the Session recipe +- Added new function: `checkCode` to Passwordless and ThirdPartyPasswordless recipes +- Added new function: `verifyCredentials` to EmailPassword and ThirdPartyEmailPassword recipes +- Added the `MultiFactorAuth` and `TOTP` recipes. + +### Breaking changes + +- Now only supporting CDI 5.1. Compatible with core version >= 9.1 +- Added new support codes to sign in/up APIs. This means that there are new possible values coming from the default implementation for the `reason` strings of `SIGN_IN_NOT_ALLOWED`, `SIGN_UP_NOT_ALLOWED` and `SIGN_IN_UP_NOT_ALLOWED` responses. +- `Session` recipe: + - The sign out API new returns a 401 instead of 200 in case the input access token has expired or is missing. +- `AccountLinking` recipe: + - Changed the signature of the following functions, each taking a new (optional) `session` parameter: + - `createPrimaryUserIdOrLinkAccounts` + - `isSignUpAllowed` + - `isSignInAllowed` + - `isEmailChangeAllowed` + - Changed the signature of the `shouldDoAutomaticAccountLinking` callback: it now takes a new (optional) session parameter. +- `EmailPassword`: + - Changed the signature of the following overrideable functions: + - `signUp` + - Takes a new (optional) `session` parameter + - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"` + - `signIn` + - Takes a new (optional) `session` parameter + - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"` + - Changed the signature of overrideable APIs, adding a new (optional) session parameter: + - `signInPOST` + - `signUpPOST` + - Changed the signature of functions: + - `signUp` + - Takes a new (optional) `session` parameter + - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"` + - `signIn` + - Takes a new (optional) `session` parameter + - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED" +- `Multitenancy`: + - Changed the signature of the following functions: + - `createOrUpdateTenant`: Added optional `firstFactors` and `requiredSecondaryFactors` parameters. + - `getTenant`: Added `firstFactors` and `requiredSecondaryFactors` to the return type + - `listAllTenants`: Added `firstFactors` and `requiredSecondaryFactors` to the returned tenants + - Changed the signature of the following overrideable functions: + - `createOrUpdateTenant`: Now gets optional `firstFactors` and `requiredSecondaryFactors` in the input. + - `getTenant`: Added `firstFactors` and `requiredSecondaryFactors` to the return type + - `listAllTenants`: Added `firstFactors` and `requiredSecondaryFactors` to the returned tenants + - Changed the signature of the overrideable apis: + - `loginMethodsGET`: Now returns `firstFactors` +- `Passwordless`: + - `revokeCode` (and the related overrideable func) can now be called with either `preAuthSessionId` or `codeId` instead of only `codeId`. + - Added new email and sms type for MFA + - Changed the signature of the following functions: + - `signInUp`, `createCode`: Takes a new (optional) `session` parameter + - `consumeCode`: + - Takes a new (optional) `session` parameter + - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"` + - It now also returns `consumedDevice` if the code was successfully consumed + - Changed the signature of the following overrideable functions: + - `createCode`: Takes a new (optional) `session` parameter + - `consumeCode`: + - Takes a new (optional) `session` parameter + - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"` + - It now also returns `consumedDevice` if the code was successfully consumed + - Changed the signature of overrideable APIs, adding a new (optional) session parameter: + - `createCodePOST` + - `resendCodePOST` + - `consumeCodePOST` +- Session claims: + - The `build` function and the `fetchValue` callback of session claims now take a new `currentPayload` param. + - This affects built-in claims: `EmailVerificationClaim`, `UserRoleClaim`, `PermissionClaim`, `AllowedDomainsClaim`. + - This will affect all custom claims as well built on our base classes. +- `ThirdParty`: + - Changed the signature of the following functions: + - `manuallyCreateOrUpdateUser`: + - Takes a new (optional) `session` parameter + - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"` + - Changed the signature of the following overrideable functions: + - `signInUp`: + - Takes a new (optional) `session` parameter + - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"` + - `manuallyCreateOrUpdateUser` + - Takes a new (optional) `session` parameter + - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"` + - Changed the signature of overrideable APIs, adding a new (optional) session parameter: + - `signInUpPOST` +- `ThirdPartyEmailPassword`: + - Added new function: `emailPasswordVerifyCredentials` + - Changed the signature of the following functions: + - `thirdPartyManuallyCreateOrUpdateUser`: + - Takes a new (optional) `session` parameter + - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"` + - `emailPasswordSignUp` + - Takes a new (optional) `session` parameter + - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"` + - Changed the signature of the following overrideable functions: + - `thirdPartySignInUp`: + - Takes a new (optional) `session` parameter + - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"` + - `thirdPartyManuallyCreateOrUpdateUser` + - Takes a new (optional) `session` parameter + - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"` + - `emailPasswordSignUp` + - Takes a new (optional) `session` parameter + - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"` + - Changed the signature of overrideable APIs, adding a new (optional) session parameter: + - `emailPasswordSignInPOST` + - `emailPasswordSignUpPOST` + - `thirdPartySignInUpPOST` +- `ThirdPartyPasswordless`: + - `revokeCode` (and the related overrideable func) can now be called with either `preAuthSessionId` or `codeId` instead of only `codeId`. + - Changed the signature of the following functions: + - `thirdPartyManuallyCreateOrUpdateUser`: + - Takes a new (optional) `session` parameter + - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"` + - `passwordlessSignInUp`, `createCode`: Takes a new (optional) `session` parameter + - `consumeCode`: + - Takes a new (optional) `session` parameter + - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"` + - It now also returns `consumedDevice` if the code was successfully consumed + - Changed the signature of the following overrideable functions: + - `thirdPartySignInUp`: + - Takes a new (optional) `session` parameter + - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"` + - `thirdPartyManuallyCreateOrUpdateUser` + - Takes a new (optional) `session` parameter + - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"` + - `createCode`: Takes a new (optional) `session` parameter + - `consumeCode`: + - Takes a new (optional) `session` parameter + - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"` + - It now also returns `consumedDevice` if the code was successfully consumed + - Changed the signature of overrideable APIs, adding a new (optional) session parameter: + - `thirdPartySignInUpPOST` + - `createCodePOST` + - `resendCodePOST` + - `consumeCodePOST` + +#### Migration guide + +##### shouldDoAutomaticAccountLinking signature change + +If you use the `userContext` or `tenantId` parameters passed to `shouldDoAutomaticAccountLinking`, please update your implementation to account for the new parameter. + +Before: + +```ts +AccountLinking.init({ + shouldDoAutomaticAccountLinking: async (newAccountInfo, user, tenantId, userContext) => { + return { + shouldAutomaticallyLink: true, + shouldRequireVerification: true, + }; + }, +}); +``` + +After: + +```ts +AccountLinking.init({ + shouldDoAutomaticAccountLinking: async (newAccountInfo, user, session, tenantId, userContext) => { + return { + shouldAutomaticallyLink: true, + shouldRequireVerification: true, + }; + }, +}); +``` + +##### Optional `session` parameter added to public functions + +We've added a new optional `session` parameter to many function calls. In all cases, these have been added as the last parameter before `userContext`, so this should only affect you if you are using that. You only need to pass a session as a parameter if you are using account linking and want to try and link the user signing in/up to the session user. +You can get the necessary session object using `verifySession` in an API call. + +Here we use the example of `EmailPassword.signIn` but this fits other functions with changed signatures. + +Before: + +```ts +const signInResp = await EmailPassword.signIn("public", "asdf@asdf.asfd", "testpw", { myContextVar: true }); +``` + +After: + +```ts +const signInResp = await EmailPassword.signIn("public", "asdf@asdf.asfd", "testpw", undefined, { myContextVar: true }); +``` + +##### `fetchValue` signature change + +If you use the `userContext` parameter passed to `fetchValue`, please update your implementation to account for the new parameter. + +Before: + +```ts +const boolClaim = new BooleanClaim({ + key: "asdf", + fetchValue: (userId, recipeUserId, tenantId, userContext) => { + return userContext.claimValue; + }, +}); +``` + +After: + +```ts +const boolClaim = new BooleanClaim({ + key: "asdf", + fetchValue: (userId, recipeUserId, tenantId, currentPayload, userContext) => { + return userContext.claimValue; + }, +}); +``` + +##### `build` signature change + +If you were using the `build` function for custom or built-in session claims, you should update the call signature to also pass the new parameter. + +Before: + +```ts +Session.init({ + override: { + functions: (originalImplementation) => { + return { + ...originalImplementation, + createNewSession: async function (input) { + input.accessTokenPayload = { + ...input.accessTokenPayload, + ...(await UserRoleClaim.build( + input.userId, + input.recipeUserId, + input.tenantId, + input.userContext + )), + }; + + return originalImplementation.createNewSession(input); + }, + }; + }, + }, +}); +``` + +After: + +```ts +Session.init({ + override: { + functions: (originalImplementation) => { + return { + ...originalImplementation, + createNewSession: async function (input) { + input.accessTokenPayload = { + ...input.accessTokenPayload, + ...(await UserRoleClaim.build( + input.userId, + input.recipeUserId, + input.tenantId, + input.accessTokenPayload, + input.userContext + )), + }; + + return originalImplementation.createNewSession(input); + }, + }; + }, + }, +}); +``` + +##### Post sign-in/up actions + +Since now sign in/up APIs and functions can be called with a session (e.g.: during MFA flows), you may need to add an extra check to your overrides to account for that: + +Before: + +```ts +// While this example uses Passwordless, all recipes require a very similar change +Passwordless.init({ + contactMethod: "EMAIL", // This example will work with any contactMethod + flowType: "USER_INPUT_CODE_AND_MAGIC_LINK", // This example will work with any flowType + + override: { + functions: (originalImplementation) => { + return { + ...originalImplementation, + consumeCode: async (input) => { + + // First we call the original implementation of consumeCode. + let response = await originalImplementation.consumeCode(input); + + // Post sign up response, we check if it was successful + if (response.status === "OK") { + if (response.createdNewRecipeUser && response.user.loginMethods.length === 1) { + // TODO: post sign up logic + } else { + // TODO: post sign in logic + } + } + return response; + } + } + } + } +}), +``` + +After: + +```ts +// While this example uses Passwordless, all recipes require a very similar change +Passwordless.init({ + contactMethod: "EMAIL", // This example will work with any contactMethod + flowType: "USER_INPUT_CODE_AND_MAGIC_LINK", // This example will work with any flowType + + override: { + functions: (originalImplementation) => { + return { + ...originalImplementation, + consumeCode: async (input) => { + + // First we call the original implementation of consumeCode. + let response = await originalImplementation.consumeCode(input); + + // Post sign up response, we check if it was successful + if (response.status === "OK") { + if (input.session === undefined) { + if (response.createdNewRecipeUser && response.user.loginMethods.length === 1) { + // TODO: post sign up logic + } else { + // TODO: post sign in logic + } + } + } + return response; + } + } + } + } +}), +``` + +##### Sign-in/up linking to the session user + +Sign in/up APIs and functions will now attempt to link the authenticating user to the session user if a session is available (depending on AccountLinking settings). You can disable this and get the old behaviour by: + +Before: + +```ts +// While this example uses Passwordless, all recipes require a very similar change +Passwordless.init({ + contactMethod: "EMAIL", // This example will work with any contactMethod + flowType: "USER_INPUT_CODE_AND_MAGIC_LINK", // This example will work with any flowType +}), +``` + +After: + +```ts +// While this example uses Passwordless, all recipes require a very similar change +Passwordless.init({ + contactMethod: "EMAIL", // This example will work with any contactMethod + flowType: "USER_INPUT_CODE_AND_MAGIC_LINK", // This example will work with any flowType + + override: { + functions: (originalImplementation) => { + return { + ...originalImplementation, + consumeCode: async (input) => { + input.session = undefined; + return originalImplementation.consumeCode(input); + } + } + } + } +}), +``` + +#### Introducing account-linking + +With this release, we are introducing a new AccountLinking recipe, 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. + +#### The new User object and primary vs non-primary users + +In this release, we've removed the recipes specific user types and instead introduced a new `User` class to support the "Primary user" concept introduced by account linking + +- The new `User` class now provides the same interface for all recipes. +- It contains an `isPrimary` field that you can use to differentiate between primary and recipe users +- The `loginMethods` array contains objects that covers all props of the old (recipe specific) user types, with the exception of the id. Please check the migration section below to get the exact mapping between old and new props. +- Non-primary users: + - The `loginMethods` array should contain exactly 1 element. + - `user.id` will be the same as `user.loginMethods[0].recipeUserId.getAsString()`. + - `user.id` will change if it is linked to another user. + - They can become a primary user if, and only if there are no other primary users with the same email, third party info or phone number as this user across all the tenants that this user is a part of. +- Primary users + - The `loginMethods` array can have 1 or more elements, each corresponding to a single recipe user. + - `user.id` will not change even if other users are linked to it. + - Other non-primary users can be linked to it. The user ID of the linked accounts will now be the primary users ID. +- Check [here](https://supertokens.com/docs/thirdpartyemailpassword/common-customizations/account-linking/overview#primary-user-vs-non-primary-user) for more information about differences between primary and recipe users. + +#### Primary vs RecipeUserId + +Because of account linking we've introduced a new Primary user concept (see above). In most cases, you should only use the primary user id (`user.id` or `session.getUserId()`) if you are associating data to users. Still, in some cases you need to specifically refer to a login method, which is covered by the new `RecipeUserId` class: + +- You can get it: + - From a session by: `session.getRecipeUserId()`. + - By finding the appropriate entry in the `loginMethods` array of a `User` object (see above): `user.loginMethods[0].recipeUserId`. +- It wraps a simple string value that you can get by calling `recipeUserId.getAsString()`. +- We've introduced it to differentiate between primary and recipe user ids in our APIs on a type level. +- Check [here](https://supertokens.com/docs/thirdpartyemailpassword/user-object#primary-vs-recipe-user-id) for more information. + ### Breaking changes -- `supertokens_python.recipe.emailverification.types.User` has been renamed to `supertokens_python.recipe.emailverification.types.EmailVerificationUser` -- The user object has been changed to be a global one, containing information about all emails, phone numbers, third party info and login methods associated with that user. -- Type of `get_email_for_user_id` in `emailverification.init` has changed -- Session recipe's error handlers take an extra param of recipe_user_id as well -- Session recipe, removes `validate_claims_in_jwt_payload` that is exposed to the user. -- TODO.. + +- Now only supporting CDI 4.0. Compatible with core version >= 7.0 +- Now supporting FDI 1.18 +- Removed the recipe specific `User` type, now all functions are using the new generic `User` type. + - Check [here](https://supertokens.com/docs/thirdpartyemailpassword/user-object) for more information. +- The `build` function and the `fetchValue` callback of session claims now take a new `recipeUserId` param. + - This affects built-in claims: `EmailVerificationClaim`, `UserRoleClaim`, `PermissionClaim`, `AllowedDomainsClaim`. + - This will affect all custom claims as well built on our base classes. +- Now ignoring protected props in the payload in `createNewSession` and `createNewSessionWithoutRequestResponse` +- `createdNewUser` has been renamed to `createdNewRecipeUser` in sign up related APIs and functions + +- EmailPassword: + - removed `getUserById`, `getUserByEmail`. You should use `supertokens.getUser`, and `supertokens. listUsersByAccountInfo` instead + - added `consumePasswordResetToken`. This function allows the consumption of the reset password token without changing the password. It will return OK if the token was valid. + - added an overrideable `createNewRecipeUser` function that is called during sign up and password reset flow (in case a new email password user is being created on the fly). This is mostly for internal use. + - `recipeUserId` is added to the input of `getContent` of the email delivery config + - `email` was added to the input of `createResetPasswordToken` , `sendResetPasswordEmail`, `createResetPasswordLink` + - `updateEmailOrPassword` : + - now takes `recipeUserId` instead of `userId` + - can return the new `EMAIL_CHANGE_NOT_ALLOWED_ERROR` status + - `signIn`: + - returns new `recipeUserId` prop in the `status: OK` case + - `signUp`: + - returns new `recipeUserId` prop in the `status: OK` case + - `resetPasswordUsingToken`: + - removed from the recipe interface, making it no longer overrideable (directly) + - the related function in the index files now call `consumePasswordResetToken` and `updateEmailOrPassword` + - any necessary behaviour changes can be achieved by overriding those two function instead + - `signInPOST`: + - can return status `SIGN_IN_NOT_ALLOWED` + - `signUpPOST`: + - can return status `SIGN_UP_NOT_ALLOWED` + - `generatePasswordResetTokenPOST`: + - can now return `PASSWORD_RESET_NOT_ALLOWED` + - `passwordResetPOST`: + - now returns the `user` and the `email` whose password was reset + - can now return `PASSWORD_POLICY_VIOLATED_ERROR` +- EmailVerification: + - `createEmailVerificationToken`, `createEmailVerificationLink`, `isEmailVerified`, `revokeEmailVerificationTokens` , `unverifyEmail`: + - now takes `recipeUserId` instead of `userId` + - `sendEmailVerificationEmail` : + - now takes an additional `recipeUserId` parameter + - `verifyEmailUsingToken`: + - now takes a new `attemptAccountLinking` parameter + - returns the `recipeUserId` instead of `id` + - `sendEmail` now requires a new `recipeUserId` as part of the user info + - `getEmailForUserId` config option was renamed to `getEmailForRecipeUserId` + - `verifyEmailPOST`, `generateEmailVerifyTokenPOST`: returns an optional `newSession` in case the current user session needs to be updated +- Passwordless: + - removed `getUserById`, `getUserByEmail`, `getUserByPhoneNumber` + - `updateUser` : + - now takes `recipeUserId` instead of `userId` + - can return `"EMAIL_CHANGE_NOT_ALLOWED_ERROR` and `PHONE_NUMBER_CHANGE_NOT_ALLOWED_ERROR` statuses + - `createCodePOST` and `consumeCodePOST` can now return `SIGN_IN_UP_NOT_ALLOWED` +- Session: + - access tokens and session objects now contain the recipe user id + - Support for new access token version + - `recipeUserId` is now added to the payload of the `TOKEN_THEFT_DETECTED` error + - `createNewSession`: now takes `recipeUserId` instead of `userId` + - Removed `validateClaimsInJWTPayload` + - `revokeAllSessionsForUser` now takes an optional `revokeSessionsForLinkedAccounts` param + - `getAllSessionHandlesForUser` now takes an optional `fetchSessionsForAllLinkedAccounts` param + - `regenerateAccessToken` return value now includes `recipeUserId` + - `getGlobalClaimValidators` and `validateClaims` now get a new `recipeUserId` param + - Added `getRecipeUserId` to the session class +- ThirdParty: + - The `signInUp` override: + - gets a new `isVerified` param + - can return new status: `SIGN_IN_UP_NOT_ALLOWED` + - `manuallyCreateOrUpdateUser`: + - gets a new `isVerified` param + - can return new statuses: `EMAIL_CHANGE_NOT_ALLOWED_ERROR`, `SIGN_IN_UP_NOT_ALLOWED` + - Removed `getUserByThirdPartyInfo`, `getUsersByEmail`, `getUserById` + - `signInUpPOST` can now return `SIGN_IN_UP_NOT_ALLOWED` +- ThirdPartyEmailPassword: + - Removed `getUserByThirdPartyInfo`, `getUsersByEmail`, `getUserById` + - `thirdPartyManuallyCreateOrUpdateUser`: + - now get a new `isVerified` param + - can return new statuses: `EMAIL_CHANGE_NOT_ALLOWED_ERROR`, `SIGN_IN_UP_NOT_ALLOWED` + - The `thirdPartySignInUp` override: + - now get a new `isVerified` param + - can return new status: `SIGN_IN_UP_NOT_ALLOWED` + - `email` was added to the input of `createResetPasswordToken` , `sendResetPasswordEmail`, `createResetPasswordLink` + - added an overrideable `createNewEmailPasswordRecipeUser` function that is called during email password sign up and in the “invitation link” flow + - added `consumePasswordResetToken` + - `updateEmailOrPassword` : + - now takes `recipeUserId` instead of `userId` + - can return the new `EMAIL_CHANGE_NOT_ALLOWED_ERROR` status + - `resetPasswordUsingToken`: + - removed from the recipe interface, making it no longer overrideable (directly) + - the related function in the index files now call `consumePasswordResetToken` and `updateEmailOrPassword` + - any necessary behaviour changes can be achieved by overriding those two function instead + - added an overrideable `createNewEmailPasswordRecipeUser` function that is called during sign up and in the “invitation link” flow + - `emailPasswordSignIn`: + - returns new `recipeUserId` prop in the `status: OK` case + - `emailPasswordSignUp`: + - returns new `recipeUserId` prop in the `status: OK` case + - `emailPasswordSignInPOST`: + - can return status `SIGN_IN_NOT_ALLOWED` + - `emailPasswordSignUpPOST`: + - can return status `SIGN_UP_NOT_ALLOWED` + - `generatePasswordResetTokenPOST`: + - can now return `PASSWORD_RESET_NOT_ALLOWED` + - `passwordResetPOST`: + - now returns the `user` and the `email` whose password was reset + - can now return `PASSWORD_POLICY_VIOLATED_ERROR` + - `thirdPartySignInUpPOST` can now return `SIGN_IN_UP_NOT_ALLOWED` +- ThirdPartyPasswordless: + - Removed `getUserByThirdPartyInfo`, `getUsersByEmail`, `getUserByPhoneNumber`, `getUserById` + - `thirdPartyManuallyCreateOrUpdateUser`: + - gets a new `isVerified` param + - can return new statuses: `EMAIL_CHANGE_NOT_ALLOWED_ERROR`, `SIGN_IN_UP_NOT_ALLOWED` + - The `thirdPartySignInUp` override: + - gets a new `isVerified` param + - can return new status: `SIGN_IN_UP_NOT_ALLOWED` + - `updatePasswordlessUser`: + - now takes `recipeUserId` instead of `userId` + - can return `"EMAIL_CHANGE_NOT_ALLOWED_ERROR` and `PHONE_NUMBER_CHANGE_NOT_ALLOWED_ERROR` statuses + - `thirdPartySignInUpPOST` can now return `SIGN_IN_UP_NOT_ALLOWED` + - `createCodePOST` and `consumeCodePOST` can now return `SIGN_IN_UP_NOT_ALLOWED` +- Multitenancy: + - `associateUserToTenant` can now return `ASSOCIATION_NOT_ALLOWED_ERROR` + - `associateUserToTenant` and `disassociateUserFromTenant` now take `RecipeUserId` instead of a string user id + +### Changes + +- Added `RecipeUserId` and a generic `User` class +- Added `getUser`, `listUsersByAccountInfo`, `convertToRecipeUserId` to the main exports +- Updated compilation target of typescript to ES2017 to make debugging easier. +- Added account-linking recipe + +### Migration guide + +#### New User structure + +We've added a generic `User` class 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` (or `user.loginMethods[0].recipeUserId` in case you need `RecipeUserId`) +- `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` + +#### RecipeUserId + +Some functions now require you to pass a `RecipeUserId` instead of a string user id. If you are using our auth recipes, you can find the recipeUserId as: `user.loginMethods[0].recipeUserId` (you'll need to worry about selecting the right login method after enabling account linking). Alternatively, if you already have a string user id you can convert it to a `RecipeUserId` using `supertokens.convertToRecipeUserId(userIdString)` + +#### Checking if a user signed up or signed in + +- In the 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; +``` + +- In the emailpassword sign up API, you can check if a user signed up by: + +``` + const isNewUser = res.user.loginMethods.length === 1; +``` + +#### Changing user emails + +- We recommend that you check if the email change of a user is allowed, before calling the update function + - Check [here](https://supertokens.com/docs/thirdpartyemailpassword/common-customizations/change-email-post-login) for more information + +``` +import {isEmailChangeAllowed} from "supertokens-node/recipe/accountlinking"; +/// ... +app.post("/change-email", verifySession(), async (req: SessionRequest, res: express.Response) => { + let session = req.session!; + let email = req.body.email; + + // ... + if (!(await isEmailChangeAllowed(session.getRecipeUserId(), email, false))) { + // this can come here if you have enabled the account linking feature, and + // if there is a security risk in changing this user's email. + } + + // Update the email + let resp = await ThirdPartyEmailPassword.updateEmailOrPassword({ + recipeUserId: session.getRecipeUserId(), + email: email, + }); + // ... +}); +``` ## [0.24.4] - 2024-10-16 From 0228a31d4d473828f4622809e1ec46bab64020f6 Mon Sep 17 00:00:00 2001 From: Sattvik Chakravarthy Date: Fri, 1 Nov 2024 16:13:06 +0530 Subject: [PATCH 02/11] fix: changelog re-org --- CHANGELOG.md | 715 +++++++++++++++++++++------------------------------ 1 file changed, 296 insertions(+), 419 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c21d65d0..03d22192 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,289 +8,397 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] - ## [0.25.0] - 2024-09-18 ### Overview -- Enable smooth switching between `useDynamicAccessTokenSigningKey` settings by allowing refresh calls to change the signing key type of a session +- Added `RecipeUserId` and a generic `User` class +- Added `get_user`, `list_users_by_account_info`, `convert_to_recipe_user_id` to the main exports +- Added account-linking recipe +- Enable smooth switching between `use_dynamic_access_token_signing_key` settings by allowing refresh calls to change the signing key type of a session - Added a core call cache that should reduce traffic to your SuperTokens core instances - Refactored sign in/up API codes to reduce code duplication - Added MFA related information to dashboard APIs -- Added a cache to reduce the number of requests made to the core. This can be disabled using the `disableCoreCallCache: true`, in the config. -- Added new `overwriteSessionDuringSignInUp` configuration option to the Session recipe -- Added new function: `checkCode` to Passwordless and ThirdPartyPasswordless recipes -- Added new function: `verifyCredentials` to EmailPassword and ThirdPartyEmailPassword recipes +- Added a cache to reduce the number of requests made to the core. This can be disabled using the `disable_core_call_cache: true`, in the config. +- Added new function: `check_code` to Passwordless and ThirdPartyPasswordless recipes +- Added new function: `verify_credentials` to EmailPassword and ThirdPartyEmailPassword recipes - Added the `MultiFactorAuth` and `TOTP` recipes. ### Breaking changes - Now only supporting CDI 5.1. Compatible with core version >= 9.1 - Added new support codes to sign in/up APIs. This means that there are new possible values coming from the default implementation for the `reason` strings of `SIGN_IN_NOT_ALLOWED`, `SIGN_UP_NOT_ALLOWED` and `SIGN_IN_UP_NOT_ALLOWED` responses. +- Removed the recipe specific `User` type, now all functions are using the new generic `User` type. + - Check [here](https://supertokens.com/docs/thirdpartyemailpassword/user-object) for more information. +- The `build` function and the `fetch_value` callback of session claims now take a new `recipe_user_id` param. + - This affects built-in claims: `EmailVerificationClaim`, `UserRoleClaim`, `PermissionClaim`, `AllowedDomainsClaim`. + - This will affect all custom claims as well built on our base classes. +- Now ignoring protected props in the payload in `create_new_session` and `create_new_session_without_request_response` +- `created_new_user` has been renamed to `created_new_recipe_user` in sign up related APIs and functions - `Session` recipe: - The sign out API new returns a 401 instead of 200 in case the input access token has expired or is missing. -- `AccountLinking` recipe: - - Changed the signature of the following functions, each taking a new (optional) `session` parameter: - - `createPrimaryUserIdOrLinkAccounts` - - `isSignUpAllowed` - - `isSignInAllowed` - - `isEmailChangeAllowed` - - Changed the signature of the `shouldDoAutomaticAccountLinking` callback: it now takes a new (optional) session parameter. - `EmailPassword`: + - removed `get_user_by_id`, `get_user_by_email`. You should use `supertokens.get_user`, and `supertokens.list_users_by_account_info` instead + - added `consume_password_reset_token`. This function allows the consumption of the reset password token without changing the password. It will return OK if the token was valid. + - added an overrideable `create_new_recipe_user` function that is called during sign up and password reset flow (in case a new email password user is being created on the fly). This is mostly for internal use. + - `recipe_user_id` is added to the input of `get_content` of the email delivery config + - `email` was added to the input of `create_reset_password_token` , `send_reset_password_email`, `create_reset_password_link` + - `update_email_or_password` : + - now takes `recipe_user_id` instead of `user_id` + - can return the new `EMAIL_CHANGE_NOT_ALLOWED_ERROR` status + - `reset_password_using_token`: + - removed from the recipe interface, making it no longer overrideable (directly) + - the related function in the index files now call `consume_password_reset_token` and `update_email_or_password` + - any necessary behaviour changes can be achieved by overriding those two function instead + - `sign_in_post`: + - can return status `SIGN_IN_NOT_ALLOWED` + - `sign_up_post`: + - can return status `SIGN_UP_NOT_ALLOWED` + - `generate_password_reset_token_post`: + - can now return `PASSWORD_RESET_NOT_ALLOWED` + - `password_reset_post`: + - now returns the `user` and the `email` whose password was reset + - can now return `PASSWORD_POLICY_VIOLATED_ERROR` - Changed the signature of the following overrideable functions: - - `signUp` + - `sign_up` - Takes a new (optional) `session` parameter - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"` - - `signIn` + - returns new `recipe_user_id` prop in the `status: OK` case + - `sign_in` - Takes a new (optional) `session` parameter - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"` + - returns new `recipe_user_id` prop in the `status: OK` case - Changed the signature of overrideable APIs, adding a new (optional) session parameter: - - `signInPOST` - - `signUpPOST` + - `sign_in_post` + - `sign_up_post` - Changed the signature of functions: - - `signUp` + - `sign_up` - Takes a new (optional) `session` parameter - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"` - - `signIn` + - `sign_in` - Takes a new (optional) `session` parameter - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED" +- `EmailVerification`: + - `create_email_verification_token`, `create_email_verification_link`, `is_email_verified`, `revoke_email_verification_tokens` , `unverify_email`: + - now takes `recipe_user_id` instead of `user_id` + - `send_email_verification_email` : + - now takes an additional `recipe_user_id` parameter + - `verify_email_using_token`: + - now takes a new `attempt_account_linking` parameter + - returns the `recipe_user_id` instead of `id` + - `send_email` now requires a new `recipe_user_id` as part of the user info + - `get_email_for_user_id` config option was renamed to `get_email_for_recipe_user_id` + - `verify_email_post`, `generate_email_verify_token_post`: returns an optional `new_session` in case the current user session needs to be updated - `Multitenancy`: + - `associate_user_to_tenant` can now return `ASSOCIATION_NOT_ALLOWED_ERROR` + - `associate_user_to_tenant` and `disassociate_user_from_tenant` now take `RecipeUserId` instead of a string user id - Changed the signature of the following functions: - - `createOrUpdateTenant`: Added optional `firstFactors` and `requiredSecondaryFactors` parameters. - - `getTenant`: Added `firstFactors` and `requiredSecondaryFactors` to the return type - - `listAllTenants`: Added `firstFactors` and `requiredSecondaryFactors` to the returned tenants + - `create_or_update_tenant`: Added optional `first_factors` and `required_secondary_factors` parameters. + - `get_tenant`: Added `first_factors` and `required_secondary_factors` to the return type + - `list_all_tenants`: Added `first_factors` and `required_secondary_factors` to the returned tenants - Changed the signature of the following overrideable functions: - - `createOrUpdateTenant`: Now gets optional `firstFactors` and `requiredSecondaryFactors` in the input. - - `getTenant`: Added `firstFactors` and `requiredSecondaryFactors` to the return type - - `listAllTenants`: Added `firstFactors` and `requiredSecondaryFactors` to the returned tenants + - `create_or_update_tenant`: Now gets optional `first_factors` and `required_secondary_factors` in the input. + - `get_tenant`: Added `first_factors` and `required_secondary_factors` to the return type + - `list_all_tenants`: Added `first_factors` and `required_secondary_factors` to the returned tenants - Changed the signature of the overrideable apis: - - `loginMethodsGET`: Now returns `firstFactors` + - `login_methods_get`: Now returns `first_factors` - `Passwordless`: - - `revokeCode` (and the related overrideable func) can now be called with either `preAuthSessionId` or `codeId` instead of only `codeId`. + - removed `get_user_by_id`, `get_user_by_email`, `get_user_by_phone_number` + - `update_user` : + - now takes `recipe_user_id` instead of `user_id` + - can return `"EMAIL_CHANGE_NOT_ALLOWED_ERROR` and `PHONE_NUMBER_CHANGE_NOT_ALLOWED_ERROR` statuses + - `create_code_post` and `consume_code_post` can now return `SIGN_IN_UP_NOT_ALLOWED` + - `revoke_code` (and the related overrideable func) can now be called with either `pre_auth_session_id` or `code_id` instead of only `code_id`. - Added new email and sms type for MFA - Changed the signature of the following functions: - - `signInUp`, `createCode`: Takes a new (optional) `session` parameter - - `consumeCode`: + - `sign_in_up`, `create_code`: Takes a new (optional) `session` parameter + - `consume_code`: - Takes a new (optional) `session` parameter - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"` - - It now also returns `consumedDevice` if the code was successfully consumed + - It now also returns `consumed_device` if the code was successfully consumed - Changed the signature of the following overrideable functions: - - `createCode`: Takes a new (optional) `session` parameter - - `consumeCode`: + - `create_code`: Takes a new (optional) `session` parameter + - `consume_code`: - Takes a new (optional) `session` parameter - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"` - - It now also returns `consumedDevice` if the code was successfully consumed + - It now also returns `consumed_device` if the code was successfully consumed - Changed the signature of overrideable APIs, adding a new (optional) session parameter: - - `createCodePOST` - - `resendCodePOST` - - `consumeCodePOST` + - `create_code_post` + - `resend_code_post` + - `consume_code_post` +- `Session`: + - access tokens and session objects now contain the recipe user id + - Support for new access token version + - `recipe_user_id` is now added to the payload of the `TOKEN_THEFT_DETECTED` error + - `create_new_session`: now takes `recipe_user_id` instead of `user_id` + - Removed `validate_claims_in_jwt_payload` + - `revoke_all_sessions_for_user` now takes an optional `revoke_sessions_for_linked_accounts` param + - `get_all_session_handles_for_user` now takes an optional `fetch_sessions_for_all_linked_accounts` param + - `regenerate_access_token` return value now includes `recipe_user_id` + - `get_global_claim_validators` and `validate_claims` now get a new `recipe_user_id` param + - Added `get_recipe_user_id` to the session class - Session claims: - - The `build` function and the `fetchValue` callback of session claims now take a new `currentPayload` param. + - The `build` function and the `fetch_value` callback of session claims now take a new `current_payload` param. - This affects built-in claims: `EmailVerificationClaim`, `UserRoleClaim`, `PermissionClaim`, `AllowedDomainsClaim`. - This will affect all custom claims as well built on our base classes. - `ThirdParty`: + - Removed `get_user_by_third_party_info`, `get_users_by_email`, `get_user_by_id` + - `sign_in_up_post` can now return `SIGN_IN_UP_NOT_ALLOWED` - Changed the signature of the following functions: - - `manuallyCreateOrUpdateUser`: + - `manually_create_or_update_user`: - Takes a new (optional) `session` parameter - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"` - Changed the signature of the following overrideable functions: - - `signInUp`: + - `sign_in_up`: + - gets a new `is_verified` param + - can return new status: `SIGN_IN_UP_NOT_ALLOWED` - Takes a new (optional) `session` parameter - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"` - - `manuallyCreateOrUpdateUser` + - `manually_create_or_update_user` + - gets a new `is_verified` param + - can return new statuses: `EMAIL_CHANGE_NOT_ALLOWED_ERROR`, `SIGN_IN_UP_NOT_ALLOWED` - Takes a new (optional) `session` parameter - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"` - Changed the signature of overrideable APIs, adding a new (optional) session parameter: - - `signInUpPOST` -- `ThirdPartyEmailPassword`: - - Added new function: `emailPasswordVerifyCredentials` - - Changed the signature of the following functions: - - `thirdPartyManuallyCreateOrUpdateUser`: - - Takes a new (optional) `session` parameter - - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"` - - `emailPasswordSignUp` - - Takes a new (optional) `session` parameter - - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"` - - Changed the signature of the following overrideable functions: - - `thirdPartySignInUp`: - - Takes a new (optional) `session` parameter - - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"` - - `thirdPartyManuallyCreateOrUpdateUser` - - Takes a new (optional) `session` parameter - - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"` - - `emailPasswordSignUp` - - Takes a new (optional) `session` parameter - - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"` - - Changed the signature of overrideable APIs, adding a new (optional) session parameter: - - `emailPasswordSignInPOST` - - `emailPasswordSignUpPOST` - - `thirdPartySignInUpPOST` -- `ThirdPartyPasswordless`: - - `revokeCode` (and the related overrideable func) can now be called with either `preAuthSessionId` or `codeId` instead of only `codeId`. - - Changed the signature of the following functions: - - `thirdPartyManuallyCreateOrUpdateUser`: - - Takes a new (optional) `session` parameter - - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"` - - `passwordlessSignInUp`, `createCode`: Takes a new (optional) `session` parameter - - `consumeCode`: - - Takes a new (optional) `session` parameter - - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"` - - It now also returns `consumedDevice` if the code was successfully consumed - - Changed the signature of the following overrideable functions: - - `thirdPartySignInUp`: - - Takes a new (optional) `session` parameter - - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"` - - `thirdPartyManuallyCreateOrUpdateUser` - - Takes a new (optional) `session` parameter - - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"` - - `createCode`: Takes a new (optional) `session` parameter - - `consumeCode`: - - Takes a new (optional) `session` parameter - - Can now return with `status: "LINKING_TO_SESSION_USER_FAILED"` - - It now also returns `consumedDevice` if the code was successfully consumed - - Changed the signature of overrideable APIs, adding a new (optional) session parameter: - - `thirdPartySignInUpPOST` - - `createCodePOST` - - `resendCodePOST` - - `consumeCodePOST` + - `sign_in_up_post` #### Migration guide -##### shouldDoAutomaticAccountLinking signature change +#### Introducing account-linking -If you use the `userContext` or `tenantId` parameters passed to `shouldDoAutomaticAccountLinking`, please update your implementation to account for the new parameter. +With this release, we are introducing a new AccountLinking recipe, this will let you: -Before: +- link accounts automatically, +- implement manual account linking flows. -```ts -AccountLinking.init({ - shouldDoAutomaticAccountLinking: async (newAccountInfo, user, tenantId, userContext) => { - return { - shouldAutomaticallyLink: true, - shouldRequireVerification: true, - }; - }, -}); +Check our [guide](https://supertokens.com/docs/thirdpartyemailpassword/common-customizations/account-linking/overview) for more information. + +#### The new User object and primary vs non-primary users + +In this release, we've removed the recipes specific user types and instead introduced a new `User` class to support the "Primary user" concept introduced by account linking + +- The new `User` class now provides the same interface for all recipes. +- It contains an `is_primary` field that you can use to differentiate between primary and recipe users +- The `login_methods` array contains objects that covers all props of the old (recipe specific) user types, with the exception of the id. Please check the migration section below to get the exact mapping between old and new props. +- Non-primary users: + - The `login_methods` array should contain exactly 1 element. + - `user.id` will be the same as `user.login_methods[0].recipe_user_id.get_as_string()`. + - `user.id` will change if it is linked to another user. + - They can become a primary user if, and only if there are no other primary users with the same email, third party info or phone number as this user across all the tenants that this user is a part of. +- Primary users + - The `login_methods` array can have 1 or more elements, each corresponding to a single recipe user. + - `user.id` will not change even if other users are linked to it. + - Other non-primary users can be linked to it. The user ID of the linked accounts will now be the primary users ID. +- Check [here](https://supertokens.com/docs/thirdpartyemailpassword/common-customizations/account-linking/overview#primary-user-vs-non-primary-user) for more information about differences between primary and recipe users. + +#### Primary vs RecipeUserId + +Because of account linking we've introduced a new Primary user concept (see above). In most cases, you should only use the primary user id (`user.id` or `session.get_user_id()`) if you are associating data to users. Still, in some cases you need to specifically refer to a login method, which is covered by the new `RecipeUserId` class: + +- You can get it: + - From a session by: `session.get_recipe_user_id()`. + - By finding the appropriate entry in the `login_methods` array of a `User` object (see above): `user.login_methods[0].recipe_user_id`. +- It wraps a simple string value that you can get by calling `recipe_user_id.get_as_string()`. +- We've introduced it to differentiate between primary and recipe user ids in our APIs on a type level. +- Check [here](https://supertokens.com/docs/thirdpartyemailpassword/user-object#primary-vs-recipe-user-id) for more information. + +#### New User structure + +We've added a generic `User` class 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` (or `user.login_methods[0].recipe_user_id` in case you need `RecipeUserId`) +- `user.email` becomes `user.emails[0]` +- `user.phone_number` becomes `user.phone_numbers[0]` +- `user.third_party` becomes `user.third_party[0]` +- `user.time_joined` is still `user.time_joined` +- `user.tenant_ids` is still `user.tenant_ids` + +#### RecipeUserId + +Some functions now require you to pass a `RecipeUserId` instead of a string user id. If you are using our auth recipes, you can find the recipeUserId as: `user.login_methods[0].recipe_user_id` (you'll need to worry about selecting the right login method after enabling account linking). Alternatively, if you already have a string user id you can convert it to a `RecipeUserId` using `supertokens_python.convert_to_recipe_user_id(userIdString)` + +#### Checking if a user signed up or signed in + +- In the passwordless consumeCode / social login signinup APIs, you can check if a user signed up by: + +```python +# Here res refers to the result the function/api functions mentioned above. +is_new_user = res.created_new_recipe_user and len(res.user.login_methods) == 1 ``` -After: +- In the emailpassword sign up API, you can check if a user signed up by: -```ts -AccountLinking.init({ - shouldDoAutomaticAccountLinking: async (newAccountInfo, user, session, tenantId, userContext) => { - return { - shouldAutomaticallyLink: true, - shouldRequireVerification: true, - }; - }, -}); +```python +is_new_user = len(res.user.login_methods) == 1 ``` -##### Optional `session` parameter added to public functions +#### Changing user emails + +- We recommend that you check if the email change of a user is allowed, before calling the update function + - Check [here](https://supertokens.com/docs/thirdpartyemailpassword/common-customizations/change-email-post-login) for more information + +```python +from fastapi import Depends +from supertokens_python.recipe.session.framework.fastapi import verify_session +from supertokens_python.recipe.session import SessionContainer +from supertokens_python.recipe.accountlinking.asyncio import is_email_change_allowed +from supertokens_python.recipe.emailpassword.asyncio import update_email_or_password + +# ... + +@app.post("/change-email") +async def change_email(req: ChangeEmailBody, session: SessionContainer = Depends(verify_session())): + email = req.email + if not await is_email_change_allowed(session.get_recipe_user_id(), email, False): + # this can come here if you have enabled the account linking feature, and + # if there is a security risk in changing this user's email. + pass + + # Update the email + await update_email_or_password( + session.get_recipe_user_id(), + email, + ) + + # ... +``` -We've added a new optional `session` parameter to many function calls. In all cases, these have been added as the last parameter before `userContext`, so this should only affect you if you are using that. You only need to pass a session as a parameter if you are using account linking and want to try and link the user signing in/up to the session user. -You can get the necessary session object using `verifySession` in an API call. +#### Optional `session` parameter added to public functions -Here we use the example of `EmailPassword.signIn` but this fits other functions with changed signatures. +We've added a new optional `session` parameter to many function calls. In all cases, these have been added as the last parameter before `user_context`, so this should only affect you if you are using that. You only need to pass a session as a parameter if you are using account linking and want to try and link the user signing in/up to the session user. +You can get the necessary session object using `verify_session` in an API call. + +Here we use the example of `EmailPassword.sign_in` but this fits other functions with changed signatures. Before: -```ts -const signInResp = await EmailPassword.signIn("public", "asdf@asdf.asfd", "testpw", { myContextVar: true }); +```python +from supertokens_python.recipe.emailpassword.asyncio import sign_in + +sign_in_resp = await sign_in("public", "asdf@asdf.asfd", "testpw", { "myContextVar": True }) ``` After: -```ts -const signInResp = await EmailPassword.signIn("public", "asdf@asdf.asfd", "testpw", undefined, { myContextVar: true }); +```python +from supertokens_python.recipe.emailpassword.asyncio import sign_in + +sign_in_resp = await sign_in("public", "asdf@asdf.asfd", "testpw", None, { "myContextVar": True }) ``` -##### `fetchValue` signature change +#### `fetch_value` signature change -If you use the `userContext` parameter passed to `fetchValue`, please update your implementation to account for the new parameter. +If you use the `user_context` parameter passed to `fetch_value`, please update your implementation to account for the new parameter. Before: -```ts -const boolClaim = new BooleanClaim({ - key: "asdf", - fetchValue: (userId, recipeUserId, tenantId, userContext) => { - return userContext.claimValue; - }, -}); +```python +from typing import Any, Dict +from supertokens_python.recipe.session.claims import BooleanClaim +from supertokens_python.types import RecipeUserId + +def fetch_value(user_id: str, recipe_user_id: RecipeUserId, tenant_id: str, user_context: Dict[str, Any]) -> bool: + return user_context["claimValue"] + + +bool_claim = BooleanClaim( + key="asdf", + fetch_value=fetch_value, +) ``` After: -```ts -const boolClaim = new BooleanClaim({ - key: "asdf", - fetchValue: (userId, recipeUserId, tenantId, currentPayload, userContext) => { - return userContext.claimValue; - }, -}); +```python +from typing import Any, Dict +from supertokens_python.recipe.session.claims import BooleanClaim +from supertokens_python.types import RecipeUserId + +def fetch_value(user_id: str, recipe_user_id: RecipeUserId, tenant_id: str, current_payload: Dict[str, Any], user_context: Dict[str, Any]) -> bool: + return user_context["claimValue"] + + +bool_claim = BooleanClaim( + key="asdf", + fetch_value=fetch_value, +) ``` -##### `build` signature change +#### `build` signature change If you were using the `build` function for custom or built-in session claims, you should update the call signature to also pass the new parameter. Before: -```ts -Session.init({ - override: { - functions: (originalImplementation) => { - return { - ...originalImplementation, - createNewSession: async function (input) { - input.accessTokenPayload = { - ...input.accessTokenPayload, - ...(await UserRoleClaim.build( - input.userId, - input.recipeUserId, - input.tenantId, - input.userContext - )), - }; - - return originalImplementation.createNewSession(input); - }, - }; - }, - }, -}); +```python +from typing import Any, Dict, Optional +from supertokens_python.recipe import session +from supertokens_python.recipe.session.interfaces import RecipeInterface +from supertokens_python.recipe.userroles import UserRoleClaim +from supertokens_python.types import RecipeUserId + + +def functions_override(original_implementation: RecipeInterface): + o_create_new_session = original_implementation.create_new_session + + async def n_create_new_session( + user_id: str, + recipe_user_id: RecipeUserId, + access_token_payload: Optional[Dict[str, Any]], + session_data_in_database: Optional[Dict[str, Any]], + disable_anti_csrf: Optional[bool], + tenant_id: str, + user_context: Dict[str, Any], + ): + access_token_payload = { + **(access_token_payload or {}), + **(await UserRoleClaim.build(user_id, recipe_user_id, tenant_id, user_context)) + } + return await o_create_new_session(user_id, recipe_user_id, access_token_payload, session_data_in_database, disable_anti_csrf, tenant_id, user_context) + + original_implementation.create_new_session = n_create_new_session + + return original_implementation + +session.init(override=session.InputOverrideConfig(functions=functions_override)) ``` After: -```ts -Session.init({ - override: { - functions: (originalImplementation) => { - return { - ...originalImplementation, - createNewSession: async function (input) { - input.accessTokenPayload = { - ...input.accessTokenPayload, - ...(await UserRoleClaim.build( - input.userId, - input.recipeUserId, - input.tenantId, - input.accessTokenPayload, - input.userContext - )), - }; - - return originalImplementation.createNewSession(input); - }, - }; - }, - }, -}); +```python +from typing import Any, Dict, Optional +from supertokens_python.recipe import session +from supertokens_python.recipe.session.interfaces import RecipeInterface +from supertokens_python.recipe.userroles import UserRoleClaim +from supertokens_python.types import RecipeUserId + + +def functions_override(original_implementation: RecipeInterface): + o_create_new_session = original_implementation.create_new_session + + async def n_create_new_session( + user_id: str, + recipe_user_id: RecipeUserId, + access_token_payload: Optional[Dict[str, Any]], + session_data_in_database: Optional[Dict[str, Any]], + disable_anti_csrf: Optional[bool], + tenant_id: str, + user_context: Dict[str, Any], + ): + access_token_payload = { + **(access_token_payload or {}), + **(await UserRoleClaim.build(user_id, recipe_user_id, tenant_id, access_token_payload or {}, user_context)) + } + return await o_create_new_session(user_id, recipe_user_id, access_token_payload, session_data_in_database, disable_anti_csrf, tenant_id, user_context) + + original_implementation.create_new_session = n_create_new_session + + return original_implementation + +session.init(override=session.InputOverrideConfig(functions=functions_override)) ``` -##### Post sign-in/up actions +#### Post sign-in/up actions Since now sign in/up APIs and functions can be called with a session (e.g.: during MFA flows), you may need to add an extra check to your overrides to account for that: @@ -362,7 +470,7 @@ Passwordless.init({ }), ``` -##### Sign-in/up linking to the session user +#### Sign-in/up linking to the session user Sign in/up APIs and functions will now attempt to link the authenticating user to the session user if a session is available (depending on AccountLinking settings). You can disable this and get the old behaviour by: @@ -398,245 +506,14 @@ Passwordless.init({ }), ``` -#### Introducing account-linking - -With this release, we are introducing a new AccountLinking recipe, 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. - -#### The new User object and primary vs non-primary users - -In this release, we've removed the recipes specific user types and instead introduced a new `User` class to support the "Primary user" concept introduced by account linking - -- The new `User` class now provides the same interface for all recipes. -- It contains an `isPrimary` field that you can use to differentiate between primary and recipe users -- The `loginMethods` array contains objects that covers all props of the old (recipe specific) user types, with the exception of the id. Please check the migration section below to get the exact mapping between old and new props. -- Non-primary users: - - The `loginMethods` array should contain exactly 1 element. - - `user.id` will be the same as `user.loginMethods[0].recipeUserId.getAsString()`. - - `user.id` will change if it is linked to another user. - - They can become a primary user if, and only if there are no other primary users with the same email, third party info or phone number as this user across all the tenants that this user is a part of. -- Primary users - - The `loginMethods` array can have 1 or more elements, each corresponding to a single recipe user. - - `user.id` will not change even if other users are linked to it. - - Other non-primary users can be linked to it. The user ID of the linked accounts will now be the primary users ID. -- Check [here](https://supertokens.com/docs/thirdpartyemailpassword/common-customizations/account-linking/overview#primary-user-vs-non-primary-user) for more information about differences between primary and recipe users. - -#### Primary vs RecipeUserId - -Because of account linking we've introduced a new Primary user concept (see above). In most cases, you should only use the primary user id (`user.id` or `session.getUserId()`) if you are associating data to users. Still, in some cases you need to specifically refer to a login method, which is covered by the new `RecipeUserId` class: - -- You can get it: - - From a session by: `session.getRecipeUserId()`. - - By finding the appropriate entry in the `loginMethods` array of a `User` object (see above): `user.loginMethods[0].recipeUserId`. -- It wraps a simple string value that you can get by calling `recipeUserId.getAsString()`. -- We've introduced it to differentiate between primary and recipe user ids in our APIs on a type level. -- Check [here](https://supertokens.com/docs/thirdpartyemailpassword/user-object#primary-vs-recipe-user-id) for more information. - -### Breaking changes - -- Now only supporting CDI 4.0. Compatible with core version >= 7.0 -- Now supporting FDI 1.18 -- Removed the recipe specific `User` type, now all functions are using the new generic `User` type. - - Check [here](https://supertokens.com/docs/thirdpartyemailpassword/user-object) for more information. -- The `build` function and the `fetchValue` callback of session claims now take a new `recipeUserId` param. - - This affects built-in claims: `EmailVerificationClaim`, `UserRoleClaim`, `PermissionClaim`, `AllowedDomainsClaim`. - - This will affect all custom claims as well built on our base classes. -- Now ignoring protected props in the payload in `createNewSession` and `createNewSessionWithoutRequestResponse` -- `createdNewUser` has been renamed to `createdNewRecipeUser` in sign up related APIs and functions - -- EmailPassword: - - removed `getUserById`, `getUserByEmail`. You should use `supertokens.getUser`, and `supertokens. listUsersByAccountInfo` instead - - added `consumePasswordResetToken`. This function allows the consumption of the reset password token without changing the password. It will return OK if the token was valid. - - added an overrideable `createNewRecipeUser` function that is called during sign up and password reset flow (in case a new email password user is being created on the fly). This is mostly for internal use. - - `recipeUserId` is added to the input of `getContent` of the email delivery config - - `email` was added to the input of `createResetPasswordToken` , `sendResetPasswordEmail`, `createResetPasswordLink` - - `updateEmailOrPassword` : - - now takes `recipeUserId` instead of `userId` - - can return the new `EMAIL_CHANGE_NOT_ALLOWED_ERROR` status - - `signIn`: - - returns new `recipeUserId` prop in the `status: OK` case - - `signUp`: - - returns new `recipeUserId` prop in the `status: OK` case - - `resetPasswordUsingToken`: - - removed from the recipe interface, making it no longer overrideable (directly) - - the related function in the index files now call `consumePasswordResetToken` and `updateEmailOrPassword` - - any necessary behaviour changes can be achieved by overriding those two function instead - - `signInPOST`: - - can return status `SIGN_IN_NOT_ALLOWED` - - `signUpPOST`: - - can return status `SIGN_UP_NOT_ALLOWED` - - `generatePasswordResetTokenPOST`: - - can now return `PASSWORD_RESET_NOT_ALLOWED` - - `passwordResetPOST`: - - now returns the `user` and the `email` whose password was reset - - can now return `PASSWORD_POLICY_VIOLATED_ERROR` -- EmailVerification: - - `createEmailVerificationToken`, `createEmailVerificationLink`, `isEmailVerified`, `revokeEmailVerificationTokens` , `unverifyEmail`: - - now takes `recipeUserId` instead of `userId` - - `sendEmailVerificationEmail` : - - now takes an additional `recipeUserId` parameter - - `verifyEmailUsingToken`: - - now takes a new `attemptAccountLinking` parameter - - returns the `recipeUserId` instead of `id` - - `sendEmail` now requires a new `recipeUserId` as part of the user info - - `getEmailForUserId` config option was renamed to `getEmailForRecipeUserId` - - `verifyEmailPOST`, `generateEmailVerifyTokenPOST`: returns an optional `newSession` in case the current user session needs to be updated -- Passwordless: - - removed `getUserById`, `getUserByEmail`, `getUserByPhoneNumber` - - `updateUser` : - - now takes `recipeUserId` instead of `userId` - - can return `"EMAIL_CHANGE_NOT_ALLOWED_ERROR` and `PHONE_NUMBER_CHANGE_NOT_ALLOWED_ERROR` statuses - - `createCodePOST` and `consumeCodePOST` can now return `SIGN_IN_UP_NOT_ALLOWED` -- Session: - - access tokens and session objects now contain the recipe user id - - Support for new access token version - - `recipeUserId` is now added to the payload of the `TOKEN_THEFT_DETECTED` error - - `createNewSession`: now takes `recipeUserId` instead of `userId` - - Removed `validateClaimsInJWTPayload` - - `revokeAllSessionsForUser` now takes an optional `revokeSessionsForLinkedAccounts` param - - `getAllSessionHandlesForUser` now takes an optional `fetchSessionsForAllLinkedAccounts` param - - `regenerateAccessToken` return value now includes `recipeUserId` - - `getGlobalClaimValidators` and `validateClaims` now get a new `recipeUserId` param - - Added `getRecipeUserId` to the session class -- ThirdParty: - - The `signInUp` override: - - gets a new `isVerified` param - - can return new status: `SIGN_IN_UP_NOT_ALLOWED` - - `manuallyCreateOrUpdateUser`: - - gets a new `isVerified` param - - can return new statuses: `EMAIL_CHANGE_NOT_ALLOWED_ERROR`, `SIGN_IN_UP_NOT_ALLOWED` - - Removed `getUserByThirdPartyInfo`, `getUsersByEmail`, `getUserById` - - `signInUpPOST` can now return `SIGN_IN_UP_NOT_ALLOWED` -- ThirdPartyEmailPassword: - - Removed `getUserByThirdPartyInfo`, `getUsersByEmail`, `getUserById` - - `thirdPartyManuallyCreateOrUpdateUser`: - - now get a new `isVerified` param - - can return new statuses: `EMAIL_CHANGE_NOT_ALLOWED_ERROR`, `SIGN_IN_UP_NOT_ALLOWED` - - The `thirdPartySignInUp` override: - - now get a new `isVerified` param - - can return new status: `SIGN_IN_UP_NOT_ALLOWED` - - `email` was added to the input of `createResetPasswordToken` , `sendResetPasswordEmail`, `createResetPasswordLink` - - added an overrideable `createNewEmailPasswordRecipeUser` function that is called during email password sign up and in the “invitation link” flow - - added `consumePasswordResetToken` - - `updateEmailOrPassword` : - - now takes `recipeUserId` instead of `userId` - - can return the new `EMAIL_CHANGE_NOT_ALLOWED_ERROR` status - - `resetPasswordUsingToken`: - - removed from the recipe interface, making it no longer overrideable (directly) - - the related function in the index files now call `consumePasswordResetToken` and `updateEmailOrPassword` - - any necessary behaviour changes can be achieved by overriding those two function instead - - added an overrideable `createNewEmailPasswordRecipeUser` function that is called during sign up and in the “invitation link” flow - - `emailPasswordSignIn`: - - returns new `recipeUserId` prop in the `status: OK` case - - `emailPasswordSignUp`: - - returns new `recipeUserId` prop in the `status: OK` case - - `emailPasswordSignInPOST`: - - can return status `SIGN_IN_NOT_ALLOWED` - - `emailPasswordSignUpPOST`: - - can return status `SIGN_UP_NOT_ALLOWED` - - `generatePasswordResetTokenPOST`: - - can now return `PASSWORD_RESET_NOT_ALLOWED` - - `passwordResetPOST`: - - now returns the `user` and the `email` whose password was reset - - can now return `PASSWORD_POLICY_VIOLATED_ERROR` - - `thirdPartySignInUpPOST` can now return `SIGN_IN_UP_NOT_ALLOWED` -- ThirdPartyPasswordless: - - Removed `getUserByThirdPartyInfo`, `getUsersByEmail`, `getUserByPhoneNumber`, `getUserById` - - `thirdPartyManuallyCreateOrUpdateUser`: - - gets a new `isVerified` param - - can return new statuses: `EMAIL_CHANGE_NOT_ALLOWED_ERROR`, `SIGN_IN_UP_NOT_ALLOWED` - - The `thirdPartySignInUp` override: - - gets a new `isVerified` param - - can return new status: `SIGN_IN_UP_NOT_ALLOWED` - - `updatePasswordlessUser`: - - now takes `recipeUserId` instead of `userId` - - can return `"EMAIL_CHANGE_NOT_ALLOWED_ERROR` and `PHONE_NUMBER_CHANGE_NOT_ALLOWED_ERROR` statuses - - `thirdPartySignInUpPOST` can now return `SIGN_IN_UP_NOT_ALLOWED` - - `createCodePOST` and `consumeCodePOST` can now return `SIGN_IN_UP_NOT_ALLOWED` -- Multitenancy: - - `associateUserToTenant` can now return `ASSOCIATION_NOT_ALLOWED_ERROR` - - `associateUserToTenant` and `disassociateUserFromTenant` now take `RecipeUserId` instead of a string user id - -### Changes - -- Added `RecipeUserId` and a generic `User` class -- Added `getUser`, `listUsersByAccountInfo`, `convertToRecipeUserId` to the main exports -- Updated compilation target of typescript to ES2017 to make debugging easier. -- Added account-linking recipe - -### Migration guide - -#### New User structure - -We've added a generic `User` class 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` (or `user.loginMethods[0].recipeUserId` in case you need `RecipeUserId`) -- `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` - -#### RecipeUserId - -Some functions now require you to pass a `RecipeUserId` instead of a string user id. If you are using our auth recipes, you can find the recipeUserId as: `user.loginMethods[0].recipeUserId` (you'll need to worry about selecting the right login method after enabling account linking). Alternatively, if you already have a string user id you can convert it to a `RecipeUserId` using `supertokens.convertToRecipeUserId(userIdString)` - -#### Checking if a user signed up or signed in - -- In the 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; -``` - -- In the emailpassword sign up API, you can check if a user signed up by: - -``` - const isNewUser = res.user.loginMethods.length === 1; -``` - -#### Changing user emails - -- We recommend that you check if the email change of a user is allowed, before calling the update function - - Check [here](https://supertokens.com/docs/thirdpartyemailpassword/common-customizations/change-email-post-login) for more information - -``` -import {isEmailChangeAllowed} from "supertokens-node/recipe/accountlinking"; -/// ... -app.post("/change-email", verifySession(), async (req: SessionRequest, res: express.Response) => { - let session = req.session!; - let email = req.body.email; - - // ... - if (!(await isEmailChangeAllowed(session.getRecipeUserId(), email, false))) { - // this can come here if you have enabled the account linking feature, and - // if there is a security risk in changing this user's email. - } - - // Update the email - let resp = await ThirdPartyEmailPassword.updateEmailOrPassword({ - recipeUserId: session.getRecipeUserId(), - email: email, - }); - // ... -}); -``` - ## [0.24.4] - 2024-10-16 - Updates `phonenumbers` and `twilio` to latest versions ->>>>>>> 0.24 ## [0.24.3] - 2024-09-24 - Adds support for form field related improvements by making fields accept any type of values - Adds support for optional fields to properly optional ->>>>>>> 0.24 ### Migration From 867f37c8d0ae0217c3bc739d65c648b51b8c1fa8 Mon Sep 17 00:00:00 2001 From: Sattvik Chakravarthy Date: Fri, 1 Nov 2024 16:41:09 +0530 Subject: [PATCH 03/11] fix: snippet in changelog --- CHANGELOG.md | 178 ++++++++++++++++++++++++++------------------------- 1 file changed, 91 insertions(+), 87 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03d22192..eae05392 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -402,72 +402,53 @@ session.init(override=session.InputOverrideConfig(functions=functions_override)) Since now sign in/up APIs and functions can be called with a session (e.g.: during MFA flows), you may need to add an extra check to your overrides to account for that: -Before: +```python +# While this example uses Passwordless, all recipes require a very similar change +from typing import Any, Dict, Optional, Union +from supertokens_python.recipe import passwordless +from supertokens_python.recipe.passwordless.interfaces import ConsumeCodeOkResult, RecipeInterface +from supertokens_python.recipe.session import SessionContainer -```ts -// While this example uses Passwordless, all recipes require a very similar change -Passwordless.init({ - contactMethod: "EMAIL", // This example will work with any contactMethod - flowType: "USER_INPUT_CODE_AND_MAGIC_LINK", // This example will work with any flowType - - override: { - functions: (originalImplementation) => { - return { - ...originalImplementation, - consumeCode: async (input) => { - - // First we call the original implementation of consumeCode. - let response = await originalImplementation.consumeCode(input); - - // Post sign up response, we check if it was successful - if (response.status === "OK") { - if (response.createdNewRecipeUser && response.user.loginMethods.length === 1) { - // TODO: post sign up logic - } else { - // TODO: post sign in logic - } - } - return response; - } - } - } - } -}), -``` +def functions_override(original_implementation: RecipeInterface): + o_consume_code = original_implementation.consume_code + + async def n_consume_code( + pre_auth_session_id: str, + user_input_code: Union[str, None], + device_id: Union[str, None], + link_code: Union[str, None], + session: Optional[SessionContainer], + should_try_linking_with_session_user: Union[bool, None], + tenant_id: str, + user_context: Dict[str, Any], + ): + resp = await o_consume_code( + pre_auth_session_id, + user_input_code, device_id, + link_code, + session, + should_try_linking_with_session_user, + tenant_id, + user_context + ) -After: + if isinstance(resp, ConsumeCodeOkResult): + if session is None: + if resp.created_new_recipe_user and len(resp.user.login_methods) == 1: + pass # TODO: post sign up logic + else: + pass # TODO: post sign in logic -```ts -// While this example uses Passwordless, all recipes require a very similar change -Passwordless.init({ - contactMethod: "EMAIL", // This example will work with any contactMethod - flowType: "USER_INPUT_CODE_AND_MAGIC_LINK", // This example will work with any flowType - - override: { - functions: (originalImplementation) => { - return { - ...originalImplementation, - consumeCode: async (input) => { - - // First we call the original implementation of consumeCode. - let response = await originalImplementation.consumeCode(input); - - // Post sign up response, we check if it was successful - if (response.status === "OK") { - if (input.session === undefined) { - if (response.createdNewRecipeUser && response.user.loginMethods.length === 1) { - // TODO: post sign up logic - } else { - // TODO: post sign in logic - } - } - } - return response; - } - } - } - } -}), + return resp + + original_implementation.consume_code = n_consume_code + return original_implementation + +passwordless.init( + passwordless.ContactConfig('EMAIL'), + 'USER_INPUT_CODE_AND_MAGIC_LINK', + override=passwordless.InputOverrideConfig(functions=functions_override) +) ``` #### Sign-in/up linking to the session user @@ -476,34 +457,57 @@ Sign in/up APIs and functions will now attempt to link the authenticating user t Before: -```ts -// While this example uses Passwordless, all recipes require a very similar change -Passwordless.init({ - contactMethod: "EMAIL", // This example will work with any contactMethod - flowType: "USER_INPUT_CODE_AND_MAGIC_LINK", // This example will work with any flowType -}), +```python +from supertokens_python.recipe import passwordless + +# While this example uses Passwordless, all recipes require a very similar change +passwordless.init( + passwordless.ContactConfig('EMAIL'), + 'USER_INPUT_CODE_AND_MAGIC_LINK' +) ``` After: -```ts -// While this example uses Passwordless, all recipes require a very similar change -Passwordless.init({ - contactMethod: "EMAIL", // This example will work with any contactMethod - flowType: "USER_INPUT_CODE_AND_MAGIC_LINK", // This example will work with any flowType - - override: { - functions: (originalImplementation) => { - return { - ...originalImplementation, - consumeCode: async (input) => { - input.session = undefined; - return originalImplementation.consumeCode(input); - } - } - } - } -}), +```python +# While this example uses Passwordless, all recipes require a very similar change + +from typing import Any, Dict, Optional, Union +from supertokens_python.recipe import passwordless +from supertokens_python.recipe.passwordless.interfaces import RecipeInterface +from supertokens_python.recipe.session import SessionContainer + +def functions_override(original_implementation: RecipeInterface): + o_consume_code = original_implementation.consume_code + + async def n_consume_code( + pre_auth_session_id: str, + user_input_code: Union[str, None], + device_id: Union[str, None], + link_code: Union[str, None], + session: Optional[SessionContainer], + should_try_linking_with_session_user: Union[bool, None], + tenant_id: str, + user_context: Dict[str, Any], + ): + return await o_consume_code( + pre_auth_session_id, + user_input_code, device_id, + link_code, + None, # do not pass session + should_try_linking_with_session_user, + tenant_id, + user_context + ) + + original_implementation.consume_code = n_consume_code + return original_implementation + +passwordless.init( + passwordless.ContactConfig('EMAIL'), + 'USER_INPUT_CODE_AND_MAGIC_LINK', + override=passwordless.InputOverrideConfig(functions=functions_override) +) ``` ## [0.24.4] - 2024-10-16 From eb090f74df031f9df698870007a624ce6a0dfb2e Mon Sep 17 00:00:00 2001 From: Sattvik Chakravarthy Date: Fri, 1 Nov 2024 17:57:10 +0530 Subject: [PATCH 04/11] fix: parallise flask website --- .circleci/config_continue.yml | 9 +- .../setupAndTestWithFrontendWithFlask.sh | 8 +- .circleci/websiteFlask.sh | 132 ++++++++---------- 3 files changed, 71 insertions(+), 78 deletions(-) diff --git a/.circleci/config_continue.yml b/.circleci/config_continue.yml index d60e7b65..524f0b7b 100644 --- a/.circleci/config_continue.yml +++ b/.circleci/config_continue.yml @@ -75,6 +75,10 @@ jobs: docker: - image: rishabhpoddar/supertokens_python_driver_testing resource_class: large + parameters: + fdi-version: + type: string + parallelism: 4 steps: - checkout - run: update-alternatives --install "/usr/bin/java" "java" "/usr/java/jdk-15.0.1/bin/java" 2 @@ -82,7 +86,7 @@ jobs: - run: git config --global url."https://github.com/".insteadOf ssh://git@github.com/ - run: echo "127.0.0.1 localhost.org" >> /etc/hosts - run: make with-flask - - run: (cd .circleci/ && ./websiteFlask.sh) + - run: (cd .circleci/ && ./websiteFlask.sh << parameters.fdi-version >>) - slack/status test-website-django: docker: @@ -316,6 +320,9 @@ workflows: - test-dev-tag-as-not-passed context: - slack-notification + matrix: + parameters: + fdi-version: placeholder filters: tags: only: /dev-v[0-9]+(\.[0-9]+)*/ diff --git a/.circleci/setupAndTestWithFrontendWithFlask.sh b/.circleci/setupAndTestWithFrontendWithFlask.sh index 2e220687..fe0fb04c 100755 --- a/.circleci/setupAndTestWithFrontendWithFlask.sh +++ b/.circleci/setupAndTestWithFrontendWithFlask.sh @@ -59,7 +59,13 @@ npm i git+https://github.com:supertokens/supertokens-node.git#$3 npm i cd ../../ npm i -SUPERTOKENS_CORE_TAG=$coreTag NODE_PORT=8081 INSTALL_PATH=../supertokens-root npm test + +if ! [[ -z "${CIRCLE_NODE_TOTAL}" ]]; then + TEST_MODE=testing SUPERTOKENS_CORE_TAG=$coreTag NODE_PORT=8081 INSTALL_PATH=../supertokens-root npx mocha --exit --no-config --require isomorphic-fetch --timeout 500000 $(npx mocha-split-tests -r ./runtime.log -t $CIRCLE_NODE_TOTAL -g $CIRCLE_NODE_INDEX -f 'test/*.test.js') +else + TEST_MODE=testing SUPERTOKENS_CORE_TAG=$coreTag NODE_PORT=8081 INSTALL_PATH=../supertokens-root npm test +fi + if [[ $? -ne 0 ]] then echo "test failed... killing $pid, $pid2 and exiting!" diff --git a/.circleci/websiteFlask.sh b/.circleci/websiteFlask.sh index bc752463..5f2dcb2e 100755 --- a/.circleci/websiteFlask.sh +++ b/.circleci/websiteFlask.sh @@ -3,11 +3,6 @@ coreDriverLength=`echo $coreDriverJson | jq ".versions | length"` coreDriverArray=`echo $coreDriverJson | jq ".versions"` echo "got core driver relations" -frontendDriverJson=`cat ../frontendDriverInterfaceSupported.json` -frontendDriverLength=`echo $frontendDriverJson | jq ".versions | length"` -frontendDriverArray=`echo $frontendDriverJson | jq ".versions"` -echo "got frontend driver relations" - # get driver version version=`cat ../setup.py | grep -e 'version='` while IFS='"' read -ra ADDR; do @@ -21,7 +16,6 @@ while IFS='"' read -ra ADDR; do done done <<< "$version" -someFrontendTestsRan=false i=0 coreDriverVersion=`echo $coreDriverArray | jq ". | last"` coreDriverVersion=`echo $coreDriverVersion | tr -d '"'` @@ -34,84 +28,70 @@ then exit 1 fi coreFree=$(echo $coreFree | jq .core | tr -d '"') -while [ $i -lt $frontendDriverLength ]; do - frontendDriverVersion=`echo $frontendDriverArray | jq ".[$i]"` - frontendDriverVersion=`echo $frontendDriverVersion | tr -d '"'` - i=$((i+1)) - - if [[ $frontendDriverVersion == '1.0' ]]; then - continue - fi - frontendVersionXY=`curl -s -X GET \ - "https://api.supertokens.io/0/frontend-driver-interface/dependency/frontend/latest?password=$SUPERTOKENS_API_KEY&frontendName=website&mode=DEV&version=$frontendDriverVersion&driverName=python" \ - -H 'api-version: 1'` - if [[ `echo $frontendVersionXY | jq .frontend` == "null" ]] - then - echo "fetching latest X.Y version for frontend given frontend-driver-interface X.Y version: $frontendDriverVersion, name: webiste gave response: $frontend. Please make sure all relevant versions have been pushed." - exit 1 - fi - frontendVersionXY=$(echo $frontendVersionXY | jq .frontend | tr -d '"') +frontendDriverVersion=$1 +frontendDriverVersion=`echo $frontendDriverVersion | tr -d '"'` - frontendInfo=`curl -s -X GET \ - "https://api.supertokens.io/0/driver/latest?password=$SUPERTOKENS_API_KEY&mode=DEV&version=$frontendVersionXY&name=website" \ - -H 'api-version: 0'` - if [[ `echo $frontendInfo | jq .tag` == "null" ]] - then - echo "fetching latest X.Y.Z version for frontend, X.Y version: $frontendVersionXY gave response: $frontendInfo" - exit 1 - fi - frontendTag=$(echo $frontendInfo | jq .tag | tr -d '"') - frontendVersion=$(echo $frontendInfo | jq .version | tr -d '"') +frontendVersionXY=`curl -s -X GET \ +"https://api.supertokens.io/0/frontend-driver-interface/dependency/frontend/latest?password=$SUPERTOKENS_API_KEY&frontendName=website&mode=DEV&version=$frontendDriverVersion&driverName=node" \ +-H 'api-version: 1'` +if [[ `echo $frontendVersionXY | jq .frontend` == "null" ]] +then + echo "fetching latest X.Y version for frontend given frontend-driver-interface X.Y version: $frontendDriverVersion, name: website gave response: $frontend. Please make sure all relevant versions have been pushed." + exit 1 +fi +frontendVersionXY=$(echo $frontendVersionXY | jq .frontend | tr -d '"') - nodeVersionXY=`curl -s -X GET \ - "https://api.supertokens.io/0/frontend-driver-interface/dependency/driver/latest?password=$SUPERTOKENS_API_KEY&mode=DEV&version=$frontendDriverVersion&driverName=node&frontendName=website" \ - -H 'api-version: 1'` - if [[ `echo $nodeVersionXY | jq .driver` == "null" ]] - then - echo "fetching latest X.Y version for driver given frontend-driver-interface X.Y version: $frontendDriverVersion gave response: $nodeVersionXY. Please make sure all relevant drivers have been pushed." - exit 1 - fi - nodeVersionXY=$(echo $nodeVersionXY | jq .driver | tr -d '"') +frontendInfo=`curl -s -X GET \ +"https://api.supertokens.io/0/frontend/latest?password=$SUPERTOKENS_API_KEY&mode=DEV&version=$frontendVersionXY&name=website" \ +-H 'api-version: 0'` +if [[ `echo $frontendInfo | jq .tag` == "null" ]] +then + echo "fetching latest X.Y.Z version for frontend, X.Y version: $frontendVersionXY gave response: $frontendInfo" + exit 1 +fi +frontendTag=$(echo $frontendInfo | jq .tag | tr -d '"') +frontendVersion=$(echo $frontendInfo | jq .version | tr -d '"') - nodeInfo=`curl -s -X GET \ - "https://api.supertokens.io/0/driver/latest?password=$SUPERTOKENS_API_KEY&mode=DEV&version=$nodeVersionXY&name=node" \ - -H 'api-version: 0'` - if [[ `echo $nodeInfo | jq .tag` == "null" ]] - then - echo "fetching latest X.Y.Z version for driver, X.Y version: $nodeVersionXY gave response: $nodeInfo" - exit 1 - fi - nodeTag=$(echo $nodeInfo | jq .tag | tr -d '"') +nodeVersionXY=`curl -s -X GET \ +"https://api.supertokens.io/0/frontend-driver-interface/dependency/driver/latest?password=$SUPERTOKENS_API_KEY&mode=DEV&version=$frontendDriverVersion&driverName=node&frontendName=website" \ +-H 'api-version: 1'` +if [[ `echo $nodeVersionXY | jq .driver` == "null" ]] +then + echo "fetching latest X.Y version for driver given frontend-driver-interface X.Y version: $frontendDriverVersion gave response: $nodeVersionXY. Please make sure all relevant drivers have been pushed." + exit 1 +fi +nodeVersionXY=$(echo $nodeVersionXY | jq .driver | tr -d '"') - someFrontendTestsRan=true +nodeInfo=`curl -s -X GET \ +"https://api.supertokens.io/0/driver/latest?password=$SUPERTOKENS_API_KEY&mode=DEV&version=$nodeVersionXY&name=node" \ +-H 'api-version: 0'` +if [[ `echo $nodeInfo | jq .tag` == "null" ]] +then + echo "fetching latest X.Y.Z version for driver, X.Y version: $nodeVersionXY gave response: $nodeInfo" + exit 1 +fi +nodeTag=$(echo $nodeInfo | jq .tag | tr -d '"') - tries=1 - while [ $tries -le 3 ] - do - tries=$(( $tries + 1 )) - ./setupAndTestWithFrontendWithFlask.sh $coreFree $frontendTag $nodeTag - if [[ $? -ne 0 ]] +tries=1 +while [ $tries -le 3 ] +do + tries=$(( $tries + 1 )) + ./setupAndTestWithFrontendWithFlask.sh $coreFree $frontendTag $nodeTag + if [[ $? -ne 0 ]] + then + if [[ $tries -le 3 ]] then - if [[ $tries -le 3 ]] - then - rm -rf ../../supertokens-root - rm -rf ../../supertokens-website - echo "failed test.. retrying!" - else - echo "test failed for website tests... exiting!" - exit 1 - fi - else rm -rf ../../supertokens-root rm -rf ../../supertokens-website - break + echo "failed test.. retrying!" + else + echo "test failed for website tests... exiting!" + exit 1 fi - done + else + rm -rf ../../supertokens-root + rm -rf ../../supertokens-website + break + fi done - -if [[ $someFrontendTestsRan = "false" ]] -then - echo "no tests ran... failing!" - exit 1 -fi \ No newline at end of file From 8b344aa45530b91d1d6aef9891f3fd47d82ce64f Mon Sep 17 00:00:00 2001 From: Sattvik Chakravarthy Date: Mon, 4 Nov 2024 11:54:47 +0530 Subject: [PATCH 05/11] fix: parallelise all website tests --- .circleci/config_continue.yml | 51 ++++++- .circleci/setupAndTestWithFrontend.sh | 8 +- .../setupAndTestWithFrontendWithDjango.sh | 8 +- .../setupAndTestWithFrontendWithDjango2x.sh | 8 +- .../setupAndTestWithFrontendWithDrfAsync.sh | 8 +- .../setupAndTestWithFrontendWithDrfSync.sh | 8 +- .circleci/websiteDjango.sh | 131 ++++++++---------- .circleci/websiteDjango2x.sh | 131 ++++++++---------- .circleci/websiteDrfAsync.sh | 131 ++++++++---------- .circleci/websiteDrfSync.sh | 131 ++++++++---------- .circleci/websiteFastApi.sh | 130 ++++++++--------- 11 files changed, 360 insertions(+), 385 deletions(-) diff --git a/.circleci/config_continue.yml b/.circleci/config_continue.yml index 524f0b7b..f152675d 100644 --- a/.circleci/config_continue.yml +++ b/.circleci/config_continue.yml @@ -62,6 +62,10 @@ jobs: docker: - image: rishabhpoddar/supertokens_python_driver_testing resource_class: large + parameters: + fdi-version: + type: string + parallelism: 4 steps: - checkout - run: update-alternatives --install "/usr/bin/java" "java" "/usr/java/jdk-15.0.1/bin/java" 2 @@ -69,7 +73,7 @@ jobs: - run: git config --global url."https://github.com/".insteadOf ssh://git@github.com/ - run: echo "127.0.0.1 localhost.org" >> /etc/hosts - run: make with-fastapi - - run: (cd .circleci/ && ./websiteFastApi.sh) + - run: (cd .circleci/ && ./websiteFastApi.sh << parameters.fdi-version >>) - slack/status test-website-flask: docker: @@ -92,6 +96,10 @@ jobs: docker: - image: rishabhpoddar/supertokens_python_driver_testing resource_class: large + parameters: + fdi-version: + type: string + parallelism: 4 steps: - checkout - run: update-alternatives --install "/usr/bin/java" "java" "/usr/java/jdk-15.0.1/bin/java" 2 @@ -99,12 +107,16 @@ jobs: - run: git config --global url."https://github.com/".insteadOf ssh://git@github.com/ - run: echo "127.0.0.1 localhost.org" >> /etc/hosts - run: make with-django - - run: (cd .circleci/ && ./websiteDjango.sh) + - run: (cd .circleci/ && ./websiteDjango.sh << parameters.fdi-version >>) - slack/status test-website-drf-async: docker: - image: rishabhpoddar/supertokens_python_driver_testing resource_class: large + parameters: + fdi-version: + type: string + parallelism: 4 steps: - checkout - run: update-alternatives --install "/usr/bin/java" "java" "/usr/java/jdk-15.0.1/bin/java" 2 @@ -118,12 +130,16 @@ jobs: - run: echo "alias pip3='python -m pip'" >> ~/.bashrc - run: echo "127.0.0.1 localhost.org" >> /etc/hosts - run: make with-drf - - run: (cd .circleci/ && ./websiteDrfAsync.sh) + - run: (cd .circleci/ && ./websiteDrfAsync.sh << parameters.fdi-version >>) - slack/status test-website-drf-sync: docker: - image: rishabhpoddar/supertokens_python_driver_testing resource_class: large + parameters: + fdi-version: + type: string + parallelism: 4 steps: - checkout - run: update-alternatives --install "/usr/bin/java" "java" "/usr/java/jdk-15.0.1/bin/java" 2 @@ -137,12 +153,16 @@ jobs: - run: echo "alias pip3='python -m pip'" >> ~/.bashrc - run: echo "127.0.0.1 localhost.org" >> /etc/hosts - run: make with-drf - - run: (cd .circleci/ && ./websiteDrfSync.sh) + - run: (cd .circleci/ && ./websiteDrfSync.sh << parameters.fdi-version >>) - slack/status test-website-django2x: docker: - image: rishabhpoddar/supertokens_python_driver_testing resource_class: large + parameters: + fdi-version: + type: string + parallelism: 4 steps: - checkout - run: update-alternatives --install "/usr/bin/java" "java" "/usr/java/jdk-15.0.1/bin/java" 2 @@ -150,7 +170,7 @@ jobs: - run: git config --global url."https://github.com/".insteadOf ssh://git@github.com/ - run: echo "127.0.0.1 localhost.org" >> /etc/hosts - run: make with-django2x - - run: (cd .circleci/ && ./websiteDjango2x.sh) + - run: (cd .circleci/ && ./websiteDjango2x.sh << parameters.fdi-version >>) - slack/status test-website-flask-nest-asyncio: docker: @@ -158,6 +178,10 @@ jobs: resource_class: large environment: SUPERTOKENS_NEST_ASYNCIO: "1" + parameters: + fdi-version: + type: string + parallelism: 4 steps: - checkout - run: update-alternatives --install "/usr/bin/java" "java" "/usr/java/jdk-15.0.1/bin/java" 2 @@ -166,7 +190,7 @@ jobs: - run: echo "127.0.0.1 localhost.org" >> /etc/hosts - run: make with-flask - run: python -m pip install nest-asyncio - - run: (cd .circleci/ && ./websiteFlask.sh) + - run: (cd .circleci/ && ./websiteFlask.sh << parameters.fdi-version >>) - slack/status test-authreact-fastapi: docker: @@ -310,6 +334,9 @@ workflows: - test-dev-tag-as-not-passed context: - slack-notification + matrix: + parameters: + fdi-version: placeholder filters: tags: only: /dev-v[0-9]+(\.[0-9]+)*/ @@ -333,6 +360,9 @@ workflows: - test-dev-tag-as-not-passed context: - slack-notification + matrix: + parameters: + fdi-version: placeholder filters: tags: only: /dev-v[0-9]+(\.[0-9]+)*/ @@ -343,6 +373,9 @@ workflows: - test-dev-tag-as-not-passed context: - slack-notification + matrix: + parameters: + fdi-version: placeholder filters: tags: only: /dev-v[0-9]+(\.[0-9]+)*/ @@ -353,6 +386,9 @@ workflows: - test-dev-tag-as-not-passed context: - slack-notification + matrix: + parameters: + fdi-version: placeholder filters: tags: only: /dev-v[0-9]+(\.[0-9]+)*/ @@ -363,6 +399,9 @@ workflows: - test-dev-tag-as-not-passed context: - slack-notification + matrix: + parameters: + fdi-version: placeholder filters: tags: only: /dev-v[0-9]+(\.[0-9]+)*/ diff --git a/.circleci/setupAndTestWithFrontend.sh b/.circleci/setupAndTestWithFrontend.sh index 1e0e096c..a58f3d5a 100755 --- a/.circleci/setupAndTestWithFrontend.sh +++ b/.circleci/setupAndTestWithFrontend.sh @@ -59,7 +59,13 @@ npm i git+https://github.com:supertokens/supertokens-node.git#$3 npm i cd ../../ npm i -SUPERTOKENS_CORE_TAG=$coreTag NODE_PORT=8081 INSTALL_PATH=../supertokens-root npm test + +if ! [[ -z "${CIRCLE_NODE_TOTAL}" ]]; then + TEST_MODE=testing SUPERTOKENS_CORE_TAG=$coreTag NODE_PORT=8081 INSTALL_PATH=../supertokens-root npx mocha --exit --no-config --require isomorphic-fetch --timeout 500000 $(npx mocha-split-tests -r ./runtime.log -t $CIRCLE_NODE_TOTAL -g $CIRCLE_NODE_INDEX -f 'test/*.test.js') +else + TEST_MODE=testing SUPERTOKENS_CORE_TAG=$coreTag NODE_PORT=8081 INSTALL_PATH=../supertokens-root npm test +fi + if [[ $? -ne 0 ]] then echo "test failed... killing $pid, $pid2 and exiting!" diff --git a/.circleci/setupAndTestWithFrontendWithDjango.sh b/.circleci/setupAndTestWithFrontendWithDjango.sh index 4a76cdd9..d7286099 100755 --- a/.circleci/setupAndTestWithFrontendWithDjango.sh +++ b/.circleci/setupAndTestWithFrontendWithDjango.sh @@ -59,7 +59,13 @@ npm i git+https://github.com:supertokens/supertokens-node.git#$3 npm i cd ../../ npm i -SUPERTOKENS_CORE_TAG=$coreTag NODE_PORT=8081 INSTALL_PATH=../supertokens-root npm test + +if ! [[ -z "${CIRCLE_NODE_TOTAL}" ]]; then + TEST_MODE=testing SUPERTOKENS_CORE_TAG=$coreTag NODE_PORT=8081 INSTALL_PATH=../supertokens-root npx mocha --exit --no-config --require isomorphic-fetch --timeout 500000 $(npx mocha-split-tests -r ./runtime.log -t $CIRCLE_NODE_TOTAL -g $CIRCLE_NODE_INDEX -f 'test/*.test.js') +else + TEST_MODE=testing SUPERTOKENS_CORE_TAG=$coreTag NODE_PORT=8081 INSTALL_PATH=../supertokens-root npm test +fi + if [[ $? -ne 0 ]] then echo "test failed... killing $pid, $pid2 and exiting!" diff --git a/.circleci/setupAndTestWithFrontendWithDjango2x.sh b/.circleci/setupAndTestWithFrontendWithDjango2x.sh index 9f194c82..d0571aba 100755 --- a/.circleci/setupAndTestWithFrontendWithDjango2x.sh +++ b/.circleci/setupAndTestWithFrontendWithDjango2x.sh @@ -59,7 +59,13 @@ npm i git+https://github.com:supertokens/supertokens-node.git#$3 npm i cd ../../ npm i -SUPERTOKENS_CORE_TAG=$coreTag NODE_PORT=8081 INSTALL_PATH=../supertokens-root npm test + +if ! [[ -z "${CIRCLE_NODE_TOTAL}" ]]; then + TEST_MODE=testing SUPERTOKENS_CORE_TAG=$coreTag NODE_PORT=8081 INSTALL_PATH=../supertokens-root npx mocha --exit --no-config --require isomorphic-fetch --timeout 500000 $(npx mocha-split-tests -r ./runtime.log -t $CIRCLE_NODE_TOTAL -g $CIRCLE_NODE_INDEX -f 'test/*.test.js') +else + TEST_MODE=testing SUPERTOKENS_CORE_TAG=$coreTag NODE_PORT=8081 INSTALL_PATH=../supertokens-root npm test +fi + if [[ $? -ne 0 ]] then echo "test failed... killing $pid, $pid2 and exiting!" diff --git a/.circleci/setupAndTestWithFrontendWithDrfAsync.sh b/.circleci/setupAndTestWithFrontendWithDrfAsync.sh index a8825147..cc0b3152 100755 --- a/.circleci/setupAndTestWithFrontendWithDrfAsync.sh +++ b/.circleci/setupAndTestWithFrontendWithDrfAsync.sh @@ -59,7 +59,13 @@ npm i git+https://github.com:supertokens/supertokens-node.git#$3 npm i cd ../../ npm i -SUPERTOKENS_CORE_TAG=$coreTag NODE_PORT=8081 INSTALL_PATH=../supertokens-root npm test + +if ! [[ -z "${CIRCLE_NODE_TOTAL}" ]]; then + TEST_MODE=testing SUPERTOKENS_CORE_TAG=$coreTag NODE_PORT=8081 INSTALL_PATH=../supertokens-root npx mocha --exit --no-config --require isomorphic-fetch --timeout 500000 $(npx mocha-split-tests -r ./runtime.log -t $CIRCLE_NODE_TOTAL -g $CIRCLE_NODE_INDEX -f 'test/*.test.js') +else + TEST_MODE=testing SUPERTOKENS_CORE_TAG=$coreTag NODE_PORT=8081 INSTALL_PATH=../supertokens-root npm test +fi + if [[ $? -ne 0 ]] then echo "test failed... killing $pid, $pid2 and exiting!" diff --git a/.circleci/setupAndTestWithFrontendWithDrfSync.sh b/.circleci/setupAndTestWithFrontendWithDrfSync.sh index 25721b07..15d19f32 100755 --- a/.circleci/setupAndTestWithFrontendWithDrfSync.sh +++ b/.circleci/setupAndTestWithFrontendWithDrfSync.sh @@ -59,7 +59,13 @@ npm i git+https://github.com:supertokens/supertokens-node.git#$3 npm i cd ../../ npm i -SUPERTOKENS_CORE_TAG=$coreTag NODE_PORT=8081 INSTALL_PATH=../supertokens-root npm test + +if ! [[ -z "${CIRCLE_NODE_TOTAL}" ]]; then + TEST_MODE=testing SUPERTOKENS_CORE_TAG=$coreTag NODE_PORT=8081 INSTALL_PATH=../supertokens-root npx mocha --exit --no-config --require isomorphic-fetch --timeout 500000 $(npx mocha-split-tests -r ./runtime.log -t $CIRCLE_NODE_TOTAL -g $CIRCLE_NODE_INDEX -f 'test/*.test.js') +else + TEST_MODE=testing SUPERTOKENS_CORE_TAG=$coreTag NODE_PORT=8081 INSTALL_PATH=../supertokens-root npm test +fi + if [[ $? -ne 0 ]] then echo "test failed... killing $pid, $pid2 and exiting!" diff --git a/.circleci/websiteDjango.sh b/.circleci/websiteDjango.sh index 6490fd75..b4377d01 100755 --- a/.circleci/websiteDjango.sh +++ b/.circleci/websiteDjango.sh @@ -3,11 +3,6 @@ coreDriverLength=`echo $coreDriverJson | jq ".versions | length"` coreDriverArray=`echo $coreDriverJson | jq ".versions"` echo "got core driver relations" -frontendDriverJson=`cat ../frontendDriverInterfaceSupported.json` -frontendDriverLength=`echo $frontendDriverJson | jq ".versions | length"` -frontendDriverArray=`echo $frontendDriverJson | jq ".versions"` -echo "got frontend driver relations" - # get driver version version=`cat ../setup.py | grep -e 'version='` while IFS='"' read -ra ADDR; do @@ -34,84 +29,70 @@ then exit 1 fi coreFree=$(echo $coreFree | jq .core | tr -d '"') -while [ $i -lt $frontendDriverLength ]; do - frontendDriverVersion=`echo $frontendDriverArray | jq ".[$i]"` - frontendDriverVersion=`echo $frontendDriverVersion | tr -d '"'` - i=$((i+1)) - - if [[ $frontendDriverVersion == '1.0' ]]; then - continue - fi - frontendVersionXY=`curl -s -X GET \ - "https://api.supertokens.io/0/frontend-driver-interface/dependency/frontend/latest?password=$SUPERTOKENS_API_KEY&frontendName=website&mode=DEV&version=$frontendDriverVersion&driverName=python" \ - -H 'api-version: 1'` - if [[ `echo $frontendVersionXY | jq .frontend` == "null" ]] - then - echo "fetching latest X.Y version for frontend given frontend-driver-interface X.Y version: $frontendDriverVersion, name: webiste gave response: $frontend. Please make sure all relevant versions have been pushed." - exit 1 - fi - frontendVersionXY=$(echo $frontendVersionXY | jq .frontend | tr -d '"') +frontendDriverVersion=$1 +frontendDriverVersion=`echo $frontendDriverVersion | tr -d '"'` - frontendInfo=`curl -s -X GET \ - "https://api.supertokens.io/0/driver/latest?password=$SUPERTOKENS_API_KEY&mode=DEV&version=$frontendVersionXY&name=website" \ - -H 'api-version: 0'` - if [[ `echo $frontendInfo | jq .tag` == "null" ]] - then - echo "fetching latest X.Y.Z version for frontend, X.Y version: $frontendVersionXY gave response: $frontendInfo" - exit 1 - fi - frontendTag=$(echo $frontendInfo | jq .tag | tr -d '"') - frontendVersion=$(echo $frontendInfo | jq .version | tr -d '"') +frontendVersionXY=`curl -s -X GET \ +"https://api.supertokens.io/0/frontend-driver-interface/dependency/frontend/latest?password=$SUPERTOKENS_API_KEY&frontendName=website&mode=DEV&version=$frontendDriverVersion&driverName=node" \ +-H 'api-version: 1'` +if [[ `echo $frontendVersionXY | jq .frontend` == "null" ]] +then + echo "fetching latest X.Y version for frontend given frontend-driver-interface X.Y version: $frontendDriverVersion, name: website gave response: $frontend. Please make sure all relevant versions have been pushed." + exit 1 +fi +frontendVersionXY=$(echo $frontendVersionXY | jq .frontend | tr -d '"') - nodeVersionXY=`curl -s -X GET \ - "https://api.supertokens.io/0/frontend-driver-interface/dependency/driver/latest?password=$SUPERTOKENS_API_KEY&mode=DEV&version=$frontendDriverVersion&driverName=node&frontendName=website" \ - -H 'api-version: 1'` - if [[ `echo $nodeVersionXY | jq .driver` == "null" ]] - then - echo "fetching latest X.Y version for driver given frontend-driver-interface X.Y version: $frontendDriverVersion gave response: $nodeVersionXY. Please make sure all relevant drivers have been pushed." - exit 1 - fi - nodeVersionXY=$(echo $nodeVersionXY | jq .driver | tr -d '"') +frontendInfo=`curl -s -X GET \ +"https://api.supertokens.io/0/frontend/latest?password=$SUPERTOKENS_API_KEY&mode=DEV&version=$frontendVersionXY&name=website" \ +-H 'api-version: 0'` +if [[ `echo $frontendInfo | jq .tag` == "null" ]] +then + echo "fetching latest X.Y.Z version for frontend, X.Y version: $frontendVersionXY gave response: $frontendInfo" + exit 1 +fi +frontendTag=$(echo $frontendInfo | jq .tag | tr -d '"') +frontendVersion=$(echo $frontendInfo | jq .version | tr -d '"') - nodeInfo=`curl -s -X GET \ - "https://api.supertokens.io/0/driver/latest?password=$SUPERTOKENS_API_KEY&mode=DEV&version=$nodeVersionXY&name=node" \ - -H 'api-version: 0'` - if [[ `echo $nodeInfo | jq .tag` == "null" ]] - then - echo "fetching latest X.Y.Z version for driver, X.Y version: $nodeVersionXY gave response: $nodeInfo" - exit 1 - fi - nodeTag=$(echo $nodeInfo | jq .tag | tr -d '"') +nodeVersionXY=`curl -s -X GET \ +"https://api.supertokens.io/0/frontend-driver-interface/dependency/driver/latest?password=$SUPERTOKENS_API_KEY&mode=DEV&version=$frontendDriverVersion&driverName=node&frontendName=website" \ +-H 'api-version: 1'` +if [[ `echo $nodeVersionXY | jq .driver` == "null" ]] +then + echo "fetching latest X.Y version for driver given frontend-driver-interface X.Y version: $frontendDriverVersion gave response: $nodeVersionXY. Please make sure all relevant drivers have been pushed." + exit 1 +fi +nodeVersionXY=$(echo $nodeVersionXY | jq .driver | tr -d '"') - someFrontendTestsRan=true +nodeInfo=`curl -s -X GET \ +"https://api.supertokens.io/0/driver/latest?password=$SUPERTOKENS_API_KEY&mode=DEV&version=$nodeVersionXY&name=node" \ +-H 'api-version: 0'` +if [[ `echo $nodeInfo | jq .tag` == "null" ]] +then + echo "fetching latest X.Y.Z version for driver, X.Y version: $nodeVersionXY gave response: $nodeInfo" + exit 1 +fi +nodeTag=$(echo $nodeInfo | jq .tag | tr -d '"') - tries=1 - while [ $tries -le 3 ] - do - tries=$(( $tries + 1 )) - ./setupAndTestWithFrontendWithDjango.sh $coreFree $frontendTag $nodeTag - if [[ $? -ne 0 ]] +tries=1 +while [ $tries -le 3 ] +do + tries=$(( $tries + 1 )) + ./setupAndTestWithFrontendWithDjango.sh $coreFree $frontendTag $nodeTag + if [[ $? -ne 0 ]] + then + if [[ $tries -le 3 ]] then - if [[ $tries -le 3 ]] - then - rm -rf ../../supertokens-root - rm -rf ../../supertokens-website - echo "failed test.. retrying!" - else - echo "test failed for website tests... exiting!" - exit 1 - fi - else rm -rf ../../supertokens-root rm -rf ../../supertokens-website - break + echo "failed test.. retrying!" + else + echo "test failed for website tests... exiting!" + exit 1 fi - done + else + rm -rf ../../supertokens-root + rm -rf ../../supertokens-website + break + fi done - -if [[ $someFrontendTestsRan = "false" ]] -then - echo "no tests ran... failing!" - exit 1 -fi \ No newline at end of file diff --git a/.circleci/websiteDjango2x.sh b/.circleci/websiteDjango2x.sh index 954c65ec..8ffd38a2 100755 --- a/.circleci/websiteDjango2x.sh +++ b/.circleci/websiteDjango2x.sh @@ -3,11 +3,6 @@ coreDriverLength=`echo $coreDriverJson | jq ".versions | length"` coreDriverArray=`echo $coreDriverJson | jq ".versions"` echo "got core driver relations" -frontendDriverJson=`cat ../frontendDriverInterfaceSupported.json` -frontendDriverLength=`echo $frontendDriverJson | jq ".versions | length"` -frontendDriverArray=`echo $frontendDriverJson | jq ".versions"` -echo "got frontend driver relations" - # get driver version version=`cat ../setup.py | grep -e 'version='` while IFS='"' read -ra ADDR; do @@ -34,84 +29,70 @@ then exit 1 fi coreFree=$(echo $coreFree | jq .core | tr -d '"') -while [ $i -lt $frontendDriverLength ]; do - frontendDriverVersion=`echo $frontendDriverArray | jq ".[$i]"` - frontendDriverVersion=`echo $frontendDriverVersion | tr -d '"'` - i=$((i+1)) - - if [[ $frontendDriverVersion == '1.0' ]]; then - continue - fi - frontendVersionXY=`curl -s -X GET \ - "https://api.supertokens.io/0/frontend-driver-interface/dependency/frontend/latest?password=$SUPERTOKENS_API_KEY&frontendName=website&mode=DEV&version=$frontendDriverVersion&driverName=python" \ - -H 'api-version: 1'` - if [[ `echo $frontendVersionXY | jq .frontend` == "null" ]] - then - echo "fetching latest X.Y version for frontend given frontend-driver-interface X.Y version: $frontendDriverVersion, name: webiste gave response: $frontend. Please make sure all relevant versions have been pushed." - exit 1 - fi - frontendVersionXY=$(echo $frontendVersionXY | jq .frontend | tr -d '"') +frontendDriverVersion=$1 +frontendDriverVersion=`echo $frontendDriverVersion | tr -d '"'` - frontendInfo=`curl -s -X GET \ - "https://api.supertokens.io/0/driver/latest?password=$SUPERTOKENS_API_KEY&mode=DEV&version=$frontendVersionXY&name=website" \ - -H 'api-version: 0'` - if [[ `echo $frontendInfo | jq .tag` == "null" ]] - then - echo "fetching latest X.Y.Z version for frontend, X.Y version: $frontendVersionXY gave response: $frontendInfo" - exit 1 - fi - frontendTag=$(echo $frontendInfo | jq .tag | tr -d '"') - frontendVersion=$(echo $frontendInfo | jq .version | tr -d '"') +frontendVersionXY=`curl -s -X GET \ +"https://api.supertokens.io/0/frontend-driver-interface/dependency/frontend/latest?password=$SUPERTOKENS_API_KEY&frontendName=website&mode=DEV&version=$frontendDriverVersion&driverName=node" \ +-H 'api-version: 1'` +if [[ `echo $frontendVersionXY | jq .frontend` == "null" ]] +then + echo "fetching latest X.Y version for frontend given frontend-driver-interface X.Y version: $frontendDriverVersion, name: website gave response: $frontend. Please make sure all relevant versions have been pushed." + exit 1 +fi +frontendVersionXY=$(echo $frontendVersionXY | jq .frontend | tr -d '"') - nodeVersionXY=`curl -s -X GET \ - "https://api.supertokens.io/0/frontend-driver-interface/dependency/driver/latest?password=$SUPERTOKENS_API_KEY&mode=DEV&version=$frontendDriverVersion&driverName=node&frontendName=website" \ - -H 'api-version: 1'` - if [[ `echo $nodeVersionXY | jq .driver` == "null" ]] - then - echo "fetching latest X.Y version for driver given frontend-driver-interface X.Y version: $frontendDriverVersion gave response: $nodeVersionXY. Please make sure all relevant drivers have been pushed." - exit 1 - fi - nodeVersionXY=$(echo $nodeVersionXY | jq .driver | tr -d '"') +frontendInfo=`curl -s -X GET \ +"https://api.supertokens.io/0/frontend/latest?password=$SUPERTOKENS_API_KEY&mode=DEV&version=$frontendVersionXY&name=website" \ +-H 'api-version: 0'` +if [[ `echo $frontendInfo | jq .tag` == "null" ]] +then + echo "fetching latest X.Y.Z version for frontend, X.Y version: $frontendVersionXY gave response: $frontendInfo" + exit 1 +fi +frontendTag=$(echo $frontendInfo | jq .tag | tr -d '"') +frontendVersion=$(echo $frontendInfo | jq .version | tr -d '"') - nodeInfo=`curl -s -X GET \ - "https://api.supertokens.io/0/driver/latest?password=$SUPERTOKENS_API_KEY&mode=DEV&version=$nodeVersionXY&name=node" \ - -H 'api-version: 0'` - if [[ `echo $nodeInfo | jq .tag` == "null" ]] - then - echo "fetching latest X.Y.Z version for driver, X.Y version: $nodeVersionXY gave response: $nodeInfo" - exit 1 - fi - nodeTag=$(echo $nodeInfo | jq .tag | tr -d '"') +nodeVersionXY=`curl -s -X GET \ +"https://api.supertokens.io/0/frontend-driver-interface/dependency/driver/latest?password=$SUPERTOKENS_API_KEY&mode=DEV&version=$frontendDriverVersion&driverName=node&frontendName=website" \ +-H 'api-version: 1'` +if [[ `echo $nodeVersionXY | jq .driver` == "null" ]] +then + echo "fetching latest X.Y version for driver given frontend-driver-interface X.Y version: $frontendDriverVersion gave response: $nodeVersionXY. Please make sure all relevant drivers have been pushed." + exit 1 +fi +nodeVersionXY=$(echo $nodeVersionXY | jq .driver | tr -d '"') - someFrontendTestsRan=true +nodeInfo=`curl -s -X GET \ +"https://api.supertokens.io/0/driver/latest?password=$SUPERTOKENS_API_KEY&mode=DEV&version=$nodeVersionXY&name=node" \ +-H 'api-version: 0'` +if [[ `echo $nodeInfo | jq .tag` == "null" ]] +then + echo "fetching latest X.Y.Z version for driver, X.Y version: $nodeVersionXY gave response: $nodeInfo" + exit 1 +fi +nodeTag=$(echo $nodeInfo | jq .tag | tr -d '"') - tries=1 - while [ $tries -le 3 ] - do - tries=$(( $tries + 1 )) - ./setupAndTestWithFrontendWithDjango2x.sh $coreFree $frontendTag $nodeTag - if [[ $? -ne 0 ]] +tries=1 +while [ $tries -le 3 ] +do + tries=$(( $tries + 1 )) + ./setupAndTestWithFrontendWithDjango2x.sh $coreFree $frontendTag $nodeTag + if [[ $? -ne 0 ]] + then + if [[ $tries -le 3 ]] then - if [[ $tries -le 3 ]] - then - rm -rf ../../supertokens-root - rm -rf ../../supertokens-website - echo "failed test.. retrying!" - else - echo "test failed for website tests... exiting!" - exit 1 - fi - else rm -rf ../../supertokens-root rm -rf ../../supertokens-website - break + echo "failed test.. retrying!" + else + echo "test failed for website tests... exiting!" + exit 1 fi - done + else + rm -rf ../../supertokens-root + rm -rf ../../supertokens-website + break + fi done - -if [[ $someFrontendTestsRan = "false" ]] -then - echo "no tests ran... failing!" - exit 1 -fi \ No newline at end of file diff --git a/.circleci/websiteDrfAsync.sh b/.circleci/websiteDrfAsync.sh index 88bd4164..84946124 100755 --- a/.circleci/websiteDrfAsync.sh +++ b/.circleci/websiteDrfAsync.sh @@ -3,11 +3,6 @@ coreDriverLength=`echo $coreDriverJson | jq ".versions | length"` coreDriverArray=`echo $coreDriverJson | jq ".versions"` echo "got core driver relations" -frontendDriverJson=`cat ../frontendDriverInterfaceSupported.json` -frontendDriverLength=`echo $frontendDriverJson | jq ".versions | length"` -frontendDriverArray=`echo $frontendDriverJson | jq ".versions"` -echo "got frontend driver relations" - # get driver version version=`cat ../setup.py | grep -e 'version='` while IFS='"' read -ra ADDR; do @@ -34,84 +29,70 @@ then exit 1 fi coreFree=$(echo $coreFree | jq .core | tr -d '"') -while [ $i -lt $frontendDriverLength ]; do - frontendDriverVersion=`echo $frontendDriverArray | jq ".[$i]"` - frontendDriverVersion=`echo $frontendDriverVersion | tr -d '"'` - i=$((i+1)) - - if [[ $frontendDriverVersion == '1.0' ]]; then - continue - fi - frontendVersionXY=`curl -s -X GET \ - "https://api.supertokens.io/0/frontend-driver-interface/dependency/frontend/latest?password=$SUPERTOKENS_API_KEY&frontendName=website&mode=DEV&version=$frontendDriverVersion&driverName=python" \ - -H 'api-version: 1'` - if [[ `echo $frontendVersionXY | jq .frontend` == "null" ]] - then - echo "fetching latest X.Y version for frontend given frontend-driver-interface X.Y version: $frontendDriverVersion, name: webiste gave response: $frontend. Please make sure all relevant versions have been pushed." - exit 1 - fi - frontendVersionXY=$(echo $frontendVersionXY | jq .frontend | tr -d '"') +frontendDriverVersion=$1 +frontendDriverVersion=`echo $frontendDriverVersion | tr -d '"'` - frontendInfo=`curl -s -X GET \ - "https://api.supertokens.io/0/driver/latest?password=$SUPERTOKENS_API_KEY&mode=DEV&version=$frontendVersionXY&name=website" \ - -H 'api-version: 0'` - if [[ `echo $frontendInfo | jq .tag` == "null" ]] - then - echo "fetching latest X.Y.Z version for frontend, X.Y version: $frontendVersionXY gave response: $frontendInfo" - exit 1 - fi - frontendTag=$(echo $frontendInfo | jq .tag | tr -d '"') - frontendVersion=$(echo $frontendInfo | jq .version | tr -d '"') +frontendVersionXY=`curl -s -X GET \ +"https://api.supertokens.io/0/frontend-driver-interface/dependency/frontend/latest?password=$SUPERTOKENS_API_KEY&frontendName=website&mode=DEV&version=$frontendDriverVersion&driverName=node" \ +-H 'api-version: 1'` +if [[ `echo $frontendVersionXY | jq .frontend` == "null" ]] +then + echo "fetching latest X.Y version for frontend given frontend-driver-interface X.Y version: $frontendDriverVersion, name: website gave response: $frontend. Please make sure all relevant versions have been pushed." + exit 1 +fi +frontendVersionXY=$(echo $frontendVersionXY | jq .frontend | tr -d '"') - nodeVersionXY=`curl -s -X GET \ - "https://api.supertokens.io/0/frontend-driver-interface/dependency/driver/latest?password=$SUPERTOKENS_API_KEY&mode=DEV&version=$frontendDriverVersion&driverName=node&frontendName=website" \ - -H 'api-version: 1'` - if [[ `echo $nodeVersionXY | jq .driver` == "null" ]] - then - echo "fetching latest X.Y version for driver given frontend-driver-interface X.Y version: $frontendDriverVersion gave response: $nodeVersionXY. Please make sure all relevant drivers have been pushed." - exit 1 - fi - nodeVersionXY=$(echo $nodeVersionXY | jq .driver | tr -d '"') +frontendInfo=`curl -s -X GET \ +"https://api.supertokens.io/0/frontend/latest?password=$SUPERTOKENS_API_KEY&mode=DEV&version=$frontendVersionXY&name=website" \ +-H 'api-version: 0'` +if [[ `echo $frontendInfo | jq .tag` == "null" ]] +then + echo "fetching latest X.Y.Z version for frontend, X.Y version: $frontendVersionXY gave response: $frontendInfo" + exit 1 +fi +frontendTag=$(echo $frontendInfo | jq .tag | tr -d '"') +frontendVersion=$(echo $frontendInfo | jq .version | tr -d '"') - nodeInfo=`curl -s -X GET \ - "https://api.supertokens.io/0/driver/latest?password=$SUPERTOKENS_API_KEY&mode=DEV&version=$nodeVersionXY&name=node" \ - -H 'api-version: 0'` - if [[ `echo $nodeInfo | jq .tag` == "null" ]] - then - echo "fetching latest X.Y.Z version for driver, X.Y version: $nodeVersionXY gave response: $nodeInfo" - exit 1 - fi - nodeTag=$(echo $nodeInfo | jq .tag | tr -d '"') +nodeVersionXY=`curl -s -X GET \ +"https://api.supertokens.io/0/frontend-driver-interface/dependency/driver/latest?password=$SUPERTOKENS_API_KEY&mode=DEV&version=$frontendDriverVersion&driverName=node&frontendName=website" \ +-H 'api-version: 1'` +if [[ `echo $nodeVersionXY | jq .driver` == "null" ]] +then + echo "fetching latest X.Y version for driver given frontend-driver-interface X.Y version: $frontendDriverVersion gave response: $nodeVersionXY. Please make sure all relevant drivers have been pushed." + exit 1 +fi +nodeVersionXY=$(echo $nodeVersionXY | jq .driver | tr -d '"') - someFrontendTestsRan=true +nodeInfo=`curl -s -X GET \ +"https://api.supertokens.io/0/driver/latest?password=$SUPERTOKENS_API_KEY&mode=DEV&version=$nodeVersionXY&name=node" \ +-H 'api-version: 0'` +if [[ `echo $nodeInfo | jq .tag` == "null" ]] +then + echo "fetching latest X.Y.Z version for driver, X.Y version: $nodeVersionXY gave response: $nodeInfo" + exit 1 +fi +nodeTag=$(echo $nodeInfo | jq .tag | tr -d '"') - tries=1 - while [ $tries -le 3 ] - do - tries=$(( $tries + 1 )) - ./setupAndTestWithFrontendWithDrfAsync.sh $coreFree $frontendTag $nodeTag - if [[ $? -ne 0 ]] +tries=1 +while [ $tries -le 3 ] +do + tries=$(( $tries + 1 )) + ./setupAndTestWithFrontendWithDrfAsync.sh $coreFree $frontendTag $nodeTag + if [[ $? -ne 0 ]] + then + if [[ $tries -le 3 ]] then - if [[ $tries -le 3 ]] - then - rm -rf ../../supertokens-root - rm -rf ../../supertokens-website - echo "failed test.. retrying!" - else - echo "test failed for website tests... exiting!" - exit 1 - fi - else rm -rf ../../supertokens-root rm -rf ../../supertokens-website - break + echo "failed test.. retrying!" + else + echo "test failed for website tests... exiting!" + exit 1 fi - done + else + rm -rf ../../supertokens-root + rm -rf ../../supertokens-website + break + fi done - -if [[ $someFrontendTestsRan = "false" ]] -then - echo "no tests ran... failing!" - exit 1 -fi \ No newline at end of file diff --git a/.circleci/websiteDrfSync.sh b/.circleci/websiteDrfSync.sh index fb54193d..bff46ded 100755 --- a/.circleci/websiteDrfSync.sh +++ b/.circleci/websiteDrfSync.sh @@ -3,11 +3,6 @@ coreDriverLength=`echo $coreDriverJson | jq ".versions | length"` coreDriverArray=`echo $coreDriverJson | jq ".versions"` echo "got core driver relations" -frontendDriverJson=`cat ../frontendDriverInterfaceSupported.json` -frontendDriverLength=`echo $frontendDriverJson | jq ".versions | length"` -frontendDriverArray=`echo $frontendDriverJson | jq ".versions"` -echo "got frontend driver relations" - # get driver version version=`cat ../setup.py | grep -e 'version='` while IFS='"' read -ra ADDR; do @@ -34,84 +29,70 @@ then exit 1 fi coreFree=$(echo $coreFree | jq .core | tr -d '"') -while [ $i -lt $frontendDriverLength ]; do - frontendDriverVersion=`echo $frontendDriverArray | jq ".[$i]"` - frontendDriverVersion=`echo $frontendDriverVersion | tr -d '"'` - i=$((i+1)) - - if [[ $frontendDriverVersion == '1.0' ]]; then - continue - fi - frontendVersionXY=`curl -s -X GET \ - "https://api.supertokens.io/0/frontend-driver-interface/dependency/frontend/latest?password=$SUPERTOKENS_API_KEY&frontendName=website&mode=DEV&version=$frontendDriverVersion&driverName=python" \ - -H 'api-version: 1'` - if [[ `echo $frontendVersionXY | jq .frontend` == "null" ]] - then - echo "fetching latest X.Y version for frontend given frontend-driver-interface X.Y version: $frontendDriverVersion, name: webiste gave response: $frontend. Please make sure all relevant versions have been pushed." - exit 1 - fi - frontendVersionXY=$(echo $frontendVersionXY | jq .frontend | tr -d '"') +frontendDriverVersion=$1 +frontendDriverVersion=`echo $frontendDriverVersion | tr -d '"'` - frontendInfo=`curl -s -X GET \ - "https://api.supertokens.io/0/driver/latest?password=$SUPERTOKENS_API_KEY&mode=DEV&version=$frontendVersionXY&name=website" \ - -H 'api-version: 0'` - if [[ `echo $frontendInfo | jq .tag` == "null" ]] - then - echo "fetching latest X.Y.Z version for frontend, X.Y version: $frontendVersionXY gave response: $frontendInfo" - exit 1 - fi - frontendTag=$(echo $frontendInfo | jq .tag | tr -d '"') - frontendVersion=$(echo $frontendInfo | jq .version | tr -d '"') +frontendVersionXY=`curl -s -X GET \ +"https://api.supertokens.io/0/frontend-driver-interface/dependency/frontend/latest?password=$SUPERTOKENS_API_KEY&frontendName=website&mode=DEV&version=$frontendDriverVersion&driverName=node" \ +-H 'api-version: 1'` +if [[ `echo $frontendVersionXY | jq .frontend` == "null" ]] +then + echo "fetching latest X.Y version for frontend given frontend-driver-interface X.Y version: $frontendDriverVersion, name: website gave response: $frontend. Please make sure all relevant versions have been pushed." + exit 1 +fi +frontendVersionXY=$(echo $frontendVersionXY | jq .frontend | tr -d '"') - nodeVersionXY=`curl -s -X GET \ - "https://api.supertokens.io/0/frontend-driver-interface/dependency/driver/latest?password=$SUPERTOKENS_API_KEY&mode=DEV&version=$frontendDriverVersion&driverName=node&frontendName=website" \ - -H 'api-version: 1'` - if [[ `echo $nodeVersionXY | jq .driver` == "null" ]] - then - echo "fetching latest X.Y version for driver given frontend-driver-interface X.Y version: $frontendDriverVersion gave response: $nodeVersionXY. Please make sure all relevant drivers have been pushed." - exit 1 - fi - nodeVersionXY=$(echo $nodeVersionXY | jq .driver | tr -d '"') +frontendInfo=`curl -s -X GET \ +"https://api.supertokens.io/0/frontend/latest?password=$SUPERTOKENS_API_KEY&mode=DEV&version=$frontendVersionXY&name=website" \ +-H 'api-version: 0'` +if [[ `echo $frontendInfo | jq .tag` == "null" ]] +then + echo "fetching latest X.Y.Z version for frontend, X.Y version: $frontendVersionXY gave response: $frontendInfo" + exit 1 +fi +frontendTag=$(echo $frontendInfo | jq .tag | tr -d '"') +frontendVersion=$(echo $frontendInfo | jq .version | tr -d '"') - nodeInfo=`curl -s -X GET \ - "https://api.supertokens.io/0/driver/latest?password=$SUPERTOKENS_API_KEY&mode=DEV&version=$nodeVersionXY&name=node" \ - -H 'api-version: 0'` - if [[ `echo $nodeInfo | jq .tag` == "null" ]] - then - echo "fetching latest X.Y.Z version for driver, X.Y version: $nodeVersionXY gave response: $nodeInfo" - exit 1 - fi - nodeTag=$(echo $nodeInfo | jq .tag | tr -d '"') +nodeVersionXY=`curl -s -X GET \ +"https://api.supertokens.io/0/frontend-driver-interface/dependency/driver/latest?password=$SUPERTOKENS_API_KEY&mode=DEV&version=$frontendDriverVersion&driverName=node&frontendName=website" \ +-H 'api-version: 1'` +if [[ `echo $nodeVersionXY | jq .driver` == "null" ]] +then + echo "fetching latest X.Y version for driver given frontend-driver-interface X.Y version: $frontendDriverVersion gave response: $nodeVersionXY. Please make sure all relevant drivers have been pushed." + exit 1 +fi +nodeVersionXY=$(echo $nodeVersionXY | jq .driver | tr -d '"') - someFrontendTestsRan=true +nodeInfo=`curl -s -X GET \ +"https://api.supertokens.io/0/driver/latest?password=$SUPERTOKENS_API_KEY&mode=DEV&version=$nodeVersionXY&name=node" \ +-H 'api-version: 0'` +if [[ `echo $nodeInfo | jq .tag` == "null" ]] +then + echo "fetching latest X.Y.Z version for driver, X.Y version: $nodeVersionXY gave response: $nodeInfo" + exit 1 +fi +nodeTag=$(echo $nodeInfo | jq .tag | tr -d '"') - tries=1 - while [ $tries -le 3 ] - do - tries=$(( $tries + 1 )) - ./setupAndTestWithFrontendWithDrfSync.sh $coreFree $frontendTag $nodeTag - if [[ $? -ne 0 ]] +tries=1 +while [ $tries -le 3 ] +do + tries=$(( $tries + 1 )) + ./setupAndTestWithFrontendWithDrfSync.sh $coreFree $frontendTag $nodeTag + if [[ $? -ne 0 ]] + then + if [[ $tries -le 3 ]] then - if [[ $tries -le 3 ]] - then - rm -rf ../../supertokens-root - rm -rf ../../supertokens-website - echo "failed test.. retrying!" - else - echo "test failed for website tests... exiting!" - exit 1 - fi - else rm -rf ../../supertokens-root rm -rf ../../supertokens-website - break + echo "failed test.. retrying!" + else + echo "test failed for website tests... exiting!" + exit 1 fi - done + else + rm -rf ../../supertokens-root + rm -rf ../../supertokens-website + break + fi done - -if [[ $someFrontendTestsRan = "false" ]] -then - echo "no tests ran... failing!" - exit 1 -fi \ No newline at end of file diff --git a/.circleci/websiteFastApi.sh b/.circleci/websiteFastApi.sh index a3655715..f645fb95 100755 --- a/.circleci/websiteFastApi.sh +++ b/.circleci/websiteFastApi.sh @@ -3,11 +3,6 @@ coreDriverLength=`echo $coreDriverJson | jq ".versions | length"` coreDriverArray=`echo $coreDriverJson | jq ".versions"` echo "got core driver relations" -frontendDriverJson=`cat ../frontendDriverInterfaceSupported.json` -frontendDriverLength=`echo $frontendDriverJson | jq ".versions | length"` -frontendDriverArray=`echo $frontendDriverJson | jq ".versions"` -echo "got frontend driver relations" - # get driver version version=`cat ../setup.py | grep -e 'version='` while IFS='"' read -ra ADDR; do @@ -34,84 +29,71 @@ then exit 1 fi coreFree=$(echo $coreFree | jq .core | tr -d '"') -while [ $i -lt $frontendDriverLength ]; do - frontendDriverVersion=`echo $frontendDriverArray | jq ".[$i]"` - frontendDriverVersion=`echo $frontendDriverVersion | tr -d '"'` - i=$((i+1)) - if [[ $frontendDriverVersion == '1.0' ]]; then - continue - fi - frontendVersionXY=`curl -s -X GET \ - "https://api.supertokens.io/0/frontend-driver-interface/dependency/frontend/latest?password=$SUPERTOKENS_API_KEY&frontendName=website&mode=DEV&version=$frontendDriverVersion&driverName=python" \ - -H 'api-version: 1'` - if [[ `echo $frontendVersionXY | jq .frontend` == "null" ]] - then - echo "fetching latest X.Y version for frontend given frontend-driver-interface X.Y version: $frontendDriverVersion, name: webiste gave response: $frontend. Please make sure all relevant versions have been pushed." - exit 1 - fi - frontendVersionXY=$(echo $frontendVersionXY | jq .frontend | tr -d '"') +frontendDriverVersion=$1 +frontendDriverVersion=`echo $frontendDriverVersion | tr -d '"'` - frontendInfo=`curl -s -X GET \ - "https://api.supertokens.io/0/driver/latest?password=$SUPERTOKENS_API_KEY&mode=DEV&version=$frontendVersionXY&name=website" \ - -H 'api-version: 0'` - if [[ `echo $frontendInfo | jq .tag` == "null" ]] - then - echo "fetching latest X.Y.Z version for frontend, X.Y version: $frontendVersionXY gave response: $frontendInfo" - exit 1 - fi - frontendTag=$(echo $frontendInfo | jq .tag | tr -d '"') - frontendVersion=$(echo $frontendInfo | jq .version | tr -d '"') +frontendVersionXY=`curl -s -X GET \ +"https://api.supertokens.io/0/frontend-driver-interface/dependency/frontend/latest?password=$SUPERTOKENS_API_KEY&frontendName=website&mode=DEV&version=$frontendDriverVersion&driverName=node" \ +-H 'api-version: 1'` +if [[ `echo $frontendVersionXY | jq .frontend` == "null" ]] +then + echo "fetching latest X.Y version for frontend given frontend-driver-interface X.Y version: $frontendDriverVersion, name: website gave response: $frontend. Please make sure all relevant versions have been pushed." + exit 1 +fi +frontendVersionXY=$(echo $frontendVersionXY | jq .frontend | tr -d '"') - nodeVersionXY=`curl -s -X GET \ - "https://api.supertokens.io/0/frontend-driver-interface/dependency/driver/latest?password=$SUPERTOKENS_API_KEY&mode=DEV&version=$frontendDriverVersion&driverName=node&frontendName=website" \ - -H 'api-version: 1'` - if [[ `echo $nodeVersionXY | jq .driver` == "null" ]] - then - echo "fetching latest X.Y version for driver given frontend-driver-interface X.Y version: $frontendDriverVersion gave response: $nodeVersionXY. Please make sure all relevant drivers have been pushed." - exit 1 - fi - nodeVersionXY=$(echo $nodeVersionXY | jq .driver | tr -d '"') +frontendInfo=`curl -s -X GET \ +"https://api.supertokens.io/0/frontend/latest?password=$SUPERTOKENS_API_KEY&mode=DEV&version=$frontendVersionXY&name=website" \ +-H 'api-version: 0'` +if [[ `echo $frontendInfo | jq .tag` == "null" ]] +then + echo "fetching latest X.Y.Z version for frontend, X.Y version: $frontendVersionXY gave response: $frontendInfo" + exit 1 +fi +frontendTag=$(echo $frontendInfo | jq .tag | tr -d '"') +frontendVersion=$(echo $frontendInfo | jq .version | tr -d '"') - nodeInfo=`curl -s -X GET \ - "https://api.supertokens.io/0/driver/latest?password=$SUPERTOKENS_API_KEY&mode=DEV&version=$nodeVersionXY&name=node" \ - -H 'api-version: 0'` - if [[ `echo $nodeInfo | jq .tag` == "null" ]] - then - echo "fetching latest X.Y.Z version for driver, X.Y version: $nodeVersionXY gave response: $nodeInfo" - exit 1 - fi - nodeTag=$(echo $nodeInfo | jq .tag | tr -d '"') +nodeVersionXY=`curl -s -X GET \ +"https://api.supertokens.io/0/frontend-driver-interface/dependency/driver/latest?password=$SUPERTOKENS_API_KEY&mode=DEV&version=$frontendDriverVersion&driverName=node&frontendName=website" \ +-H 'api-version: 1'` +if [[ `echo $nodeVersionXY | jq .driver` == "null" ]] +then + echo "fetching latest X.Y version for driver given frontend-driver-interface X.Y version: $frontendDriverVersion gave response: $nodeVersionXY. Please make sure all relevant drivers have been pushed." + exit 1 +fi +nodeVersionXY=$(echo $nodeVersionXY | jq .driver | tr -d '"') - someFrontendTestsRan=true +nodeInfo=`curl -s -X GET \ +"https://api.supertokens.io/0/driver/latest?password=$SUPERTOKENS_API_KEY&mode=DEV&version=$nodeVersionXY&name=node" \ +-H 'api-version: 0'` +if [[ `echo $nodeInfo | jq .tag` == "null" ]] +then + echo "fetching latest X.Y.Z version for driver, X.Y version: $nodeVersionXY gave response: $nodeInfo" + exit 1 +fi +nodeTag=$(echo $nodeInfo | jq .tag | tr -d '"') - tries=1 - while [ $tries -le 3 ] - do - tries=$(( $tries + 1 )) - ./setupAndTestWithFrontend.sh $coreFree $frontendTag $nodeTag - if [[ $? -ne 0 ]] +tries=1 +while [ $tries -le 3 ] +do + tries=$(( $tries + 1 )) + ./setupAndTestWithFrontend.sh $coreFree $frontendTag $nodeTag + if [[ $? -ne 0 ]] + then + if [[ $tries -le 3 ]] then - if [[ $tries -le 3 ]] - then - rm -rf ../../supertokens-root - rm -rf ../../supertokens-website - echo "failed test.. retrying!" - else - echo "test failed for website tests... exiting!" - exit 1 - fi - else rm -rf ../../supertokens-root rm -rf ../../supertokens-website - break + echo "failed test.. retrying!" + else + echo "test failed for website tests... exiting!" + exit 1 fi - done + else + rm -rf ../../supertokens-root + rm -rf ../../supertokens-website + break + fi done - -if [[ $someFrontendTestsRan = "false" ]] -then - echo "no tests ran... failing!" - exit 1 -fi \ No newline at end of file From eb8d22dd93f19a5123793a4f633a121fbef0900b Mon Sep 17 00:00:00 2001 From: Sattvik Chakravarthy Date: Tue, 5 Nov 2024 13:39:25 +0530 Subject: [PATCH 06/11] fix: auth react tests --- tests/auth-react/django3x/mysite/utils.py | 14 +++++++++----- tests/auth-react/fastapi-server/app.py | 12 +++++++++--- tests/auth-react/flask-server/app.py | 11 ++++++++--- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/tests/auth-react/django3x/mysite/utils.py b/tests/auth-react/django3x/mysite/utils.py index c3d03d50..d47a2843 100644 --- a/tests/auth-react/django3x/mysite/utils.py +++ b/tests/auth-react/django3x/mysite/utils.py @@ -986,11 +986,15 @@ async def should_do_automatic_account_linking( ) if mysite.store.enabled_recipes is not None: - recipe_list = [ - item["init"] - for item in recipe_list - if item["id"] in mysite.store.enabled_recipes - ] + new_recipe_list = [] + for item in recipe_list: + for recipe_id in mysite.store.enabled_recipes: + if item["id"] in recipe_id: + new_recipe_list.append(item["init"]) # type: ignore + break + + recipe_list = new_recipe_list + else: recipe_list = [item["init"] for item in recipe_list] diff --git a/tests/auth-react/fastapi-server/app.py b/tests/auth-react/fastapi-server/app.py index 9d686962..4a3b2f4b 100644 --- a/tests/auth-react/fastapi-server/app.py +++ b/tests/auth-react/fastapi-server/app.py @@ -1044,9 +1044,15 @@ async def should_do_automatic_account_linking( global enabled_recipes if enabled_recipes is not None: - recipe_list = [ - item["init"] for item in recipe_list if item["id"] in enabled_recipes - ] + new_recipe_list = [] + for item in recipe_list: + for recipe_id in enabled_recipes: + if item["id"] in recipe_id: + new_recipe_list.append(item["init"]) # type: ignore + break + + recipe_list = new_recipe_list + else: recipe_list = [item["init"] for item in recipe_list] diff --git a/tests/auth-react/flask-server/app.py b/tests/auth-react/flask-server/app.py index 3ee60c66..23f91dde 100644 --- a/tests/auth-react/flask-server/app.py +++ b/tests/auth-react/flask-server/app.py @@ -1050,9 +1050,14 @@ async def should_do_automatic_account_linking( global enabled_recipes if enabled_recipes is not None: - recipe_list = [ - item["init"] for item in recipe_list if item["id"] in enabled_recipes - ] + new_recipe_list = [] + for item in recipe_list: + for recipe_id in enabled_recipes: + if item["id"] in recipe_id: + new_recipe_list.append(item["init"]) # type: ignore + break + + recipe_list = new_recipe_list else: recipe_list = [item["init"] for item in recipe_list] From 3758212590d9f9b2bda7055c32acb0a74de75829 Mon Sep 17 00:00:00 2001 From: Sattvik Chakravarthy Date: Tue, 5 Nov 2024 17:33:33 +0530 Subject: [PATCH 07/11] fix: unit test --- tests/utils.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/tests/utils.py b/tests/utils.py index f7493d05..a7430c67 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -151,17 +151,21 @@ def start_st(host: str = "localhost", port: str = "3567"): def setup_multitenancy_feature(host: str = "localhost", port: str = "3567"): - OPAQUE_KEY_WITH_MULTITENANCY_FEATURE = "ijaleljUd2kU9XXWLiqFYv5br8nutTxbyBqWypQdv2N-BocoNriPrnYQd0NXPm8rVkeEocN9ayq0B7c3Pv-BTBIhAZSclXMlgyfXtlwAOJk=9BfESEleW6LyTov47dXu" + _ = host + _ = port + # inmemory core no longer requires license to function - import requests + # OPAQUE_KEY_WITH_MULTITENANCY_FEATURE = "ijaleljUd2kU9XXWLiqFYv5br8nutTxbyBqWypQdv2N-BocoNriPrnYQd0NXPm8rVkeEocN9ayq0B7c3Pv-BTBIhAZSclXMlgyfXtlwAOJk=9BfESEleW6LyTov47dXu" - requests.put( - f"http://{host}:{port}/ee/license", - json={ - "licenseKey": OPAQUE_KEY_WITH_MULTITENANCY_FEATURE, - }, - timeout=10, - ) + # import requests + + # requests.put( + # f"http://{host}:{port}/ee/license", + # json={ + # "licenseKey": OPAQUE_KEY_WITH_MULTITENANCY_FEATURE, + # }, + # timeout=10, + # ) def setup_st(): From 5bbcd03346ab7b40f2f9d972038c0cc14ac36cc1 Mon Sep 17 00:00:00 2001 From: Sattvik Chakravarthy Date: Tue, 5 Nov 2024 19:42:17 +0530 Subject: [PATCH 08/11] fix: tp json --- supertokens_python/types.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/supertokens_python/types.py b/supertokens_python/types.py index 4e9b8ecd..207a0507 100644 --- a/supertokens_python/types.py +++ b/supertokens_python/types.py @@ -212,7 +212,7 @@ def to_json(self) -> Dict[str, Any]: "tenantIds": self.tenant_ids, "emails": self.emails, "phoneNumbers": self.phone_numbers, - "thirdParty": self.third_party, + "thirdParty": [tp.to_json() for tp in self.third_party], "loginMethods": [lm.to_json() for lm in self.login_methods], "timeJoined": self.time_joined, } From 0c327b95e8852d909b68528c836235983a044252 Mon Sep 17 00:00:00 2001 From: Sattvik Chakravarthy Date: Tue, 5 Nov 2024 22:03:52 +0530 Subject: [PATCH 09/11] fix: tp json --- supertokens_python/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/supertokens_python/utils.py b/supertokens_python/utils.py index b199e55a..fcd78906 100644 --- a/supertokens_python/utils.py +++ b/supertokens_python/utils.py @@ -341,7 +341,7 @@ def get_backwards_compatible_user_info( "timeJoined": login_method.time_joined, } if login_method.third_party: - user_obj["thirdParty"] = login_method.third_party + user_obj["thirdParty"] = login_method.third_party.to_json() if login_method.email: user_obj["email"] = login_method.email if login_method.phone_number: From 0ac99aa482f44b8bfd921a633fcaffe437ce9e00 Mon Sep 17 00:00:00 2001 From: Sattvik Chakravarthy Date: Wed, 6 Nov 2024 09:36:20 +0530 Subject: [PATCH 10/11] fix: tp json --- supertokens_python/recipe/thirdparty/types.py | 4 ++++ supertokens_python/types.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/supertokens_python/recipe/thirdparty/types.py b/supertokens_python/recipe/thirdparty/types.py index 3e8ec703..c1d1468d 100644 --- a/supertokens_python/recipe/thirdparty/types.py +++ b/supertokens_python/recipe/thirdparty/types.py @@ -36,6 +36,10 @@ def __eq__(self, other: object) -> bool: def to_json(self) -> Dict[str, Any]: return {"userId": self.user_id, "id": self.id} + @staticmethod + def from_json(json: Dict[str, Any]) -> "ThirdPartyInfo": + return ThirdPartyInfo(json["userId"], json["id"]) + class RawUserInfoFromProvider: def __init__( diff --git a/supertokens_python/types.py b/supertokens_python/types.py index 207a0507..c731f01b 100644 --- a/supertokens_python/types.py +++ b/supertokens_python/types.py @@ -225,7 +225,7 @@ def from_json(json: Dict[str, Any]) -> "User": tenant_ids=json["tenantIds"], emails=json["emails"], phone_numbers=json["phoneNumbers"], - third_party=json["thirdParty"], + third_party=[ThirdPartyInfo.from_json(tp) for tp in json["thirdParty"]], login_methods=[LoginMethod.from_json(lm) for lm in json["loginMethods"]], time_joined=json["timeJoined"], ) From c8bb398dae124714eb1f219b367220bb324d6be9 Mon Sep 17 00:00:00 2001 From: Sattvik Chakravarthy Date: Wed, 6 Nov 2024 10:46:14 +0530 Subject: [PATCH 11/11] fix: tp json --- supertokens_python/types.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/supertokens_python/types.py b/supertokens_python/types.py index c731f01b..2cf34204 100644 --- a/supertokens_python/types.py +++ b/supertokens_python/types.py @@ -219,13 +219,15 @@ def to_json(self) -> Dict[str, Any]: @staticmethod def from_json(json: Dict[str, Any]) -> "User": + from supertokens_python.recipe.thirdparty.types import ThirdPartyInfo as TPI + return User( user_id=json["id"], is_primary_user=json["isPrimaryUser"], tenant_ids=json["tenantIds"], emails=json["emails"], phone_numbers=json["phoneNumbers"], - third_party=[ThirdPartyInfo.from_json(tp) for tp in json["thirdParty"]], + third_party=[TPI.from_json(tp) for tp in json["thirdParty"]], login_methods=[LoginMethod.from_json(lm) for lm in json["loginMethods"]], time_joined=json["timeJoined"], )