From 3fab804bb283ea93c3b4e4c277f8f5bae59a9d19 Mon Sep 17 00:00:00 2001 From: Bhumil Date: Mon, 28 Nov 2022 18:47:19 +0530 Subject: [PATCH 1/2] passwordless interface changes for account linking --- .../recipe/passwordless/api/implementation.js | 11 +++- lib/build/recipe/passwordless/types.d.ts | 47 ++++++++++++++++ .../api/implementation.js | 6 +- .../api/passwordlessAPIImplementation.js | 6 +- .../recipe/thirdpartypasswordless/types.d.ts | 47 ++++++++++++++++ .../recipe/passwordless/api/implementation.ts | 9 ++- lib/ts/recipe/passwordless/types.ts | 55 ++++++++++++++++++- .../api/implementation.ts | 3 + .../api/passwordlessAPIImplementation.ts | 3 + lib/ts/recipe/thirdpartypasswordless/types.ts | 48 ++++++++++++++++ 10 files changed, 230 insertions(+), 5 deletions(-) diff --git a/lib/build/recipe/passwordless/api/implementation.js b/lib/build/recipe/passwordless/api/implementation.js index 22317eb05..75c95fa84 100644 --- a/lib/build/recipe/passwordless/api/implementation.js +++ b/lib/build/recipe/passwordless/api/implementation.js @@ -61,7 +61,7 @@ function getAPIImplementation() { if (emailVerificationInstance) { const tokenResponse = yield emailVerificationInstance.recipeInterfaceImpl.createEmailVerificationToken( { - userId: user.id, + userId: user.recipeUserId, email: user.email, userContext: input.userContext, } @@ -85,6 +85,7 @@ function getAPIImplementation() { return { status: "OK", createdNewUser: response.createdNewUser, + createdNewRecipeUser: false, user: response.user, session, }; @@ -287,6 +288,14 @@ function getAPIImplementation() { } }); }, + linkAccountToExistingAccountPOST: function (_input) { + return __awaiter(this, void 0, void 0, function* () { + return { + status: "ACCOUNT_LINKING_NOT_ALLOWED_ERROR", + description: "", + }; + }); + }, }; } exports.default = getAPIImplementation; diff --git a/lib/build/recipe/passwordless/types.d.ts b/lib/build/recipe/passwordless/types.d.ts index ec6af87a7..b4db114b5 100644 --- a/lib/build/recipe/passwordless/types.d.ts +++ b/lib/build/recipe/passwordless/types.d.ts @@ -311,6 +311,7 @@ export declare type APIInterface = { | { status: "OK"; createdNewUser: boolean; + createdNewRecipeUser: boolean; user: User; session: SessionContainerInterface; } @@ -323,7 +324,53 @@ export declare type APIInterface = { | { status: "RESTART_FLOW_ERROR"; } + | { + status: "SIGNUP_NOT_ALLOWED"; + reason: string; + } >; + linkAccountToExistingAccountPOST: + | undefined + | (( + input: ( + | { + userInputCode: string; + deviceId: string; + preAuthSessionId: string; + } + | { + linkCode: string; + preAuthSessionId: string; + } + ) & { + session: SessionContainerInterface; + options: APIOptions; + userContext: any; + } + ) => Promise< + | { + status: "OK"; + user: User; + createdNewRecipeUser: boolean; + session: SessionContainerInterface; + wereAccountsAlreadyLinked: boolean; + } + | { + status: "RECIPE_USER_ID_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"; + primaryUserId: string; + description: string; + } + | { + status: "ACCOUNT_INFO_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"; + primaryUserId: string; + description: string; + } + | { + status: "ACCOUNT_LINKING_NOT_ALLOWED_ERROR"; + description: string; + } + | GeneralErrorResponse + >); emailExistsGET?: (input: { email: string; options: APIOptions; diff --git a/lib/build/recipe/thirdpartypasswordless/api/implementation.js b/lib/build/recipe/thirdpartypasswordless/api/implementation.js index 1aa40b32f..5e16c51f5 100644 --- a/lib/build/recipe/thirdpartypasswordless/api/implementation.js +++ b/lib/build/recipe/thirdpartypasswordless/api/implementation.js @@ -5,7 +5,7 @@ const implementation_2 = require("../../thirdparty/api/implementation"); const passwordlessAPIImplementation_1 = require("./passwordlessAPIImplementation"); const thirdPartyAPIImplementation_1 = require("./thirdPartyAPIImplementation"); function getAPIImplementation() { - var _a, _b, _c, _d, _e, _f, _g, _h, _j; + var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k; let passwordlessImplementation = implementation_1.default(); let thirdPartyImplementation = implementation_2.default(); return { @@ -45,6 +45,10 @@ function getAPIImplementation() { (_j = thirdPartyImplementation.appleRedirectHandlerPOST) === null || _j === void 0 ? void 0 : _j.bind(thirdPartyAPIImplementation_1.default(this)), + linkPasswordlessAccountToExistingAccountPOST: + (_k = passwordlessImplementation.linkAccountToExistingAccountPOST) === null || _k === void 0 + ? void 0 + : _k.bind(passwordlessAPIImplementation_1.default(this)), }; } exports.default = getAPIImplementation; diff --git a/lib/build/recipe/thirdpartypasswordless/api/passwordlessAPIImplementation.js b/lib/build/recipe/thirdpartypasswordless/api/passwordlessAPIImplementation.js index 25e56c8b2..321f35dd6 100644 --- a/lib/build/recipe/thirdpartypasswordless/api/passwordlessAPIImplementation.js +++ b/lib/build/recipe/thirdpartypasswordless/api/passwordlessAPIImplementation.js @@ -1,7 +1,7 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); function getIterfaceImpl(apiImplmentation) { - var _a, _b, _c, _d, _e; + var _a, _b, _c, _d, _e, _f; return { emailExistsGET: (_a = apiImplmentation.passwordlessUserEmailExistsGET) === null || _a === void 0 @@ -17,6 +17,10 @@ function getIterfaceImpl(apiImplmentation) { : _d.bind(apiImplmentation), resendCodePOST: (_e = apiImplmentation.resendCodePOST) === null || _e === void 0 ? void 0 : _e.bind(apiImplmentation), + linkAccountToExistingAccountPOST: + (_f = apiImplmentation.linkPasswordlessAccountToExistingAccountPOST) === null || _f === void 0 + ? void 0 + : _f.bind(apiImplmentation), }; } exports.default = getIterfaceImpl; diff --git a/lib/build/recipe/thirdpartypasswordless/types.d.ts b/lib/build/recipe/thirdpartypasswordless/types.d.ts index 0663c5851..8506af1d0 100644 --- a/lib/build/recipe/thirdpartypasswordless/types.d.ts +++ b/lib/build/recipe/thirdpartypasswordless/types.d.ts @@ -426,6 +426,7 @@ export declare type APIInterface = { | { status: "OK"; createdNewUser: boolean; + createdNewRecipeUser: boolean; user: User; session: SessionContainerInterface; } @@ -438,6 +439,10 @@ export declare type APIInterface = { | { status: "RESTART_FLOW_ERROR"; } + | { + status: "SIGNUP_NOT_ALLOWED"; + reason: string; + } >); passwordlessUserEmailExistsGET: | undefined @@ -465,6 +470,48 @@ export declare type APIInterface = { } | GeneralErrorResponse >); + linkPasswordlessAccountToExistingAccountPOST: + | undefined + | (( + input: ( + | { + userInputCode: string; + deviceId: string; + preAuthSessionId: string; + } + | { + linkCode: string; + preAuthSessionId: string; + } + ) & { + session: SessionContainerInterface; + options: PasswordlessAPIOptions; + userContext: any; + } + ) => Promise< + | { + status: "OK"; + user: User; + createdNewRecipeUser: boolean; + session: SessionContainerInterface; + wereAccountsAlreadyLinked: boolean; + } + | { + status: "RECIPE_USER_ID_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"; + primaryUserId: string; + description: string; + } + | { + status: "ACCOUNT_INFO_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"; + primaryUserId: string; + description: string; + } + | { + status: "ACCOUNT_LINKING_NOT_ALLOWED_ERROR"; + description: string; + } + | GeneralErrorResponse + >); }; export declare type TypeThirdPartyPasswordlessEmailDeliveryInput = TypePasswordlessEmailDeliveryInput; export declare type TypeThirdPartyPasswordlessSmsDeliveryInput = TypePasswordlessSmsDeliveryInput; diff --git a/lib/ts/recipe/passwordless/api/implementation.ts b/lib/ts/recipe/passwordless/api/implementation.ts index 58c5d6363..9a6344dc0 100644 --- a/lib/ts/recipe/passwordless/api/implementation.ts +++ b/lib/ts/recipe/passwordless/api/implementation.ts @@ -32,7 +32,7 @@ export default function getAPIImplementation(): APIInterface { if (emailVerificationInstance) { const tokenResponse = await emailVerificationInstance.recipeInterfaceImpl.createEmailVerificationToken( { - userId: user.id, + userId: user.recipeUserId, email: user.email, userContext: input.userContext, } @@ -59,6 +59,7 @@ export default function getAPIImplementation(): APIInterface { return { status: "OK", createdNewUser: response.createdNewUser, + createdNewRecipeUser: false, // TODO user: response.user, session, }; @@ -264,5 +265,11 @@ export default function getAPIImplementation(): APIInterface { }; } }, + linkAccountToExistingAccountPOST: async function (_input) { + return { + status: "ACCOUNT_LINKING_NOT_ALLOWED_ERROR", + description: "", + }; + }, }; } diff --git a/lib/ts/recipe/passwordless/types.ts b/lib/ts/recipe/passwordless/types.ts index cbae22ff3..9bfbd0c6d 100644 --- a/lib/ts/recipe/passwordless/types.ts +++ b/lib/ts/recipe/passwordless/types.ts @@ -249,7 +249,7 @@ export type RecipeInterface = { getUserByPhoneNumber: (input: { phoneNumber: string; userContext: any }) => Promise; updateUser: (input: { - userId: string; + userId: string; // the id can be either recipeUserId or primaryUserId email?: string | null; phoneNumber?: string | null; userContext: any; @@ -359,6 +359,7 @@ export type APIInterface = { | { status: "OK"; createdNewUser: boolean; + createdNewRecipeUser: boolean; user: User; session: SessionContainerInterface; } @@ -369,8 +370,60 @@ export type APIInterface = { } | GeneralErrorResponse | { status: "RESTART_FLOW_ERROR" } + | { + status: "SIGNUP_NOT_ALLOWED"; + reason: string; + } >; + linkAccountToExistingAccountPOST: + | undefined + | (( + input: ( + | { + userInputCode: string; + deviceId: string; + preAuthSessionId: string; + } + | { + linkCode: string; + preAuthSessionId: string; + } + ) & { + session: SessionContainerInterface; + options: APIOptions; + userContext: any; + } + ) => Promise< + | { + status: "OK"; + user: User; + createdNewRecipeUser: boolean; + session: SessionContainerInterface; + wereAccountsAlreadyLinked: boolean; + } + | { + status: "RECIPE_USER_ID_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"; + primaryUserId: string; + description: string; + } + | { + status: "ACCOUNT_INFO_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"; + primaryUserId: string; + description: string; + } + | { + status: "ACCOUNT_LINKING_NOT_ALLOWED_ERROR"; + description: string; + } + // | { + // status: "ACCOUNT_NOT_VERIFIED_ERROR"; This error is not possible + // isNotVerifiedAccountFromInputSession: boolean; + // description: string; + // } + | GeneralErrorResponse + >); + emailExistsGET?: (input: { email: string; options: APIOptions; diff --git a/lib/ts/recipe/thirdpartypasswordless/api/implementation.ts b/lib/ts/recipe/thirdpartypasswordless/api/implementation.ts index 8fba76f81..82915088b 100644 --- a/lib/ts/recipe/thirdpartypasswordless/api/implementation.ts +++ b/lib/ts/recipe/thirdpartypasswordless/api/implementation.ts @@ -21,5 +21,8 @@ export default function getAPIImplementation(): APIInterface { authorisationUrlGET: thirdPartyImplementation.authorisationUrlGET?.bind(DerivedTP(this)), thirdPartySignInUpPOST: thirdPartyImplementation.signInUpPOST?.bind(DerivedTP(this)), appleRedirectHandlerPOST: thirdPartyImplementation.appleRedirectHandlerPOST?.bind(DerivedTP(this)), + linkPasswordlessAccountToExistingAccountPOST: passwordlessImplementation.linkAccountToExistingAccountPOST?.bind( + DerivedPwdless(this) + ), }; } diff --git a/lib/ts/recipe/thirdpartypasswordless/api/passwordlessAPIImplementation.ts b/lib/ts/recipe/thirdpartypasswordless/api/passwordlessAPIImplementation.ts index 0e4c79a32..568aa322b 100644 --- a/lib/ts/recipe/thirdpartypasswordless/api/passwordlessAPIImplementation.ts +++ b/lib/ts/recipe/thirdpartypasswordless/api/passwordlessAPIImplementation.ts @@ -8,5 +8,8 @@ export default function getIterfaceImpl(apiImplmentation: ThirdPartyPasswordless createCodePOST: apiImplmentation.createCodePOST?.bind(apiImplmentation), phoneNumberExistsGET: apiImplmentation.passwordlessUserPhoneNumberExistsGET?.bind(apiImplmentation), resendCodePOST: apiImplmentation.resendCodePOST?.bind(apiImplmentation), + linkAccountToExistingAccountPOST: apiImplmentation.linkPasswordlessAccountToExistingAccountPOST?.bind( + apiImplmentation + ), }; } diff --git a/lib/ts/recipe/thirdpartypasswordless/types.ts b/lib/ts/recipe/thirdpartypasswordless/types.ts index 80b40bc2b..22a9d3553 100644 --- a/lib/ts/recipe/thirdpartypasswordless/types.ts +++ b/lib/ts/recipe/thirdpartypasswordless/types.ts @@ -472,6 +472,7 @@ export type APIInterface = { | { status: "OK"; createdNewUser: boolean; + createdNewRecipeUser: boolean; user: User; session: SessionContainerInterface; } @@ -482,6 +483,10 @@ export type APIInterface = { } | GeneralErrorResponse | { status: "RESTART_FLOW_ERROR" } + | { + status: "SIGNUP_NOT_ALLOWED"; + reason: string; + } >); passwordlessUserEmailExistsGET: @@ -511,6 +516,49 @@ export type APIInterface = { } | GeneralErrorResponse >); + + linkPasswordlessAccountToExistingAccountPOST: + | undefined + | (( + input: ( + | { + userInputCode: string; + deviceId: string; + preAuthSessionId: string; + } + | { + linkCode: string; + preAuthSessionId: string; + } + ) & { + session: SessionContainerInterface; + options: PasswordlessAPIOptions; + userContext: any; + } + ) => Promise< + | { + status: "OK"; + user: User; + createdNewRecipeUser: boolean; + session: SessionContainerInterface; + wereAccountsAlreadyLinked: boolean; + } + | { + status: "RECIPE_USER_ID_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"; + primaryUserId: string; + description: string; + } + | { + status: "ACCOUNT_INFO_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"; + primaryUserId: string; + description: string; + } + | { + status: "ACCOUNT_LINKING_NOT_ALLOWED_ERROR"; + description: string; + } + | GeneralErrorResponse + >); }; export type TypeThirdPartyPasswordlessEmailDeliveryInput = TypePasswordlessEmailDeliveryInput; From 6eba04ff755fce7292b187ca6c88aee651af1c80 Mon Sep 17 00:00:00 2001 From: Bhumil Date: Mon, 28 Nov 2022 18:58:03 +0530 Subject: [PATCH 2/2] code review changes --- lib/build/recipe/passwordless/types.d.ts | 5 +++++ lib/build/recipe/thirdpartypasswordless/types.d.ts | 5 +++++ lib/ts/recipe/passwordless/types.ts | 10 +++++----- lib/ts/recipe/thirdpartypasswordless/types.ts | 5 +++++ 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/lib/build/recipe/passwordless/types.d.ts b/lib/build/recipe/passwordless/types.d.ts index b4db114b5..755f79c85 100644 --- a/lib/build/recipe/passwordless/types.d.ts +++ b/lib/build/recipe/passwordless/types.d.ts @@ -369,6 +369,11 @@ export declare type APIInterface = { status: "ACCOUNT_LINKING_NOT_ALLOWED_ERROR"; description: string; } + | { + status: "ACCOUNT_NOT_VERIFIED_ERROR"; + isNotVerifiedAccountFromInputSession: boolean; + description: string; + } | GeneralErrorResponse >); emailExistsGET?: (input: { diff --git a/lib/build/recipe/thirdpartypasswordless/types.d.ts b/lib/build/recipe/thirdpartypasswordless/types.d.ts index 8506af1d0..41a5140d4 100644 --- a/lib/build/recipe/thirdpartypasswordless/types.d.ts +++ b/lib/build/recipe/thirdpartypasswordless/types.d.ts @@ -510,6 +510,11 @@ export declare type APIInterface = { status: "ACCOUNT_LINKING_NOT_ALLOWED_ERROR"; description: string; } + | { + status: "ACCOUNT_NOT_VERIFIED_ERROR"; + isNotVerifiedAccountFromInputSession: boolean; + description: string; + } | GeneralErrorResponse >); }; diff --git a/lib/ts/recipe/passwordless/types.ts b/lib/ts/recipe/passwordless/types.ts index 9bfbd0c6d..bfa43dc69 100644 --- a/lib/ts/recipe/passwordless/types.ts +++ b/lib/ts/recipe/passwordless/types.ts @@ -416,11 +416,11 @@ export type APIInterface = { status: "ACCOUNT_LINKING_NOT_ALLOWED_ERROR"; description: string; } - // | { - // status: "ACCOUNT_NOT_VERIFIED_ERROR"; This error is not possible - // isNotVerifiedAccountFromInputSession: boolean; - // description: string; - // } + | { + status: "ACCOUNT_NOT_VERIFIED_ERROR"; + isNotVerifiedAccountFromInputSession: boolean; + description: string; + } | GeneralErrorResponse >); diff --git a/lib/ts/recipe/thirdpartypasswordless/types.ts b/lib/ts/recipe/thirdpartypasswordless/types.ts index 22a9d3553..5d76974cf 100644 --- a/lib/ts/recipe/thirdpartypasswordless/types.ts +++ b/lib/ts/recipe/thirdpartypasswordless/types.ts @@ -557,6 +557,11 @@ export type APIInterface = { status: "ACCOUNT_LINKING_NOT_ALLOWED_ERROR"; description: string; } + | { + status: "ACCOUNT_NOT_VERIFIED_ERROR"; + isNotVerifiedAccountFromInputSession: boolean; + description: string; + } | GeneralErrorResponse >); };