diff --git a/lib/build/index2.js b/lib/build/index2.js index 5d7e04946..d7f1150c5 100644 --- a/lib/build/index2.js +++ b/lib/build/index2.js @@ -379,9 +379,11 @@ var priorityOrder = [ }, { rid: "thirdparty", includes: ["thirdparty"], factorsProvided: ["thirdparty"] }, ]; -function chooseComponentBasedOnFirstFactors(firstFactors, routeComponents) { +function chooseComponentBasedOnFirstFactors(firstFactors, routeComponents, allowSubRecipeComp) { var fallbackRid; var fallbackComponent; + var subRecipeRid; + var subRecipeComponent; var _loop_1 = function (rid, factorsProvided) { if ( firstFactors.every(function (factor) { @@ -392,8 +394,6 @@ function chooseComponentBasedOnFirstFactors(firstFactors, routeComponents) { return comp.recipeID === rid; }); if (matchingComp) { - // This means that this gets overwritten by items lower in the prios list. - // This is intentional since this way we end up with the most specific recipe that covers all required factrors (pwless instead of tppwless) fallbackRid = rid; fallbackComponent = matchingComp; if (firstFactors.length === factorsProvided.length) { @@ -403,6 +403,19 @@ function chooseComponentBasedOnFirstFactors(firstFactors, routeComponents) { return { value: matchingComp }; } } + } else if ( + allowSubRecipeComp && + factorsProvided.some(function (factor) { + return firstFactors.includes(factor); + }) + ) { + var matchingComp = routeComponents.find(function (comp) { + return comp.recipeID === rid; + }); + if (matchingComp) { + subRecipeRid = rid; + subRecipeComponent = matchingComp; + } } }; // We first try to find an exact match, and fall back on something that covers all factors (but maybe more) @@ -414,6 +427,14 @@ function chooseComponentBasedOnFirstFactors(firstFactors, routeComponents) { if (typeof state_1 === "object") return state_1.value; } if (fallbackComponent === undefined) { + if (subRecipeComponent) { + genericComponentOverrideContext.logDebugMessage( + "Rendering " + .concat(subRecipeRid, " because it overlaps factors: ") + .concat(firstFactors, " and we are not rendering the auth page") + ); + return subRecipeComponent; + } throw new Error("No enabled recipes overlap with the requested firstFactors: " + firstFactors); } genericComponentOverrideContext.logDebugMessage( @@ -452,6 +473,9 @@ var RecipeRouter = /** @class */ (function () { ) { var _a; var path = normalisedUrl.getAsStringDangerous(); + var isNonAuthPage = + path !== + genericComponentOverrideContext.SuperTokens.getInstanceOrThrow().appInfo.websiteBasePath.getAsStringDangerous(); var routeComponents = preBuiltUIList.reduce(function (components, c) { var routes = c.getPathsToFeatureComponentWithRecipeIdMap(); for (var _i = 0, _a = Object.entries(routes); _i < _a.length; _i++) { @@ -497,7 +521,11 @@ var RecipeRouter = /** @class */ (function () { return componentMatchingRid; } if (mfaRecipe && mfaRecipe.config.firstFactors !== undefined) { - return chooseComponentBasedOnFirstFactors(mfaRecipe.config.firstFactors, routeComponents); + return chooseComponentBasedOnFirstFactors( + mfaRecipe.config.firstFactors, + routeComponents, + isNonAuthPage + ); } else { return defaultComp; } @@ -521,7 +549,7 @@ var RecipeRouter = /** @class */ (function () { return componentMatchingRid; } if (dynamicLoginMethods.firstFactors !== undefined) { - return chooseComponentBasedOnFirstFactors(dynamicLoginMethods.firstFactors, routeComponents); + return chooseComponentBasedOnFirstFactors(dynamicLoginMethods.firstFactors, routeComponents, isNonAuthPage); } // We may get here if the app is using an older BE that doesn't support MFA var enabledRecipeCount = Object.keys(dynamicLoginMethods).filter(function (key) { diff --git a/lib/ts/recipe/recipeRouter/index.tsx b/lib/ts/recipe/recipeRouter/index.tsx index a29c3fee5..a4cc5b70d 100644 --- a/lib/ts/recipe/recipeRouter/index.tsx +++ b/lib/ts/recipe/recipeRouter/index.tsx @@ -36,17 +36,18 @@ const priorityOrder: { function chooseComponentBasedOnFirstFactors( firstFactors: string[], - routeComponents: ComponentWithRecipeAndMatchingMethod[] + routeComponents: ComponentWithRecipeAndMatchingMethod[], + allowSubRecipeComp: boolean ) { let fallbackRid; let fallbackComponent; + let subRecipeRid; + let subRecipeComponent; // We first try to find an exact match, and fall back on something that covers all factors (but maybe more) for (const { rid, factorsProvided } of priorityOrder) { if (firstFactors.every((factor) => factorsProvided.includes(factor))) { const matchingComp = routeComponents.find((comp) => comp.recipeID === rid); if (matchingComp) { - // This means that this gets overwritten by items lower in the prios list. - // This is intentional since this way we end up with the most specific recipe that covers all required factrors (pwless instead of tppwless) fallbackRid = rid; fallbackComponent = matchingComp; if (firstFactors.length === factorsProvided.length) { @@ -54,10 +55,23 @@ function chooseComponentBasedOnFirstFactors( return matchingComp; } } + } else if (allowSubRecipeComp && factorsProvided.some((factor) => firstFactors.includes(factor))) { + const matchingComp = routeComponents.find((comp) => comp.recipeID === rid); + if (matchingComp) { + subRecipeRid = rid; + subRecipeComponent = matchingComp; + } } } if (fallbackComponent === undefined) { + if (subRecipeComponent) { + logDebugMessage( + `Rendering ${subRecipeRid} because it overlaps factors: ${firstFactors} and we are not rendering the auth page` + ); + return subRecipeComponent; + } + throw new Error("No enabled recipes overlap with the requested firstFactors: " + firstFactors); } @@ -75,6 +89,7 @@ export abstract class RecipeRouter { dynamicLoginMethods?: GetLoginMethodsResponseNormalized ): ComponentWithRecipeAndMatchingMethod | undefined { const path = normalisedUrl.getAsStringDangerous(); + const isNonAuthPage = path !== SuperTokens.getInstanceOrThrow().appInfo.websiteBasePath.getAsStringDangerous(); const routeComponents = preBuiltUIList.reduce((components, c) => { const routes = c.getPathsToFeatureComponentWithRecipeIdMap(); @@ -119,7 +134,11 @@ export abstract class RecipeRouter { } if (mfaRecipe && mfaRecipe.config.firstFactors !== undefined) { - return chooseComponentBasedOnFirstFactors(mfaRecipe.config.firstFactors, routeComponents); + return chooseComponentBasedOnFirstFactors( + mfaRecipe.config.firstFactors, + routeComponents, + isNonAuthPage + ); } else { return defaultComp; } @@ -141,7 +160,7 @@ export abstract class RecipeRouter { } if (dynamicLoginMethods.firstFactors !== undefined) { - return chooseComponentBasedOnFirstFactors(dynamicLoginMethods.firstFactors, routeComponents); + return chooseComponentBasedOnFirstFactors(dynamicLoginMethods.firstFactors, routeComponents, isNonAuthPage); } // We may get here if the app is using an older BE that doesn't support MFA