From a52383a6fdcddd26a2a667a932ec3bfb7b358d05 Mon Sep 17 00:00:00 2001 From: Victor Bojica Date: Fri, 25 Jul 2025 17:20:28 +0300 Subject: [PATCH 01/12] add util function for getting the available first factors --- lib/build/index.d.ts | 7 +++++++ lib/build/index.js | 24 ++++++++++++++++++++++++ lib/ts/index.ts | 34 +++++++++++++++++++++++++++++++++- 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/lib/build/index.d.ts b/lib/build/index.d.ts index 3ecb49e7b..6dc5b6a68 100644 --- a/lib/build/index.d.ts +++ b/lib/build/index.d.ts @@ -5,6 +5,7 @@ import { UserContext, User as UserType } from "./types"; import { AccountInfoInput } from "./recipe/accountlinking/types"; import RecipeUserId from "./recipeUserId"; import { User } from "./user"; +import { SessionContainerInterface } from "./recipe/session/types"; export type { TypeInput as SuperTokensConfig, SuperTokensPublicConfig, @@ -115,6 +116,11 @@ export default class SuperTokensWrapper { userContext: UserContext | undefined ): import("./framework").BaseRequest | undefined; static isRecipeInitialized(recipeId: string): boolean; + static getAvailableFirstFactors( + tenantId: string, + session?: SessionContainerInterface, + userContext?: Record + ): Promise; } export declare let init: typeof SuperTokens.init; export declare let getAllCORSHeaders: typeof SuperTokensWrapper.getAllCORSHeaders; @@ -131,6 +137,7 @@ export declare let listUsersByAccountInfo: typeof SuperTokensWrapper.listUsersBy export declare let convertToRecipeUserId: typeof SuperTokensWrapper.convertToRecipeUserId; export declare let getRequestFromUserContext: typeof SuperTokensWrapper.getRequestFromUserContext; export declare let isRecipeInitialized: typeof SuperTokensWrapper.isRecipeInitialized; +export declare let getAvailableFirstFactors: typeof SuperTokensWrapper.getAvailableFirstFactors; export declare let Error: typeof SuperTokensError; export { default as RecipeUserId } from "./recipeUserId"; export { User } from "./user"; diff --git a/lib/build/index.js b/lib/build/index.js index 148a3f25f..a9ef97cb0 100644 --- a/lib/build/index.js +++ b/lib/build/index.js @@ -22,6 +22,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.User = exports.RecipeUserId = exports.Error = + exports.getAvailableFirstFactors = exports.isRecipeInitialized = exports.getRequestFromUserContext = exports.convertToRecipeUserId = @@ -44,6 +45,8 @@ const recipe_1 = __importDefault(require("./recipe/accountlinking/recipe")); const recipeUserId_1 = __importDefault(require("./recipeUserId")); const user_1 = require("./user"); const utils_1 = require("./utils"); +const multifactorauth_1 = require("./recipe/multifactorauth"); +const authUtils_1 = require("./authUtils"); // For Express class SuperTokensWrapper { static getAllCORSHeaders() { @@ -129,6 +132,26 @@ class SuperTokensWrapper { .recipeModules.map((recipe) => recipe.getRecipeId()) .includes(recipeId); } + static async getAvailableFirstFactors(tenantId, session, userContext) { + const factorIds = Object.values(multifactorauth_1.FactorIds); + try { + const availableFirstFactors = + await authUtils_1.AuthUtils.filterOutInvalidFirstFactorsOrThrowIfAllAreInvalid( + factorIds, + tenantId, + !!session, + (0, utils_1.getUserContext)(userContext) + ); + return availableFirstFactors; + } catch (error) { + if (error instanceof error_1.default) { + if (error.type === error_1.default.BAD_INPUT_ERROR) { + return []; + } + } + throw error; + } + } } SuperTokensWrapper.init = supertokens_1.default.init; SuperTokensWrapper.Error = error_1.default; @@ -150,6 +173,7 @@ exports.listUsersByAccountInfo = SuperTokensWrapper.listUsersByAccountInfo; exports.convertToRecipeUserId = SuperTokensWrapper.convertToRecipeUserId; exports.getRequestFromUserContext = SuperTokensWrapper.getRequestFromUserContext; exports.isRecipeInitialized = SuperTokensWrapper.isRecipeInitialized; +exports.getAvailableFirstFactors = SuperTokensWrapper.getAvailableFirstFactors; exports.Error = SuperTokensWrapper.Error; var recipeUserId_2 = require("./recipeUserId"); Object.defineProperty(exports, "RecipeUserId", { diff --git a/lib/ts/index.ts b/lib/ts/index.ts index 1354be71a..0d8382f11 100644 --- a/lib/ts/index.ts +++ b/lib/ts/index.ts @@ -1,4 +1,4 @@ -/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved. + /* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved. * * This software is licensed under the Apache License, Version 2.0 (the * "License") as published by the Apache Software Foundation. @@ -21,6 +21,9 @@ import { AccountInfoInput } from "./recipe/accountlinking/types"; import RecipeUserId from "./recipeUserId"; import { User } from "./user"; import { getUserContext } from "./utils"; +import { SessionContainerInterface } from "./recipe/session/types"; +import { FactorIds } from "./recipe/multifactorauth"; +import { AuthUtils } from "./authUtils"; export type { TypeInput as SuperTokensConfig, @@ -177,6 +180,33 @@ export default class SuperTokensWrapper { .recipeModules.map((recipe) => recipe.getRecipeId()) .includes(recipeId); } + + static async getAvailableFirstFactors( + tenantId: string, + session?: SessionContainerInterface, + userContext?: Record + ) { + const factorIds = Object.values(FactorIds); + + try { + const availableFirstFactors = await AuthUtils.filterOutInvalidFirstFactorsOrThrowIfAllAreInvalid( + factorIds, + tenantId, + !!session, + getUserContext(userContext) + ); + + return availableFirstFactors; + } catch (error) { + if (error instanceof SuperTokensError) { + if (error.type === SuperTokensError.BAD_INPUT_ERROR) { + return []; + } + } + + throw error; + } + } } export let init = SuperTokensWrapper.init; @@ -209,6 +239,8 @@ export let getRequestFromUserContext = SuperTokensWrapper.getRequestFromUserCont export let isRecipeInitialized = SuperTokensWrapper.isRecipeInitialized; +export let getAvailableFirstFactors = SuperTokensWrapper.getAvailableFirstFactors; + export let Error = SuperTokensWrapper.Error; export { default as RecipeUserId } from "./recipeUserId"; From d2bc9410bb9a6ab443b7b86d562f065f36289120 Mon Sep 17 00:00:00 2001 From: Victor Bojica Date: Mon, 4 Aug 2025 13:41:53 +0300 Subject: [PATCH 02/12] fix: better plugin sdk version checking --- lib/build/plugins.js | 21 ++++--- lib/build/versionChecker.d.ts | 2 + lib/build/versionChecker.js | 97 ++++++++++++++++++++++++++++++ lib/ts/plugins.ts | 22 +++---- lib/ts/versionChecker.ts | 107 ++++++++++++++++++++++++++++++++++ 5 files changed, 230 insertions(+), 19 deletions(-) create mode 100644 lib/build/versionChecker.d.ts create mode 100644 lib/build/versionChecker.js create mode 100644 lib/ts/versionChecker.ts diff --git a/lib/build/plugins.js b/lib/build/plugins.js index b5dbe060d..526f04d65 100644 --- a/lib/build/plugins.js +++ b/lib/build/plugins.js @@ -18,6 +18,7 @@ exports.loadPlugins = loadPlugins; const version_1 = require("./version"); const postSuperTokensInitCallbacks_1 = require("./postSuperTokensInitCallbacks"); const utils_1 = require("./utils"); +const versionChecker_1 = require("./versionChecker"); function getPublicPlugin(plugin) { return { id: plugin.id, @@ -122,16 +123,18 @@ function loadPlugins({ plugins, config, normalisedAppInfo }) { if (seenPlugins.has(plugin.id)) { continue; } - const versionContraints = Array.isArray(plugin.compatibleSDKVersions) - ? plugin.compatibleSDKVersions - : [plugin.compatibleSDKVersions]; - if (!versionContraints.includes(version_1.version)) { - // TODO: better checks - throw new Error( - `Plugin version mismatch. Version ${ - version_1.version - } not found in compatible versions: ${versionContraints.join(", ")}` + if (plugin.compatibleSDKVersions) { + const versionCheck = (0, versionChecker_1.isVersionCompatible)( + version_1.version, + plugin.compatibleSDKVersions ); + if (!versionCheck) { + throw new Error( + `Incompatible SDK version for plugin ${plugin.id}. Version "${ + version_1.version + }" not found in compatible versions: ${JSON.stringify(plugin.compatibleSDKVersions)}` + ); + } } const dependencies = getPluginDependencies({ plugin, diff --git a/lib/build/versionChecker.d.ts b/lib/build/versionChecker.d.ts new file mode 100644 index 000000000..e92cca007 --- /dev/null +++ b/lib/build/versionChecker.d.ts @@ -0,0 +1,2 @@ +// @ts-nocheck +export declare const isVersionCompatible: (currentVersion: string, constraints: string | string[]) => boolean; diff --git a/lib/build/versionChecker.js b/lib/build/versionChecker.js new file mode 100644 index 000000000..7d0485c3d --- /dev/null +++ b/lib/build/versionChecker.js @@ -0,0 +1,97 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.isVersionCompatible = void 0; +const parseVersion = (version) => { + const match = version.match(/^(\d+)\.(\d+)\.(\d+)(?:-(.+))?$/); + if (!match) { + throw new Error(`Invalid version format: ${version}`); + } + return { + major: parseInt(match[1]), + minor: parseInt(match[2]), + patch: parseInt(match[3]), + prerelease: match[4], + }; +}; +const compareVersions = (a, b) => { + if (a.major !== b.major) return a.major - b.major; + if (a.minor !== b.minor) return a.minor - b.minor; + if (a.patch !== b.patch) return a.patch - b.patch; + // canary versions + if (a.prerelease && !b.prerelease) return -1; + if (!a.prerelease && b.prerelease) return 1; + if (a.prerelease && b.prerelease) { + return a.prerelease.localeCompare(b.prerelease); + } + return 0; +}; +// checks if a version satisfies a range constraint. supports: ">=0.49.0", "0.49.x", "~0.49.0", "^0.49.0", "0.49.1" +const satisfiesRange = (version, range) => { + const parsedVersion = parseVersion(version); + if (range === version) return true; + const rangeMatch = range.match(/^([<>=~^]+)\s*(.+)$/); + if (rangeMatch) { + const operator = rangeMatch[1]; + const rangeVersion = rangeMatch[2]; + const parsedRangeVersion = parseVersion(rangeVersion); + const comparison = compareVersions(parsedVersion, parsedRangeVersion); + switch (operator) { + case ">=": + return comparison >= 0; + case ">": + return comparison > 0; + case "<=": + return comparison <= 0; + case "<": + return comparison < 0; + case "=": + case "==": + return comparison === 0; + case "~": + return ( + parsedVersion.major === parsedRangeVersion.major && + parsedVersion.minor === parsedRangeVersion.minor && + parsedVersion.patch >= parsedRangeVersion.patch + ); + case "^": + if (parsedRangeVersion.major === 0) { + return ( + parsedVersion.major === 0 && + parsedVersion.minor === parsedRangeVersion.minor && + parsedVersion.patch >= parsedRangeVersion.patch + ); + } else { + return ( + parsedVersion.major === parsedRangeVersion.major && + parsedVersion.minor >= parsedRangeVersion.minor + ); + } + default: + return false; + } + } + // x-ranges like "0.49.x" + const xRangeMatch = range.match(/^(\d+)\.(\d+)\.x$/); + if (xRangeMatch) { + return ( + parsedVersion.major === parseInt(xRangeMatch[1], 10) && parsedVersion.minor === parseInt(xRangeMatch[2], 10) + ); + } + // wildcard ranges like "0.x" + const wildcardMatch = range.match(/^(\d+)\.x$/); + if (wildcardMatch) { + return parsedVersion.major === parseInt(wildcardMatch[1], 10); + } + const exactRangeVersion = parseVersion(range); + return compareVersions(parsedVersion, exactRangeVersion) === 0; +}; +const isVersionCompatible = (currentVersion, constraints) => { + const constraintArray = Array.isArray(constraints) ? constraints : [constraints]; + for (const constraint of constraintArray) { + if (satisfiesRange(currentVersion, constraint)) { + return true; + } + } + return false; +}; +exports.isVersionCompatible = isVersionCompatible; diff --git a/lib/ts/plugins.ts b/lib/ts/plugins.ts index c146e9331..6857bd4b7 100644 --- a/lib/ts/plugins.ts +++ b/lib/ts/plugins.ts @@ -4,6 +4,7 @@ import { PluginRouteHandler, AllRecipeConfigs, TypeInput, NormalisedAppinfo } fr import { version } from "./version"; import { PostSuperTokensInitCallbacks } from "./postSuperTokensInitCallbacks"; import { getPublicConfig } from "./utils"; +import { isVersionCompatible } from "./versionChecker"; export function getPublicPlugin(plugin: SuperTokensPlugin): SuperTokensPublicPlugin { return { @@ -149,16 +150,17 @@ export function loadPlugins({ continue; } - const versionContraints = Array.isArray(plugin.compatibleSDKVersions) - ? plugin.compatibleSDKVersions - : [plugin.compatibleSDKVersions]; - if (!versionContraints.includes(version)) { - // TODO: better checks - throw new Error( - `Plugin version mismatch. Version ${version} not found in compatible versions: ${versionContraints.join( - ", " - )}` - ); + if (plugin.compatibleSDKVersions) { + const versionCheck = isVersionCompatible(version, plugin.compatibleSDKVersions); + if (!versionCheck) { + throw new Error( + `Incompatible SDK version for plugin ${ + plugin.id + }. Version "${version}" not found in compatible versions: ${JSON.stringify( + plugin.compatibleSDKVersions + )}` + ); + } } const dependencies = getPluginDependencies({ diff --git a/lib/ts/versionChecker.ts b/lib/ts/versionChecker.ts new file mode 100644 index 000000000..13732b631 --- /dev/null +++ b/lib/ts/versionChecker.ts @@ -0,0 +1,107 @@ +const parseVersion = (version: string): { major: number; minor: number; patch: number; prerelease?: string } => { + const match = version.match(/^(\d+)\.(\d+)\.(\d+)(?:-(.+))?$/); + if (!match) { + throw new Error(`Invalid version format: ${version}`); + } + + return { + major: parseInt(match[1]), + minor: parseInt(match[2]), + patch: parseInt(match[3]), + prerelease: match[4], + }; +}; + +const compareVersions = (a: ReturnType, b: ReturnType): number => { + if (a.major !== b.major) return a.major - b.major; + if (a.minor !== b.minor) return a.minor - b.minor; + if (a.patch !== b.patch) return a.patch - b.patch; + + // canary versions + if (a.prerelease && !b.prerelease) return -1; + if (!a.prerelease && b.prerelease) return 1; + if (a.prerelease && b.prerelease) { + return a.prerelease.localeCompare(b.prerelease); + } + + return 0; +}; + +// checks if a version satisfies a range constraint. supports: ">=0.49.0", "0.49.x", "~0.49.0", "^0.49.0", "0.49.1" +const satisfiesRange = (version: string, range: string): boolean => { + const parsedVersion = parseVersion(version); + + if (range === version) return true; + + const rangeMatch = range.match(/^([<>=~^]+)\s*(.+)$/); + if (rangeMatch) { + const operator = rangeMatch[1]; + const rangeVersion = rangeMatch[2]; + const parsedRangeVersion = parseVersion(rangeVersion); + const comparison = compareVersions(parsedVersion, parsedRangeVersion); + + switch (operator) { + case ">=": + return comparison >= 0; + case ">": + return comparison > 0; + case "<=": + return comparison <= 0; + case "<": + return comparison < 0; + case "=": + case "==": + return comparison === 0; + case "~": + return ( + parsedVersion.major === parsedRangeVersion.major && + parsedVersion.minor === parsedRangeVersion.minor && + parsedVersion.patch >= parsedRangeVersion.patch + ); + case "^": + if (parsedRangeVersion.major === 0) { + return ( + parsedVersion.major === 0 && + parsedVersion.minor === parsedRangeVersion.minor && + parsedVersion.patch >= parsedRangeVersion.patch + ); + } else { + return ( + parsedVersion.major === parsedRangeVersion.major && + parsedVersion.minor >= parsedRangeVersion.minor + ); + } + default: + return false; + } + } + + // x-ranges like "0.49.x" + const xRangeMatch = range.match(/^(\d+)\.(\d+)\.x$/); + if (xRangeMatch) { + return ( + parsedVersion.major === parseInt(xRangeMatch[1], 10) && parsedVersion.minor === parseInt(xRangeMatch[2], 10) + ); + } + + // wildcard ranges like "0.x" + const wildcardMatch = range.match(/^(\d+)\.x$/); + if (wildcardMatch) { + return parsedVersion.major === parseInt(wildcardMatch[1], 10); + } + + const exactRangeVersion = parseVersion(range); + return compareVersions(parsedVersion, exactRangeVersion) === 0; +}; + +export const isVersionCompatible = (currentVersion: string, constraints: string | string[]): boolean => { + const constraintArray = Array.isArray(constraints) ? constraints : [constraints]; + + for (const constraint of constraintArray) { + if (satisfiesRange(currentVersion, constraint)) { + return true; + } + } + + return false; +}; From 8fbb046707d46cf2552d946dad80205a5d4c2a96 Mon Sep 17 00:00:00 2001 From: Victor Bojica Date: Wed, 6 Aug 2025 12:59:10 +0300 Subject: [PATCH 03/12] feat: add error handling for plugin route handlers --- lib/build/error.d.ts | 7 +++++++ lib/build/error.js | 9 +++++++++ lib/build/plugins.d.ts | 4 +++- lib/build/plugins.js | 8 ++++++-- lib/build/supertokens.d.ts | 4 +++- lib/build/supertokens.js | 24 +++++++++++++++++++++++- lib/ts/error.ts | 17 +++++++++++++++++ lib/ts/plugins.ts | 10 +++++----- lib/ts/supertokens.ts | 29 +++++++++++++++++++++++++++-- 9 files changed, 100 insertions(+), 12 deletions(-) diff --git a/lib/build/error.d.ts b/lib/build/error.d.ts index 41083aef0..3a43dd5d3 100644 --- a/lib/build/error.d.ts +++ b/lib/build/error.d.ts @@ -2,6 +2,7 @@ export default class SuperTokensError extends Error { private static errMagic; static BAD_INPUT_ERROR: "BAD_INPUT_ERROR"; + static PLUGIN_ERROR: "PLUGIN_ERROR"; type: string; payload: any; fromRecipe: string | undefined; @@ -18,6 +19,12 @@ export default class SuperTokensError extends Error { type: "BAD_INPUT_ERROR"; payload: undefined; } + | { + message: string; + type: "PLUGIN_ERROR"; + payload: undefined; + } ); static isErrorFromSuperTokens(obj: any): obj is SuperTokensError; + static fromError(err: Error, type: string): SuperTokensError; } diff --git a/lib/build/error.js b/lib/build/error.js index 9a41d42c8..02ba34c23 100644 --- a/lib/build/error.js +++ b/lib/build/error.js @@ -24,7 +24,16 @@ class SuperTokensError extends Error { static isErrorFromSuperTokens(obj) { return obj.errMagic === SuperTokensError.errMagic; } + static fromError(err, type) { + const newError = new SuperTokensError({ + message: err.message, + type, + }); + newError.stack = err.stack; + return newError; + } } SuperTokensError.errMagic = "ndskajfasndlfkj435234krjdsa"; SuperTokensError.BAD_INPUT_ERROR = "BAD_INPUT_ERROR"; +SuperTokensError.PLUGIN_ERROR = "PLUGIN_ERROR"; exports.default = SuperTokensError; diff --git a/lib/build/plugins.d.ts b/lib/build/plugins.d.ts index 64ca21d6b..66156fde6 100644 --- a/lib/build/plugins.d.ts +++ b/lib/build/plugins.d.ts @@ -41,6 +41,8 @@ export declare function loadPlugins({ normalisedAppInfo: NormalisedAppinfo; }): { config: TypeInput; - pluginRouteHandlers: PluginRouteHandler[]; + pluginRouteHandlers: (PluginRouteHandler & { + pluginId: string; + })[]; overrideMaps: Record[]; }; diff --git a/lib/build/plugins.js b/lib/build/plugins.js index 526f04d65..cbf416f39 100644 --- a/lib/build/plugins.js +++ b/lib/build/plugins.js @@ -179,9 +179,13 @@ function loadPlugins({ plugins, config, normalisedAppInfo }) { if (result.status === "ERROR") { throw new Error(result.message); } - handlers = result.routeHandlers; + handlers = result.routeHandlers.map((handler) => + Object.assign(Object.assign({}, handler), { pluginId: plugin.id }) + ); } else { - handlers = plugin.routeHandlers; + handlers = plugin.routeHandlers.map((handler) => + Object.assign(Object.assign({}, handler), { pluginId: plugin.id }) + ); } pluginRouteHandlers.push(...handlers); } diff --git a/lib/build/supertokens.d.ts b/lib/build/supertokens.d.ts index d21672947..fab2d4a64 100644 --- a/lib/build/supertokens.d.ts +++ b/lib/build/supertokens.d.ts @@ -18,7 +18,9 @@ export default class SuperTokens { appInfo: NormalisedAppinfo; isInServerlessEnv: boolean; recipeModules: RecipeModule[]; - pluginRouteHandlers: PluginRouteHandler[]; + pluginRouteHandlers: (PluginRouteHandler & { + pluginId: string; + })[]; pluginOverrideMaps: NonNullable[]; supertokens: undefined | SuperTokensInfo; telemetryEnabled: boolean; diff --git a/lib/build/supertokens.js b/lib/build/supertokens.js index 5612eb64e..7f423c996 100644 --- a/lib/build/supertokens.js +++ b/lib/build/supertokens.js @@ -30,6 +30,7 @@ const logger_1 = require("./logger"); const postSuperTokensInitCallbacks_1 = require("./postSuperTokensInitCallbacks"); const constants_2 = require("./recipe/multitenancy/constants"); const recipe_1 = __importDefault(require("./recipe/session/recipe")); +const error_2 = __importDefault(require("./error")); class SuperTokens { constructor(config) { var _a, _b, _c, _d, _e, _f; @@ -163,7 +164,24 @@ class SuperTokens { .getInstanceOrThrowError() .verifySession(handlerFromApis.verifySessionOptions, request, response, userContext); } - handlerFromApis.handler(request, response, session, userContext); + (0, logger_1.logDebugMessage)( + "middleware: Request being handled by plugin. ID is: " + handlerFromApis.pluginId + ); + try { + await handlerFromApis.handler(request, response, session, userContext); + } catch (err) { + // passthrough for errors from SuperTokens - let errorHandler handle them + if (error_2.default.isErrorFromSuperTokens(err)) { + throw err; + } else { + (0, logger_1.logDebugMessage)( + "middleware: Error from plugin, transforming to SuperTokensError. Plugin ID: " + + handlerFromApis.pluginId + ); + // transform errors to SuperTokensError to be handled by the errorHandler + throw error_2.default.fromError(err, error_2.default.PLUGIN_ERROR); + } + } return true; } // if the prefix of the URL doesn't match the base path, we skip @@ -325,6 +343,10 @@ class SuperTokens { (0, logger_1.logDebugMessage)("errorHandler: Sending 400 status code response"); return (0, utils_1.sendNon200ResponseWithMessage)(response, err.message, 400); } + if (err.type === error_1.default.PLUGIN_ERROR) { + (0, logger_1.logDebugMessage)("errorHandler: Sending 400 status code response"); + return (0, utils_1.sendNon200ResponseWithMessage)(response, err.message, 400); + } for (let i = 0; i < this.recipeModules.length; i++) { (0, logger_1.logDebugMessage)( "errorHandler: Checking recipe for match: " + this.recipeModules[i].getRecipeId() diff --git a/lib/ts/error.ts b/lib/ts/error.ts index dfcb1acc7..557d7e1d0 100644 --- a/lib/ts/error.ts +++ b/lib/ts/error.ts @@ -16,6 +16,7 @@ export default class SuperTokensError extends Error { private static errMagic = "ndskajfasndlfkj435234krjdsa"; static BAD_INPUT_ERROR: "BAD_INPUT_ERROR" = "BAD_INPUT_ERROR"; + static PLUGIN_ERROR: "PLUGIN_ERROR" = "PLUGIN_ERROR"; public type: string; public payload: any; @@ -42,6 +43,11 @@ export default class SuperTokensError extends Error { type: "BAD_INPUT_ERROR"; payload: undefined; } + | { + message: string; + type: "PLUGIN_ERROR"; + payload: undefined; + } ) { super(options.message); this.type = options.type; @@ -52,4 +58,15 @@ export default class SuperTokensError extends Error { static isErrorFromSuperTokens(obj: any): obj is SuperTokensError { return obj.errMagic === SuperTokensError.errMagic; } + + static fromError(err: Error, type: string): SuperTokensError { + const newError = new SuperTokensError({ + message: err.message, + type, + }); + + newError.stack = err.stack; + + return newError; + } } diff --git a/lib/ts/plugins.ts b/lib/ts/plugins.ts index 6857bd4b7..82ad63cc5 100644 --- a/lib/ts/plugins.ts +++ b/lib/ts/plugins.ts @@ -139,7 +139,7 @@ export function loadPlugins({ normalisedAppInfo: NormalisedAppinfo; }): { config: TypeInput; - pluginRouteHandlers: PluginRouteHandler[]; + pluginRouteHandlers: (PluginRouteHandler & { pluginId: string })[]; overrideMaps: Record[]; } { const inputPluginList = plugins ?? []; @@ -187,7 +187,7 @@ export function loadPlugins({ const processedPlugins: SuperTokensPublicPlugin[] = finalPluginList.map(getPublicPlugin); let _config = { ...config }; - const pluginRouteHandlers: PluginRouteHandler[] = []; + const pluginRouteHandlers: (PluginRouteHandler & { pluginId: string })[] = []; for (const [pluginIndex, plugin] of finalPluginList.entries()) { if (plugin.config) { // @ts-ignore @@ -200,15 +200,15 @@ export function loadPlugins({ const publicConfig = getPublicConfig({ ..._config, appInfo: normalisedAppInfo }); if (plugin.routeHandlers) { - let handlers: PluginRouteHandler[] = []; + let handlers: (PluginRouteHandler & { pluginId: string })[] = []; if (typeof plugin.routeHandlers === "function") { const result = plugin.routeHandlers(publicConfig, processedPlugins, version); if (result.status === "ERROR") { throw new Error(result.message); } - handlers = result.routeHandlers; + handlers = result.routeHandlers.map((handler) => ({ ...handler, pluginId: plugin.id })); } else { - handlers = plugin.routeHandlers; + handlers = plugin.routeHandlers.map((handler) => ({ ...handler, pluginId: plugin.id })); } pluginRouteHandlers.push(...handlers); diff --git a/lib/ts/supertokens.ts b/lib/ts/supertokens.ts index 22c459802..a60332795 100644 --- a/lib/ts/supertokens.ts +++ b/lib/ts/supertokens.ts @@ -44,6 +44,7 @@ import { PostSuperTokensInitCallbacks } from "./postSuperTokensInitCallbacks"; import { DEFAULT_TENANT_ID } from "./recipe/multitenancy/constants"; import { SessionContainerInterface } from "./recipe/session/types"; import Session from "./recipe/session/recipe"; +import SuperTokensError from "./error"; export default class SuperTokens { private static instance: SuperTokens | undefined; @@ -56,7 +57,7 @@ export default class SuperTokens { recipeModules: RecipeModule[]; - pluginRouteHandlers: PluginRouteHandler[]; + pluginRouteHandlers: (PluginRouteHandler & { pluginId: string })[]; pluginOverrideMaps: NonNullable[]; @@ -445,7 +446,26 @@ export default class SuperTokens { userContext ); } - handlerFromApis.handler(request, response, session, userContext); + + logDebugMessage("middleware: Request being handled by plugin. ID is: " + handlerFromApis.pluginId); + + try { + await handlerFromApis.handler(request, response, session, userContext); + } catch (err) { + // passthrough for errors from SuperTokens - let errorHandler handle them + if (SuperTokensError.isErrorFromSuperTokens(err)) { + throw err; + } else { + logDebugMessage( + "middleware: Error from plugin, transforming to SuperTokensError. Plugin ID: " + + handlerFromApis.pluginId + ); + + // transform errors to SuperTokensError to be handled by the errorHandler + throw SuperTokensError.fromError(err, SuperTokensError.PLUGIN_ERROR); + } + } + return true; } @@ -622,6 +642,11 @@ export default class SuperTokens { return sendNon200ResponseWithMessage(response, err.message, 400); } + if (err.type === STError.PLUGIN_ERROR) { + logDebugMessage("errorHandler: Sending 400 status code response"); + return sendNon200ResponseWithMessage(response, err.message, 400); + } + for (let i = 0; i < this.recipeModules.length; i++) { logDebugMessage("errorHandler: Checking recipe for match: " + this.recipeModules[i].getRecipeId()); if (this.recipeModules[i].isErrorFromThisRecipe(err)) { From abd11707dce10a2d380764a6dd0b1b521dbaae38 Mon Sep 17 00:00:00 2001 From: Victor Bojica Date: Wed, 6 Aug 2025 18:01:59 +0300 Subject: [PATCH 04/12] fix: fix circular dependency breaking tests --- lib/build/index.d.ts | 2 +- lib/build/index.js | 15 +++++++-------- lib/ts/index.ts | 4 ++-- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/lib/build/index.d.ts b/lib/build/index.d.ts index 6dc5b6a68..b9c5277a1 100644 --- a/lib/build/index.d.ts +++ b/lib/build/index.d.ts @@ -120,7 +120,7 @@ export default class SuperTokensWrapper { tenantId: string, session?: SessionContainerInterface, userContext?: Record - ): Promise; + ): Promise; } export declare let init: typeof SuperTokens.init; export declare let getAllCORSHeaders: typeof SuperTokensWrapper.getAllCORSHeaders; diff --git a/lib/build/index.js b/lib/build/index.js index a9ef97cb0..f3469d260 100644 --- a/lib/build/index.js +++ b/lib/build/index.js @@ -46,7 +46,6 @@ const recipeUserId_1 = __importDefault(require("./recipeUserId")); const user_1 = require("./user"); const utils_1 = require("./utils"); const multifactorauth_1 = require("./recipe/multifactorauth"); -const authUtils_1 = require("./authUtils"); // For Express class SuperTokensWrapper { static getAllCORSHeaders() { @@ -135,13 +134,13 @@ class SuperTokensWrapper { static async getAvailableFirstFactors(tenantId, session, userContext) { const factorIds = Object.values(multifactorauth_1.FactorIds); try { - const availableFirstFactors = - await authUtils_1.AuthUtils.filterOutInvalidFirstFactorsOrThrowIfAllAreInvalid( - factorIds, - tenantId, - !!session, - (0, utils_1.getUserContext)(userContext) - ); + const { AuthUtils } = require("./authUtils"); + const availableFirstFactors = await AuthUtils.filterOutInvalidFirstFactorsOrThrowIfAllAreInvalid( + factorIds, + tenantId, + !!session, + (0, utils_1.getUserContext)(userContext) + ); return availableFirstFactors; } catch (error) { if (error instanceof error_1.default) { diff --git a/lib/ts/index.ts b/lib/ts/index.ts index 0d8382f11..f6a8b88c4 100644 --- a/lib/ts/index.ts +++ b/lib/ts/index.ts @@ -1,4 +1,4 @@ - /* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved. +/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved. * * This software is licensed under the Apache License, Version 2.0 (the * "License") as published by the Apache Software Foundation. @@ -23,7 +23,6 @@ import { User } from "./user"; import { getUserContext } from "./utils"; import { SessionContainerInterface } from "./recipe/session/types"; import { FactorIds } from "./recipe/multifactorauth"; -import { AuthUtils } from "./authUtils"; export type { TypeInput as SuperTokensConfig, @@ -189,6 +188,7 @@ export default class SuperTokensWrapper { const factorIds = Object.values(FactorIds); try { + const { AuthUtils } = require("./authUtils"); const availableFirstFactors = await AuthUtils.filterOutInvalidFirstFactorsOrThrowIfAllAreInvalid( factorIds, tenantId, From 0d53c65dd33dad08ad257979359922014e6ebf37 Mon Sep 17 00:00:00 2001 From: Victor Bojica Date: Wed, 6 Aug 2025 18:02:16 +0300 Subject: [PATCH 05/12] fix: plugin version fix --- test/plugins/plugins.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/plugins/plugins.ts b/test/plugins/plugins.ts index 6f5dc4ae6..352dcba90 100644 --- a/test/plugins/plugins.ts +++ b/test/plugins/plugins.ts @@ -37,7 +37,7 @@ export function dependencyFactory(dependencies?: SuperTokensPlugin[]) { return function dependency( config: SuperTokensPublicConfig, pluginsAbove: SuperTokensPublicPlugin[], - sdkVersion: string + sdkVersion: string, ): { status: "OK"; pluginsToAdd?: SuperTokensPlugin[] } | { status: "ERROR"; message: string } { const addedPluginIds: string[] = pluginsAbove.map((p) => p.id); const pluginsToAdd: SuperTokensPlugin[] = dependencies!.filter((p) => !addedPluginIds.includes(p.id)); @@ -77,7 +77,7 @@ export function pluginFactory({ return { id: identifier, - compatibleSDKVersions: ["23.0"], + compatibleSDKVersions: ["23.0.x"], overrideMap, init: addInit ? initFactory(identifier) : undefined, dependencies: dependencyFactory(dependencies), From 962327e4bfb1e6ca53d5693a1908865a9762cbe2 Mon Sep 17 00:00:00 2001 From: Victor Bojica Date: Thu, 7 Aug 2025 15:17:25 +0300 Subject: [PATCH 06/12] fix: prevent plugins from overriding appInfo and experimental properties from config --- lib/build/plugins.js | 4 ++-- lib/ts/plugins.ts | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/build/plugins.js b/lib/build/plugins.js index cbf416f39..f6782bc8f 100644 --- a/lib/build/plugins.js +++ b/lib/build/plugins.js @@ -165,8 +165,8 @@ function loadPlugins({ plugins, config, normalisedAppInfo }) { Object.assign(Object.assign({}, _config), { appInfo: normalisedAppInfo }) ) ), - { appInfo } = _a, - pluginConfigOverride = __rest(_a, ["appInfo"]); + { appInfo, recipeList, experimental } = _a, + pluginConfigOverride = __rest(_a, ["appInfo", "recipeList", "experimental"]); _config = Object.assign(Object.assign({}, _config), pluginConfigOverride); } const publicConfig = (0, utils_1.getPublicConfig)( diff --git a/lib/ts/plugins.ts b/lib/ts/plugins.ts index 82ad63cc5..060492919 100644 --- a/lib/ts/plugins.ts +++ b/lib/ts/plugins.ts @@ -191,13 +191,16 @@ export function loadPlugins({ for (const [pluginIndex, plugin] of finalPluginList.entries()) { if (plugin.config) { // @ts-ignore - const { appInfo, ...pluginConfigOverride } = plugin.config( + const { appInfo, recipeList, experimental, ...pluginConfigOverride } = plugin.config( getPublicConfig({ ..._config, appInfo: normalisedAppInfo }) ); _config = { ..._config, ...pluginConfigOverride }; } - const publicConfig = getPublicConfig({ ..._config, appInfo: normalisedAppInfo }); + const publicConfig = getPublicConfig({ + ..._config, + appInfo: normalisedAppInfo, + }); if (plugin.routeHandlers) { let handlers: (PluginRouteHandler & { pluginId: string })[] = []; From ee4dc83c4f3c5fc497c3fb9ce3271faee0ac13ae Mon Sep 17 00:00:00 2001 From: Victor Bojica Date: Thu, 7 Aug 2025 15:19:46 +0300 Subject: [PATCH 07/12] fix: add and fix tests for plugin config overrides --- package-lock.json | 18 +++ package.json | 3 +- test/plugins/plugins.test.ts | 235 +++++++++++++++++++++++++++-------- test/plugins/plugins.ts | 24 +++- test/plugins/recipe.ts | 6 + test/plugins/types.ts | 6 + 6 files changed, 240 insertions(+), 52 deletions(-) diff --git a/package-lock.json b/package-lock.json index fc6333007..cecebe643 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,6 +44,7 @@ "@types/nodemailer": "^6.4.4", "@types/pako": "^2.0.3", "@types/set-cookie-parser": "^2.4.9", + "@types/sinon": "^17.0.4", "@types/validator": "10.11.0", "aws-sdk-mock": "^5.4.0", "body-parser": "1.20.1", @@ -1872,6 +1873,23 @@ "@types/node": "*" } }, + "node_modules/@types/sinon": { + "version": "17.0.4", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-17.0.4.tgz", + "integrity": "sha512-RHnIrhfPO3+tJT0s7cFaXGZvsL4bbR3/k7z3P312qMS4JaS2Tk+KiwiLx1S0rQ56ERj00u1/BtdyVd0FY+Pdew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/sinonjs__fake-timers": "*" + } + }, + "node_modules/@types/sinonjs__fake-timers": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.5.tgz", + "integrity": "sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/type-is": { "version": "1.6.6", "resolved": "https://registry.npmjs.org/@types/type-is/-/type-is-1.6.6.tgz", diff --git a/package.json b/package.json index 23a15c530..24075b0fb 100644 --- a/package.json +++ b/package.json @@ -161,6 +161,7 @@ "@types/nodemailer": "^6.4.4", "@types/pako": "^2.0.3", "@types/set-cookie-parser": "^2.4.9", + "@types/sinon": "^17.0.4", "@types/validator": "10.11.0", "aws-sdk-mock": "^5.4.0", "body-parser": "1.20.1", @@ -193,4 +194,4 @@ "browser": { "fs": false } -} +} \ No newline at end of file diff --git a/test/plugins/plugins.test.ts b/test/plugins/plugins.test.ts index c77f4eaae..4a0b37bf9 100644 --- a/test/plugins/plugins.test.ts +++ b/test/plugins/plugins.test.ts @@ -1,6 +1,7 @@ import { resetAll } from "../utils"; import { apiOverrideFactory, + configOverrideFactory, functionOverrideFactory, Plugin1, Plugin2, @@ -16,17 +17,32 @@ import STExpress from "../.."; import { SuperTokensPlugin, SuperTokensPublicConfig } from "../../lib/build"; import assert from "assert"; import SuperTokens from "../../lib/build/supertokens"; +import * as plugins from "../../lib/build/plugins"; import { PluginRouteHandler, UserContext } from "../../lib/build/types"; import { DummyRequest, DummyResponse } from "./misc"; import { PostSuperTokensInitCallbacks } from "../../lib/ts/postSuperTokensInitCallbacks"; - -function recipeFactory({ overrideFunctions, overrideApis }: { overrideFunctions: boolean; overrideApis: boolean }) { - return PluginTestRecipe.init({ +import sinon from "sinon"; + +function recipeFactory({ + overrideFunctions, + overrideApis, + overrideConfig, +}: { + overrideFunctions: boolean; + overrideApis: boolean; + overrideConfig: boolean; +}) { + let originalConfig = { override: { functions: overrideFunctions ? functionOverrideFactory("override") : (oI) => oI, apis: overrideApis ? apiOverrideFactory("override") : (oI) => oI, }, - }); + testProperty: [], + }; + const config = overrideConfig + ? configOverrideFactory("override")(originalConfig) + : configOverrideFactory("original")(originalConfig); + return PluginTestRecipe.init(config); } const partialSupertokensConfig = { @@ -51,102 +67,180 @@ describe("Plugins", () => { const overrideTestParams: { overrideFunctions: boolean; overrideApis: boolean; - pluginFactortyConfigs: { identifier: string; overrideFunctions: boolean; overrideApis: boolean }[]; + overrideConfig: boolean; + pluginFactortyConfigs: { + identifier: string; + overrideFunctions: boolean; + overrideApis: boolean; + overrideConfig: boolean; + }[]; expectedFunctionOrder: string[]; expectedApiOrder: string[]; + expectedConfigOrder: string[]; }[] = [ // No plugins { overrideFunctions: false, overrideApis: false, + overrideConfig: false, pluginFactortyConfigs: [], expectedFunctionOrder: ["original"], expectedApiOrder: ["original"], + expectedConfigOrder: ["original"], }, { overrideFunctions: true, overrideApis: false, + overrideConfig: false, pluginFactortyConfigs: [], expectedFunctionOrder: ["override", "original"], expectedApiOrder: ["original"], + expectedConfigOrder: ["original"], }, { overrideFunctions: false, overrideApis: true, + overrideConfig: false, pluginFactortyConfigs: [], expectedFunctionOrder: ["original"], expectedApiOrder: ["override", "original"], + expectedConfigOrder: ["original"], + }, + { + overrideFunctions: false, + overrideApis: false, + overrideConfig: true, + pluginFactortyConfigs: [], + expectedFunctionOrder: ["original"], + expectedApiOrder: ["original"], + expectedConfigOrder: ["override"], }, // Single plugin with overrides { overrideFunctions: true, overrideApis: false, - pluginFactortyConfigs: [{ identifier: "plugin1", overrideFunctions: true, overrideApis: false }], + overrideConfig: false, + pluginFactortyConfigs: [ + { identifier: "plugin1", overrideFunctions: true, overrideApis: false, overrideConfig: false }, + ], expectedFunctionOrder: ["override", "plugin1", "original"], expectedApiOrder: ["original"], + expectedConfigOrder: ["original"], }, { overrideFunctions: true, overrideApis: false, - pluginFactortyConfigs: [{ identifier: "plugin1", overrideFunctions: false, overrideApis: true }], + overrideConfig: false, + pluginFactortyConfigs: [ + { identifier: "plugin1", overrideFunctions: false, overrideApis: true, overrideConfig: false }, + ], expectedFunctionOrder: ["override", "original"], expectedApiOrder: ["plugin1", "original"], + expectedConfigOrder: ["original"], }, { overrideFunctions: false, overrideApis: true, - pluginFactortyConfigs: [{ identifier: "plugin1", overrideFunctions: true, overrideApis: false }], + overrideConfig: false, + pluginFactortyConfigs: [ + { identifier: "plugin1", overrideFunctions: true, overrideApis: false, overrideConfig: false }, + ], expectedFunctionOrder: ["plugin1", "original"], expectedApiOrder: ["override", "original"], + expectedConfigOrder: ["original"], }, { overrideFunctions: false, overrideApis: true, - pluginFactortyConfigs: [{ identifier: "plugin1", overrideFunctions: false, overrideApis: true }], + overrideConfig: false, + pluginFactortyConfigs: [ + { identifier: "plugin1", overrideFunctions: false, overrideApis: true, overrideConfig: false }, + ], expectedFunctionOrder: ["original"], expectedApiOrder: ["override", "plugin1", "original"], + expectedConfigOrder: ["original"], + }, + { + overrideFunctions: false, + overrideApis: false, + overrideConfig: true, + pluginFactortyConfigs: [ + { identifier: "plugin1", overrideFunctions: false, overrideApis: true, overrideConfig: false }, + ], + expectedFunctionOrder: ["original"], + expectedApiOrder: ["plugin1", "original"], + expectedConfigOrder: ["override"], + }, + { + overrideFunctions: false, + overrideApis: false, + overrideConfig: true, + pluginFactortyConfigs: [ + { identifier: "plugin1", overrideFunctions: false, overrideApis: true, overrideConfig: true }, + ], + expectedFunctionOrder: ["original"], + expectedApiOrder: ["plugin1", "original"], + expectedConfigOrder: ["override", "plugin1"], }, // Multiple plugins with overrides { overrideFunctions: true, overrideApis: false, + overrideConfig: false, pluginFactortyConfigs: [ - { identifier: "plugin1", overrideFunctions: true, overrideApis: false }, - { identifier: "plugin2", overrideFunctions: true, overrideApis: false }, + { identifier: "plugin1", overrideFunctions: true, overrideApis: false, overrideConfig: true }, + { identifier: "plugin2", overrideFunctions: true, overrideApis: false, overrideConfig: false }, ], expectedFunctionOrder: ["override", "plugin2", "plugin1", "original"], expectedApiOrder: ["original"], + expectedConfigOrder: ["original", "plugin1"], }, { overrideFunctions: false, overrideApis: true, + overrideConfig: false, pluginFactortyConfigs: [ - { identifier: "plugin1", overrideFunctions: false, overrideApis: true }, - { identifier: "plugin2", overrideFunctions: false, overrideApis: true }, + { identifier: "plugin1", overrideFunctions: false, overrideApis: true, overrideConfig: false }, + { identifier: "plugin2", overrideFunctions: false, overrideApis: true, overrideConfig: true }, ], expectedFunctionOrder: ["original"], expectedApiOrder: ["override", "plugin2", "plugin1", "original"], + expectedConfigOrder: ["original", "plugin2"], }, // Multiple plugins, all overrides { overrideFunctions: true, overrideApis: true, + overrideConfig: true, pluginFactortyConfigs: [ - { identifier: "plugin1", overrideFunctions: true, overrideApis: true }, - { identifier: "plugin2", overrideFunctions: true, overrideApis: true }, + { identifier: "plugin1", overrideFunctions: true, overrideApis: true, overrideConfig: true }, + { identifier: "plugin2", overrideFunctions: true, overrideApis: true, overrideConfig: true }, ], expectedFunctionOrder: ["override", "plugin2", "plugin1", "original"], expectedApiOrder: ["override", "plugin2", "plugin1", "original"], + expectedConfigOrder: ["override", "plugin1", "plugin2"], }, ]; overrideTestParams.forEach( - ({ overrideFunctions, overrideApis, pluginFactortyConfigs, expectedFunctionOrder, expectedApiOrder }) => { + ( + { + overrideFunctions, + overrideApis, + overrideConfig, + pluginFactortyConfigs, + expectedFunctionOrder, + expectedApiOrder, + expectedConfigOrder, + }, + testNo, + ) => { const plugins = pluginFactortyConfigs.map((pfc) => pluginFactory(pfc)); const testNameList = [ - `fnOverride=${overrideFunctions}`, + `${testNo}. fnOverride=${overrideFunctions}`, `apiOverride=${overrideApis}`, + `configOverride=${overrideConfig}`, `plugins=[${plugins.map((p) => p.id).join(",")}]`, ...pluginFactortyConfigs.map((pfc) => { const overrideList: string[] = []; @@ -156,6 +250,9 @@ describe("Plugins", () => { if (pfc.overrideApis) { overrideList.push("api"); } + if (pfc.overrideConfig) { + overrideList.push("config"); + } return `${pfc.identifier}=[${overrideList.join(",")}]`; }), ]; @@ -165,7 +262,11 @@ describe("Plugins", () => { STExpress.init({ ...partialSupertokensConfig, recipeList: [ - recipeFactory({ overrideFunctions: overrideFunctions, overrideApis: overrideApis }), + recipeFactory({ + overrideFunctions: overrideFunctions, + overrideApis: overrideApis, + overrideConfig: overrideConfig, + }), ], experimental: { plugins, @@ -175,13 +276,15 @@ describe("Plugins", () => { const recipe = PluginTestRecipe.getInstanceOrThrowError(); const recipeOutput = recipe.recipeInterfaceImpl.signIn("msg", []); const apiOutput = recipe.apiImpl.signInPOST("msg", []); + const configOutput = recipe.configImpl; assert.deepEqual(recipeOutput.stack, expectedFunctionOrder); assert.deepEqual(apiOutput.stack, expectedApiOrder); assert.deepEqual(recipeOutput.message, "msg"); assert.deepEqual(apiOutput.message, "msg"); + assert.deepEqual(configOutput.testProperty, expectedConfigOrder); }); - } + }, ); }); @@ -190,6 +293,7 @@ describe("Plugins", () => { plugins: SuperTokensPlugin[]; expectedFnOrder: string[]; expectedApiOrder: string[]; + expectedConfigOrder: string[]; expectedInitOrder: string[]; testName: string; }[] = [ @@ -197,6 +301,7 @@ describe("Plugins", () => { plugins: [Plugin1, Plugin1], expectedFnOrder: ["plugin1", "original"], expectedApiOrder: ["original"], + expectedConfigOrder: ["original", "plugin1"], expectedInitOrder: ["plugin1"], testName: "1,1 => 1", }, @@ -204,6 +309,7 @@ describe("Plugins", () => { plugins: [Plugin1, Plugin2], expectedFnOrder: ["plugin2", "plugin1", "original"], expectedApiOrder: ["original"], + expectedConfigOrder: ["original", "plugin1", "plugin2"], expectedInitOrder: ["plugin1", "plugin2"], testName: "1,2 => 2,1", }, @@ -211,6 +317,7 @@ describe("Plugins", () => { plugins: [Plugin3Dep1], expectedFnOrder: ["plugin3dep1", "plugin1", "original"], expectedApiOrder: ["original"], + expectedConfigOrder: ["original", "plugin1", "plugin3dep1"], expectedInitOrder: ["plugin1", "plugin3dep1"], testName: "3->1 => 3,1", }, @@ -218,6 +325,7 @@ describe("Plugins", () => { plugins: [Plugin3Dep2_1], expectedFnOrder: ["plugin3dep2_1", "plugin1", "plugin2", "original"], expectedApiOrder: ["original"], + expectedConfigOrder: ["original", "plugin2", "plugin1", "plugin3dep2_1"], expectedInitOrder: ["plugin2", "plugin1", "plugin3dep2_1"], testName: "3->(2,1) => 3,2,1", }, @@ -225,6 +333,7 @@ describe("Plugins", () => { plugins: [Plugin3Dep1, Plugin4Dep2], expectedFnOrder: ["plugin4dep2", "plugin2", "plugin3dep1", "plugin1", "original"], expectedApiOrder: ["original"], + expectedConfigOrder: ["original", "plugin1", "plugin3dep1", "plugin2", "plugin4dep2"], expectedInitOrder: ["plugin1", "plugin3dep1", "plugin2", "plugin4dep2"], testName: "3->1,4->2 => 4,2,3,1", }, @@ -232,6 +341,7 @@ describe("Plugins", () => { plugins: [Plugin4Dep3__2_1], expectedFnOrder: ["plugin4dep3__2_1", "plugin3dep2_1", "plugin1", "plugin2", "original"], expectedApiOrder: ["original"], + expectedConfigOrder: ["original", "plugin2", "plugin1", "plugin3dep2_1", "plugin4dep3__2_1"], expectedInitOrder: ["plugin2", "plugin1", "plugin3dep2_1", "plugin4dep3__2_1"], testName: "4->3->(2,1) => 4,3,1,2", }, @@ -239,55 +349,66 @@ describe("Plugins", () => { plugins: [Plugin3Dep1, Plugin4Dep1], expectedFnOrder: ["plugin4dep1", "plugin3dep1", "plugin1", "original"], expectedApiOrder: ["original"], + expectedConfigOrder: ["original", "plugin1", "plugin3dep1", "plugin4dep1"], expectedInitOrder: ["plugin1", "plugin3dep1", "plugin4dep1"], testName: "3->1,4->1 => 4,3,1", }, ]; - dependencyTestParams.forEach(({ plugins, expectedFnOrder, expectedApiOrder, expectedInitOrder, testName }) => { - it(testName, () => { - STExpress.init({ - ...partialSupertokensConfig, - recipeList: [recipeFactory({ overrideFunctions: false, overrideApis: false })], - experimental: { - plugins, - }, - }); + dependencyTestParams.forEach( + ({ plugins, expectedFnOrder, expectedApiOrder, expectedConfigOrder, expectedInitOrder, testName }) => { + it(testName, () => { + STExpress.init({ + ...partialSupertokensConfig, + recipeList: [ + recipeFactory({ overrideFunctions: false, overrideApis: false, overrideConfig: false }), + ], + experimental: { + plugins, + }, + }); - const recipe = PluginTestRecipe.getInstanceOrThrowError(); - const recipeOutput = recipe.recipeInterfaceImpl.signIn("msg", []); - const apiOutput = recipe.apiImpl.signInPOST("msg", []); + const recipe = PluginTestRecipe.getInstanceOrThrowError(); + const recipeOutput = recipe.recipeInterfaceImpl.signIn("msg", []); + const apiOutput = recipe.apiImpl.signInPOST("msg", []); + const configOutput = recipe.configImpl; - assert.deepEqual(recipeOutput.stack, expectedFnOrder); - assert.deepEqual(apiOutput.stack, expectedApiOrder); - assert.deepEqual(PluginTestRecipe.initCalls, expectedInitOrder); - assert.deepEqual(recipeOutput.message, "msg"); - assert.deepEqual(apiOutput.message, "msg"); - }); - }); + assert.deepEqual(recipeOutput.stack, expectedFnOrder); + assert.deepEqual(apiOutput.stack, expectedApiOrder); + assert.deepEqual(PluginTestRecipe.initCalls, expectedInitOrder); + assert.deepEqual(recipeOutput.message, "msg"); + assert.deepEqual(apiOutput.message, "msg"); + assert.deepEqual(configOutput.testProperty, expectedConfigOrder); + }); + }, + ); }); describe("Config Overrides", () => { - it("override public property", () => { + it("override public property should not be applied", () => { const plugin = pluginFactory({ identifier: "plugin1", overrideFunctions: false, overrideApis: false, + overrideConfig: false, }); - plugin.config = (oC: SuperTokensPublicConfig) => ({ - ...oC, - appInfo: { ...oC.appInfo, appName: "override" }, - }); + plugin.config = (oC: SuperTokensPublicConfig) => { + const newoc = { + ...oC, + appInfo: { ...oC.appInfo, appName: "override" }, + }; + return newoc; + }; STExpress.init({ ...partialSupertokensConfig, - recipeList: [recipeFactory({ overrideFunctions: false, overrideApis: false })], + recipeList: [recipeFactory({ overrideFunctions: false, overrideApis: false, overrideConfig: false })], experimental: { plugins: [plugin], }, }); - assert.strictEqual(SuperTokens.getInstanceOrThrowError().appInfo.appName, "override"); + assert.strictEqual(SuperTokens.getInstanceOrThrowError().appInfo.appName, "pluginsTest"); }); it("override non-public property", () => { @@ -295,18 +416,25 @@ describe("Plugins", () => { identifier: "plugin1", overrideFunctions: false, overrideApis: false, + overrideConfig: false, }); - plugin.config = (oC: SuperTokensPublicConfig) => ({ ...oC, recipeList: [] }); + plugin.config = (oC: SuperTokensPublicConfig) => ({ ...oC, recipeList: [], experimental: {} }); + const loadPluginsSpy = sinon.spy(plugins, "loadPlugins"); STExpress.init({ ...partialSupertokensConfig, - recipeList: [recipeFactory({ overrideFunctions: false, overrideApis: false })], + recipeList: [recipeFactory({ overrideFunctions: false, overrideApis: false, overrideConfig: false })], experimental: { plugins: [plugin], }, }); + assert.equal(loadPluginsSpy.callCount, 1); + assert.notDeepEqual(loadPluginsSpy.returnValues[0].config.experimental, {}); + assert.notDeepEqual(SuperTokens.getInstanceOrThrowError().recipeModules, []); + + loadPluginsSpy.restore(); }); }); @@ -326,12 +454,13 @@ describe("Plugins", () => { identifier: "plugin1", overrideFunctions: false, overrideApis: false, + overrideConfig: false, }); plugin.routeHandlers = [routeHandler]; STExpress.init({ ...partialSupertokensConfig, - recipeList: [recipeFactory({ overrideFunctions: false, overrideApis: false })], + recipeList: [recipeFactory({ overrideFunctions: false, overrideApis: false, overrideConfig: false })], experimental: { plugins: [plugin], }, @@ -351,12 +480,15 @@ describe("Plugins", () => { identifier: "plugin1", overrideFunctions: false, overrideApis: false, + overrideConfig: false, }); plugin.routeHandlers = () => ({ status: "OK", routeHandlers: [routeHandler] }); STExpress.init({ ...partialSupertokensConfig, - recipeList: [recipeFactory({ overrideFunctions: false, overrideApis: false })], + recipeList: [ + recipeFactory({ overrideFunctions: false, overrideApis: false, overrideConfig: false }), + ], experimental: { plugins: [plugin], }, @@ -376,12 +508,15 @@ describe("Plugins", () => { identifier: "plugin1", overrideFunctions: false, overrideApis: false, + overrideConfig: false, }); plugin.routeHandlers = () => ({ status: "ERROR", message: "error" }); STExpress.init({ ...partialSupertokensConfig, - recipeList: [recipeFactory({ overrideFunctions: false, overrideApis: false })], + recipeList: [ + recipeFactory({ overrideFunctions: false, overrideApis: false, overrideConfig: false }), + ], experimental: { plugins: [plugin], }, diff --git a/test/plugins/plugins.ts b/test/plugins/plugins.ts index 352dcba90..fcac398c8 100644 --- a/test/plugins/plugins.ts +++ b/test/plugins/plugins.ts @@ -23,6 +23,15 @@ export function apiOverrideFactory(identifier: string) { }; } +export function configOverrideFactory(identifier: string) { + return function override(originalConfig) { + return { + ...originalConfig, + testProperty: [...(originalConfig.testProperty || []), identifier], + }; + }; +} + export function initFactory(identifier: string) { return function init(config: SuperTokensPublicConfig, pluginsAbove: SuperTokensPublicPlugin[], sdkVersion: string) { PluginTestRecipe.initCalls.push(identifier); @@ -37,7 +46,7 @@ export function dependencyFactory(dependencies?: SuperTokensPlugin[]) { return function dependency( config: SuperTokensPublicConfig, pluginsAbove: SuperTokensPublicPlugin[], - sdkVersion: string, + sdkVersion: string ): { status: "OK"; pluginsToAdd?: SuperTokensPlugin[] } | { status: "ERROR"; message: string } { const addedPluginIds: string[] = pluginsAbove.map((p) => p.id); const pluginsToAdd: SuperTokensPlugin[] = dependencies!.filter((p) => !addedPluginIds.includes(p.id)); @@ -52,12 +61,14 @@ export function pluginFactory({ identifier, overrideFunctions = false, overrideApis = false, + overrideConfig = false, dependencies, addInit = false, }: { identifier: string; overrideFunctions: boolean; overrideApis: boolean; + overrideConfig: boolean; dependencies?: SuperTokensPlugin[]; addInit?: boolean; }): SuperTokensPlugin { @@ -75,6 +86,10 @@ export function pluginFactory({ overrideMap[PluginTestRecipe.RECIPE_ID].apis = apiOverrideFactory(identifier); } + if (overrideConfig) { + overrideMap[PluginTestRecipe.RECIPE_ID].config = configOverrideFactory(identifier); + } + return { id: identifier, compatibleSDKVersions: ["23.0.x"], @@ -88,18 +103,21 @@ export const Plugin1 = pluginFactory({ identifier: "plugin1", overrideFunctions: true, overrideApis: false, + overrideConfig: true, addInit: true, }); export const Plugin2 = pluginFactory({ identifier: "plugin2", overrideFunctions: true, overrideApis: false, + overrideConfig: true, addInit: true, }); export const Plugin3Dep1 = pluginFactory({ identifier: "plugin3dep1", overrideFunctions: true, overrideApis: false, + overrideConfig: true, dependencies: [Plugin1], addInit: true, }); @@ -107,6 +125,7 @@ export const Plugin3Dep2_1 = pluginFactory({ identifier: "plugin3dep2_1", overrideFunctions: true, overrideApis: false, + overrideConfig: true, dependencies: [Plugin2, Plugin1], addInit: true, }); @@ -114,6 +133,7 @@ export const Plugin4Dep1 = pluginFactory({ identifier: "plugin4dep1", overrideFunctions: true, overrideApis: false, + overrideConfig: true, dependencies: [Plugin1], addInit: true, }); @@ -121,6 +141,7 @@ export const Plugin4Dep2 = pluginFactory({ identifier: "plugin4dep2", overrideFunctions: true, overrideApis: false, + overrideConfig: true, dependencies: [Plugin2], addInit: true, }); @@ -128,6 +149,7 @@ export const Plugin4Dep3__2_1 = pluginFactory({ identifier: "plugin4dep3__2_1", overrideFunctions: true, overrideApis: false, + overrideConfig: true, dependencies: [Plugin3Dep2_1], addInit: true, }); diff --git a/test/plugins/recipe.ts b/test/plugins/recipe.ts index 2f1e194eb..6255cabe4 100644 --- a/test/plugins/recipe.ts +++ b/test/plugins/recipe.ts @@ -9,6 +9,7 @@ export function validateAndNormalizeUserInput(appInfo, config) { let override = { functions: (originalImplementation) => originalImplementation, apis: (originalImplementation) => originalImplementation, + config: (originalConfig) => originalConfig, ...config?.override, }; @@ -22,6 +23,8 @@ export default class Recipe extends RecipeModule { config; + configImpl; + recipeInterfaceImpl; apiImpl; @@ -40,6 +43,9 @@ export default class Recipe extends RecipeModule { let builder = new OverrideableBuilder(getAPIImplementation()); this.apiImpl = builder.override(this.config.override.apis).build(); } + { + this.configImpl = this.config.override.config(config); + } } static getInstanceOrThrowError() { diff --git a/test/plugins/types.ts b/test/plugins/types.ts index 1a671fede..0f8714b10 100644 --- a/test/plugins/types.ts +++ b/test/plugins/types.ts @@ -15,6 +15,10 @@ export type RecipeInterface = { signIn: (message: string, stack: string[]) => RecipeReturnType<"Recipe">; }; +export type ConfigInterface = { + testProperty: string[]; +}; + export type PluginTestConfig = { override?: { functions?: ( @@ -22,6 +26,7 @@ export type PluginTestConfig = { builder?: OverrideableBuilder ) => RecipeInterface; apis?: (originalImplementation: APIInterface, builder?: OverrideableBuilder) => APIInterface; + config?: (originalConfig: ConfigInterface) => ConfigInterface; }; }; @@ -32,5 +37,6 @@ export type NormalizedPluginTestConfig = { builder?: OverrideableBuilder ) => RecipeInterface; apis: (originalImplementation: APIInterface, builder?: OverrideableBuilder) => APIInterface; + config: (originalConfig: ConfigInterface) => ConfigInterface; }; }; From 541a81d1e53937f14af3d727b42de95c6a7f86b7 Mon Sep 17 00:00:00 2001 From: Victor Bojica Date: Thu, 7 Aug 2025 15:36:39 +0300 Subject: [PATCH 08/12] chore: typo fix --- test/plugins/plugins.test.ts | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/test/plugins/plugins.test.ts b/test/plugins/plugins.test.ts index 4a0b37bf9..e8ca19c84 100644 --- a/test/plugins/plugins.test.ts +++ b/test/plugins/plugins.test.ts @@ -68,7 +68,7 @@ describe("Plugins", () => { overrideFunctions: boolean; overrideApis: boolean; overrideConfig: boolean; - pluginFactortyConfigs: { + pluginFactoryConfigs: { identifier: string; overrideFunctions: boolean; overrideApis: boolean; @@ -83,7 +83,7 @@ describe("Plugins", () => { overrideFunctions: false, overrideApis: false, overrideConfig: false, - pluginFactortyConfigs: [], + pluginFactoryConfigs: [], expectedFunctionOrder: ["original"], expectedApiOrder: ["original"], expectedConfigOrder: ["original"], @@ -92,7 +92,7 @@ describe("Plugins", () => { overrideFunctions: true, overrideApis: false, overrideConfig: false, - pluginFactortyConfigs: [], + pluginFactoryConfigs: [], expectedFunctionOrder: ["override", "original"], expectedApiOrder: ["original"], expectedConfigOrder: ["original"], @@ -101,7 +101,7 @@ describe("Plugins", () => { overrideFunctions: false, overrideApis: true, overrideConfig: false, - pluginFactortyConfigs: [], + pluginFactoryConfigs: [], expectedFunctionOrder: ["original"], expectedApiOrder: ["override", "original"], expectedConfigOrder: ["original"], @@ -110,7 +110,7 @@ describe("Plugins", () => { overrideFunctions: false, overrideApis: false, overrideConfig: true, - pluginFactortyConfigs: [], + pluginFactoryConfigs: [], expectedFunctionOrder: ["original"], expectedApiOrder: ["original"], expectedConfigOrder: ["override"], @@ -120,7 +120,7 @@ describe("Plugins", () => { overrideFunctions: true, overrideApis: false, overrideConfig: false, - pluginFactortyConfigs: [ + pluginFactoryConfigs: [ { identifier: "plugin1", overrideFunctions: true, overrideApis: false, overrideConfig: false }, ], expectedFunctionOrder: ["override", "plugin1", "original"], @@ -131,7 +131,7 @@ describe("Plugins", () => { overrideFunctions: true, overrideApis: false, overrideConfig: false, - pluginFactortyConfigs: [ + pluginFactoryConfigs: [ { identifier: "plugin1", overrideFunctions: false, overrideApis: true, overrideConfig: false }, ], expectedFunctionOrder: ["override", "original"], @@ -142,7 +142,7 @@ describe("Plugins", () => { overrideFunctions: false, overrideApis: true, overrideConfig: false, - pluginFactortyConfigs: [ + pluginFactoryConfigs: [ { identifier: "plugin1", overrideFunctions: true, overrideApis: false, overrideConfig: false }, ], expectedFunctionOrder: ["plugin1", "original"], @@ -153,7 +153,7 @@ describe("Plugins", () => { overrideFunctions: false, overrideApis: true, overrideConfig: false, - pluginFactortyConfigs: [ + pluginFactoryConfigs: [ { identifier: "plugin1", overrideFunctions: false, overrideApis: true, overrideConfig: false }, ], expectedFunctionOrder: ["original"], @@ -164,7 +164,7 @@ describe("Plugins", () => { overrideFunctions: false, overrideApis: false, overrideConfig: true, - pluginFactortyConfigs: [ + pluginFactoryConfigs: [ { identifier: "plugin1", overrideFunctions: false, overrideApis: true, overrideConfig: false }, ], expectedFunctionOrder: ["original"], @@ -175,7 +175,7 @@ describe("Plugins", () => { overrideFunctions: false, overrideApis: false, overrideConfig: true, - pluginFactortyConfigs: [ + pluginFactoryConfigs: [ { identifier: "plugin1", overrideFunctions: false, overrideApis: true, overrideConfig: true }, ], expectedFunctionOrder: ["original"], @@ -187,7 +187,7 @@ describe("Plugins", () => { overrideFunctions: true, overrideApis: false, overrideConfig: false, - pluginFactortyConfigs: [ + pluginFactoryConfigs: [ { identifier: "plugin1", overrideFunctions: true, overrideApis: false, overrideConfig: true }, { identifier: "plugin2", overrideFunctions: true, overrideApis: false, overrideConfig: false }, ], @@ -199,7 +199,7 @@ describe("Plugins", () => { overrideFunctions: false, overrideApis: true, overrideConfig: false, - pluginFactortyConfigs: [ + pluginFactoryConfigs: [ { identifier: "plugin1", overrideFunctions: false, overrideApis: true, overrideConfig: false }, { identifier: "plugin2", overrideFunctions: false, overrideApis: true, overrideConfig: true }, ], @@ -212,7 +212,7 @@ describe("Plugins", () => { overrideFunctions: true, overrideApis: true, overrideConfig: true, - pluginFactortyConfigs: [ + pluginFactoryConfigs: [ { identifier: "plugin1", overrideFunctions: true, overrideApis: true, overrideConfig: true }, { identifier: "plugin2", overrideFunctions: true, overrideApis: true, overrideConfig: true }, ], @@ -228,21 +228,21 @@ describe("Plugins", () => { overrideFunctions, overrideApis, overrideConfig, - pluginFactortyConfigs, + pluginFactoryConfigs, expectedFunctionOrder, expectedApiOrder, expectedConfigOrder, }, testNo, ) => { - const plugins = pluginFactortyConfigs.map((pfc) => pluginFactory(pfc)); + const plugins = pluginFactoryConfigs.map((pfc) => pluginFactory(pfc)); const testNameList = [ `${testNo}. fnOverride=${overrideFunctions}`, `apiOverride=${overrideApis}`, `configOverride=${overrideConfig}`, `plugins=[${plugins.map((p) => p.id).join(",")}]`, - ...pluginFactortyConfigs.map((pfc) => { + ...pluginFactoryConfigs.map((pfc) => { const overrideList: string[] = []; if (pfc.overrideFunctions) { overrideList.push("fn"); From 93ca2e5665ab9d03729de448be8099dc2f6df26e Mon Sep 17 00:00:00 2001 From: Victor Bojica Date: Wed, 22 Oct 2025 19:16:44 +0300 Subject: [PATCH 09/12] improve error handling --- lib/build/error.d.ts | 14 +++---- lib/build/error.js | 32 ++++++++++++---- lib/build/index.d.ts | 4 +- lib/build/index.js | 57 +++++++++++++++++++++++++++- lib/build/supertokens.js | 81 ++++++++++++++++++++++++++++++++-------- lib/ts/error.ts | 38 ++++++++++++------- lib/ts/index.ts | 5 ++- lib/ts/supertokens.ts | 32 ++++++++-------- 8 files changed, 200 insertions(+), 63 deletions(-) diff --git a/lib/build/error.d.ts b/lib/build/error.d.ts index 3a43dd5d3..f0ad2511c 100644 --- a/lib/build/error.d.ts +++ b/lib/build/error.d.ts @@ -2,6 +2,7 @@ export default class SuperTokensError extends Error { private static errMagic; static BAD_INPUT_ERROR: "BAD_INPUT_ERROR"; + static UNKNOWN_ERROR: "UNKNOWN_ERROR"; static PLUGIN_ERROR: "PLUGIN_ERROR"; type: string; payload: any; @@ -19,12 +20,11 @@ export default class SuperTokensError extends Error { type: "BAD_INPUT_ERROR"; payload: undefined; } - | { - message: string; - type: "PLUGIN_ERROR"; - payload: undefined; - } ); - static isErrorFromSuperTokens(obj: any): obj is SuperTokensError; - static fromError(err: Error, type: string): SuperTokensError; + static isErrorFromSuperTokens(obj: any): obj is SuperTokensError | SuperTokensPluginError; +} +export declare class SuperTokensPluginError extends SuperTokensError { + code: number; + constructor(options: { message: string; payload?: any; code?: number }); } +export declare const transformErrorToSuperTokensError: (err: any) => SuperTokensError; diff --git a/lib/build/error.js b/lib/build/error.js index 02ba34c23..53290eea6 100644 --- a/lib/build/error.js +++ b/lib/build/error.js @@ -14,6 +14,8 @@ * under the License. */ Object.defineProperty(exports, "__esModule", { value: true }); +exports.transformErrorToSuperTokensError = exports.SuperTokensPluginError = void 0; +const logger_1 = require("./logger"); class SuperTokensError extends Error { constructor(options) { super(options.message); @@ -24,16 +26,30 @@ class SuperTokensError extends Error { static isErrorFromSuperTokens(obj) { return obj.errMagic === SuperTokensError.errMagic; } - static fromError(err, type) { - const newError = new SuperTokensError({ - message: err.message, - type, - }); - newError.stack = err.stack; - return newError; - } } SuperTokensError.errMagic = "ndskajfasndlfkj435234krjdsa"; SuperTokensError.BAD_INPUT_ERROR = "BAD_INPUT_ERROR"; +SuperTokensError.UNKNOWN_ERROR = "UNKNOWN_ERROR"; SuperTokensError.PLUGIN_ERROR = "PLUGIN_ERROR"; exports.default = SuperTokensError; +class SuperTokensPluginError extends SuperTokensError { + constructor(options) { + super(Object.assign(Object.assign({}, options), { type: SuperTokensError.PLUGIN_ERROR })); + this.code = options.code || 400; + } +} +exports.SuperTokensPluginError = SuperTokensPluginError; +const transformErrorToSuperTokensError = (err) => { + // passthrough for errors from SuperTokens - let errorHandler handle them + if (SuperTokensError.isErrorFromSuperTokens(err)) { + return err; + } + (0, logger_1.logDebugMessage)( + `transformErrorToSuperTokensError: Transforming error to SuperTokensError. Error: ${ + err === null || err === void 0 ? void 0 : err.message + }.\nStack:\n${err === null || err === void 0 ? void 0 : err.stack}` + ); + // mask the original stack trace by not copying it on the new error + return new SuperTokensError({ message: "Unknown error", type: SuperTokensError.UNKNOWN_ERROR }); +}; +exports.transformErrorToSuperTokensError = transformErrorToSuperTokensError; diff --git a/lib/build/index.d.ts b/lib/build/index.d.ts index b9c5277a1..e2bd3ebee 100644 --- a/lib/build/index.d.ts +++ b/lib/build/index.d.ts @@ -1,6 +1,6 @@ // @ts-nocheck import SuperTokens from "./supertokens"; -import SuperTokensError from "./error"; +import SuperTokensError, { SuperTokensPluginError } from "./error"; import { UserContext, User as UserType } from "./types"; import { AccountInfoInput } from "./recipe/accountlinking/types"; import RecipeUserId from "./recipeUserId"; @@ -15,6 +15,7 @@ export type { export default class SuperTokensWrapper { static init: typeof SuperTokens.init; static Error: typeof SuperTokensError; + static PluginError: typeof SuperTokensPluginError; static RecipeUserId: typeof RecipeUserId; static User: typeof User; static getAllCORSHeaders(): string[]; @@ -139,5 +140,6 @@ export declare let getRequestFromUserContext: typeof SuperTokensWrapper.getReque export declare let isRecipeInitialized: typeof SuperTokensWrapper.isRecipeInitialized; export declare let getAvailableFirstFactors: typeof SuperTokensWrapper.getAvailableFirstFactors; export declare let Error: typeof SuperTokensError; +export declare let PluginError: typeof SuperTokensPluginError; export { default as RecipeUserId } from "./recipeUserId"; export { User } from "./user"; diff --git a/lib/build/index.js b/lib/build/index.js index f3469d260..fb496bec9 100644 --- a/lib/build/index.js +++ b/lib/build/index.js @@ -13,6 +13,58 @@ * License for the specific language governing permissions and limitations * under the License. */ +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { + enumerable: true, + get: function () { + return m[k]; + }, + }; + } + Object.defineProperty(o, k2, desc); + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); +var __setModuleDefault = + (this && this.__setModuleDefault) || + (Object.create + ? function (o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); + } + : function (o, v) { + o["default"] = v; + }); +var __importStar = + (this && this.__importStar) || + (function () { + var ownKeys = function (o) { + ownKeys = + Object.getOwnPropertyNames || + function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) + for (var k = ownKeys(mod), i = 0; i < k.length; i++) + if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; + })(); var __importDefault = (this && this.__importDefault) || function (mod) { @@ -21,6 +73,7 @@ var __importDefault = Object.defineProperty(exports, "__esModule", { value: true }); exports.User = exports.RecipeUserId = + exports.PluginError = exports.Error = exports.getAvailableFirstFactors = exports.isRecipeInitialized = @@ -40,7 +93,7 @@ exports.User = exports.init = void 0; const supertokens_1 = __importDefault(require("./supertokens")); -const error_1 = __importDefault(require("./error")); +const error_1 = __importStar(require("./error")); const recipe_1 = __importDefault(require("./recipe/accountlinking/recipe")); const recipeUserId_1 = __importDefault(require("./recipeUserId")); const user_1 = require("./user"); @@ -154,6 +207,7 @@ class SuperTokensWrapper { } SuperTokensWrapper.init = supertokens_1.default.init; SuperTokensWrapper.Error = error_1.default; +SuperTokensWrapper.PluginError = error_1.SuperTokensPluginError; SuperTokensWrapper.RecipeUserId = recipeUserId_1.default; SuperTokensWrapper.User = user_1.User; exports.default = SuperTokensWrapper; @@ -174,6 +228,7 @@ exports.getRequestFromUserContext = SuperTokensWrapper.getRequestFromUserContext exports.isRecipeInitialized = SuperTokensWrapper.isRecipeInitialized; exports.getAvailableFirstFactors = SuperTokensWrapper.getAvailableFirstFactors; exports.Error = SuperTokensWrapper.Error; +exports.PluginError = SuperTokensWrapper.PluginError; var recipeUserId_2 = require("./recipeUserId"); Object.defineProperty(exports, "RecipeUserId", { enumerable: true, diff --git a/lib/build/supertokens.js b/lib/build/supertokens.js index 7f423c996..a1a2cf4a6 100644 --- a/lib/build/supertokens.js +++ b/lib/build/supertokens.js @@ -13,6 +13,58 @@ * License for the specific language governing permissions and limitations * under the License. */ +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { + enumerable: true, + get: function () { + return m[k]; + }, + }; + } + Object.defineProperty(o, k2, desc); + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); +var __setModuleDefault = + (this && this.__setModuleDefault) || + (Object.create + ? function (o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); + } + : function (o, v) { + o["default"] = v; + }); +var __importStar = + (this && this.__importStar) || + (function () { + var ownKeys = function (o) { + ownKeys = + Object.getOwnPropertyNames || + function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) + for (var k = ownKeys(mod), i = 0; i < k.length; i++) + if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; + })(); var __importDefault = (this && this.__importDefault) || function (mod) { @@ -25,12 +77,11 @@ const querier_1 = require("./querier"); const constants_1 = require("./constants"); const normalisedURLDomain_1 = __importDefault(require("./normalisedURLDomain")); const normalisedURLPath_1 = __importDefault(require("./normalisedURLPath")); -const error_1 = __importDefault(require("./error")); +const error_1 = __importStar(require("./error")); const logger_1 = require("./logger"); const postSuperTokensInitCallbacks_1 = require("./postSuperTokensInitCallbacks"); const constants_2 = require("./recipe/multitenancy/constants"); const recipe_1 = __importDefault(require("./recipe/session/recipe")); -const error_2 = __importDefault(require("./error")); class SuperTokens { constructor(config) { var _a, _b, _c, _d, _e, _f; @@ -170,17 +221,12 @@ class SuperTokens { try { await handlerFromApis.handler(request, response, session, userContext); } catch (err) { - // passthrough for errors from SuperTokens - let errorHandler handle them - if (error_2.default.isErrorFromSuperTokens(err)) { - throw err; - } else { - (0, logger_1.logDebugMessage)( - "middleware: Error from plugin, transforming to SuperTokensError. Plugin ID: " + - handlerFromApis.pluginId - ); - // transform errors to SuperTokensError to be handled by the errorHandler - throw error_2.default.fromError(err, error_2.default.PLUGIN_ERROR); - } + (0, logger_1.logDebugMessage)( + "middleware: Error from plugin, transforming to SuperTokensError. Plugin ID: " + + handlerFromApis.pluginId + ); + // transform errors to SuperTokensError to be handled by the errorHandler + throw (0, error_1.transformErrorToSuperTokensError)(err); } return true; } @@ -344,8 +390,13 @@ class SuperTokens { return (0, utils_1.sendNon200ResponseWithMessage)(response, err.message, 400); } if (err.type === error_1.default.PLUGIN_ERROR) { - (0, logger_1.logDebugMessage)("errorHandler: Sending 400 status code response"); - return (0, utils_1.sendNon200ResponseWithMessage)(response, err.message, 400); + const code = "code" in err && err.code ? err.code : 400; + (0, logger_1.logDebugMessage)(`errorHandler: Sending ${code} status code response`); + return (0, utils_1.sendNon200ResponseWithMessage)(response, err.message, code); + } + if (err.type === error_1.default.UNKNOWN_ERROR) { + (0, logger_1.logDebugMessage)("errorHandler: Sending 500 status code response"); + return (0, utils_1.sendNon200ResponseWithMessage)(response, err.message, 500); } for (let i = 0; i < this.recipeModules.length; i++) { (0, logger_1.logDebugMessage)( diff --git a/lib/ts/error.ts b/lib/ts/error.ts index 557d7e1d0..cead82971 100644 --- a/lib/ts/error.ts +++ b/lib/ts/error.ts @@ -13,9 +13,13 @@ * under the License. */ +import { logDebugMessage } from "./logger"; + export default class SuperTokensError extends Error { private static errMagic = "ndskajfasndlfkj435234krjdsa"; + static BAD_INPUT_ERROR: "BAD_INPUT_ERROR" = "BAD_INPUT_ERROR"; + static UNKNOWN_ERROR: "UNKNOWN_ERROR" = "UNKNOWN_ERROR"; static PLUGIN_ERROR: "PLUGIN_ERROR" = "PLUGIN_ERROR"; public type: string; @@ -43,11 +47,6 @@ export default class SuperTokensError extends Error { type: "BAD_INPUT_ERROR"; payload: undefined; } - | { - message: string; - type: "PLUGIN_ERROR"; - payload: undefined; - } ) { super(options.message); this.type = options.type; @@ -55,18 +54,29 @@ export default class SuperTokensError extends Error { this.errMagic = SuperTokensError.errMagic; } - static isErrorFromSuperTokens(obj: any): obj is SuperTokensError { + static isErrorFromSuperTokens(obj: any): obj is SuperTokensError | SuperTokensPluginError { return obj.errMagic === SuperTokensError.errMagic; } +} - static fromError(err: Error, type: string): SuperTokensError { - const newError = new SuperTokensError({ - message: err.message, - type, - }); - - newError.stack = err.stack; +export class SuperTokensPluginError extends SuperTokensError { + public code: number; - return newError; + constructor(options: { message: string; payload?: any; code?: number }) { + super({ ...options, type: SuperTokensError.PLUGIN_ERROR }); + this.code = options.code || 400; } } + +export const transformErrorToSuperTokensError = (err: any): SuperTokensError => { + // passthrough for errors from SuperTokens - let errorHandler handle them + if (SuperTokensError.isErrorFromSuperTokens(err)) { + return err; + } + + logDebugMessage( + `transformErrorToSuperTokensError: Transforming error to SuperTokensError. Error: ${err?.message}.\nStack:\n${err?.stack}` + ); + // mask the original stack trace by not copying it on the new error + return new SuperTokensError({ message: "Unknown error", type: SuperTokensError.UNKNOWN_ERROR }); +}; diff --git a/lib/ts/index.ts b/lib/ts/index.ts index f6a8b88c4..9b6190d5d 100644 --- a/lib/ts/index.ts +++ b/lib/ts/index.ts @@ -14,7 +14,7 @@ */ import SuperTokens from "./supertokens"; -import SuperTokensError from "./error"; +import SuperTokensError, { SuperTokensPluginError } from "./error"; import { UserContext, User as UserType } from "./types"; import AccountLinking from "./recipe/accountlinking/recipe"; import { AccountInfoInput } from "./recipe/accountlinking/types"; @@ -36,6 +36,7 @@ export default class SuperTokensWrapper { static init = SuperTokens.init; static Error = SuperTokensError; + static PluginError = SuperTokensPluginError; static RecipeUserId = RecipeUserId; static User = User; @@ -243,5 +244,7 @@ export let getAvailableFirstFactors = SuperTokensWrapper.getAvailableFirstFactor export let Error = SuperTokensWrapper.Error; +export let PluginError = SuperTokensWrapper.PluginError; + export { default as RecipeUserId } from "./recipeUserId"; export { User } from "./user"; diff --git a/lib/ts/supertokens.ts b/lib/ts/supertokens.ts index a60332795..ab86c5411 100644 --- a/lib/ts/supertokens.ts +++ b/lib/ts/supertokens.ts @@ -38,13 +38,12 @@ import NormalisedURLDomain from "./normalisedURLDomain"; import NormalisedURLPath from "./normalisedURLPath"; import type { BaseRequest, BaseResponse } from "./framework"; import type { TypeFramework } from "./framework/types"; -import STError from "./error"; +import STError, { transformErrorToSuperTokensError } from "./error"; import { enableDebugLogs, logDebugMessage } from "./logger"; import { PostSuperTokensInitCallbacks } from "./postSuperTokensInitCallbacks"; import { DEFAULT_TENANT_ID } from "./recipe/multitenancy/constants"; import { SessionContainerInterface } from "./recipe/session/types"; import Session from "./recipe/session/recipe"; -import SuperTokensError from "./error"; export default class SuperTokens { private static instance: SuperTokens | undefined; @@ -452,18 +451,13 @@ export default class SuperTokens { try { await handlerFromApis.handler(request, response, session, userContext); } catch (err) { - // passthrough for errors from SuperTokens - let errorHandler handle them - if (SuperTokensError.isErrorFromSuperTokens(err)) { - throw err; - } else { - logDebugMessage( - "middleware: Error from plugin, transforming to SuperTokensError. Plugin ID: " + - handlerFromApis.pluginId - ); - - // transform errors to SuperTokensError to be handled by the errorHandler - throw SuperTokensError.fromError(err, SuperTokensError.PLUGIN_ERROR); - } + logDebugMessage( + "middleware: Error from plugin, transforming to SuperTokensError. Plugin ID: " + + handlerFromApis.pluginId + ); + + // transform errors to SuperTokensError to be handled by the errorHandler + throw transformErrorToSuperTokensError(err); } return true; @@ -643,8 +637,14 @@ export default class SuperTokens { } if (err.type === STError.PLUGIN_ERROR) { - logDebugMessage("errorHandler: Sending 400 status code response"); - return sendNon200ResponseWithMessage(response, err.message, 400); + const code = "code" in err && err.code ? err.code : 400; + logDebugMessage(`errorHandler: Sending ${code} status code response`); + return sendNon200ResponseWithMessage(response, err.message, code); + } + + if (err.type === STError.UNKNOWN_ERROR) { + logDebugMessage("errorHandler: Sending 500 status code response"); + return sendNon200ResponseWithMessage(response, err.message, 500); } for (let i = 0; i < this.recipeModules.length; i++) { From f68e9664fa8f211e37d399f5fed6c9792a240651 Mon Sep 17 00:00:00 2001 From: Mihaly Lengyel Date: Wed, 19 Nov 2025 22:56:57 +0100 Subject: [PATCH 10/12] ci: update the core test image --- compose.yml | 2 +- package.json | 2 +- test/plugins/plugins.test.ts | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compose.yml b/compose.yml index 9d01cf43d..ce4cb5028 100644 --- a/compose.yml +++ b/compose.yml @@ -1,7 +1,7 @@ services: core: # Uses `$SUPERTOKENS_CORE_VERSION` when available, else latest - image: supertokens/supertokens-core:dev-branch-${SUPERTOKENS_CORE_VERSION:-master} + image: supertokens/supertokens-dev-postgresql:${SUPERTOKENS_CORE_VERSION:-master} ports: # Uses `$SUPERTOKENS_CORE_PORT` when available, else 3567 for local port - ${SUPERTOKENS_CORE_PORT:-3567}:3567 diff --git a/package.json b/package.json index 24075b0fb..f36c93121 100644 --- a/package.json +++ b/package.json @@ -194,4 +194,4 @@ "browser": { "fs": false } -} \ No newline at end of file +} diff --git a/test/plugins/plugins.test.ts b/test/plugins/plugins.test.ts index e8ca19c84..d8ebfc3e5 100644 --- a/test/plugins/plugins.test.ts +++ b/test/plugins/plugins.test.ts @@ -233,7 +233,7 @@ describe("Plugins", () => { expectedApiOrder, expectedConfigOrder, }, - testNo, + testNo ) => { const plugins = pluginFactoryConfigs.map((pfc) => pluginFactory(pfc)); @@ -284,7 +284,7 @@ describe("Plugins", () => { assert.deepEqual(apiOutput.message, "msg"); assert.deepEqual(configOutput.testProperty, expectedConfigOrder); }); - }, + } ); }); @@ -380,7 +380,7 @@ describe("Plugins", () => { assert.deepEqual(apiOutput.message, "msg"); assert.deepEqual(configOutput.testProperty, expectedConfigOrder); }); - }, + } ); }); From 7a6cad7e56102f06ffbe8c57e8ff615c73a735e1 Mon Sep 17 00:00:00 2001 From: Mihaly Lengyel Date: Wed, 26 Nov 2025 18:01:20 +0100 Subject: [PATCH 11/12] feat: remove circular dependencies and fix tests --- compose.yml | 15 +- lib/build/authUtils.d.ts | 17 +- lib/build/authUtils.js | 151 ++++++---- lib/build/combinedRemoteJWKSet.d.ts | 10 +- lib/build/combinedRemoteJWKSet.js | 17 +- lib/build/customFramework.js | 11 +- lib/build/index.js | 66 ++-- lib/build/nextjs.d.ts | 2 +- lib/build/normalisedURLDomain.d.ts | 1 + lib/build/normalisedURLDomain.js | 9 +- lib/build/querier.d.ts | 27 +- lib/build/querier.js | 120 +++++++- lib/build/recipe/accountlinking/index.js | 33 +- lib/build/recipe/accountlinking/recipe.d.ts | 2 + lib/build/recipe/accountlinking/recipe.js | 42 ++- lib/build/recipe/dashboard/api/analytics.d.ts | 14 +- lib/build/recipe/dashboard/api/analytics.js | 14 +- .../recipe/dashboard/api/apiKeyProtector.d.ts | 11 +- .../recipe/dashboard/api/apiKeyProtector.js | 20 +- lib/build/recipe/dashboard/api/dashboard.d.ts | 9 +- lib/build/recipe/dashboard/api/dashboard.js | 12 +- .../recipe/dashboard/api/implementation.d.ts | 3 +- .../recipe/dashboard/api/implementation.js | 12 +- .../createOrUpdateThirdPartyConfig.d.ts | 15 +- .../createOrUpdateThirdPartyConfig.js | 26 +- .../api/multitenancy/createTenant.d.ts | 10 +- .../api/multitenancy/createTenant.js | 2 +- .../api/multitenancy/deleteTenant.d.ts | 14 +- .../api/multitenancy/deleteTenant.js | 12 +- .../multitenancy/deleteThirdPartyConfig.d.ts | 15 +- .../multitenancy/deleteThirdPartyConfig.js | 48 +-- .../api/multitenancy/getTenantInfo.d.ts | 15 +- .../api/multitenancy/getTenantInfo.js | 25 +- .../api/multitenancy/getThirdPartyConfig.d.ts | 15 +- .../api/multitenancy/getThirdPartyConfig.js | 8 +- .../listAllTenantsWithLoginMethods.d.ts | 13 +- .../listAllTenantsWithLoginMethods.js | 16 +- .../multitenancy/updateTenantCoreConfig.d.ts | 15 +- .../multitenancy/updateTenantCoreConfig.js | 10 +- .../multitenancy/updateTenantFirstFactor.d.ts | 15 +- .../multitenancy/updateTenantFirstFactor.js | 19 +- .../updateTenantSecondaryFactor.d.ts | 15 +- .../updateTenantSecondaryFactor.js | 14 +- .../dashboard/api/multitenancy/utils.d.ts | 5 +- .../dashboard/api/multitenancy/utils.js | 25 +- .../recipe/dashboard/api/search/tagsGet.d.ts | 14 +- .../recipe/dashboard/api/search/tagsGet.js | 4 +- lib/build/recipe/dashboard/api/signIn.d.ts | 5 +- lib/build/recipe/dashboard/api/signIn.js | 6 +- lib/build/recipe/dashboard/api/signOut.d.ts | 10 +- lib/build/recipe/dashboard/api/signOut.js | 4 +- .../api/user/create/emailpasswordUser.d.ts | 18 +- .../api/user/create/emailpasswordUser.js | 5 +- .../api/user/create/passwordlessUser.d.ts | 18 +- .../api/user/create/passwordlessUser.js | 10 +- .../dashboard/api/userdetails/userDelete.d.ts | 8 +- .../dashboard/api/userdetails/userDelete.js | 9 +- .../api/userdetails/userEmailVerifyGet.js | 25 +- .../api/userdetails/userEmailVerifyPut.d.ts | 15 +- .../api/userdetails/userEmailVerifyPut.js | 35 ++- .../userdetails/userEmailVerifyTokenPost.d.ts | 15 +- .../userdetails/userEmailVerifyTokenPost.js | 6 +- .../dashboard/api/userdetails/userGet.js | 16 +- .../api/userdetails/userMetadataGet.js | 9 +- .../api/userdetails/userMetadataPut.d.ts | 14 +- .../api/userdetails/userMetadataPut.js | 14 +- .../api/userdetails/userPasswordPut.d.ts | 15 +- .../api/userdetails/userPasswordPut.js | 6 +- .../dashboard/api/userdetails/userPut.d.ts | 15 +- .../dashboard/api/userdetails/userPut.js | 67 ++--- .../api/userdetails/userSessionsGet.js | 18 +- .../api/userdetails/userSessionsPost.d.ts | 14 +- .../api/userdetails/userSessionsPost.js | 6 +- .../api/userdetails/userUnlinkGet.d.ts | 14 +- .../api/userdetails/userUnlinkGet.js | 7 +- .../api/userroles/addRoleToUser.d.ts | 9 +- .../dashboard/api/userroles/addRoleToUser.js | 9 +- .../api/userroles/getRolesForUser.d.ts | 9 +- .../api/userroles/getRolesForUser.js | 9 +- .../permissions/getPermissionsForRole.d.ts | 9 +- .../permissions/getPermissionsForRole.js | 9 +- .../permissions/removePermissions.d.ts | 9 +- .../permissions/removePermissions.js | 13 +- .../api/userroles/removeUserRole.d.ts | 9 +- .../dashboard/api/userroles/removeUserRole.js | 9 +- .../roles/createRoleOrAddPermissions.d.ts | 9 +- .../roles/createRoleOrAddPermissions.js | 13 +- .../api/userroles/roles/deleteRole.d.ts | 9 +- .../api/userroles/roles/deleteRole.js | 9 +- .../api/userroles/roles/getAllRoles.js | 14 +- .../recipe/dashboard/api/usersCountGet.d.ts | 14 +- .../recipe/dashboard/api/usersCountGet.js | 10 +- lib/build/recipe/dashboard/api/usersGet.d.ts | 9 +- lib/build/recipe/dashboard/api/usersGet.js | 12 +- lib/build/recipe/dashboard/recipe.d.ts | 9 +- lib/build/recipe/dashboard/recipe.js | 38 ++- .../dashboard/recipeImplementation.d.ts | 3 +- .../recipe/dashboard/recipeImplementation.js | 4 +- lib/build/recipe/dashboard/types.d.ts | 18 +- lib/build/recipe/dashboard/utils.d.ts | 2 + lib/build/recipe/dashboard/utils.js | 51 +--- .../recipe/emailpassword/api/emailExists.d.ts | 2 +- .../emailpassword/api/implementation.d.ts | 3 +- .../emailpassword/api/implementation.js | 92 +++--- .../recipe/emailpassword/api/signin.d.ts | 2 + lib/build/recipe/emailpassword/api/signin.js | 3 +- .../recipe/emailpassword/api/signup.d.ts | 2 + lib/build/recipe/emailpassword/api/signup.js | 3 +- .../emailpassword/passwordResetFunctions.js | 3 +- lib/build/recipe/emailpassword/recipe.d.ts | 2 + lib/build/recipe/emailpassword/recipe.js | 25 +- .../emailpassword/recipeImplementation.d.ts | 2 + .../emailpassword/recipeImplementation.js | 43 +-- lib/build/recipe/emailpassword/types.d.ts | 6 + lib/build/recipe/emailpassword/utils.d.ts | 4 +- .../emailverification/api/emailVerify.d.ts | 2 + .../emailverification/api/emailVerify.js | 29 +- .../api/generateEmailVerifyToken.d.ts | 2 + .../api/generateEmailVerifyToken.js | 20 +- .../emailverification/api/implementation.d.ts | 3 +- .../emailverification/api/implementation.js | 27 +- .../emailVerificationFunctions.js | 3 +- .../recipe/emailverification/recipe.d.ts | 2 + lib/build/recipe/emailverification/recipe.js | 42 +-- .../recipeImplementation.d.ts | 2 + .../emailverification/recipeImplementation.js | 24 +- lib/build/recipe/emailverification/utils.d.ts | 2 +- lib/build/recipe/jwt/recipe.d.ts | 9 +- lib/build/recipe/jwt/recipe.js | 14 +- .../multifactorauth/api/implementation.d.ts | 7 +- .../multifactorauth/api/implementation.js | 23 +- .../api/resyncSessionAndFetchMFAInfo.d.ts | 2 + .../api/resyncSessionAndFetchMFAInfo.js | 22 +- lib/build/recipe/multifactorauth/index.d.ts | 6 +- lib/build/recipe/multifactorauth/index.js | 32 +- .../multifactorauth/multiFactorAuthClaim.d.ts | 5 +- .../multifactorauth/multiFactorAuthClaim.js | 7 +- lib/build/recipe/multifactorauth/recipe.d.ts | 21 +- lib/build/recipe/multifactorauth/recipe.js | 61 +++- .../multifactorauth/recipeImplementation.d.ts | 6 +- .../multifactorauth/recipeImplementation.js | 21 +- lib/build/recipe/multifactorauth/types.d.ts | 2 +- lib/build/recipe/multifactorauth/utils.d.ts | 2 + lib/build/recipe/multifactorauth/utils.js | 98 +++--- .../multitenancy/allowedDomainsClaim.d.ts | 4 +- .../multitenancy/allowedDomainsClaim.js | 17 +- .../multitenancy/api/implementation.d.ts | 3 +- .../recipe/multitenancy/api/implementation.js | 4 +- lib/build/recipe/multitenancy/index.d.ts | 5 +- lib/build/recipe/multitenancy/index.js | 10 +- lib/build/recipe/multitenancy/recipe.d.ts | 13 +- lib/build/recipe/multitenancy/recipe.js | 24 +- lib/build/recipe/multitenancy/types.d.ts | 2 +- lib/build/recipe/multitenancy/utils.d.ts | 2 + lib/build/recipe/multitenancy/utils.js | 10 +- lib/build/recipe/oauth2provider/api/auth.d.ts | 2 + lib/build/recipe/oauth2provider/api/auth.js | 12 +- .../recipe/oauth2provider/api/endSession.d.ts | 3 + .../recipe/oauth2provider/api/endSession.js | 17 +- .../oauth2provider/api/implementation.d.ts | 3 +- .../oauth2provider/api/implementation.js | 8 +- .../recipe/oauth2provider/api/login.d.ts | 2 + lib/build/recipe/oauth2provider/api/login.js | 10 +- .../recipe/oauth2provider/api/logout.d.ts | 2 + lib/build/recipe/oauth2provider/api/logout.js | 10 +- .../recipe/oauth2provider/api/userInfo.d.ts | 2 + .../recipe/oauth2provider/api/userInfo.js | 23 +- .../recipe/oauth2provider/api/utils.d.ts | 7 + lib/build/recipe/oauth2provider/api/utils.js | 30 +- lib/build/recipe/oauth2provider/recipe.d.ts | 9 +- lib/build/recipe/oauth2provider/recipe.js | 25 +- .../oauth2provider/recipeImplementation.d.ts | 2 + .../oauth2provider/recipeImplementation.js | 31 +- lib/build/recipe/openid/recipe.d.ts | 5 +- lib/build/recipe/openid/recipe.js | 15 +- .../recipe/openid/recipeImplementation.d.ts | 3 +- .../recipe/openid/recipeImplementation.js | 5 +- .../recipe/passwordless/api/consumeCode.d.ts | 2 + .../recipe/passwordless/api/consumeCode.js | 3 +- .../recipe/passwordless/api/createCode.d.ts | 2 + .../recipe/passwordless/api/createCode.js | 3 +- .../passwordless/api/implementation.d.ts | 3 +- .../recipe/passwordless/api/implementation.js | 72 +++-- .../recipe/passwordless/api/resendCode.d.ts | 2 + .../recipe/passwordless/api/resendCode.js | 3 +- .../services/backwardCompatibility/index.js | 3 +- lib/build/recipe/passwordless/recipe.d.ts | 2 + lib/build/recipe/passwordless/recipe.js | 24 +- .../passwordless/recipeImplementation.d.ts | 3 +- .../passwordless/recipeImplementation.js | 32 +- .../services/backwardCompatibility/index.js | 4 +- .../smsdelivery/services/supertokens/index.js | 4 +- .../recipe/session/api/implementation.d.ts | 4 +- .../recipe/session/api/implementation.js | 6 +- lib/build/recipe/session/api/signout.d.ts | 2 + lib/build/recipe/session/api/signout.js | 4 +- .../recipe/session/framework/custom.d.ts | 4 +- lib/build/recipe/session/index.js | 80 +++-- lib/build/recipe/session/recipe.d.ts | 33 +- lib/build/recipe/session/recipe.js | 64 +++- lib/build/recipe/session/sessionFunctions.js | 2 +- .../session/sessionRequestFunctions.d.ts | 13 +- .../recipe/session/sessionRequestFunctions.js | 47 +-- lib/build/recipe/session/utils.d.ts | 9 +- lib/build/recipe/session/utils.js | 22 +- .../recipe/thirdparty/api/implementation.d.ts | 3 +- .../recipe/thirdparty/api/implementation.js | 25 +- lib/build/recipe/thirdparty/api/signinup.d.ts | 2 + lib/build/recipe/thirdparty/api/signinup.js | 3 +- .../thirdparty/providers/configUtils.d.ts | 12 +- .../thirdparty/providers/configUtils.js | 4 - .../recipe/thirdparty/providers/custom.js | 8 +- .../recipe/thirdparty/providers/utils.js | 6 +- lib/build/recipe/thirdparty/recipe.d.ts | 2 + lib/build/recipe/thirdparty/recipe.js | 20 +- .../thirdparty/recipeImplementation.d.ts | 7 +- .../recipe/thirdparty/recipeImplementation.js | 27 +- lib/build/recipe/totp/api/createDevice.d.ts | 2 + lib/build/recipe/totp/api/createDevice.js | 22 +- lib/build/recipe/totp/api/implementation.d.ts | 3 +- lib/build/recipe/totp/api/implementation.js | 78 +---- lib/build/recipe/totp/api/listDevices.d.ts | 2 + lib/build/recipe/totp/api/listDevices.js | 22 +- lib/build/recipe/totp/api/removeDevice.d.ts | 2 + lib/build/recipe/totp/api/removeDevice.js | 25 +- lib/build/recipe/totp/api/verifyDevice.d.ts | 2 + lib/build/recipe/totp/api/verifyDevice.js | 22 +- lib/build/recipe/totp/api/verifyTOTP.d.ts | 2 + lib/build/recipe/totp/api/verifyTOTP.js | 22 +- lib/build/recipe/totp/recipe.d.ts | 11 +- lib/build/recipe/totp/recipe.js | 28 +- .../recipe/totp/recipeImplementation.d.ts | 7 +- lib/build/recipe/totp/recipeImplementation.js | 7 +- lib/build/recipe/totp/types.d.ts | 2 +- lib/build/recipe/usermetadata/recipe.d.ts | 9 +- lib/build/recipe/usermetadata/recipe.js | 12 +- lib/build/recipe/userroles/recipe.d.ts | 9 +- lib/build/recipe/userroles/recipe.js | 30 +- .../recipe/webauthn/api/implementation.d.ts | 3 +- .../recipe/webauthn/api/implementation.js | 110 ++++--- .../recipe/webauthn/api/listCredentials.d.ts | 2 + .../recipe/webauthn/api/listCredentials.js | 22 +- .../webauthn/api/registerCredential.d.ts | 2 + .../recipe/webauthn/api/registerCredential.js | 17 +- .../recipe/webauthn/api/removeCredential.d.ts | 2 + .../recipe/webauthn/api/removeCredential.js | 17 +- lib/build/recipe/webauthn/api/signin.d.ts | 2 + lib/build/recipe/webauthn/api/signin.js | 3 +- lib/build/recipe/webauthn/api/signup.d.ts | 2 + lib/build/recipe/webauthn/api/signup.js | 3 +- .../services/backwardCompatibility/index.js | 3 +- lib/build/recipe/webauthn/recipe.d.ts | 2 + lib/build/recipe/webauthn/recipe.js | 51 ++-- .../recipe/webauthn/recipeImplementation.d.ts | 2 + .../recipe/webauthn/recipeImplementation.js | 22 +- lib/build/recipe/webauthn/utils.d.ts | 4 +- lib/build/recipeIdToRecipeType.d.ts | 35 +++ lib/build/recipeIdToRecipeType.js | 23 ++ lib/build/recipeModule.d.ts | 8 +- lib/build/recipeModule.js | 11 +- lib/build/supertokens.d.ts | 3 + lib/build/supertokens.js | 54 +++- lib/build/thirdpartyUtils.js | 6 +- lib/build/types.d.ts | 6 +- lib/build/utils.d.ts | 24 -- lib/build/utils.js | 159 ++++------ lib/ts/authUtils.ts | 180 +++++++---- lib/ts/combinedRemoteJWKSet.ts | 6 +- lib/ts/customFramework.ts | 13 +- lib/ts/index.ts | 61 ++-- lib/ts/nextjs.ts | 2 +- lib/ts/normalisedURLDomain.ts | 6 +- lib/ts/querier.ts | 109 ++++++- lib/ts/recipe/accountlinking/index.ts | 33 +- lib/ts/recipe/accountlinking/recipe.ts | 55 ++-- lib/ts/recipe/dashboard/api/analytics.ts | 24 +- .../recipe/dashboard/api/apiKeyProtector.ts | 13 +- lib/ts/recipe/dashboard/api/dashboard.ts | 19 +- lib/ts/recipe/dashboard/api/implementation.ts | 13 +- .../createOrUpdateThirdPartyConfig.ts | 39 ++- .../api/multitenancy/createTenant.ts | 10 +- .../api/multitenancy/deleteTenant.ts | 19 +- .../multitenancy/deleteThirdPartyConfig.ts | 61 ++-- .../api/multitenancy/getTenantInfo.ts | 28 +- .../api/multitenancy/getThirdPartyConfig.ts | 21 +- .../listAllTenantsWithLoginMethods.ts | 19 +- .../multitenancy/updateTenantCoreConfig.ts | 22 +- .../multitenancy/updateTenantFirstFactor.ts | 22 +- .../updateTenantSecondaryFactor.ts | 26 +- .../dashboard/api/multitenancy/utils.ts | 13 +- lib/ts/recipe/dashboard/api/search/tagsGet.ts | 16 +- lib/ts/recipe/dashboard/api/signIn.ts | 9 +- lib/ts/recipe/dashboard/api/signOut.ts | 16 +- .../api/user/create/emailpasswordUser.ts | 23 +- .../api/user/create/passwordlessUser.ts | 28 +- .../dashboard/api/userdetails/userDelete.ts | 15 +- .../api/userdetails/userEmailVerifyGet.ts | 36 ++- .../api/userdetails/userEmailVerifyPut.ts | 49 ++- .../userdetails/userEmailVerifyTokenPost.ts | 21 +- .../dashboard/api/userdetails/userGet.ts | 29 +- .../api/userdetails/userMetadataGet.ts | 21 +- .../api/userdetails/userMetadataPut.ts | 26 +- .../api/userdetails/userPasswordPut.ts | 19 +- .../dashboard/api/userdetails/userPut.ts | 83 +++-- .../api/userdetails/userSessionsGet.ts | 30 +- .../api/userdetails/userSessionsPost.ts | 18 +- .../api/userdetails/userUnlinkGet.ts | 19 +- .../dashboard/api/userroles/addRoleToUser.ts | 21 +- .../api/userroles/getRolesForUser.ts | 21 +- .../permissions/getPermissionsForRole.ts | 20 +- .../permissions/removePermissions.ts | 24 +- .../dashboard/api/userroles/removeUserRole.ts | 21 +- .../roles/createRoleOrAddPermissions.ts | 26 +- .../api/userroles/roles/deleteRole.ts | 20 +- .../api/userroles/roles/getAllRoles.ts | 12 +- lib/ts/recipe/dashboard/api/usersCountGet.ts | 17 +- lib/ts/recipe/dashboard/api/usersGet.ts | 19 +- lib/ts/recipe/dashboard/recipe.ts | 45 ++- .../recipe/dashboard/recipeImplementation.ts | 3 +- lib/ts/recipe/dashboard/types.ts | 18 +- lib/ts/recipe/dashboard/utils.ts | 45 ++- .../recipe/emailpassword/api/emailExists.ts | 2 +- .../emailpassword/api/implementation.ts | 98 +++--- lib/ts/recipe/emailpassword/api/signin.ts | 3 + lib/ts/recipe/emailpassword/api/signup.ts | 3 + .../emailpassword/passwordResetFunctions.ts | 3 +- lib/ts/recipe/emailpassword/recipe.ts | 22 +- .../emailpassword/recipeImplementation.ts | 51 ++-- lib/ts/recipe/emailpassword/types.ts | 7 + lib/ts/recipe/emailpassword/utils.ts | 2 +- .../emailverification/api/emailVerify.ts | 30 +- .../api/generateEmailVerifyToken.ts | 17 +- .../emailverification/api/implementation.ts | 52 ++-- .../emailVerificationFunctions.ts | 3 +- lib/ts/recipe/emailverification/recipe.ts | 34 ++- .../emailverification/recipeImplementation.ts | 26 +- lib/ts/recipe/emailverification/utils.ts | 2 +- lib/ts/recipe/jwt/recipe.ts | 19 +- .../multifactorauth/api/implementation.ts | 21 +- .../api/resyncSessionAndFetchMFAInfo.ts | 17 +- lib/ts/recipe/multifactorauth/index.ts | 28 +- .../multifactorauth/multiFactorAuthClaim.ts | 6 +- lib/ts/recipe/multifactorauth/recipe.ts | 82 +++-- .../multifactorauth/recipeImplementation.ts | 18 +- lib/ts/recipe/multifactorauth/types.ts | 2 +- lib/ts/recipe/multifactorauth/utils.ts | 121 +++++--- .../multitenancy/allowedDomainsClaim.ts | 13 +- .../recipe/multitenancy/api/implementation.ts | 5 +- lib/ts/recipe/multitenancy/index.ts | 10 +- lib/ts/recipe/multitenancy/recipe.ts | 30 +- lib/ts/recipe/multitenancy/types.ts | 2 +- lib/ts/recipe/multitenancy/utils.ts | 5 +- lib/ts/recipe/oauth2provider/api/auth.ts | 12 +- .../recipe/oauth2provider/api/endSession.ts | 15 +- .../oauth2provider/api/implementation.ts | 9 +- lib/ts/recipe/oauth2provider/api/login.ts | 10 +- lib/ts/recipe/oauth2provider/api/logout.ts | 10 +- lib/ts/recipe/oauth2provider/api/userInfo.ts | 17 +- lib/ts/recipe/oauth2provider/api/utils.ts | 33 +- lib/ts/recipe/oauth2provider/recipe.ts | 32 +- .../oauth2provider/recipeImplementation.ts | 27 +- lib/ts/recipe/openid/recipe.ts | 16 +- lib/ts/recipe/openid/recipeImplementation.ts | 6 +- lib/ts/recipe/passwordless/api/consumeCode.ts | 3 + lib/ts/recipe/passwordless/api/createCode.ts | 3 + .../recipe/passwordless/api/implementation.ts | 77 +++-- lib/ts/recipe/passwordless/api/resendCode.ts | 3 + .../services/backwardCompatibility/index.ts | 6 +- lib/ts/recipe/passwordless/recipe.ts | 24 +- .../passwordless/recipeImplementation.ts | 33 +- .../services/backwardCompatibility/index.ts | 2 +- .../smsdelivery/services/supertokens/index.ts | 2 +- lib/ts/recipe/session/api/implementation.ts | 8 +- lib/ts/recipe/session/api/signout.ts | 4 + lib/ts/recipe/session/framework/custom.ts | 4 +- lib/ts/recipe/session/index.ts | 32 +- lib/ts/recipe/session/recipe.ts | 92 +++++- lib/ts/recipe/session/sessionFunctions.ts | 2 +- .../recipe/session/sessionRequestFunctions.ts | 29 +- lib/ts/recipe/session/utils.ts | 28 +- .../recipe/thirdparty/api/implementation.ts | 21 +- lib/ts/recipe/thirdparty/api/signinup.ts | 3 + .../thirdparty/providers/configUtils.ts | 18 +- lib/ts/recipe/thirdparty/providers/custom.ts | 20 +- lib/ts/recipe/thirdparty/providers/utils.ts | 2 +- lib/ts/recipe/thirdparty/recipe.ts | 19 +- .../recipe/thirdparty/recipeImplementation.ts | 32 +- lib/ts/recipe/totp/api/createDevice.ts | 17 +- lib/ts/recipe/totp/api/implementation.ts | 21 +- lib/ts/recipe/totp/api/listDevices.ts | 17 +- lib/ts/recipe/totp/api/removeDevice.ts | 20 +- lib/ts/recipe/totp/api/verifyDevice.ts | 17 +- lib/ts/recipe/totp/api/verifyTOTP.ts | 17 +- lib/ts/recipe/totp/recipe.ts | 40 +-- lib/ts/recipe/totp/recipeImplementation.ts | 12 +- lib/ts/recipe/totp/types.ts | 2 +- lib/ts/recipe/usermetadata/recipe.ts | 17 +- lib/ts/recipe/userroles/recipe.ts | 37 ++- lib/ts/recipe/webauthn/api/implementation.ts | 112 ++++--- lib/ts/recipe/webauthn/api/listCredentials.ts | 17 +- .../recipe/webauthn/api/registerCredential.ts | 17 +- .../recipe/webauthn/api/removeCredential.ts | 17 +- lib/ts/recipe/webauthn/api/signin.ts | 3 + lib/ts/recipe/webauthn/api/signup.ts | 3 + .../services/backwardCompatibility/index.ts | 3 +- lib/ts/recipe/webauthn/recipe.ts | 31 +- .../recipe/webauthn/recipeImplementation.ts | 22 +- lib/ts/recipe/webauthn/utils.ts | 2 +- lib/ts/recipeIdToRecipeType.ts | 35 +++ lib/ts/recipeModule.ts | 17 +- lib/ts/supertokens.ts | 52 +++- lib/ts/thirdpartyUtils.ts | 2 +- lib/ts/types.ts | 6 +- lib/ts/utils.ts | 103 +------ package-lock.json | 284 +++++++++++++++--- test/config.test.js | 4 +- test/emailpassword/deleteUser.test.js | 22 +- test/emailpassword/emailverify.test.js | 22 -- test/emailpassword/updateEmailPass.test.js | 20 -- test/emailpassword/users.test.js | 10 - test/framework/awsLambda.test.js | 48 --- test/framework/awsLambda.withTenantId.test.js | 43 --- test/framework/fastify.test.js | 48 --- test/framework/fastify.withTenantId.test.js | 48 --- test/framework/hapi.test.js | 48 --- test/framework/hapi.withTenantId.test.js | 48 --- test/framework/koa.test.js | 48 --- test/framework/koa.withTenantId.test.js | 48 --- test/framework/loopback.test.js | 48 --- test/framework/loopback.withTenantId.test.js | 48 --- test/frontendIntegration/index.js | 3 +- test/jwt/config.test.js | 14 - test/jwt/createJWTFeature.test.js | 35 --- test/jwt/getJWKS.test.js | 35 --- test/jwt/override.test.js | 14 - test/oauth2/config.test.js | 7 - test/openid/api.test.js | 21 -- test/openid/config.test.js | 39 +-- test/openid/openid.test.js | 21 -- test/openid/override.test.js | 14 - test/plugins/recipe.ts | 7 +- test/querier.test.js | 49 ++- test/ratelimiting.test.js | 41 ++- test/recipeModuleManager.test.js | 93 +++--- test/session.test.js | 59 +--- test/session/accessTokenVersions.test.js | 18 +- .../sessionHandlingFuncsWithoutReq.test.js | 8 - ...sessionAccessTokenSigningKeyUpdate.test.js | 6 +- test/thirdparty/signinupFeature.test.js | 7 - .../useridmapping/createUserIdMapping.test.js | 28 -- .../useridmapping/deleteUserIdMapping.test.js | 35 --- test/useridmapping/getUserIdMapping.test.js | 21 -- .../recipeTests/emailpassword.test.js | 35 --- .../recipeTests/passwordless.test.js | 35 --- .../recipeTests/supertokens.test.js | 14 - .../recipeTests/thirdparty.test.js | 28 -- .../updateOrDeleteUserIdMappingInfo.test.js | 21 -- test/usermetadata/clearUserMetadata.test.js | 13 - test/usermetadata/config.test.js | 7 - test/usermetadata/getUserMetadata.test.js | 14 - test/usermetadata/override.test.js | 14 - test/usermetadata/updateUserMetadata.test.js | 28 -- test/userroles/addRoleToUser.test.js | 21 -- test/userroles/claims.test.js | 49 --- test/userroles/config.test.js | 7 - .../createNewRoleOrAddPermissions.test.js | 35 --- test/userroles/deleteRole.test.js | 14 - test/userroles/getPermissionsForRole.test.js | 14 - test/userroles/getRolesForUser.test.js | 7 - .../getRolesThatHavePermissions.test.js | 14 - test/userroles/getUsersThatHaveRole.test.js | 14 - .../removePermissionsFromRole.test.js | 14 - test/userroles/removeUserRole.test.js | 21 -- test/utils.js | 11 +- 474 files changed, 4753 insertions(+), 4926 deletions(-) create mode 100644 lib/build/recipeIdToRecipeType.d.ts create mode 100644 lib/build/recipeIdToRecipeType.js create mode 100644 lib/ts/recipeIdToRecipeType.ts diff --git a/compose.yml b/compose.yml index 327995818..6cd49f77f 100644 --- a/compose.yml +++ b/compose.yml @@ -2,11 +2,16 @@ services: core: # Uses `$SUPERTOKENS_CORE_VERSION` when available, else latest image: supertokens/supertokens-dev-postgresql:${SUPERTOKENS_CORE_VERSION:-master} - entrypoint: [ - "/usr/lib/supertokens/jre/bin/java", - "-classpath", "/usr/lib/supertokens/core/*:/usr/lib/supertokens/plugin-interface/*:/usr/lib/supertokens/ee/*", - "io.supertokens.Main", "/usr/lib/supertokens/", "DEV", "test_mode" - ] + entrypoint: + [ + "/usr/lib/supertokens/jre/bin/java", + "-classpath", + "/usr/lib/supertokens/core/*:/usr/lib/supertokens/plugin-interface/*:/usr/lib/supertokens/ee/*", + "io.supertokens.Main", + "/usr/lib/supertokens/", + "DEV", + "test_mode", + ] ports: # Uses `$SUPERTOKENS_CORE_PORT` when available, else 3567 for local port - ${SUPERTOKENS_CORE_PORT:-3567}:3567 diff --git a/lib/build/authUtils.d.ts b/lib/build/authUtils.d.ts index 7ef2f235c..80a39543e 100644 --- a/lib/build/authUtils.d.ts +++ b/lib/build/authUtils.d.ts @@ -4,7 +4,8 @@ import { UserContext } from "./types"; import { LoginMethod, User } from "./user"; import RecipeUserId from "./recipeUserId"; import { AccountInfoWithRecipeId } from "./recipe/accountlinking/types"; -import { BaseRequest, BaseResponse } from "./framework"; +import type { BaseRequest, BaseResponse } from "./framework"; +import type SuperTokens from "./supertokens"; export declare const AuthUtils: { /** * This helper function can be used to map error statuses (w/ an optional reason) to error responses with human readable reasons. @@ -45,6 +46,7 @@ export declare const AuthUtils: { * if the session user should become primary but we couldn't make it primary because of a conflicting primary user. */ preAuthChecks: ({ + stInstance, authenticatingAccountInfo, tenantId, isSignUp, @@ -57,6 +59,7 @@ export declare const AuthUtils: { shouldTryLinkingWithSessionUser, userContext, }: { + stInstance: SuperTokens; authenticatingAccountInfo: AccountInfoWithRecipeId; authenticatingUser: User | undefined; tenantId: string; @@ -103,6 +106,7 @@ export declare const AuthUtils: { * if the session user should be primary but we couldn't make it primary because of a conflicting primary user. */ postAuthChecks: ({ + stInstance, authenticatedUser, recipeUserId, isSignUp, @@ -113,6 +117,7 @@ export declare const AuthUtils: { tenantId, userContext, }: { + stInstance: SuperTokens; authenticatedUser: User; recipeUserId: RecipeUserId; tenantId: string; @@ -143,6 +148,7 @@ export declare const AuthUtils: { * most importantly, this way all secondary factors are app-wide instead of mixing app-wide (totp) and tenant-wide (password) factors. */ getAuthenticatingUserAndAddToCurrentTenantIfRequired: ({ + stInstance, recipeId, accountInfo, checkCredentialsOnTenant, @@ -150,6 +156,7 @@ export declare const AuthUtils: { session, userContext, }: { + stInstance: SuperTokens; recipeId: string; accountInfo: | { @@ -206,6 +213,7 @@ export declare const AuthUtils: { * if the session user should be primary but we couldn't make it primary because of a conflicting primary user. */ checkAuthTypeAndLinkingStatus: ( + stInstance: SuperTokens, session: SessionContainerInterface | undefined, shouldTryLinkingWithSessionUser: boolean | undefined, accountInfo: AccountInfoWithRecipeId, @@ -250,6 +258,7 @@ export declare const AuthUtils: { * if the session user should be primary but we couldn't make it primary because of a conflicting primary user. */ linkToSessionIfRequiredElseCreatePrimaryUserIdOrLinkByAccountInfo: ({ + stInstance, tenantId, inputUser, recipeUserId, @@ -257,6 +266,7 @@ export declare const AuthUtils: { shouldTryLinkingWithSessionUser, userContext, }: { + stInstance: SuperTokens; tenantId: string; inputUser: User; recipeUserId: RecipeUserId; @@ -288,6 +298,7 @@ export declare const AuthUtils: { * It throws INVALID_CLAIM_ERROR if shouldDoAutomaticAccountLinking returned `{ shouldAutomaticallyLink: false }` but the email verification status was wrong */ tryAndMakeSessionUserIntoAPrimaryUser: ( + stInstance: SuperTokens, session: SessionContainerInterface, skipSessionUserUpdateInCore: boolean, userContext: UserContext @@ -317,12 +328,14 @@ export declare const AuthUtils: { * if the session user is not primary. This can be resolved by making it primary and retrying the call. */ tryLinkingBySession: ({ + stInstance, linkingToSessionUserRequiresVerification, authLoginMethod, authenticatedUser, sessionUser, userContext, }: { + stInstance: SuperTokens; authenticatedUser: User; linkingToSessionUserRequiresVerification: boolean; sessionUser: User; @@ -346,12 +359,14 @@ export declare const AuthUtils: { } >; filterOutInvalidFirstFactorsOrThrowIfAllAreInvalid: ( + stInstance: SuperTokens, factorIds: string[], tenantId: string, hasSession: boolean, userContext: UserContext ) => Promise; loadSessionInAuthAPIIfNeeded: ( + stInstance: SuperTokens, req: BaseRequest, res: BaseResponse, shouldTryLinkingWithSessionUser: boolean | undefined, diff --git a/lib/build/authUtils.js b/lib/build/authUtils.js index 4a21d51cf..4ca0319fe 100644 --- a/lib/build/authUtils.js +++ b/lib/build/authUtils.js @@ -6,11 +6,6 @@ var __importDefault = }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AuthUtils = void 0; -const recipe_1 = __importDefault(require("./recipe/accountlinking/recipe")); -const session_1 = __importDefault(require("./recipe/session")); -const multitenancy_1 = __importDefault(require("./recipe/multitenancy")); -const multifactorauth_1 = __importDefault(require("./recipe/multifactorauth")); -const recipe_2 = __importDefault(require("./recipe/multifactorauth/recipe")); const utils_1 = require("./recipe/multifactorauth/utils"); const utils_2 = require("./recipe/multitenancy/utils"); const error_1 = __importDefault(require("./recipe/session/error")); @@ -68,6 +63,7 @@ exports.AuthUtils = { * if the session user should become primary but we couldn't make it primary because of a conflicting primary user. */ preAuthChecks: async function ({ + stInstance, authenticatingAccountInfo, tenantId, isSignUp, @@ -90,6 +86,7 @@ exports.AuthUtils = { // to decide if this is a first factor auth or not and if it'll link to the session user // We also load the session user here if it is available. const authTypeInfo = await exports.AuthUtils.checkAuthTypeAndLinkingStatus( + stInstance, session, shouldTryLinkingWithSessionUser, authenticatingAccountInfo, @@ -112,6 +109,7 @@ exports.AuthUtils = { // If the flowType for passwordless is USER_INPUT_CODE_AND_MAGIC_LINK and firstFactors for the tenant we only have otp-email // then we do not want to include a link in the email. const validFirstFactors = await exports.AuthUtils.filterOutInvalidFirstFactorsOrThrowIfAllAreInvalid( + stInstance, factorIds, tenantId, session !== undefined, @@ -123,6 +121,7 @@ exports.AuthUtils = { // In this case the app will try to link the session user and the authenticating user after auth, // so we need to check if this is allowed by the MFA recipe (if initialized). validFactorIds = await filterOutInvalidSecondFactorsOrThrowIfAllAreInvalid( + stInstance, factorIds, authTypeInfo.inputUserAlreadyLinkedToSessionUser, authTypeInfo.sessionUser, @@ -148,7 +147,7 @@ exports.AuthUtils = { ); (0, logger_1.logDebugMessage)("preAuthChecks checking if the user is allowed to sign up"); if ( - !(await recipe_1.default.getInstanceOrThrowError().isSignUpAllowed({ + !(await stInstance.getRecipeInstanceOrThrow("accountlinking").isSignUpAllowed({ newUser: authenticatingAccountInfo, isVerified: isVerified || signInVerifiesLoginMethod || verifiedInSessionUser, tenantId, @@ -162,7 +161,7 @@ exports.AuthUtils = { // for sign ins, this is checked after the credentials have been verified (0, logger_1.logDebugMessage)("preAuthChecks checking if the user is allowed to sign in"); if ( - !(await recipe_1.default.getInstanceOrThrowError().isSignInAllowed({ + !(await stInstance.getRecipeInstanceOrThrow("accountlinking").isSignInAllowed({ user: authenticatingUser, accountInfo: authenticatingAccountInfo, signInVerifiesLoginMethod, @@ -200,6 +199,7 @@ exports.AuthUtils = { * if the session user should be primary but we couldn't make it primary because of a conflicting primary user. */ postAuthChecks: async function ({ + stInstance, authenticatedUser, recipeUserId, isSignUp, @@ -215,7 +215,7 @@ exports.AuthUtils = { isSignUp ? "sign in" : "sign up" } with ${factorId}` ); - const mfaInstance = recipe_2.default.getInstance(); + const mfaInstance = stInstance.getRecipeInstance("multifactorauth"); let respSession = session; if (session !== undefined) { const authenticatedUserLinkedToSessionUser = authenticatedUser.loginMethods.some( @@ -227,39 +227,51 @@ exports.AuthUtils = { (0, logger_1.logDebugMessage)(`postAuthChecks marking factor as completed`); // if the authenticating user is linked to the current session user (it means that the factor got set up or completed), // we mark it as completed in the session. - await multifactorauth_1.default.markFactorAsCompleteInSession(respSession, factorId, userContext); + await mfaInstance.recipeInterfaceImpl.markFactorAsCompleteInSession({ + session: respSession, + factorId, + userContext, + }); } } else { // If the new user wasn't linked to the current one, we overwrite the session // Note: we could also get here if MFA is enabled, but the app didn't want to link the user to the session user. - respSession = await session_1.default.createNewSession( + respSession = await stInstance.getRecipeInstanceOrThrow("session").createNewSession({ req, res, tenantId, recipeUserId, - {}, - {}, - userContext - ); + accessTokenPayload: {}, + sessionDataInDatabase: {}, + userContext, + }); if (mfaInstance !== undefined) { - await multifactorauth_1.default.markFactorAsCompleteInSession(respSession, factorId, userContext); + await mfaInstance.recipeInterfaceImpl.markFactorAsCompleteInSession({ + session: respSession, + factorId, + userContext, + }); } } } else { (0, logger_1.logDebugMessage)(`postAuthChecks creating session for first factor sign in/up`); // If there is no input session, we do not need to do anything other checks and create a new session - respSession = await session_1.default.createNewSession( + respSession = await stInstance.getRecipeInstanceOrThrow("session").createNewSession({ req, res, tenantId, recipeUserId, - {}, - {}, - userContext - ); + accessTokenPayload: {}, + sessionDataInDatabase: {}, + userContext, + }); // Here we can always mark the factor as completed, since we just created the session if (mfaInstance !== undefined) { - await multifactorauth_1.default.markFactorAsCompleteInSession(respSession, factorId, userContext); + await mfaInstance.recipeInterfaceImpl.markFactorAsCompleteInSession({ + session: respSession, + factorId, + userContext, + }); } } return { status: "OK", session: respSession, user: authenticatedUser }; @@ -275,6 +287,7 @@ exports.AuthUtils = { * most importantly, this way all secondary factors are app-wide instead of mixing app-wide (totp) and tenant-wide (password) factors. */ getAuthenticatingUserAndAddToCurrentTenantIfRequired: async ({ + stInstance, recipeId, accountInfo, checkCredentialsOnTenant, @@ -287,8 +300,8 @@ exports.AuthUtils = { (0, logger_1.logDebugMessage)( `getAuthenticatingUserAndAddToCurrentTenantIfRequired called with ${JSON.stringify(accountInfo)}` ); - const existingUsers = await recipe_1.default - .getInstanceOrThrowError() + const existingUsers = await stInstance + .getRecipeInstanceOrThrow("accountlinking") .recipeInterfaceImpl.listUsersByAccountInfo({ tenantId, accountInfo, @@ -324,7 +337,9 @@ exports.AuthUtils = { (0, logger_1.logDebugMessage)( `getAuthenticatingUserAndAddToCurrentTenantIfRequired checking session user` ); - const sessionUser = await (0, _1.getUser)(session.getUserId(userContext), userContext); + const sessionUser = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: session.getUserId(userContext), userContext }); if (sessionUser === undefined) { throw new error_1.default({ type: error_1.default.UNAUTHORISED, @@ -372,11 +387,13 @@ exports.AuthUtils = { (0, logger_1.logDebugMessage)( `getAuthenticatingUserAndAddToCurrentTenantIfRequired associating user from ${lm.tenantIds[0]} with current tenant` ); - const associateRes = await multitenancy_1.default.associateUserToTenant( - tenantId, - lm.recipeUserId, - userContext - ); + const associateRes = await stInstance + .getRecipeInstanceOrThrow("multitenancy") + .recipeInterfaceImpl.associateUserToTenant({ + tenantId, + recipeUserId: lm.recipeUserId, + userContext, + }); (0, logger_1.logDebugMessage)( `getAuthenticatingUserAndAddToCurrentTenantIfRequired associating returned ${associateRes.status}` ); @@ -434,6 +451,7 @@ exports.AuthUtils = { * if the session user should be primary but we couldn't make it primary because of a conflicting primary user. */ checkAuthTypeAndLinkingStatus: async function ( + stInstance, session, shouldTryLinkingWithSessionUser, accountInfo, @@ -466,7 +484,7 @@ exports.AuthUtils = { } if ( !(0, utils_3.recipeInitDefinedShouldDoAutomaticAccountLinking)( - recipe_1.default.getInstanceOrThrowError().config + stInstance.getRecipeInstanceOrThrow("accountlinking").config ) ) { if (shouldTryLinkingWithSessionUser === true) { @@ -475,7 +493,7 @@ exports.AuthUtils = { ); } else { // This is the legacy case where shouldTryLinkingWithSessionUser is undefined - if (recipe_2.default.getInstance() !== undefined) { + if (stInstance.getRecipeInstance("multifactorauth") !== undefined) { throw new Error( "Please initialise the account linking recipe and define shouldDoAutomaticAccountLinking to enable MFA" ); @@ -514,6 +532,7 @@ exports.AuthUtils = { ); // We have to load the session user in order to get the account linking info const sessionUserResult = await exports.AuthUtils.tryAndMakeSessionUserIntoAPrimaryUser( + stInstance, session, skipSessionUserUpdateInCore, userContext @@ -542,8 +561,8 @@ exports.AuthUtils = { sessionUser = sessionUserResult.sessionUser; // We check if the app intends to link these two accounts // Note: in some cases if the accountInfo already belongs to a primary user - const shouldLink = await recipe_1.default - .getInstanceOrThrowError() + const shouldLink = await stInstance + .getRecipeInstanceOrThrow("accountlinking") .config.shouldDoAutomaticAccountLinking( accountInfo, sessionUser, @@ -591,6 +610,7 @@ exports.AuthUtils = { * if the session user should be primary but we couldn't make it primary because of a conflicting primary user. */ linkToSessionIfRequiredElseCreatePrimaryUserIdOrLinkByAccountInfo: async function ({ + stInstance, tenantId, inputUser, recipeUserId, @@ -604,6 +624,7 @@ exports.AuthUtils = { "linkToSessionIfRequiredElseCreatePrimaryUserIdOrLinkByAccountInfo retrying...." ); return exports.AuthUtils.linkToSessionIfRequiredElseCreatePrimaryUserIdOrLinkByAccountInfo({ + stInstance, tenantId, inputUser: inputUser, session, @@ -623,6 +644,7 @@ exports.AuthUtils = { ); } const authTypeRes = await exports.AuthUtils.checkAuthTypeAndLinkingStatus( + stInstance, session, shouldTryLinkingWithSessionUser, authLoginMethod, @@ -636,7 +658,7 @@ exports.AuthUtils = { if (authTypeRes.isFirstFactor) { if ( !(0, utils_3.recipeInitDefinedShouldDoAutomaticAccountLinking)( - recipe_1.default.getInstanceOrThrowError().config + stInstance.getRecipeInstanceOrThrow("accountlinking").config ) ) { (0, logger_1.logDebugMessage)( @@ -649,8 +671,8 @@ exports.AuthUtils = { ); // We try and list all users that can be linked to the input user based on the account info // later we can use these when trying to link or when checking if linking to the session user is possible. - const linkRes = await recipe_1.default - .getInstanceOrThrowError() + const linkRes = await stInstance + .getRecipeInstanceOrThrow("accountlinking") .tryLinkingByAccountInfoOrCreatePrimaryUser({ inputUser: inputUser, session, @@ -675,6 +697,7 @@ exports.AuthUtils = { "linkToSessionIfRequiredElseCreatePrimaryUserIdOrLinkByAccountInfo trying to link by session info" ); const sessionLinkingRes = await exports.AuthUtils.tryLinkingBySession({ + stInstance, sessionUser: authTypeRes.sessionUser, authenticatedUser: inputUser, authLoginMethod, @@ -704,9 +727,16 @@ exports.AuthUtils = { * * It throws INVALID_CLAIM_ERROR if shouldDoAutomaticAccountLinking returned `{ shouldAutomaticallyLink: false }` but the email verification status was wrong */ - tryAndMakeSessionUserIntoAPrimaryUser: async function (session, skipSessionUserUpdateInCore, userContext) { + tryAndMakeSessionUserIntoAPrimaryUser: async function ( + stInstance, + session, + skipSessionUserUpdateInCore, + userContext + ) { (0, logger_1.logDebugMessage)(`tryAndMakeSessionUserIntoAPrimaryUser called`); - const sessionUser = await (0, _1.getUser)(session.getUserId(), userContext); + const sessionUser = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: session.getUserId(), userContext }); if (sessionUser === undefined) { throw new error_1.default({ type: error_1.default.UNAUTHORISED, @@ -724,8 +754,8 @@ exports.AuthUtils = { // without any added benefits, since the core already checks all pre-conditions // We do this check here instead of using the shouldBecomePrimaryUser util, because // here we handle the shouldRequireVerification case differently - const shouldDoAccountLinking = await recipe_1.default - .getInstanceOrThrowError() + const shouldDoAccountLinking = await stInstance + .getRecipeInstanceOrThrow("accountlinking") .config.shouldDoAutomaticAccountLinking( sessionUser.loginMethods[0], undefined, @@ -764,8 +794,8 @@ exports.AuthUtils = { "This should never happen: email verification claim validator passed after setting value to false" ); } - const createPrimaryUserRes = await recipe_1.default - .getInstanceOrThrowError() + const createPrimaryUserRes = await stInstance + .getRecipeInstanceOrThrow("accountlinking") .recipeInterfaceImpl.createPrimaryUser({ recipeUserId: sessionUser.loginMethods[0].recipeUserId, userContext, @@ -807,6 +837,7 @@ exports.AuthUtils = { * if the session user is not primary. This can be resolved by making it primary and retrying the call. */ tryLinkingBySession: async function ({ + stInstance, linkingToSessionUserRequiresVerification, authLoginMethod, authenticatedUser, @@ -833,11 +864,13 @@ exports.AuthUtils = { // If we get here, it means that the session and the input user can be linked, so we try it. // Note that this function will not call shouldDoAutomaticAccountLinking and check the verification status before linking // it'll mark the freshly linked recipe user as verified if the email address was verified in the session user. - let linkAccountsResult = await recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl.linkAccounts({ - recipeUserId: authenticatedUser.loginMethods[0].recipeUserId, - primaryUserId: sessionUser.id, - userContext, - }); + let linkAccountsResult = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.linkAccounts({ + recipeUserId: authenticatedUser.loginMethods[0].recipeUserId, + primaryUserId: sessionUser.id, + userContext, + }); if (linkAccountsResult.status === "OK") { (0, logger_1.logDebugMessage)("tryLinkingBySession successfully linked input user to session user"); return { status: "OK", user: linkAccountsResult.user }; @@ -868,11 +901,17 @@ exports.AuthUtils = { return { status: "LINKING_TO_SESSION_USER_FAILED", reason: linkAccountsResult.status }; } }, - filterOutInvalidFirstFactorsOrThrowIfAllAreInvalid: async function (factorIds, tenantId, hasSession, userContext) { + filterOutInvalidFirstFactorsOrThrowIfAllAreInvalid: async function ( + stInstance, + factorIds, + tenantId, + hasSession, + userContext + ) { let validFactorIds = []; for (const id of factorIds) { // This util takes the tenant config into account (if it exists), then the MFA (static) config if it was initialized and set. - let validRes = await (0, utils_2.isValidFirstFactor)(tenantId, id, userContext); + let validRes = await (0, utils_2.isValidFirstFactor)(stInstance, tenantId, id, userContext); if (validRes.status === "TENANT_NOT_FOUND_ERROR") { if (hasSession) { throw new error_1.default({ @@ -902,22 +941,22 @@ exports.AuthUtils = { } return validFactorIds; }, - loadSessionInAuthAPIIfNeeded: async function (req, res, shouldTryLinkingWithSessionUser, userContext) { + loadSessionInAuthAPIIfNeeded: async function (stInstance, req, res, shouldTryLinkingWithSessionUser, userContext) { if (shouldTryLinkingWithSessionUser !== false) { (0, logger_1.logDebugMessage)( "loadSessionInAuthAPIIfNeeded: loading session because shouldTryLinkingWithSessionUser is not set to false so we may want to link later" ); - return await session_1.default.getSession( + return await stInstance.getRecipeInstanceOrThrow("session").getSession({ req, res, - { + options: { // This is optional only if shouldTryLinkingWithSessionUser is undefined // in the (old) 3.0 FDI, this flag didn't exist and we linking was based on the session presence and shouldDoAutomaticAccountLinking sessionRequired: shouldTryLinkingWithSessionUser === true, overrideGlobalClaimValidators: () => [], }, - userContext - ); + userContext, + }); } (0, logger_1.logDebugMessage)( "loadSessionInAuthAPIIfNeeded: skipping session loading because we are not linking and we would overwrite it anyway" @@ -926,6 +965,7 @@ exports.AuthUtils = { }, }; async function filterOutInvalidSecondFactorsOrThrowIfAllAreInvalid( + stInstance, factorIds, inputUserAlreadyLinkedToSessionUser, sessionUser, @@ -945,7 +985,7 @@ async function filterOutInvalidSecondFactorsOrThrowIfAllAreInvalid( (0, logger_1.logDebugMessage)( `filterOutInvalidSecondFactorsOrThrowIfAllAreInvalid called for ${factorIds.join(", ")}` ); - const mfaInstance = recipe_2.default.getInstance(); + const mfaInstance = stInstance.getRecipeInstance("multifactorauth"); if (mfaInstance !== undefined) { if (!inputUserAlreadyLinkedToSessionUser) { let factorsSetUpForUserProm; @@ -968,6 +1008,7 @@ async function filterOutInvalidSecondFactorsOrThrowIfAllAreInvalid( return mfaInfoProm.then((res) => res.mfaRequirementsForAuth); } mfaInfoProm = (0, utils_1.updateAndGetMFARelatedInfoInSession)({ + stInstance, session, userContext, }); diff --git a/lib/build/combinedRemoteJWKSet.d.ts b/lib/build/combinedRemoteJWKSet.d.ts index 482ef4756..703be957b 100644 --- a/lib/build/combinedRemoteJWKSet.d.ts +++ b/lib/build/combinedRemoteJWKSet.d.ts @@ -1,4 +1,5 @@ // @ts-nocheck +import type { Querier } from "./querier"; /** * We need this to reset the combinedJWKS in tests because we need to create a new instance of the combinedJWKS * for each test to avoid caching issues. @@ -13,9 +14,12 @@ export declare function resetCombinedJWKS(): void; Every core instance a backend is connected to is expected to connect to the same database and use the same key set for token verification. Otherwise, the result of session verification would depend on which core is currently available. */ -export declare function getCombinedJWKS(config: { - jwksRefreshIntervalSec: number; -}): ( +export declare function getCombinedJWKS( + querier: Querier, + config: { + jwksRefreshIntervalSec: number; + } +): ( protectedHeader?: import("jose").JWSHeaderParameters, token?: import("jose").FlattenedJWSInput ) => Promise; diff --git a/lib/build/combinedRemoteJWKSet.js b/lib/build/combinedRemoteJWKSet.js index 8ad30f64d..ef1dbef93 100644 --- a/lib/build/combinedRemoteJWKSet.js +++ b/lib/build/combinedRemoteJWKSet.js @@ -4,7 +4,6 @@ exports.resetCombinedJWKS = resetCombinedJWKS; exports.getCombinedJWKS = getCombinedJWKS; const jose_1 = require("jose"); const constants_1 = require("./recipe/session/constants"); -const querier_1 = require("./querier"); let combinedJWKS; /** * We need this to reset the combinedJWKS in tests because we need to create a new instance of the combinedJWKS @@ -22,16 +21,14 @@ function resetCombinedJWKS() { Every core instance a backend is connected to is expected to connect to the same database and use the same key set for token verification. Otherwise, the result of session verification would depend on which core is currently available. */ -function getCombinedJWKS(config) { +function getCombinedJWKS(querier, config) { if (combinedJWKS === undefined) { - const JWKS = querier_1.Querier.getNewInstanceOrThrowError(undefined) - .getAllCoreUrlsForPath("/.well-known/jwks.json") - .map((url) => - (0, jose_1.createRemoteJWKSet)(new URL(url), { - cacheMaxAge: config.jwksRefreshIntervalSec * 1000, - cooldownDuration: constants_1.JWKCacheCooldownInMs, - }) - ); + const JWKS = querier.getAllCoreUrlsForPath("/.well-known/jwks.json").map((url) => + (0, jose_1.createRemoteJWKSet)(new URL(url), { + cacheMaxAge: config.jwksRefreshIntervalSec * 1000, + cooldownDuration: constants_1.JWKCacheCooldownInMs, + }) + ); combinedJWKS = async (...args) => { let lastError = undefined; if (JWKS.length === 0) { diff --git a/lib/build/customFramework.js b/lib/build/customFramework.js index 9e2ab68ff..76179dc22 100644 --- a/lib/build/customFramework.js +++ b/lib/build/customFramework.js @@ -20,10 +20,11 @@ exports.withPreParsedRequestResponse = withPreParsedRequestResponse; const cookie_1 = require("cookie"); const custom_1 = require("./framework/custom"); const session_1 = __importDefault(require("./recipe/session")); -const recipe_1 = __importDefault(require("./recipe/session/recipe")); const jwt_1 = require("./recipe/session/jwt"); const accessToken_1 = require("./recipe/session/accessToken"); const combinedRemoteJWKSet_1 = require("./combinedRemoteJWKSet"); +const querier_1 = require("./querier"); +const supertokens_1 = __importDefault(require("./supertokens")); function createPreParsedRequest(request) { /** * This helper function can take any `Request` type of object @@ -116,8 +117,12 @@ async function getSessionForSSR(request) { async function getSessionForSSRUsingAccessToken(accessToken) { const hasToken = !!accessToken; try { - const sessionRecipe = recipe_1.default.getInstanceOrThrowError(); - const jwksToUse = (0, combinedRemoteJWKSet_1.getCombinedJWKS)(sessionRecipe.config); + const sessionRecipe = supertokens_1.default.getInstanceOrThrowError().getRecipeInstanceOrThrow("session"); + const querier = querier_1.Querier.getNewInstanceOrThrowError( + supertokens_1.default.getInstanceOrThrowError(), + sessionRecipe.getRecipeId() + ); + const jwksToUse = (0, combinedRemoteJWKSet_1.getCombinedJWKS)(querier, sessionRecipe.config); try { if (accessToken) { const tokenInfo = (0, jwt_1.parseJWTWithoutSignatureVerification)(accessToken); diff --git a/lib/build/index.js b/lib/build/index.js index fb496bec9..50fa3bee2 100644 --- a/lib/build/index.js +++ b/lib/build/index.js @@ -94,7 +94,6 @@ exports.User = void 0; const supertokens_1 = __importDefault(require("./supertokens")); const error_1 = __importStar(require("./error")); -const recipe_1 = __importDefault(require("./recipe/accountlinking/recipe")); const recipeUserId_1 = __importDefault(require("./recipeUserId")); const user_1 = require("./user"); const utils_1 = require("./utils"); @@ -110,18 +109,24 @@ class SuperTokensWrapper { .getUserCount(includeRecipeIds, tenantId, (0, utils_1.getUserContext)(userContext)); } static getUsersOldestFirst(input) { - return recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl.getUsers( - Object.assign(Object.assign({ timeJoinedOrder: "ASC" }, input), { - userContext: (0, utils_1.getUserContext)(input.userContext), - }) - ); + return supertokens_1.default + .getInstanceOrThrowError() + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUsers( + Object.assign(Object.assign({ timeJoinedOrder: "ASC" }, input), { + userContext: (0, utils_1.getUserContext)(input.userContext), + }) + ); } static getUsersNewestFirst(input) { - return recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl.getUsers( - Object.assign(Object.assign({ timeJoinedOrder: "DESC" }, input), { - userContext: (0, utils_1.getUserContext)(input.userContext), - }) - ); + return supertokens_1.default + .getInstanceOrThrowError() + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUsers( + Object.assign(Object.assign({ timeJoinedOrder: "DESC" }, input), { + userContext: (0, utils_1.getUserContext)(input.userContext), + }) + ); } static createUserIdMapping(input) { return supertokens_1.default @@ -152,25 +157,34 @@ class SuperTokensWrapper { ); } static async getUser(userId, userContext) { - return await recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl.getUser({ - userId, - userContext: (0, utils_1.getUserContext)(userContext), - }); + return await supertokens_1.default + .getInstanceOrThrowError() + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ + userId, + userContext: (0, utils_1.getUserContext)(userContext), + }); } static async listUsersByAccountInfo(tenantId, accountInfo, doUnionOfAccountInfo = false, userContext) { - return await recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl.listUsersByAccountInfo({ - tenantId, - accountInfo, - doUnionOfAccountInfo, - userContext: (0, utils_1.getUserContext)(userContext), - }); + return await supertokens_1.default + .getInstanceOrThrowError() + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.listUsersByAccountInfo({ + tenantId, + accountInfo, + doUnionOfAccountInfo, + userContext: (0, utils_1.getUserContext)(userContext), + }); } static async deleteUser(userId, removeAllLinkedAccounts = true, userContext) { - return await recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl.deleteUser({ - userId, - removeAllLinkedAccounts, - userContext: (0, utils_1.getUserContext)(userContext), - }); + return await supertokens_1.default + .getInstanceOrThrowError() + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.deleteUser({ + userId, + removeAllLinkedAccounts, + userContext: (0, utils_1.getUserContext)(userContext), + }); } static convertToRecipeUserId(recipeUserId) { return new recipeUserId_1.default(recipeUserId); diff --git a/lib/build/nextjs.d.ts b/lib/build/nextjs.d.ts index 2741fae6f..51a248508 100644 --- a/lib/build/nextjs.d.ts +++ b/lib/build/nextjs.d.ts @@ -1,5 +1,5 @@ // @ts-nocheck -import { CollectingResponse, PreParsedRequest } from "./framework/custom"; +import type { CollectingResponse, PreParsedRequest } from "./framework/custom"; import { SessionContainer, VerifySessionOptions } from "./recipe/session"; import { JWTPayload } from "jose"; type PartialNextRequest = { diff --git a/lib/build/normalisedURLDomain.d.ts b/lib/build/normalisedURLDomain.d.ts index b75c15d4b..60fddccf8 100644 --- a/lib/build/normalisedURLDomain.d.ts +++ b/lib/build/normalisedURLDomain.d.ts @@ -1,4 +1,5 @@ // @ts-nocheck +export declare function isAnIpAddress(ipaddress: string): boolean; export default class NormalisedURLDomain { private value; constructor(url: string); diff --git a/lib/build/normalisedURLDomain.js b/lib/build/normalisedURLDomain.js index 89d6da095..3c9989ecc 100644 --- a/lib/build/normalisedURLDomain.js +++ b/lib/build/normalisedURLDomain.js @@ -14,7 +14,12 @@ * under the License. */ Object.defineProperty(exports, "__esModule", { value: true }); -const utils_1 = require("./utils"); +exports.isAnIpAddress = isAnIpAddress; +function isAnIpAddress(ipaddress) { + return /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test( + ipaddress + ); +} class NormalisedURLDomain { constructor(url) { this.getAsStringDangerous = () => { @@ -32,7 +37,7 @@ function normaliseURLDomainOrThrowError(input, ignoreProtocol = false) { } let urlObj = new URL(input); if (ignoreProtocol) { - if (urlObj.hostname.startsWith("localhost") || (0, utils_1.isAnIpAddress)(urlObj.hostname)) { + if (urlObj.hostname.startsWith("localhost") || isAnIpAddress(urlObj.hostname)) { input = "http://" + urlObj.host; } else { input = "https://" + urlObj.host; diff --git a/lib/build/querier.d.ts b/lib/build/querier.d.ts index 3b449a94c..95c39e531 100644 --- a/lib/build/querier.d.ts +++ b/lib/build/querier.d.ts @@ -5,7 +5,9 @@ import { UserContext } from "./types"; import { NetworkInterceptor } from "./types"; import { PathParam, RequestBody, ResponseBody } from "./core/types"; import { paths } from "./core/paths"; +import type SuperTokens from "./supertokens"; export declare class Querier { + private stInstance; private static initCalled; private static hosts; private static apiKey; @@ -21,7 +23,7 @@ export declare class Querier { getAPIVersion: (userContext: UserContext) => Promise; static reset(): void; getHostsAliveForTesting: () => Set; - static getNewInstanceOrThrowError(rIdToCore?: string): Querier; + static getNewInstanceOrThrowError(stInstance: SuperTokens, rIdToCore?: string): Querier; static init( hosts?: { domain: NormalisedURLDomain; @@ -72,3 +74,26 @@ export declare class Querier { getAllCoreUrlsForPath(path: string): string[]; private sendRequestHelper; } +export declare const doFetch: typeof fetch; +export declare function postWithFetch( + url: string, + headers: Record, + body: any, + { + successLog, + errorLogHeader, + }: { + successLog: string; + errorLogHeader: string; + } +): Promise< + | { + resp: { + status: number; + body: any; + }; + } + | { + error: any; + } +>; diff --git a/lib/build/querier.js b/lib/build/querier.js index a0214e706..9d6750bc0 100644 --- a/lib/build/querier.js +++ b/lib/build/querier.js @@ -5,7 +5,8 @@ var __importDefault = return mod && mod.__esModule ? mod : { default: mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.Querier = void 0; +exports.doFetch = exports.Querier = void 0; +exports.postWithFetch = postWithFetch; /* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved. * * This software is licensed under the Apache License, Version 2.0 (the @@ -26,11 +27,12 @@ const normalisedURLPath_1 = __importDefault(require("./normalisedURLPath")); const processState_1 = require("./processState"); const constants_1 = require("./constants"); const logger_1 = require("./logger"); -const supertokens_1 = __importDefault(require("./supertokens")); +const cross_fetch_1 = __importDefault(require("cross-fetch")); class Querier { // we have rIdToCore so that recipes can force change the rId sent to core. This is a hack until the core is able // to support multiple rIds per API - constructor(hosts, rIdToCore) { + constructor(stInstance, hosts, rIdToCore) { + this.stInstance = stInstance; this.getAPIVersion = async (userContext) => { var _a; if (Querier.apiVersion !== undefined) { @@ -39,9 +41,8 @@ class Querier { processState_1.ProcessState.getInstance().addState( processState_1.PROCESS_STATE.CALLING_SERVICE_IN_GET_API_VERSION ); - const st = supertokens_1.default.getInstanceOrThrowError(); - const appInfo = st.appInfo; - const request = st.getRequestFromUserContext(userContext); + const appInfo = this.stInstance.appInfo; + const request = this.stInstance.getRequestFromUserContext(userContext); const queryParamsObj = { apiDomain: appInfo.apiDomain.getAsStringDangerous(), websiteDomain: appInfo.getOrigin({ request, userContext }).getAsStringDangerous(), @@ -70,7 +71,7 @@ class Querier { url = request.url; headers = request.headers; } - let response = await (0, utils_1.doFetch)(url + `?${queryParams}`, { + let response = await (0, exports.doFetch)(url + `?${queryParams}`, { method: "GET", headers, }); @@ -143,7 +144,7 @@ class Querier { body = request.body; } } - return (0, utils_1.doFetch)(url, { + return (0, exports.doFetch)(url, { method: "POST", body: body !== undefined ? JSON.stringify(body) : undefined, headers, @@ -193,7 +194,7 @@ class Querier { const finalURL = new URL(url); const searchParams = new URLSearchParams(params); finalURL.search = searchParams.toString(); - return (0, utils_1.doFetch)(finalURL.toString(), { + return (0, exports.doFetch)(finalURL.toString(), { method: "DELETE", body: body !== undefined ? JSON.stringify(body) : undefined, headers, @@ -281,7 +282,7 @@ class Querier { ); finalURL.search = searchParams.toString(); // Update cache and return - let response = await (0, utils_1.doFetch)(finalURL.toString(), { + let response = await (0, exports.doFetch)(finalURL.toString(), { method: "GET", headers, }); @@ -345,7 +346,7 @@ class Querier { Object.entries(params).filter(([_, value]) => value !== undefined) ); finalURL.search = searchParams.toString(); - return (0, utils_1.doFetch)(finalURL.toString(), { + return (0, exports.doFetch)(finalURL.toString(), { method: "GET", headers, }); @@ -392,7 +393,7 @@ class Querier { Object.entries(params).filter(([_, value]) => value !== undefined) ); finalURL.search = searchParams.toString(); - return (0, utils_1.doFetch)(finalURL.toString(), { + return (0, exports.doFetch)(finalURL.toString(), { method: "PUT", body: body !== undefined ? JSON.stringify(body) : undefined, headers, @@ -435,7 +436,7 @@ class Querier { body = request.body; } } - return (0, utils_1.doFetch)(url, { + return (0, exports.doFetch)(url, { method: "PATCH", body: body !== undefined ? JSON.stringify(body) : undefined, headers, @@ -544,11 +545,11 @@ class Querier { Querier.initCalled = false; Querier.apiVersion = undefined; } - static getNewInstanceOrThrowError(rIdToCore) { + static getNewInstanceOrThrowError(stInstance, rIdToCore) { if (!Querier.initCalled) { throw Error("Please call the supertokens.init function before using SuperTokens"); } - return new Querier(Querier.hosts, rIdToCore); + return new Querier(stInstance, Querier.hosts, rIdToCore); } static init(hosts, apiKey, networkInterceptor, disableCache) { if (!Querier.initCalled) { @@ -585,3 +586,92 @@ Querier.hostsAliveForTesting = new Set(); Querier.networkInterceptor = undefined; Querier.globalCacheTag = Date.now(); Querier.disableCache = false; +const doFetch = async (input, init) => { + // frameworks like nextJS cache fetch GET requests (https://nextjs.org/docs/app/building-your-application/caching#data-cache) + // we don't want that because it may lead to weird behaviour when querying the core. + if (init === undefined) { + processState_1.ProcessState.getInstance().addState( + processState_1.PROCESS_STATE.ADDING_NO_CACHE_HEADER_IN_FETCH + ); + init = { + cache: "no-store", + redirect: "manual", + }; + } else { + if (init.cache === undefined) { + processState_1.ProcessState.getInstance().addState( + processState_1.PROCESS_STATE.ADDING_NO_CACHE_HEADER_IN_FETCH + ); + init.cache = "no-store"; + init.redirect = "manual"; + } + } + // Remove the cache field if the runtime is Cloudflare Workers + // + // CF Workers did not support the cache field at all until Nov, 2024 + // when they added support for the `cache` field but it only supports + // `no-store`. + // + // The following check is to ensure that this doesn't error out in + // Cloudflare Workers where compatibility flag is set to an older version. + // + // Since there is no way for us to determine which compatibility flags are + // enabled, we are disabling the cache functionality for CF Workers altogether. + // Ref issue: https://github.com/cloudflare/workerd/issues/698 + if (isRunningInCloudflareWorker()) { + delete init.cache; + } + const fetchFunction = typeof fetch !== "undefined" ? fetch : cross_fetch_1.default; + try { + return await fetchFunction(input, init); + } catch (e) { + (0, logger_1.logDebugMessage)("Error fetching: " + e); + throw e; + } +}; +exports.doFetch = doFetch; +function isRunningInCloudflareWorker() { + return typeof navigator !== "undefined" && navigator.userAgent === "Cloudflare-Workers"; +} +async function postWithFetch(url, headers, body, { successLog, errorLogHeader }) { + let error; + let resp; + try { + const fetchResp = await (0, exports.doFetch)(url, { + method: "POST", + body: JSON.stringify(body), + headers, + }); + const respText = await fetchResp.text(); + resp = { + status: fetchResp.status, + body: JSON.parse(respText), + }; + if (fetchResp.status < 300) { + (0, logger_1.logDebugMessage)(successLog); + return { resp }; + } + (0, logger_1.logDebugMessage)(errorLogHeader); + (0, logger_1.logDebugMessage)(`Error status: ${fetchResp.status}`); + (0, logger_1.logDebugMessage)(`Error response: ${respText}`); + } catch (caught) { + error = caught; + (0, logger_1.logDebugMessage)(errorLogHeader); + if (error instanceof Error) { + (0, logger_1.logDebugMessage)(`Error: ${error.message}`); + (0, logger_1.logDebugMessage)(`Stack: ${error.stack}`); + } else { + (0, logger_1.logDebugMessage)(`Error: ${JSON.stringify(error)}`); + } + } + (0, logger_1.logDebugMessage)("Logging the input below:"); + (0, logger_1.logDebugMessage)(JSON.stringify(body, null, 2)); + if (error !== undefined) { + return { + error, + }; + } + return { + resp: resp, + }; +} diff --git a/lib/build/recipe/accountlinking/index.js b/lib/build/recipe/accountlinking/index.js index fb743ecb1..2032df5ad 100644 --- a/lib/build/recipe/accountlinking/index.js +++ b/lib/build/recipe/accountlinking/index.js @@ -32,7 +32,6 @@ exports.isEmailChangeAllowed = exports.init = void 0; const recipe_1 = __importDefault(require("./recipe")); -const __1 = require("../.."); const utils_1 = require("../../utils"); class Wrapper { /** @@ -45,7 +44,11 @@ class Wrapper { * no linking that happened. */ static async createPrimaryUserIdOrLinkAccounts(tenantId, recipeUserId, session, userContext) { - const user = await (0, __1.getUser)(recipeUserId.getAsString(), userContext); + const ctx = (0, utils_1.getUserContext)(userContext); + const user = await recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl.getUser({ + userId: recipeUserId.getAsString(), + userContext: ctx, + }); if (user === undefined) { // Should never really come here unless a programming error happened in the app throw new Error("Unknown recipeUserId"); @@ -54,7 +57,7 @@ class Wrapper { tenantId, inputUser: user, session, - userContext: (0, utils_1.getUserContext)(userContext), + userContext: ctx, }); if (linkRes.status === "NO_LINK") { return user; @@ -71,7 +74,11 @@ class Wrapper { * into a primary user itself. */ static async getPrimaryUserThatCanBeLinkedToRecipeUserId(tenantId, recipeUserId, userContext) { - const user = await (0, __1.getUser)(recipeUserId.getAsString(), userContext); + const ctx = (0, utils_1.getUserContext)(userContext); + const user = await recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl.getUser({ + userId: recipeUserId.getAsString(), + userContext: ctx, + }); if (user === undefined) { // Should never really come here unless a programming error happened in the app throw new Error("Unknown recipeUserId"); @@ -79,7 +86,7 @@ class Wrapper { return await recipe_1.default.getInstanceOrThrowError().getPrimaryUserThatCanBeLinkedToRecipeUserId({ tenantId, user, - userContext: (0, utils_1.getUserContext)(userContext), + userContext: ctx, }); } static async canCreatePrimaryUser(recipeUserId, userContext) { @@ -124,7 +131,11 @@ class Wrapper { }); } static async isSignInAllowed(tenantId, recipeUserId, session, userContext) { - const user = await (0, __1.getUser)(recipeUserId.getAsString(), userContext); + const ctx = (0, utils_1.getUserContext)(userContext); + const user = await recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl.getUser({ + userId: recipeUserId.getAsString(), + userContext: ctx, + }); if (user === undefined) { // Should never really come here unless a programming error happened in the app throw new Error("Unknown recipeUserId"); @@ -135,11 +146,15 @@ class Wrapper { session, tenantId, signInVerifiesLoginMethod: false, - userContext: (0, utils_1.getUserContext)(userContext), + userContext: ctx, }); } static async isEmailChangeAllowed(recipeUserId, newEmail, isVerified, session, userContext) { - const user = await (0, __1.getUser)(recipeUserId.getAsString(), userContext); + const ctx = (0, utils_1.getUserContext)(userContext); + const user = await recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl.getUser({ + userId: recipeUserId.getAsString(), + userContext: ctx, + }); if (user === undefined) { throw new Error("Passed in recipe user id does not exist"); } @@ -148,7 +163,7 @@ class Wrapper { newEmail, isVerified, session, - userContext: (0, utils_1.getUserContext)(userContext), + userContext: ctx, }); return res.allowed; } diff --git a/lib/build/recipe/accountlinking/recipe.d.ts b/lib/build/recipe/accountlinking/recipe.d.ts index 0fd989d5e..5b5ec51d8 100644 --- a/lib/build/recipe/accountlinking/recipe.d.ts +++ b/lib/build/recipe/accountlinking/recipe.d.ts @@ -8,12 +8,14 @@ import type { TypeNormalisedInput, RecipeInterface, TypeInput, AccountInfoWithRe import RecipeUserId from "../../recipeUserId"; import { LoginMethod } from "../../user"; import { SessionContainerInterface } from "../session/types"; +import type SuperTokens from "../../supertokens"; export default class Recipe extends RecipeModule { private static instance; static RECIPE_ID: "accountlinking"; config: TypeNormalisedInput; recipeInterfaceImpl: RecipeInterface; constructor( + stInstance: SuperTokens, recipeId: string, appInfo: NormalisedAppinfo, config: TypeInput | undefined, diff --git a/lib/build/recipe/accountlinking/recipe.js b/lib/build/recipe/accountlinking/recipe.js index f273ec084..aa2c92b55 100644 --- a/lib/build/recipe/accountlinking/recipe.js +++ b/lib/build/recipe/accountlinking/recipe.js @@ -23,16 +23,14 @@ const recipeModule_1 = __importDefault(require("../../recipeModule")); const utils_1 = require("./utils"); const supertokens_js_override_1 = __importDefault(require("supertokens-js-override")); const recipeImplementation_1 = __importDefault(require("./recipeImplementation")); -const querier_1 = require("../../querier"); const error_1 = __importDefault(require("../../error")); const processState_1 = require("../../processState"); const logger_1 = require("../../logger"); -const recipe_1 = __importDefault(require("../emailverification/recipe")); const utils_2 = require("../../utils"); const plugins_1 = require("../../plugins"); class Recipe extends recipeModule_1.default { - constructor(recipeId, appInfo, config, _recipes, _ingredients) { - super(recipeId, appInfo); + constructor(stInstance, recipeId, appInfo, config, _recipes, _ingredients) { + super(stInstance, recipeId, appInfo); this.getPrimaryUserThatCanBeLinkedToRecipeUserId = async ({ tenantId, user, userContext }) => { // first we check if this user itself is a primary user or not. If it is, we return that. if (user.isPrimaryUser) { @@ -516,9 +514,8 @@ class Recipe extends recipeModule_1.default { return { allowed: true }; }; this.verifyEmailForRecipeUserIfLinkedAccountsAreVerified = async (input) => { - try { - recipe_1.default.getInstanceOrThrowError(); - } catch (ignored) { + let emailVerificationInstance = this.stInstance.getRecipeInstance("emailverification"); + if (emailVerificationInstance === undefined) { // if email verification recipe is not initialized, we do a no-op return; } @@ -551,21 +548,19 @@ class Recipe extends recipeModule_1.default { } }); if (shouldVerifyEmail) { - let resp = await recipe_1.default - .getInstanceOrThrowError() - .recipeInterfaceImpl.createEmailVerificationToken({ - // While the token we create here is tenant specific, the verification status is not - // So we can use any tenantId the user is associated with here as long as we use the - // same in the verifyEmailUsingToken call - tenantId: input.user.tenantIds[0], - recipeUserId: input.recipeUserId, - email: recipeUserEmail, - userContext: input.userContext, - }); + let resp = await emailVerificationInstance.recipeInterfaceImpl.createEmailVerificationToken({ + // While the token we create here is tenant specific, the verification status is not + // So we can use any tenantId the user is associated with here as long as we use the + // same in the verifyEmailUsingToken call + tenantId: input.user.tenantIds[0], + recipeUserId: input.recipeUserId, + email: recipeUserEmail, + userContext: input.userContext, + }); if (resp.status === "OK") { // we purposely pass in false below cause we don't want account // linking to happen - await recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl.verifyEmailUsingToken({ + await emailVerificationInstance.recipeInterfaceImpl.verifyEmailUsingToken({ // See comment about tenantId in the createEmailVerificationToken params tenantId: input.user.tenantIds[0], token: resp.token, @@ -580,19 +575,16 @@ class Recipe extends recipeModule_1.default { this.config = (0, utils_1.validateAndNormaliseUserInput)(appInfo, config); { let builder = new supertokens_js_override_1.default( - (0, recipeImplementation_1.default)( - querier_1.Querier.getNewInstanceOrThrowError(recipeId), - this.config, - this - ) + (0, recipeImplementation_1.default)(this.querier, this.config, this) ); this.recipeInterfaceImpl = builder.override(this.config.override.functions).build(); } } static init(config) { - return (appInfo, _isInServerlessEnv, plugins) => { + return (stInstance, appInfo, _isInServerlessEnv, plugins) => { if (Recipe.instance === undefined) { Recipe.instance = new Recipe( + stInstance, Recipe.RECIPE_ID, appInfo, (0, plugins_1.applyPlugins)( diff --git a/lib/build/recipe/dashboard/api/analytics.d.ts b/lib/build/recipe/dashboard/api/analytics.d.ts index 7a3a834cd..ebcc25e93 100644 --- a/lib/build/recipe/dashboard/api/analytics.d.ts +++ b/lib/build/recipe/dashboard/api/analytics.d.ts @@ -1,12 +1,10 @@ // @ts-nocheck -import { APIInterface, APIOptions } from "../types"; -import { UserContext } from "../../../types"; +import { APIFunction } from "../types"; export type Response = { status: "OK"; }; -export default function analyticsPost( - _: APIInterface, - ___: string, - options: APIOptions, - userContext: UserContext -): Promise; +export default function analyticsPost({ + stInstance, + options, + userContext, +}: Parameters[0]): Promise; diff --git a/lib/build/recipe/dashboard/api/analytics.js b/lib/build/recipe/dashboard/api/analytics.js index 95568d4f2..c1d2955d3 100644 --- a/lib/build/recipe/dashboard/api/analytics.js +++ b/lib/build/recipe/dashboard/api/analytics.js @@ -20,14 +20,12 @@ var __importDefault = }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = analyticsPost; -const supertokens_1 = __importDefault(require("../../../supertokens")); const querier_1 = require("../../../querier"); const version_1 = require("../../../version"); const error_1 = __importDefault(require("../../../error")); -const utils_1 = require("../../../utils"); -async function analyticsPost(_, ___, options, userContext) { +async function analyticsPost({ stInstance, options, userContext }) { // If telemetry is disabled, dont send any event - if (!supertokens_1.default.getInstanceOrThrowError().telemetryEnabled) { + if (!stInstance.telemetryEnabled) { return { status: "OK", }; @@ -48,14 +46,12 @@ async function analyticsPost(_, ___, options, userContext) { let telemetryId; let numberOfUsers; try { - let querier = querier_1.Querier.getNewInstanceOrThrowError(options.recipeId); + let querier = querier_1.Querier.getNewInstanceOrThrowError(stInstance); let response = await querier.sendGetRequest("/telemetry", {}, userContext); if (response.exists) { telemetryId = response.telemetryId; } - numberOfUsers = await supertokens_1.default - .getInstanceOrThrowError() - .getUserCount(undefined, undefined, userContext); + numberOfUsers = await stInstance.getUserCount(undefined, undefined, userContext); } catch (_) { // If either telemetry id API or user count fetch fails, no event should be sent return { @@ -78,7 +74,7 @@ async function analyticsPost(_, ___, options, userContext) { dashboardVersion, }; try { - await (0, utils_1.doFetch)("https://api.supertokens.com/0/st/telemetry", { + await (0, querier_1.doFetch)("https://api.supertokens.com/0/st/telemetry", { method: "POST", body: JSON.stringify(data), headers: { diff --git a/lib/build/recipe/dashboard/api/apiKeyProtector.d.ts b/lib/build/recipe/dashboard/api/apiKeyProtector.d.ts index eb8ad8d0e..02ad26026 100644 --- a/lib/build/recipe/dashboard/api/apiKeyProtector.d.ts +++ b/lib/build/recipe/dashboard/api/apiKeyProtector.d.ts @@ -1,10 +1,3 @@ // @ts-nocheck -import { UserContext } from "../../../types"; -import { APIFunction, APIInterface, APIOptions } from "../types"; -export default function apiKeyProtector( - apiImplementation: APIInterface, - tenantId: string, - options: APIOptions, - apiFunction: APIFunction, - userContext: UserContext -): Promise; +import { APIFunction } from "../types"; +export default function apiKeyProtector(apiFunction: APIFunction, input: Parameters[0]): Promise; diff --git a/lib/build/recipe/dashboard/api/apiKeyProtector.js b/lib/build/recipe/dashboard/api/apiKeyProtector.js index 4825b948e..b4a405114 100644 --- a/lib/build/recipe/dashboard/api/apiKeyProtector.js +++ b/lib/build/recipe/dashboard/api/apiKeyProtector.js @@ -6,9 +6,25 @@ var __importDefault = }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = apiKeyProtector; +/* Copyright (c) 2022, VRAI Labs and/or its affiliates. All rights reserved. + * + * This software is licensed under the Apache License, Version 2.0 (the + * "License") as published by the Apache Software Foundation. + * + * You may not use this file except in compliance with the License. You may + * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ const error_1 = __importDefault(require("../error")); const utils_1 = require("../utils"); -async function apiKeyProtector(apiImplementation, tenantId, options, apiFunction, userContext) { +async function apiKeyProtector(apiFunction, input) { + const options = input.options; + const userContext = input.userContext; let shouldAllowAccess = false; try { shouldAllowAccess = await options.recipeImplementation.shouldAllowAccess({ @@ -30,7 +46,7 @@ async function apiKeyProtector(apiImplementation, tenantId, options, apiFunction (0, utils_1.sendUnauthorisedAccess)(options.res); return true; } - const response = await apiFunction(apiImplementation, tenantId, options, userContext); + const response = await apiFunction(input); options.res.sendJSONResponse(response); return true; } diff --git a/lib/build/recipe/dashboard/api/dashboard.d.ts b/lib/build/recipe/dashboard/api/dashboard.d.ts index 252a4acf3..aba372354 100644 --- a/lib/build/recipe/dashboard/api/dashboard.d.ts +++ b/lib/build/recipe/dashboard/api/dashboard.d.ts @@ -1,8 +1,3 @@ // @ts-nocheck -import { UserContext } from "../../../types"; -import { APIInterface, APIOptions } from "../types"; -export default function dashboard( - apiImplementation: APIInterface, - options: APIOptions, - userContext: UserContext -): Promise; +import { APIFunction } from "../types"; +export default function dashboard(input: Parameters[0]): Promise; diff --git a/lib/build/recipe/dashboard/api/dashboard.js b/lib/build/recipe/dashboard/api/dashboard.js index dc3704fe4..21a5c27c1 100644 --- a/lib/build/recipe/dashboard/api/dashboard.js +++ b/lib/build/recipe/dashboard/api/dashboard.js @@ -15,14 +15,14 @@ */ Object.defineProperty(exports, "__esModule", { value: true }); exports.default = dashboard; -async function dashboard(apiImplementation, options, userContext) { - if (apiImplementation.dashboardGET === undefined) { +async function dashboard(input) { + var _a; + const options = input.options; + const userContext = input.userContext; + if (((_a = input.apiImplementation) === null || _a === void 0 ? void 0 : _a.dashboardGET) === undefined) { return false; } - const htmlString = await apiImplementation.dashboardGET({ - options, - userContext, - }); + const htmlString = await input.apiImplementation.dashboardGET({ options, userContext }); options.res.sendHTMLResponse(htmlString); return true; } diff --git a/lib/build/recipe/dashboard/api/implementation.d.ts b/lib/build/recipe/dashboard/api/implementation.d.ts index 0218549fa..409eec4a7 100644 --- a/lib/build/recipe/dashboard/api/implementation.d.ts +++ b/lib/build/recipe/dashboard/api/implementation.d.ts @@ -1,3 +1,4 @@ // @ts-nocheck +import type SuperTokens from "../../../supertokens"; import { APIInterface } from "../types"; -export default function getAPIImplementation(): APIInterface; +export default function getAPIImplementation(stInstance: SuperTokens): APIInterface; diff --git a/lib/build/recipe/dashboard/api/implementation.js b/lib/build/recipe/dashboard/api/implementation.js index d27d45f51..42927d627 100644 --- a/lib/build/recipe/dashboard/api/implementation.js +++ b/lib/build/recipe/dashboard/api/implementation.js @@ -23,10 +23,9 @@ exports.default = getAPIImplementation; const normalisedURLDomain_1 = __importDefault(require("../../../normalisedURLDomain")); const normalisedURLPath_1 = __importDefault(require("../../../normalisedURLPath")); const querier_1 = require("../../../querier"); -const supertokens_1 = __importDefault(require("../../../supertokens")); const utils_1 = require("../../../utils"); const constants_1 = require("../constants"); -function getAPIImplementation() { +function getAPIImplementation(stInstance) { return { dashboardGET: async function (input) { const bundleBasePathString = await input.options.recipeImplementation.getDashboardBundleLocation({ @@ -36,7 +35,7 @@ function getAPIImplementation() { new normalisedURLDomain_1.default(bundleBasePathString).getAsStringDangerous() + new normalisedURLPath_1.default(bundleBasePathString).getAsStringDangerous(); let connectionURI = ""; - const superTokensInstance = supertokens_1.default.getInstanceOrThrowError(); + const superTokensInstance = stInstance; const authMode = input.options.config.authMode; if (superTokensInstance.supertokens !== undefined) { connectionURI = @@ -48,9 +47,10 @@ function getAPIImplementation() { ).getAsStringDangerous(); } let isSearchEnabled = false; - const cdiVersion = await querier_1.Querier.getNewInstanceOrThrowError(input.options.recipeId).getAPIVersion( - input.userContext - ); + const cdiVersion = await querier_1.Querier.getNewInstanceOrThrowError( + stInstance, + input.options.recipeId + ).getAPIVersion(input.userContext); if ((0, utils_1.maxVersion)("2.20", cdiVersion) === cdiVersion) { // Only enable search if CDI version is 2.20 or above isSearchEnabled = true; diff --git a/lib/build/recipe/dashboard/api/multitenancy/createOrUpdateThirdPartyConfig.d.ts b/lib/build/recipe/dashboard/api/multitenancy/createOrUpdateThirdPartyConfig.d.ts index 10331dfb0..790882c81 100644 --- a/lib/build/recipe/dashboard/api/multitenancy/createOrUpdateThirdPartyConfig.d.ts +++ b/lib/build/recipe/dashboard/api/multitenancy/createOrUpdateThirdPartyConfig.d.ts @@ -1,6 +1,5 @@ // @ts-nocheck -import { APIInterface, APIOptions } from "../../types"; -import { UserContext } from "../../../../types"; +import { APIFunction } from "../../types"; export type Response = | { status: "OK"; @@ -13,9 +12,9 @@ export type Response = status: "BOXY_ERROR"; message: string; }; -export default function createOrUpdateThirdPartyConfig( - _: APIInterface, - tenantId: string, - options: APIOptions, - userContext: UserContext -): Promise; +export default function createOrUpdateThirdPartyConfig({ + stInstance, + tenantId, + options, + userContext, +}: Parameters[0]): Promise; diff --git a/lib/build/recipe/dashboard/api/multitenancy/createOrUpdateThirdPartyConfig.js b/lib/build/recipe/dashboard/api/multitenancy/createOrUpdateThirdPartyConfig.js index da9585eb5..49b26968b 100644 --- a/lib/build/recipe/dashboard/api/multitenancy/createOrUpdateThirdPartyConfig.js +++ b/lib/build/recipe/dashboard/api/multitenancy/createOrUpdateThirdPartyConfig.js @@ -6,18 +6,17 @@ var __importDefault = }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = createOrUpdateThirdPartyConfig; -const multitenancy_1 = __importDefault(require("../../../multitenancy")); -const recipe_1 = __importDefault(require("../../../multitenancy/recipe")); const normalisedURLDomain_1 = __importDefault(require("../../../../normalisedURLDomain")); const normalisedURLPath_1 = __importDefault(require("../../../../normalisedURLPath")); const thirdpartyUtils_1 = require("../../../../thirdpartyUtils"); const constants_1 = require("../../../multitenancy/constants"); const utils_1 = require("../../../../utils"); -async function createOrUpdateThirdPartyConfig(_, tenantId, options, userContext) { +async function createOrUpdateThirdPartyConfig({ stInstance, tenantId, options, userContext }) { var _a; const requestBody = await options.req.getJSONBody(); const { providerConfig } = requestBody; - let tenantRes = await multitenancy_1.default.getTenant(tenantId, userContext); + let mtRecipe = stInstance.getRecipeInstanceOrThrow("multitenancy"); + let tenantRes = await mtRecipe.recipeInterfaceImpl.getTenant({ tenantId, userContext }); if (tenantRes === undefined) { return { status: "UNKNOWN_TENANT_ERROR", @@ -25,7 +24,6 @@ async function createOrUpdateThirdPartyConfig(_, tenantId, options, userContext) } if (tenantRes.thirdParty.providers.length === 0) { // This means that the tenant was using the static list of providers, we need to add them all before adding the new one - const mtRecipe = recipe_1.default.getInstance(); const staticProviders = (_a = mtRecipe === null || mtRecipe === void 0 ? void 0 : mtRecipe.staticThirdPartyProviders) !== null && _a !== void 0 @@ -35,14 +33,13 @@ async function createOrUpdateThirdPartyConfig(_, tenantId, options, userContext) (provider) => provider.includeInNonPublicTenantsByDefault === true || tenantId === constants_1.DEFAULT_TENANT_ID )) { - await multitenancy_1.default.createOrUpdateThirdPartyConfig( + await mtRecipe.recipeInterfaceImpl.createOrUpdateThirdPartyConfig({ tenantId, - { + config: { thirdPartyId: provider.config.thirdPartyId, }, - undefined, - userContext - ); + userContext, + }); // delay after each provider to avoid rate limiting await new Promise((r) => setTimeout(r, 500)); // 500ms } @@ -102,11 +99,10 @@ async function createOrUpdateThirdPartyConfig(_, tenantId, options, userContext) providerConfig.clients[0].clientSecret = resp.jsonResponse.clientSecret; } } - const thirdPartyRes = await multitenancy_1.default.createOrUpdateThirdPartyConfig( + const thirdPartyRes = await mtRecipe.recipeInterfaceImpl.createOrUpdateThirdPartyConfig({ tenantId, - providerConfig, - undefined, - userContext - ); + config: providerConfig, + userContext, + }); return thirdPartyRes; } diff --git a/lib/build/recipe/dashboard/api/multitenancy/createTenant.d.ts b/lib/build/recipe/dashboard/api/multitenancy/createTenant.d.ts index 7e5bad952..53370baeb 100644 --- a/lib/build/recipe/dashboard/api/multitenancy/createTenant.d.ts +++ b/lib/build/recipe/dashboard/api/multitenancy/createTenant.d.ts @@ -1,6 +1,5 @@ // @ts-nocheck -import { APIInterface, APIOptions } from "../../types"; -import { UserContext } from "../../../../types"; +import { APIFunction } from "../../types"; export type Response = | { status: "OK"; @@ -13,9 +12,4 @@ export type Response = status: "INVALID_TENANT_ID_ERROR"; message: string; }; -export default function createTenant( - _: APIInterface, - __: string, - options: APIOptions, - userContext: UserContext -): Promise; +export default function createTenant({ options, userContext }: Parameters[0]): Promise; diff --git a/lib/build/recipe/dashboard/api/multitenancy/createTenant.js b/lib/build/recipe/dashboard/api/multitenancy/createTenant.js index d03d62f55..e22d56e57 100644 --- a/lib/build/recipe/dashboard/api/multitenancy/createTenant.js +++ b/lib/build/recipe/dashboard/api/multitenancy/createTenant.js @@ -19,7 +19,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.default = createTenant; const multitenancy_1 = __importDefault(require("../../../multitenancy")); const error_1 = __importDefault(require("../../../../error")); -async function createTenant(_, __, options, userContext) { +async function createTenant({ options, userContext }) { const requestBody = await options.req.getJSONBody(); const { tenantId } = requestBody, config = __rest(requestBody, ["tenantId"]); diff --git a/lib/build/recipe/dashboard/api/multitenancy/deleteTenant.d.ts b/lib/build/recipe/dashboard/api/multitenancy/deleteTenant.d.ts index ee98ec2ec..375118fe8 100644 --- a/lib/build/recipe/dashboard/api/multitenancy/deleteTenant.d.ts +++ b/lib/build/recipe/dashboard/api/multitenancy/deleteTenant.d.ts @@ -1,6 +1,5 @@ // @ts-nocheck -import { APIInterface, APIOptions } from "../../types"; -import { UserContext } from "../../../../types"; +import { APIFunction } from "../../types"; export type Response = | { status: "OK"; @@ -9,9 +8,8 @@ export type Response = | { status: "CANNOT_DELETE_PUBLIC_TENANT_ERROR"; }; -export default function deleteTenant( - _: APIInterface, - tenantId: string, - __: APIOptions, - userContext: UserContext -): Promise; +export default function deleteTenant({ + stInstance, + tenantId, + userContext, +}: Parameters[0]): Promise; diff --git a/lib/build/recipe/dashboard/api/multitenancy/deleteTenant.js b/lib/build/recipe/dashboard/api/multitenancy/deleteTenant.js index 0d00947b9..7288a43cf 100644 --- a/lib/build/recipe/dashboard/api/multitenancy/deleteTenant.js +++ b/lib/build/recipe/dashboard/api/multitenancy/deleteTenant.js @@ -1,15 +1,11 @@ "use strict"; -var __importDefault = - (this && this.__importDefault) || - function (mod) { - return mod && mod.__esModule ? mod : { default: mod }; - }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = deleteTenant; -const multitenancy_1 = __importDefault(require("../../../multitenancy")); -async function deleteTenant(_, tenantId, __, userContext) { +async function deleteTenant({ stInstance, tenantId, userContext }) { try { - const deleteTenantRes = await multitenancy_1.default.deleteTenant(tenantId, userContext); + const deleteTenantRes = await stInstance + .getRecipeInstanceOrThrow("multitenancy") + .recipeInterfaceImpl.deleteTenant({ tenantId, userContext }); return deleteTenantRes; } catch (err) { const errMsg = err.message; diff --git a/lib/build/recipe/dashboard/api/multitenancy/deleteThirdPartyConfig.d.ts b/lib/build/recipe/dashboard/api/multitenancy/deleteThirdPartyConfig.d.ts index f554ce80b..4455702a6 100644 --- a/lib/build/recipe/dashboard/api/multitenancy/deleteThirdPartyConfig.d.ts +++ b/lib/build/recipe/dashboard/api/multitenancy/deleteThirdPartyConfig.d.ts @@ -1,6 +1,5 @@ // @ts-nocheck -import { APIInterface, APIOptions } from "../../types"; -import { UserContext } from "../../../../types"; +import { APIFunction } from "../../types"; export type Response = | { status: "OK"; @@ -9,9 +8,9 @@ export type Response = | { status: "UNKNOWN_TENANT_ERROR"; }; -export default function deleteThirdPartyConfig( - _: APIInterface, - tenantId: string, - options: APIOptions, - userContext: UserContext -): Promise; +export default function deleteThirdPartyConfig({ + stInstance, + tenantId, + options, + userContext, +}: Parameters[0]): Promise; diff --git a/lib/build/recipe/dashboard/api/multitenancy/deleteThirdPartyConfig.js b/lib/build/recipe/dashboard/api/multitenancy/deleteThirdPartyConfig.js index ce6b819d7..de65fe3ec 100644 --- a/lib/build/recipe/dashboard/api/multitenancy/deleteThirdPartyConfig.js +++ b/lib/build/recipe/dashboard/api/multitenancy/deleteThirdPartyConfig.js @@ -6,12 +6,10 @@ var __importDefault = }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = deleteThirdPartyConfig; -const multitenancy_1 = __importDefault(require("../../../multitenancy")); -const recipe_1 = __importDefault(require("../../../multitenancy/recipe")); const error_1 = __importDefault(require("../../../../error")); const multifactorauth_1 = require("../../../multifactorauth"); const constants_1 = require("../../../multitenancy/constants"); -async function deleteThirdPartyConfig(_, tenantId, options, userContext) { +async function deleteThirdPartyConfig({ stInstance, tenantId, options, userContext }) { var _a; const thirdPartyId = options.req.getKeyValueFromQuery("thirdPartyId"); if (typeof tenantId !== "string" || tenantId === "" || typeof thirdPartyId !== "string" || thirdPartyId === "") { @@ -20,7 +18,8 @@ async function deleteThirdPartyConfig(_, tenantId, options, userContext) { type: error_1.default.BAD_INPUT_ERROR, }); } - const tenantRes = await multitenancy_1.default.getTenant(tenantId, userContext); + const mtRecipe = stInstance.getRecipeInstanceOrThrow("multitenancy"); + const tenantRes = await mtRecipe.recipeInterfaceImpl.getTenant({ tenantId, userContext }); if (tenantRes === undefined) { return { status: "UNKNOWN_TENANT_ERROR", @@ -29,7 +28,7 @@ async function deleteThirdPartyConfig(_, tenantId, options, userContext) { const thirdPartyIdsFromCore = tenantRes.thirdParty.providers.map((provider) => provider.thirdPartyId); if (thirdPartyIdsFromCore.length === 0) { // this means that the tenant was using the static list of providers, we need to add them all before deleting one - const mtRecipe = recipe_1.default.getInstance(); + const mtRecipe = stInstance.getRecipeInstanceOrThrow("multitenancy"); const staticProviders = (_a = mtRecipe === null || mtRecipe === void 0 ? void 0 : mtRecipe.staticThirdPartyProviders) !== null && _a !== void 0 @@ -40,36 +39,43 @@ async function deleteThirdPartyConfig(_, tenantId, options, userContext) { provider.includeInNonPublicTenantsByDefault === true || tenantId === constants_1.DEFAULT_TENANT_ID )) { const providerId = provider.config.thirdPartyId; - await multitenancy_1.default.createOrUpdateThirdPartyConfig( + await mtRecipe.recipeInterfaceImpl.createOrUpdateThirdPartyConfig({ tenantId, - { + config: { thirdPartyId: providerId, }, - undefined, - userContext - ); + userContext, + }); // delay after each provider to avoid rate limiting await new Promise((r) => setTimeout(r, 500)); // 500ms } } else if (thirdPartyIdsFromCore.length === 1 && thirdPartyIdsFromCore[0] === thirdPartyId) { if (tenantRes.firstFactors === undefined) { // add all static first factors except thirdparty - await multitenancy_1.default.createOrUpdateTenant(tenantId, { - firstFactors: [ - multifactorauth_1.FactorIds.EMAILPASSWORD, - multifactorauth_1.FactorIds.OTP_PHONE, - multifactorauth_1.FactorIds.OTP_EMAIL, - multifactorauth_1.FactorIds.LINK_PHONE, - multifactorauth_1.FactorIds.LINK_EMAIL, - ], + await mtRecipe.recipeInterfaceImpl.createOrUpdateTenant({ + tenantId, + config: { + firstFactors: [ + multifactorauth_1.FactorIds.EMAILPASSWORD, + multifactorauth_1.FactorIds.OTP_PHONE, + multifactorauth_1.FactorIds.OTP_EMAIL, + multifactorauth_1.FactorIds.LINK_PHONE, + multifactorauth_1.FactorIds.LINK_EMAIL, + ], + }, + userContext, }); } else if (tenantRes.firstFactors.includes("thirdparty")) { // add all static first factors except thirdparty const newFirstFactors = tenantRes.firstFactors.filter((factor) => factor !== "thirdparty"); - await multitenancy_1.default.createOrUpdateTenant(tenantId, { - firstFactors: newFirstFactors, + await mtRecipe.recipeInterfaceImpl.createOrUpdateTenant({ + tenantId, + config: { + firstFactors: newFirstFactors, + }, + userContext, }); } } - return await multitenancy_1.default.deleteThirdPartyConfig(tenantId, thirdPartyId, userContext); + return await mtRecipe.recipeInterfaceImpl.deleteThirdPartyConfig({ tenantId, thirdPartyId, userContext }); } diff --git a/lib/build/recipe/dashboard/api/multitenancy/getTenantInfo.d.ts b/lib/build/recipe/dashboard/api/multitenancy/getTenantInfo.d.ts index b1b64593a..e8de154a8 100644 --- a/lib/build/recipe/dashboard/api/multitenancy/getTenantInfo.d.ts +++ b/lib/build/recipe/dashboard/api/multitenancy/getTenantInfo.d.ts @@ -1,6 +1,5 @@ // @ts-nocheck -import { APIInterface, APIOptions, CoreConfigFieldInfo } from "../../types"; -import { UserContext } from "../../../../types"; +import { APIFunction, CoreConfigFieldInfo } from "../../types"; export type Response = | { status: "OK"; @@ -21,9 +20,9 @@ export type Response = | { status: "UNKNOWN_TENANT_ERROR"; }; -export default function getTenantInfo( - _: APIInterface, - tenantId: string, - options: APIOptions, - userContext: UserContext -): Promise; +export default function getTenantInfo({ + stInstance, + tenantId, + options, + userContext, +}: Parameters[0]): Promise; diff --git a/lib/build/recipe/dashboard/api/multitenancy/getTenantInfo.js b/lib/build/recipe/dashboard/api/multitenancy/getTenantInfo.js index d76f2ee4c..f9c3e8d75 100644 --- a/lib/build/recipe/dashboard/api/multitenancy/getTenantInfo.js +++ b/lib/build/recipe/dashboard/api/multitenancy/getTenantInfo.js @@ -10,23 +10,16 @@ var __rest = } return t; }; -var __importDefault = - (this && this.__importDefault) || - function (mod) { - return mod && mod.__esModule ? mod : { default: mod }; - }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = getTenantInfo; -const multitenancy_1 = __importDefault(require("../../../multitenancy")); -const recipe_1 = __importDefault(require("../../../multitenancy/recipe")); -const supertokens_1 = __importDefault(require("../../../../supertokens")); const utils_1 = require("./utils"); const configUtils_1 = require("../../../thirdparty/providers/configUtils"); const querier_1 = require("../../../../querier"); const constants_1 = require("../../../multitenancy/constants"); -async function getTenantInfo(_, tenantId, options, userContext) { +async function getTenantInfo({ stInstance, tenantId, options, userContext }) { var _a, _b; - let tenantRes = await multitenancy_1.default.getTenant(tenantId, userContext); + const mtRecipe = stInstance.getRecipeInstanceOrThrow("multitenancy"); + let tenantRes = await mtRecipe.recipeInterfaceImpl.getTenant({ tenantId, userContext }); if (tenantRes === undefined) { return { status: "UNKNOWN_TENANT_ERROR", @@ -34,20 +27,20 @@ async function getTenantInfo(_, tenantId, options, userContext) { } let { status } = tenantRes, tenantConfig = __rest(tenantRes, ["status"]); - let firstFactors = (0, utils_1.getNormalisedFirstFactorsBasedOnTenantConfigFromCoreAndSDKInit)(tenantConfig); + let firstFactors = (0, utils_1.getNormalisedFirstFactorsBasedOnTenantConfigFromCoreAndSDKInit)( + stInstance, + tenantConfig + ); if (tenantRes === undefined) { return { status: "UNKNOWN_TENANT_ERROR", }; } - const userCount = await supertokens_1.default - .getInstanceOrThrowError() - .getUserCount(undefined, tenantId, userContext); + const userCount = await stInstance.getUserCount(undefined, tenantId, userContext); const providersFromCore = (_a = tenantRes === null || tenantRes === void 0 ? void 0 : tenantRes.thirdParty) === null || _a === void 0 ? void 0 : _a.providers; - const mtRecipe = recipe_1.default.getInstance(); const staticProviders = (_b = mtRecipe === null || mtRecipe === void 0 ? void 0 : mtRecipe.staticThirdPartyProviders) !== null && _b !== void 0 @@ -58,7 +51,7 @@ async function getTenantInfo(_, tenantId, options, userContext) { staticProviders, tenantId === constants_1.DEFAULT_TENANT_ID ); - let querier = querier_1.Querier.getNewInstanceOrThrowError(options.recipeId); + let querier = querier_1.Querier.getNewInstanceOrThrowError(stInstance, options.recipeId); let coreConfig = await querier.sendGetRequest( { path: "//recipe/dashboard/tenant/core-config", diff --git a/lib/build/recipe/dashboard/api/multitenancy/getThirdPartyConfig.d.ts b/lib/build/recipe/dashboard/api/multitenancy/getThirdPartyConfig.d.ts index 0af08fa57..6b799b88e 100644 --- a/lib/build/recipe/dashboard/api/multitenancy/getThirdPartyConfig.d.ts +++ b/lib/build/recipe/dashboard/api/multitenancy/getThirdPartyConfig.d.ts @@ -1,7 +1,6 @@ // @ts-nocheck -import { APIInterface, APIOptions } from "../../types"; +import { APIFunction } from "../../types"; import { ProviderConfig } from "../../../thirdparty/types"; -import { UserContext } from "../../../../types"; export type Response = | { status: "OK"; @@ -14,9 +13,9 @@ export type Response = | { status: "UNKNOWN_TENANT_ERROR"; }; -export default function getThirdPartyConfig( - _: APIInterface, - tenantId: string, - options: APIOptions, - userContext: UserContext -): Promise; +export default function getThirdPartyConfig({ + stInstance, + tenantId, + options, + userContext, +}: Parameters[0]): Promise; diff --git a/lib/build/recipe/dashboard/api/multitenancy/getThirdPartyConfig.js b/lib/build/recipe/dashboard/api/multitenancy/getThirdPartyConfig.js index 5e3f5622d..c9a6bed09 100644 --- a/lib/build/recipe/dashboard/api/multitenancy/getThirdPartyConfig.js +++ b/lib/build/recipe/dashboard/api/multitenancy/getThirdPartyConfig.js @@ -17,15 +17,14 @@ var __importDefault = }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = getThirdPartyConfig; -const multitenancy_1 = __importDefault(require("../../../multitenancy")); -const recipe_1 = __importDefault(require("../../../multitenancy/recipe")); const configUtils_1 = require("../../../thirdparty/providers/configUtils"); const normalisedURLDomain_1 = __importDefault(require("../../../../normalisedURLDomain")); const normalisedURLPath_1 = __importDefault(require("../../../../normalisedURLPath")); const thirdpartyUtils_1 = require("../../../../thirdpartyUtils"); -async function getThirdPartyConfig(_, tenantId, options, userContext) { +async function getThirdPartyConfig({ stInstance, tenantId, options, userContext }) { var _a, _b, _c, _d, _e; - let tenantRes = await multitenancy_1.default.getTenant(tenantId, userContext); + const mtRecipe = stInstance.getRecipeInstanceOrThrow("multitenancy"); + let tenantRes = await mtRecipe.recipeInterfaceImpl.getTenant({ tenantId, userContext }); if (tenantRes === undefined) { return { status: "UNKNOWN_TENANT_ERROR", @@ -39,7 +38,6 @@ async function getThirdPartyConfig(_, tenantId, options, userContext) { (_a = tenantRes === null || tenantRes === void 0 ? void 0 : tenantRes.thirdParty) === null || _a === void 0 ? void 0 : _a.providers; - const mtRecipe = recipe_1.default.getInstance(); let staticProviders = (mtRecipe === null || mtRecipe === void 0 ? void 0 : mtRecipe.staticThirdPartyProviders) ? mtRecipe.staticThirdPartyProviders.map((provider) => Object.assign({}, provider)) : []; diff --git a/lib/build/recipe/dashboard/api/multitenancy/listAllTenantsWithLoginMethods.d.ts b/lib/build/recipe/dashboard/api/multitenancy/listAllTenantsWithLoginMethods.d.ts index bdf50de30..c1c074c25 100644 --- a/lib/build/recipe/dashboard/api/multitenancy/listAllTenantsWithLoginMethods.d.ts +++ b/lib/build/recipe/dashboard/api/multitenancy/listAllTenantsWithLoginMethods.d.ts @@ -1,6 +1,5 @@ // @ts-nocheck -import { APIInterface, APIOptions } from "../../types"; -import { UserContext } from "../../../../types"; +import { APIFunction } from "../../types"; type TenantWithLoginMethods = { tenantId: string; firstFactors: string[]; @@ -9,10 +8,8 @@ export type Response = { status: "OK"; tenants: TenantWithLoginMethods[]; }; -export default function listAllTenantsWithLoginMethods( - _: APIInterface, - __: string, - ___: APIOptions, - userContext: UserContext -): Promise; +export default function listAllTenantsWithLoginMethods({ + stInstance, + userContext, +}: Parameters[0]): Promise; export {}; diff --git a/lib/build/recipe/dashboard/api/multitenancy/listAllTenantsWithLoginMethods.js b/lib/build/recipe/dashboard/api/multitenancy/listAllTenantsWithLoginMethods.js index aa63d5f74..81877335f 100644 --- a/lib/build/recipe/dashboard/api/multitenancy/listAllTenantsWithLoginMethods.js +++ b/lib/build/recipe/dashboard/api/multitenancy/listAllTenantsWithLoginMethods.js @@ -1,21 +1,19 @@ "use strict"; -var __importDefault = - (this && this.__importDefault) || - function (mod) { - return mod && mod.__esModule ? mod : { default: mod }; - }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = listAllTenantsWithLoginMethods; -const recipe_1 = __importDefault(require("../../../multitenancy/recipe")); const utils_1 = require("./utils"); -async function listAllTenantsWithLoginMethods(_, __, ___, userContext) { - const tenantsRes = await recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl.listAllTenants({ +async function listAllTenantsWithLoginMethods({ stInstance, userContext }) { + const mtRecipe = stInstance.getRecipeInstanceOrThrow("multitenancy"); + const tenantsRes = await mtRecipe.recipeInterfaceImpl.listAllTenants({ userContext, }); const finalTenants = []; for (let i = 0; i < tenantsRes.tenants.length; i++) { const currentTenant = tenantsRes.tenants[i]; - const loginMethods = (0, utils_1.getNormalisedFirstFactorsBasedOnTenantConfigFromCoreAndSDKInit)(currentTenant); + const loginMethods = (0, utils_1.getNormalisedFirstFactorsBasedOnTenantConfigFromCoreAndSDKInit)( + stInstance, + currentTenant + ); finalTenants.push({ tenantId: currentTenant.tenantId, firstFactors: loginMethods, diff --git a/lib/build/recipe/dashboard/api/multitenancy/updateTenantCoreConfig.d.ts b/lib/build/recipe/dashboard/api/multitenancy/updateTenantCoreConfig.d.ts index b13fbfcec..d85d8ecdd 100644 --- a/lib/build/recipe/dashboard/api/multitenancy/updateTenantCoreConfig.d.ts +++ b/lib/build/recipe/dashboard/api/multitenancy/updateTenantCoreConfig.d.ts @@ -1,6 +1,5 @@ // @ts-nocheck -import { APIInterface, APIOptions } from "../../types"; -import { UserContext } from "../../../../types"; +import { APIFunction } from "../../types"; export type Response = | { status: "OK"; @@ -12,9 +11,9 @@ export type Response = status: "INVALID_CONFIG_ERROR"; message: string; }; -export default function updateTenantCoreConfig( - _: APIInterface, - tenantId: string, - options: APIOptions, - userContext: UserContext -): Promise; +export default function updateTenantCoreConfig({ + stInstance, + tenantId, + options, + userContext, +}: Parameters[0]): Promise; diff --git a/lib/build/recipe/dashboard/api/multitenancy/updateTenantCoreConfig.js b/lib/build/recipe/dashboard/api/multitenancy/updateTenantCoreConfig.js index 0446b8fa1..939dd889a 100644 --- a/lib/build/recipe/dashboard/api/multitenancy/updateTenantCoreConfig.js +++ b/lib/build/recipe/dashboard/api/multitenancy/updateTenantCoreConfig.js @@ -1,16 +1,10 @@ "use strict"; -var __importDefault = - (this && this.__importDefault) || - function (mod) { - return mod && mod.__esModule ? mod : { default: mod }; - }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = updateTenantCoreConfig; -const recipe_1 = __importDefault(require("../../../multitenancy/recipe")); -async function updateTenantCoreConfig(_, tenantId, options, userContext) { +async function updateTenantCoreConfig({ stInstance, tenantId, options, userContext }) { const requestBody = await options.req.getJSONBody(); const { name, value } = requestBody; - const mtRecipe = recipe_1.default.getInstance(); + const mtRecipe = stInstance.getRecipeInstanceOrThrow("multitenancy"); const tenantRes = await mtRecipe.recipeInterfaceImpl.getTenant({ tenantId, userContext }); if (tenantRes === undefined) { return { diff --git a/lib/build/recipe/dashboard/api/multitenancy/updateTenantFirstFactor.d.ts b/lib/build/recipe/dashboard/api/multitenancy/updateTenantFirstFactor.d.ts index c25c1fdd6..0547c12c2 100644 --- a/lib/build/recipe/dashboard/api/multitenancy/updateTenantFirstFactor.d.ts +++ b/lib/build/recipe/dashboard/api/multitenancy/updateTenantFirstFactor.d.ts @@ -1,6 +1,5 @@ // @ts-nocheck -import { APIInterface, APIOptions } from "../../types"; -import { UserContext } from "../../../../types"; +import { APIFunction } from "../../types"; export type Response = | { status: "OK"; @@ -12,9 +11,9 @@ export type Response = | { status: "UNKNOWN_TENANT_ERROR"; }; -export default function updateTenantFirstFactor( - _: APIInterface, - tenantId: string, - options: APIOptions, - userContext: UserContext -): Promise; +export default function updateTenantFirstFactor({ + stInstance, + tenantId, + options, + userContext, +}: Parameters[0]): Promise; diff --git a/lib/build/recipe/dashboard/api/multitenancy/updateTenantFirstFactor.js b/lib/build/recipe/dashboard/api/multitenancy/updateTenantFirstFactor.js index 69d013fe8..d759d4a3d 100644 --- a/lib/build/recipe/dashboard/api/multitenancy/updateTenantFirstFactor.js +++ b/lib/build/recipe/dashboard/api/multitenancy/updateTenantFirstFactor.js @@ -1,21 +1,13 @@ "use strict"; -var __importDefault = - (this && this.__importDefault) || - function (mod) { - return mod && mod.__esModule ? mod : { default: mod }; - }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = updateTenantFirstFactor; -const recipe_1 = __importDefault(require("../../../multitenancy/recipe")); const utils_1 = require("./utils"); -async function updateTenantFirstFactor(_, tenantId, options, userContext) { +async function updateTenantFirstFactor({ stInstance, tenantId, options, userContext }) { const requestBody = await options.req.getJSONBody(); const { factorId, enable } = requestBody; - const mtRecipe = recipe_1.default.getInstance(); + const mtRecipe = stInstance.getRecipeInstanceOrThrow("multitenancy"); if (enable === true) { - if ( - !(mtRecipe === null || mtRecipe === void 0 ? void 0 : mtRecipe.allAvailableFirstFactors.includes(factorId)) - ) { + if (!mtRecipe.allAvailableFirstFactors.includes(factorId)) { return { status: "RECIPE_NOT_CONFIGURED_ON_BACKEND_SDK_ERROR", message: (0, utils_1.getFactorNotAvailableMessage)(factorId, mtRecipe.allAvailableFirstFactors), @@ -30,7 +22,10 @@ async function updateTenantFirstFactor(_, tenantId, options, userContext) { status: "UNKNOWN_TENANT_ERROR", }; } - let firstFactors = (0, utils_1.getNormalisedFirstFactorsBasedOnTenantConfigFromCoreAndSDKInit)(tenantRes); + let firstFactors = (0, utils_1.getNormalisedFirstFactorsBasedOnTenantConfigFromCoreAndSDKInit)( + stInstance, + tenantRes + ); if (enable === true) { if (!firstFactors.includes(factorId)) { firstFactors.push(factorId); diff --git a/lib/build/recipe/dashboard/api/multitenancy/updateTenantSecondaryFactor.d.ts b/lib/build/recipe/dashboard/api/multitenancy/updateTenantSecondaryFactor.d.ts index 547901072..39f3f3629 100644 --- a/lib/build/recipe/dashboard/api/multitenancy/updateTenantSecondaryFactor.d.ts +++ b/lib/build/recipe/dashboard/api/multitenancy/updateTenantSecondaryFactor.d.ts @@ -1,6 +1,5 @@ // @ts-nocheck -import { APIInterface, APIOptions } from "../../types"; -import { UserContext } from "../../../../types"; +import { APIFunction } from "../../types"; export type Response = | { status: "OK"; @@ -16,9 +15,9 @@ export type Response = | { status: "UNKNOWN_TENANT_ERROR"; }; -export default function updateTenantSecondaryFactor( - _: APIInterface, - tenantId: string, - options: APIOptions, - userContext: UserContext -): Promise; +export default function updateTenantSecondaryFactor({ + stInstance, + tenantId, + options, + userContext, +}: Parameters[0]): Promise; diff --git a/lib/build/recipe/dashboard/api/multitenancy/updateTenantSecondaryFactor.js b/lib/build/recipe/dashboard/api/multitenancy/updateTenantSecondaryFactor.js index 1879a6083..1d2b9ea9b 100644 --- a/lib/build/recipe/dashboard/api/multitenancy/updateTenantSecondaryFactor.js +++ b/lib/build/recipe/dashboard/api/multitenancy/updateTenantSecondaryFactor.js @@ -1,19 +1,12 @@ "use strict"; -var __importDefault = - (this && this.__importDefault) || - function (mod) { - return mod && mod.__esModule ? mod : { default: mod }; - }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = updateTenantSecondaryFactor; -const recipe_1 = __importDefault(require("../../../multitenancy/recipe")); -const recipe_2 = __importDefault(require("../../../multifactorauth/recipe")); const utils_1 = require("./utils"); -async function updateTenantSecondaryFactor(_, tenantId, options, userContext) { +async function updateTenantSecondaryFactor({ stInstance, tenantId, options, userContext }) { const requestBody = await options.req.getJSONBody(); const { factorId, enable } = requestBody; - const mtRecipe = recipe_1.default.getInstance(); - const mfaInstance = recipe_2.default.getInstance(); + const mtRecipe = stInstance.getRecipeInstanceOrThrow("multitenancy"); + const mfaInstance = stInstance.getRecipeInstanceOrThrow("multifactorauth"); if (mfaInstance === undefined) { return { status: "MFA_NOT_INITIALIZED_ERROR", @@ -37,6 +30,7 @@ async function updateTenantSecondaryFactor(_, tenantId, options, userContext) { } } let secondaryFactors = (0, utils_1.getNormalisedRequiredSecondaryFactorsBasedOnTenantConfigFromCoreAndSDKInit)( + stInstance, tenantRes ); if (enable === true) { diff --git a/lib/build/recipe/dashboard/api/multitenancy/utils.d.ts b/lib/build/recipe/dashboard/api/multitenancy/utils.d.ts index 76df5b8c0..d0ec61226 100644 --- a/lib/build/recipe/dashboard/api/multitenancy/utils.d.ts +++ b/lib/build/recipe/dashboard/api/multitenancy/utils.d.ts @@ -1,9 +1,12 @@ // @ts-nocheck -import { TenantConfig } from "../../../multitenancy/types"; +import type { TenantConfig } from "../../../multitenancy/types"; +import type SuperTokens from "../../../../supertokens"; export declare function getNormalisedFirstFactorsBasedOnTenantConfigFromCoreAndSDKInit( + stInstance: SuperTokens, tenantDetailsFromCore: TenantConfig ): string[]; export declare function getNormalisedRequiredSecondaryFactorsBasedOnTenantConfigFromCoreAndSDKInit( + stInstance: SuperTokens, tenantDetailsFromCore: TenantConfig ): string[]; export declare function factorIdToRecipe(factorId: string): string; diff --git a/lib/build/recipe/dashboard/api/multitenancy/utils.js b/lib/build/recipe/dashboard/api/multitenancy/utils.js index ba3404929..925eeedc1 100644 --- a/lib/build/recipe/dashboard/api/multitenancy/utils.js +++ b/lib/build/recipe/dashboard/api/multitenancy/utils.js @@ -1,9 +1,4 @@ "use strict"; -var __importDefault = - (this && this.__importDefault) || - function (mod) { - return mod && mod.__esModule ? mod : { default: mod }; - }; Object.defineProperty(exports, "__esModule", { value: true }); exports.getNormalisedFirstFactorsBasedOnTenantConfigFromCoreAndSDKInit = getNormalisedFirstFactorsBasedOnTenantConfigFromCoreAndSDKInit; @@ -11,13 +6,11 @@ exports.getNormalisedRequiredSecondaryFactorsBasedOnTenantConfigFromCoreAndSDKIn getNormalisedRequiredSecondaryFactorsBasedOnTenantConfigFromCoreAndSDKInit; exports.factorIdToRecipe = factorIdToRecipe; exports.getFactorNotAvailableMessage = getFactorNotAvailableMessage; -const recipe_1 = __importDefault(require("../../../multitenancy/recipe")); -const recipe_2 = __importDefault(require("../../../multifactorauth/recipe")); const utils_1 = require("../../../multitenancy/utils"); -const multifactorauth_1 = require("../../../multifactorauth"); -function getNormalisedFirstFactorsBasedOnTenantConfigFromCoreAndSDKInit(tenantDetailsFromCore) { +const types_1 = require("../../../multifactorauth/types"); +function getNormalisedFirstFactorsBasedOnTenantConfigFromCoreAndSDKInit(stInstance, tenantDetailsFromCore) { let firstFactors; - let mtInstance = recipe_1.default.getInstanceOrThrowError(); + let mtInstance = stInstance.getRecipeInstanceOrThrow("multitenancy"); if (tenantDetailsFromCore.firstFactors !== undefined) { firstFactors = tenantDetailsFromCore.firstFactors; // highest priority, config from core } else if (mtInstance.staticFirstFactors !== undefined) { @@ -46,8 +39,8 @@ function getNormalisedFirstFactorsBasedOnTenantConfigFromCoreAndSDKInit(tenantDe } return validFirstFactors; } -function getNormalisedRequiredSecondaryFactorsBasedOnTenantConfigFromCoreAndSDKInit(tenantDetailsFromCore) { - const mfaInstance = recipe_2.default.getInstance(); +function getNormalisedRequiredSecondaryFactorsBasedOnTenantConfigFromCoreAndSDKInit(stInstance, tenantDetailsFromCore) { + const mfaInstance = stInstance.getRecipeInstanceOrThrow("multifactorauth"); if (mfaInstance === undefined) { return []; } @@ -79,10 +72,10 @@ function getFactorNotAvailableMessage(factorId, availableFactors) { return `Please initialise ${recipeName} recipe to be able to use this login method`; } const passwordlessFactors = [ - multifactorauth_1.FactorIds.LINK_EMAIL, - multifactorauth_1.FactorIds.LINK_PHONE, - multifactorauth_1.FactorIds.OTP_EMAIL, - multifactorauth_1.FactorIds.OTP_PHONE, + types_1.FactorIds.LINK_EMAIL, + types_1.FactorIds.LINK_PHONE, + types_1.FactorIds.OTP_EMAIL, + types_1.FactorIds.OTP_PHONE, ]; const passwordlessFactorsNotAvailable = passwordlessFactors.filter((f) => !availableFactors.includes(f)); if (passwordlessFactorsNotAvailable.length === 4) { diff --git a/lib/build/recipe/dashboard/api/search/tagsGet.d.ts b/lib/build/recipe/dashboard/api/search/tagsGet.d.ts index df311a403..1049d1e4b 100644 --- a/lib/build/recipe/dashboard/api/search/tagsGet.d.ts +++ b/lib/build/recipe/dashboard/api/search/tagsGet.d.ts @@ -1,14 +1,12 @@ // @ts-nocheck -import { APIInterface, APIOptions } from "../../types"; -import { UserContext } from "../../../../types"; +import { APIFunction } from "../../types"; type TagsResponse = { status: "OK"; tags: string[]; }; -export declare const getSearchTags: ( - _: APIInterface, - ___: string, - options: APIOptions, - userContext: UserContext -) => Promise; +export declare const getSearchTags: ({ + stInstance, + options, + userContext, +}: Parameters[0]) => Promise; export {}; diff --git a/lib/build/recipe/dashboard/api/search/tagsGet.js b/lib/build/recipe/dashboard/api/search/tagsGet.js index 8fa929e30..290ecee0a 100644 --- a/lib/build/recipe/dashboard/api/search/tagsGet.js +++ b/lib/build/recipe/dashboard/api/search/tagsGet.js @@ -16,8 +16,8 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.getSearchTags = void 0; const querier_1 = require("../../../../querier"); -const getSearchTags = async (_, ___, options, userContext) => { - let querier = querier_1.Querier.getNewInstanceOrThrowError(options.recipeId); +const getSearchTags = async ({ stInstance, options, userContext }) => { + let querier = querier_1.Querier.getNewInstanceOrThrowError(stInstance, options.recipeId); let tagsResponse = await querier.sendGetRequest("/user/search/tags", {}, userContext); return tagsResponse; }; diff --git a/lib/build/recipe/dashboard/api/signIn.d.ts b/lib/build/recipe/dashboard/api/signIn.d.ts index 42ca0fba3..2d1a6703e 100644 --- a/lib/build/recipe/dashboard/api/signIn.d.ts +++ b/lib/build/recipe/dashboard/api/signIn.d.ts @@ -1,4 +1,3 @@ // @ts-nocheck -import { APIInterface, APIOptions } from "../types"; -import { UserContext } from "../../../types"; -export default function signIn(_: APIInterface, options: APIOptions, userContext: UserContext): Promise; +import { APIFunction } from "../types"; +export default function signIn(input: Parameters[0]): Promise; diff --git a/lib/build/recipe/dashboard/api/signIn.js b/lib/build/recipe/dashboard/api/signIn.js index 5f82f5054..6edaeeef2 100644 --- a/lib/build/recipe/dashboard/api/signIn.js +++ b/lib/build/recipe/dashboard/api/signIn.js @@ -23,7 +23,9 @@ exports.default = signIn; const utils_1 = require("../../../utils"); const error_1 = __importDefault(require("../../../error")); const querier_1 = require("../../../querier"); -async function signIn(_, options, userContext) { +async function signIn(input) { + const options = input.options; + const userContext = input.userContext; const { email, password } = await options.req.getJSONBody(); if (email === undefined) { throw new error_1.default({ @@ -37,7 +39,7 @@ async function signIn(_, options, userContext) { type: error_1.default.BAD_INPUT_ERROR, }); } - let querier = querier_1.Querier.getNewInstanceOrThrowError(undefined); + let querier = querier_1.Querier.getNewInstanceOrThrowError(input.stInstance); const signInResponse = await querier.sendPostRequest( "/recipe/dashboard/signin", { diff --git a/lib/build/recipe/dashboard/api/signOut.d.ts b/lib/build/recipe/dashboard/api/signOut.d.ts index b10c8509a..aab73642f 100644 --- a/lib/build/recipe/dashboard/api/signOut.d.ts +++ b/lib/build/recipe/dashboard/api/signOut.d.ts @@ -1,9 +1,3 @@ // @ts-nocheck -import { APIInterface, APIOptions } from "../types"; -import { UserContext } from "../../../types"; -export default function signOut( - _: APIInterface, - ___: string, - options: APIOptions, - userContext: UserContext -): Promise; +import { APIFunction } from "../types"; +export default function signOut({ stInstance, options, userContext }: Parameters[0]): Promise; diff --git a/lib/build/recipe/dashboard/api/signOut.js b/lib/build/recipe/dashboard/api/signOut.js index 2ea2dae3f..c033a5edd 100644 --- a/lib/build/recipe/dashboard/api/signOut.js +++ b/lib/build/recipe/dashboard/api/signOut.js @@ -17,14 +17,14 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.default = signOut; const utils_1 = require("../../../utils"); const querier_1 = require("../../../querier"); -async function signOut(_, ___, options, userContext) { +async function signOut({ stInstance, options, userContext }) { var _a; if (options.config.authMode === "api-key") { (0, utils_1.send200Response)(options.res, { status: "OK" }); } else { const sessionIdFormAuthHeader = (_a = options.req.getHeaderValue("authorization")) === null || _a === void 0 ? void 0 : _a.split(" ")[1]; - let querier = querier_1.Querier.getNewInstanceOrThrowError(undefined); + let querier = querier_1.Querier.getNewInstanceOrThrowError(stInstance); const sessionDeleteResponse = await querier.sendDeleteRequest( "/recipe/dashboard/session", undefined, diff --git a/lib/build/recipe/dashboard/api/user/create/emailpasswordUser.d.ts b/lib/build/recipe/dashboard/api/user/create/emailpasswordUser.d.ts index 5ce6dad3f..d3fa74f7a 100644 --- a/lib/build/recipe/dashboard/api/user/create/emailpasswordUser.d.ts +++ b/lib/build/recipe/dashboard/api/user/create/emailpasswordUser.d.ts @@ -1,7 +1,7 @@ // @ts-nocheck -import { APIInterface, APIOptions } from "../../../types"; -import { User, UserContext } from "../../../../../types"; -import RecipeUserId from "../../../../../recipeUserId"; +import { APIFunction } from "../../../types"; +import type { User } from "../../../../../types"; +import type RecipeUserId from "../../../../../recipeUserId"; type Response = | { status: "OK"; @@ -19,10 +19,10 @@ type Response = status: "PASSWORD_VALIDATION_ERROR"; message: string; }; -export declare const createEmailPasswordUser: ( - _: APIInterface, - tenantId: string, - options: APIOptions, - userContext: UserContext -) => Promise; +export declare const createEmailPasswordUser: ({ + stInstance, + tenantId, + options, + userContext, +}: Parameters[0]) => Promise; export {}; diff --git a/lib/build/recipe/dashboard/api/user/create/emailpasswordUser.js b/lib/build/recipe/dashboard/api/user/create/emailpasswordUser.js index cf84423bc..0e0de7604 100644 --- a/lib/build/recipe/dashboard/api/user/create/emailpasswordUser.js +++ b/lib/build/recipe/dashboard/api/user/create/emailpasswordUser.js @@ -22,11 +22,10 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.createEmailPasswordUser = void 0; const error_1 = __importDefault(require("../../../../../error")); const emailpassword_1 = __importDefault(require("../../../../emailpassword")); -const recipe_1 = __importDefault(require("../../../../emailpassword/recipe")); -const createEmailPasswordUser = async (_, tenantId, options, userContext) => { +const createEmailPasswordUser = async ({ stInstance, tenantId, options, userContext }) => { let emailPassword = undefined; try { - emailPassword = recipe_1.default.getInstanceOrThrowError(); + emailPassword = stInstance.getRecipeInstanceOrThrow("emailpassword"); } catch (error) { return { status: "FEATURE_NOT_ENABLED_ERROR", diff --git a/lib/build/recipe/dashboard/api/user/create/passwordlessUser.d.ts b/lib/build/recipe/dashboard/api/user/create/passwordlessUser.d.ts index 9c199f983..b23a67019 100644 --- a/lib/build/recipe/dashboard/api/user/create/passwordlessUser.d.ts +++ b/lib/build/recipe/dashboard/api/user/create/passwordlessUser.d.ts @@ -1,7 +1,7 @@ // @ts-nocheck -import { APIInterface, APIOptions } from "../../../types"; -import { User } from "../../../../../types"; -import RecipeUserId from "../../../../../recipeUserId"; +import { APIFunction } from "../../../types"; +import type { User } from "../../../../../types"; +import type RecipeUserId from "../../../../../recipeUserId"; type Response = | { status: string; @@ -20,10 +20,10 @@ type Response = status: "PHONE_VALIDATION_ERROR"; message: string; }; -export declare const createPasswordlessUser: ( - _: APIInterface, - tenantId: string, - options: APIOptions, - __: any -) => Promise; +export declare const createPasswordlessUser: ({ + stInstance, + tenantId, + options, + userContext, +}: Parameters[0]) => Promise; export {}; diff --git a/lib/build/recipe/dashboard/api/user/create/passwordlessUser.js b/lib/build/recipe/dashboard/api/user/create/passwordlessUser.js index 103b20e32..44cad5efe 100644 --- a/lib/build/recipe/dashboard/api/user/create/passwordlessUser.js +++ b/lib/build/recipe/dashboard/api/user/create/passwordlessUser.js @@ -21,13 +21,11 @@ var __importDefault = Object.defineProperty(exports, "__esModule", { value: true }); exports.createPasswordlessUser = void 0; const error_1 = __importDefault(require("../../../../../error")); -const passwordless_1 = __importDefault(require("../../../../passwordless")); -const recipe_1 = __importDefault(require("../../../../passwordless/recipe")); const max_1 = require("libphonenumber-js/max"); -const createPasswordlessUser = async (_, tenantId, options, __) => { +const createPasswordlessUser = async ({ stInstance, tenantId, options, userContext }) => { let passwordlessRecipe = undefined; try { - passwordlessRecipe = recipe_1.default.getInstanceOrThrowError(); + passwordlessRecipe = stInstance.getRecipeInstanceOrThrow("passwordless"); } catch (_) { return { status: "FEATURE_NOT_ENABLED_ERROR", @@ -79,8 +77,8 @@ const createPasswordlessUser = async (_, tenantId, options, __) => { phoneNumber = parsedPhoneNumber.format("E.164"); } } - return await passwordless_1.default.signInUp( - email !== undefined ? { email, tenantId } : { phoneNumber: phoneNumber, tenantId } + return await passwordlessRecipe.signInUp( + email !== undefined ? { email, tenantId, userContext } : { phoneNumber: phoneNumber, tenantId, userContext } ); }; exports.createPasswordlessUser = createPasswordlessUser; diff --git a/lib/build/recipe/dashboard/api/userdetails/userDelete.d.ts b/lib/build/recipe/dashboard/api/userdetails/userDelete.d.ts index 94e031899..20efa62bb 100644 --- a/lib/build/recipe/dashboard/api/userdetails/userDelete.d.ts +++ b/lib/build/recipe/dashboard/api/userdetails/userDelete.d.ts @@ -1,7 +1,11 @@ // @ts-nocheck -import { APIInterface, APIOptions } from "../../types"; +import { APIFunction } from "../../types"; type Response = { status: "OK"; }; -export declare const userDelete: (_: APIInterface, ___: string, options: APIOptions, __: any) => Promise; +export declare const userDelete: ({ + stInstance, + options, + userContext, +}: Parameters[0]) => Promise; export {}; diff --git a/lib/build/recipe/dashboard/api/userdetails/userDelete.js b/lib/build/recipe/dashboard/api/userdetails/userDelete.js index 53ae0bc2b..ceb5921e4 100644 --- a/lib/build/recipe/dashboard/api/userdetails/userDelete.js +++ b/lib/build/recipe/dashboard/api/userdetails/userDelete.js @@ -7,22 +7,23 @@ var __importDefault = Object.defineProperty(exports, "__esModule", { value: true }); exports.userDelete = void 0; const error_1 = __importDefault(require("../../../../error")); -const __1 = require("../../../.."); -const userDelete = async (_, ___, options, __) => { +const userDelete = async ({ stInstance, options, userContext }) => { const userId = options.req.getKeyValueFromQuery("userId"); let removeAllLinkedAccountsQueryValue = options.req.getKeyValueFromQuery("removeAllLinkedAccounts"); if (removeAllLinkedAccountsQueryValue !== undefined) { removeAllLinkedAccountsQueryValue = removeAllLinkedAccountsQueryValue.trim().toLowerCase(); } const removeAllLinkedAccounts = - removeAllLinkedAccountsQueryValue === undefined ? undefined : removeAllLinkedAccountsQueryValue === "true"; + removeAllLinkedAccountsQueryValue === undefined ? true : removeAllLinkedAccountsQueryValue === "true"; if (userId === undefined || userId === "") { throw new error_1.default({ message: "Missing required parameter 'userId'", type: error_1.default.BAD_INPUT_ERROR, }); } - await (0, __1.deleteUser)(userId, removeAllLinkedAccounts); + await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.deleteUser({ userId, removeAllLinkedAccounts, userContext }); return { status: "OK", }; diff --git a/lib/build/recipe/dashboard/api/userdetails/userEmailVerifyGet.js b/lib/build/recipe/dashboard/api/userdetails/userEmailVerifyGet.js index affe7a2ae..b4d3302f6 100644 --- a/lib/build/recipe/dashboard/api/userdetails/userEmailVerifyGet.js +++ b/lib/build/recipe/dashboard/api/userdetails/userEmailVerifyGet.js @@ -7,10 +7,8 @@ var __importDefault = Object.defineProperty(exports, "__esModule", { value: true }); exports.userEmailVerifyGet = void 0; const error_1 = __importDefault(require("../../../../error")); -const emailverification_1 = __importDefault(require("../../../emailverification")); -const recipe_1 = __importDefault(require("../../../emailverification/recipe")); const recipeUserId_1 = __importDefault(require("../../../../recipeUserId")); -const userEmailVerifyGet = async (_, ___, options, userContext) => { +const userEmailVerifyGet = async ({ stInstance, options, userContext }) => { const req = options.req; const recipeUserId = req.getKeyValueFromQuery("recipeUserId"); if (recipeUserId === undefined) { @@ -19,18 +17,33 @@ const userEmailVerifyGet = async (_, ___, options, userContext) => { type: error_1.default.BAD_INPUT_ERROR, }); } + let emailVerificationRecipe = undefined; try { - recipe_1.default.getInstanceOrThrowError(); + emailVerificationRecipe = stInstance.getRecipeInstanceOrThrow("emailverification"); } catch (e) { return { status: "FEATURE_NOT_ENABLED_ERROR", }; } - const response = await emailverification_1.default.isEmailVerified( - new recipeUserId_1.default(recipeUserId), + let email = undefined; + const emailInfo = await emailVerificationRecipe.getEmailForRecipeUserId( undefined, + new recipeUserId_1.default(recipeUserId), userContext ); + if (emailInfo.status === "OK") { + email = emailInfo.email; + } else { + throw new error_1.default({ + message: "Failed to get email for recipe user id", + type: error_1.default.BAD_INPUT_ERROR, + }); + } + const response = await emailVerificationRecipe.recipeInterfaceImpl.isEmailVerified({ + recipeUserId: new recipeUserId_1.default(recipeUserId), + email, + userContext, + }); return { status: "OK", isVerified: response, diff --git a/lib/build/recipe/dashboard/api/userdetails/userEmailVerifyPut.d.ts b/lib/build/recipe/dashboard/api/userdetails/userEmailVerifyPut.d.ts index 4135817f5..d83b8e48d 100644 --- a/lib/build/recipe/dashboard/api/userdetails/userEmailVerifyPut.d.ts +++ b/lib/build/recipe/dashboard/api/userdetails/userEmailVerifyPut.d.ts @@ -1,13 +1,12 @@ // @ts-nocheck -import { APIInterface, APIOptions } from "../../types"; -import { UserContext } from "../../../../types"; +import { APIFunction } from "../../types"; type Response = { status: "OK"; }; -export declare const userEmailVerifyPut: ( - _: APIInterface, - tenantId: string, - options: APIOptions, - userContext: UserContext -) => Promise; +export declare const userEmailVerifyPut: ({ + stInstance, + tenantId, + options, + userContext, +}: Parameters[0]) => Promise; export {}; diff --git a/lib/build/recipe/dashboard/api/userdetails/userEmailVerifyPut.js b/lib/build/recipe/dashboard/api/userdetails/userEmailVerifyPut.js index 604be3c27..9f37d040c 100644 --- a/lib/build/recipe/dashboard/api/userdetails/userEmailVerifyPut.js +++ b/lib/build/recipe/dashboard/api/userdetails/userEmailVerifyPut.js @@ -9,7 +9,7 @@ exports.userEmailVerifyPut = void 0; const error_1 = __importDefault(require("../../../../error")); const emailverification_1 = __importDefault(require("../../../emailverification")); const recipeUserId_1 = __importDefault(require("../../../../recipeUserId")); -const userEmailVerifyPut = async (_, tenantId, options, userContext) => { +const userEmailVerifyPut = async ({ stInstance, tenantId, options, userContext }) => { const requestBody = await options.req.getJSONBody(); const recipeUserId = requestBody.recipeUserId; const verified = requestBody.verified; @@ -25,13 +25,36 @@ const userEmailVerifyPut = async (_, tenantId, options, userContext) => { type: error_1.default.BAD_INPUT_ERROR, }); } + let emailVerificationRecipe = undefined; + try { + emailVerificationRecipe = stInstance.getRecipeInstanceOrThrow("emailverification"); + } catch (e) { + throw new error_1.default({ + message: "Email verification recipe not initialised", + type: error_1.default.BAD_INPUT_ERROR, + }); + } + let email = undefined; + const emailInfo = await emailVerificationRecipe.getEmailForRecipeUserId( + undefined, + new recipeUserId_1.default(recipeUserId), + userContext + ); + if (emailInfo.status === "OK") { + email = emailInfo.email; + } else { + throw new error_1.default({ + message: "Failed to get email for recipe user id", + type: error_1.default.BAD_INPUT_ERROR, + }); + } if (verified) { - const tokenResponse = await emailverification_1.default.createEmailVerificationToken( + const tokenResponse = await emailVerificationRecipe.recipeInterfaceImpl.createEmailVerificationToken({ + recipeUserId: new recipeUserId_1.default(recipeUserId), + email: email, tenantId, - new recipeUserId_1.default(recipeUserId), - undefined, - userContext - ); + userContext, + }); if (tokenResponse.status === "EMAIL_ALREADY_VERIFIED_ERROR") { return { status: "OK", diff --git a/lib/build/recipe/dashboard/api/userdetails/userEmailVerifyTokenPost.d.ts b/lib/build/recipe/dashboard/api/userdetails/userEmailVerifyTokenPost.d.ts index 22a89ae87..45ba5bbe3 100644 --- a/lib/build/recipe/dashboard/api/userdetails/userEmailVerifyTokenPost.d.ts +++ b/lib/build/recipe/dashboard/api/userdetails/userEmailVerifyTokenPost.d.ts @@ -1,13 +1,12 @@ // @ts-nocheck -import { APIInterface, APIOptions } from "../../types"; -import { UserContext } from "../../../../types"; +import { APIFunction } from "../../types"; type Response = { status: "OK" | "EMAIL_ALREADY_VERIFIED_ERROR"; }; -export declare const userEmailVerifyTokenPost: ( - _: APIInterface, - tenantId: string, - options: APIOptions, - userContext: UserContext -) => Promise; +export declare const userEmailVerifyTokenPost: ({ + stInstance, + tenantId, + options, + userContext, +}: Parameters[0]) => Promise; export {}; diff --git a/lib/build/recipe/dashboard/api/userdetails/userEmailVerifyTokenPost.js b/lib/build/recipe/dashboard/api/userdetails/userEmailVerifyTokenPost.js index 7d65748c8..0239ccaa5 100644 --- a/lib/build/recipe/dashboard/api/userdetails/userEmailVerifyTokenPost.js +++ b/lib/build/recipe/dashboard/api/userdetails/userEmailVerifyTokenPost.js @@ -9,7 +9,7 @@ exports.userEmailVerifyTokenPost = void 0; const error_1 = __importDefault(require("../../../../error")); const emailverification_1 = __importDefault(require("../../../emailverification")); const __1 = require("../../../.."); -const userEmailVerifyTokenPost = async (_, tenantId, options, userContext) => { +const userEmailVerifyTokenPost = async ({ stInstance, tenantId, options, userContext }) => { const requestBody = await options.req.getJSONBody(); const recipeUserId = requestBody.recipeUserId; if (recipeUserId === undefined || typeof recipeUserId !== "string") { @@ -18,7 +18,9 @@ const userEmailVerifyTokenPost = async (_, tenantId, options, userContext) => { type: error_1.default.BAD_INPUT_ERROR, }); } - const user = await (0, __1.getUser)(recipeUserId, userContext); + const user = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: recipeUserId, userContext }); if (!user) { throw new error_1.default({ message: "Unknown 'recipeUserId'", diff --git a/lib/build/recipe/dashboard/api/userdetails/userGet.js b/lib/build/recipe/dashboard/api/userdetails/userGet.js index 00dbdfffd..0b427de0f 100644 --- a/lib/build/recipe/dashboard/api/userdetails/userGet.js +++ b/lib/build/recipe/dashboard/api/userdetails/userGet.js @@ -7,10 +7,7 @@ var __importDefault = Object.defineProperty(exports, "__esModule", { value: true }); exports.userGet = void 0; const error_1 = __importDefault(require("../../../../error")); -const recipe_1 = __importDefault(require("../../../usermetadata/recipe")); -const usermetadata_1 = __importDefault(require("../../../usermetadata")); -const __1 = require("../../../.."); -const userGet = async (_, ___, options, userContext) => { +const userGet = async ({ stInstance, options, userContext }) => { const userId = options.req.getKeyValueFromQuery("userId"); if (userId === undefined || userId === "") { throw new error_1.default({ @@ -18,15 +15,16 @@ const userGet = async (_, ___, options, userContext) => { type: error_1.default.BAD_INPUT_ERROR, }); } - let user = await (0, __1.getUser)(userId, userContext); + let user = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId, userContext }); if (user === undefined) { return { status: "NO_USER_FOUND_ERROR", }; } - try { - recipe_1.default.getInstanceOrThrowError(); - } catch (_) { + let usermetadataRecipe = stInstance.getRecipeInstance("usermetadata"); + if (usermetadataRecipe === undefined) { return { status: "OK", user: Object.assign(Object.assign({}, user.toJson()), { @@ -35,7 +33,7 @@ const userGet = async (_, ___, options, userContext) => { }), }; } - const userMetaData = await usermetadata_1.default.getUserMetadata(userId, userContext); + const userMetaData = await usermetadataRecipe.recipeInterfaceImpl.getUserMetadata({ userId, userContext }); const { first_name, last_name } = userMetaData.metadata; return { status: "OK", diff --git a/lib/build/recipe/dashboard/api/userdetails/userMetadataGet.js b/lib/build/recipe/dashboard/api/userdetails/userMetadataGet.js index b2e71cdce..daf3db972 100644 --- a/lib/build/recipe/dashboard/api/userdetails/userMetadataGet.js +++ b/lib/build/recipe/dashboard/api/userdetails/userMetadataGet.js @@ -7,9 +7,7 @@ var __importDefault = Object.defineProperty(exports, "__esModule", { value: true }); exports.userMetaDataGet = void 0; const error_1 = __importDefault(require("../../../../error")); -const recipe_1 = __importDefault(require("../../../usermetadata/recipe")); -const usermetadata_1 = __importDefault(require("../../../usermetadata")); -const userMetaDataGet = async (_, ___, options, userContext) => { +const userMetaDataGet = async ({ stInstance, options, userContext }) => { const userId = options.req.getKeyValueFromQuery("userId"); if (userId === undefined || userId === "") { throw new error_1.default({ @@ -17,14 +15,15 @@ const userMetaDataGet = async (_, ___, options, userContext) => { type: error_1.default.BAD_INPUT_ERROR, }); } + let usermetadataRecipe = undefined; try { - recipe_1.default.getInstanceOrThrowError(); + usermetadataRecipe = stInstance.getRecipeInstanceOrThrow("usermetadata"); } catch (e) { return { status: "FEATURE_NOT_ENABLED_ERROR", }; } - const metaDataResponse = usermetadata_1.default.getUserMetadata(userId, userContext); + const metaDataResponse = usermetadataRecipe.recipeInterfaceImpl.getUserMetadata({ userId, userContext }); return { status: "OK", data: (await metaDataResponse).metadata, diff --git a/lib/build/recipe/dashboard/api/userdetails/userMetadataPut.d.ts b/lib/build/recipe/dashboard/api/userdetails/userMetadataPut.d.ts index a4cbbfe32..9c082a572 100644 --- a/lib/build/recipe/dashboard/api/userdetails/userMetadataPut.d.ts +++ b/lib/build/recipe/dashboard/api/userdetails/userMetadataPut.d.ts @@ -1,13 +1,11 @@ // @ts-nocheck -import { APIInterface, APIOptions } from "../../types"; -import { UserContext } from "../../../../types"; +import { APIFunction } from "../../types"; type Response = { status: "OK"; }; -export declare const userMetadataPut: ( - _: APIInterface, - ___: string, - options: APIOptions, - userContext: UserContext -) => Promise; +export declare const userMetadataPut: ({ + stInstance, + options, + userContext, +}: Parameters[0]) => Promise; export {}; diff --git a/lib/build/recipe/dashboard/api/userdetails/userMetadataPut.js b/lib/build/recipe/dashboard/api/userdetails/userMetadataPut.js index 0b77de89f..63eeeedc8 100644 --- a/lib/build/recipe/dashboard/api/userdetails/userMetadataPut.js +++ b/lib/build/recipe/dashboard/api/userdetails/userMetadataPut.js @@ -6,15 +6,13 @@ var __importDefault = }; Object.defineProperty(exports, "__esModule", { value: true }); exports.userMetadataPut = void 0; -const recipe_1 = __importDefault(require("../../../usermetadata/recipe")); -const usermetadata_1 = __importDefault(require("../../../usermetadata")); const error_1 = __importDefault(require("../../../../error")); -const userMetadataPut = async (_, ___, options, userContext) => { +const userMetadataPut = async ({ stInstance, options, userContext }) => { const requestBody = await options.req.getJSONBody(); const userId = requestBody.userId; const data = requestBody.data; // This is to throw an error early in case the recipe has not been initialised - recipe_1.default.getInstanceOrThrowError(); + const usermetadataRecipe = stInstance.getRecipeInstanceOrThrow("usermetadata"); if (userId === undefined || typeof userId !== "string") { throw new error_1.default({ message: "Required parameter 'userId' is missing or has an invalid type", @@ -56,8 +54,12 @@ const userMetadataPut = async (_, ___, options, userContext) => { * * Removing first ensures that the final data is exactly what the user wanted it to be */ - await usermetadata_1.default.clearUserMetadata(userId, userContext); - await usermetadata_1.default.updateUserMetadata(userId, JSON.parse(data), userContext); + await usermetadataRecipe.recipeInterfaceImpl.clearUserMetadata({ userId, userContext }); + await usermetadataRecipe.recipeInterfaceImpl.updateUserMetadata({ + userId, + metadataUpdate: JSON.parse(data), + userContext, + }); return { status: "OK", }; diff --git a/lib/build/recipe/dashboard/api/userdetails/userPasswordPut.d.ts b/lib/build/recipe/dashboard/api/userdetails/userPasswordPut.d.ts index 1b69cd932..34c645732 100644 --- a/lib/build/recipe/dashboard/api/userdetails/userPasswordPut.d.ts +++ b/lib/build/recipe/dashboard/api/userdetails/userPasswordPut.d.ts @@ -1,6 +1,5 @@ // @ts-nocheck -import { APIInterface, APIOptions } from "../../types"; -import { UserContext } from "../../../../types"; +import { APIFunction } from "../../types"; type Response = | { status: "OK"; @@ -9,10 +8,10 @@ type Response = status: "INVALID_PASSWORD_ERROR"; error: string; }; -export declare const userPasswordPut: ( - _: APIInterface, - tenantId: string, - options: APIOptions, - userContext: UserContext -) => Promise; +export declare const userPasswordPut: ({ + stInstance, + tenantId, + options, + userContext, +}: Parameters[0]) => Promise; export {}; diff --git a/lib/build/recipe/dashboard/api/userdetails/userPasswordPut.js b/lib/build/recipe/dashboard/api/userdetails/userPasswordPut.js index 9045520c5..b0a6ffab2 100644 --- a/lib/build/recipe/dashboard/api/userdetails/userPasswordPut.js +++ b/lib/build/recipe/dashboard/api/userdetails/userPasswordPut.js @@ -7,9 +7,8 @@ var __importDefault = Object.defineProperty(exports, "__esModule", { value: true }); exports.userPasswordPut = void 0; const error_1 = __importDefault(require("../../../../error")); -const emailpassword_1 = __importDefault(require("../../../emailpassword")); const recipeUserId_1 = __importDefault(require("../../../../recipeUserId")); -const userPasswordPut = async (_, tenantId, options, userContext) => { +const userPasswordPut = async ({ stInstance, tenantId, options, userContext }) => { const requestBody = await options.req.getJSONBody(); const recipeUserId = requestBody.recipeUserId; const newPassword = requestBody.newPassword; @@ -25,7 +24,8 @@ const userPasswordPut = async (_, tenantId, options, userContext) => { type: error_1.default.BAD_INPUT_ERROR, }); } - const updateResponse = await emailpassword_1.default.updateEmailOrPassword({ + const emailpasswordRecipe = stInstance.getRecipeInstanceOrThrow("emailpassword"); + const updateResponse = await emailpasswordRecipe.recipeInterfaceImpl.updateEmailOrPassword({ recipeUserId: new recipeUserId_1.default(recipeUserId), password: newPassword, tenantIdForPasswordPolicy: tenantId, diff --git a/lib/build/recipe/dashboard/api/userdetails/userPut.d.ts b/lib/build/recipe/dashboard/api/userdetails/userPut.d.ts index ff9d4f276..20380b863 100644 --- a/lib/build/recipe/dashboard/api/userdetails/userPut.d.ts +++ b/lib/build/recipe/dashboard/api/userdetails/userPut.d.ts @@ -1,6 +1,5 @@ // @ts-nocheck -import { APIInterface, APIOptions } from "../../types"; -import { UserContext } from "../../../../types"; +import { APIFunction } from "../../types"; type Response = | { status: "OK"; @@ -27,10 +26,10 @@ type Response = status: "PHONE_NUMBER_CHANGE_NOT_ALLOWED_ERROR"; error: string; }; -export declare const userPut: ( - _: APIInterface, - tenantId: string, - options: APIOptions, - userContext: UserContext -) => Promise; +export declare const userPut: ({ + stInstance, + tenantId, + options, + userContext, +}: Parameters[0]) => Promise; export {}; diff --git a/lib/build/recipe/dashboard/api/userdetails/userPut.js b/lib/build/recipe/dashboard/api/userdetails/userPut.js index c0f37c1d3..5052bb9a5 100644 --- a/lib/build/recipe/dashboard/api/userdetails/userPut.js +++ b/lib/build/recipe/dashboard/api/userdetails/userPut.js @@ -7,22 +7,14 @@ var __importDefault = Object.defineProperty(exports, "__esModule", { value: true }); exports.userPut = void 0; const error_1 = __importDefault(require("../../../../error")); -const recipe_1 = __importDefault(require("../../../emailpassword/recipe")); -const recipe_2 = __importDefault(require("../../../passwordless/recipe")); -const recipe_3 = __importDefault(require("../../../webauthn/recipe")); -const emailpassword_1 = __importDefault(require("../../../emailpassword")); -const passwordless_1 = __importDefault(require("../../../passwordless")); -const webauthn_1 = __importDefault(require("../../../webauthn")); const utils_1 = require("../../utils"); -const recipe_4 = __importDefault(require("../../../usermetadata/recipe")); -const usermetadata_1 = __importDefault(require("../../../usermetadata")); const constants_1 = require("../../../emailpassword/constants"); const utils_2 = require("../../../passwordless/utils"); const recipeUserId_1 = __importDefault(require("../../../../recipeUserId")); -const updateEmailForRecipeId = async (recipeId, recipeUserId, email, tenantId, userContext) => { +const updateEmailForRecipeId = async (stInstance, recipeId, recipeUserId, email, tenantId, userContext) => { if (recipeId === "emailpassword") { - let emailFormFields = recipe_1.default - .getInstanceOrThrowError() + let emailFormFields = stInstance + .getRecipeInstanceOrThrow("emailpassword") .config.signUpFeature.formFields.filter((field) => field.id === constants_1.FORM_FIELD_EMAIL_ID); let validationError = await emailFormFields[0].validate(email, tenantId, userContext); if (validationError !== undefined) { @@ -31,11 +23,14 @@ const updateEmailForRecipeId = async (recipeId, recipeUserId, email, tenantId, u error: validationError, }; } - const emailUpdateResponse = await emailpassword_1.default.updateEmailOrPassword({ - recipeUserId, - email, - userContext, - }); + const emailUpdateResponse = await stInstance + .getRecipeInstanceOrThrow("emailpassword") + .recipeInterfaceImpl.updateEmailOrPassword({ + recipeUserId, + email, + userContext, + tenantIdForPasswordPolicy: tenantId, + }); if (emailUpdateResponse.status === "EMAIL_ALREADY_EXISTS_ERROR") { return { status: "EMAIL_ALREADY_EXISTS_ERROR", @@ -55,7 +50,8 @@ const updateEmailForRecipeId = async (recipeId, recipeUserId, email, tenantId, u if (recipeId === "passwordless") { let isValidEmail = true; let validationError = ""; - const passwordlessConfig = recipe_2.default.getInstanceOrThrowError().config; + const passwordlessRecipe = stInstance.getRecipeInstanceOrThrow("passwordless"); + const passwordlessConfig = passwordlessRecipe.config; if (passwordlessConfig.contactMethod === "PHONE") { const validationResult = await (0, utils_2.defaultValidateEmail)(email); if (validationResult !== undefined) { @@ -75,7 +71,7 @@ const updateEmailForRecipeId = async (recipeId, recipeUserId, email, tenantId, u error: validationError, }; } - const updateResult = await passwordless_1.default.updateUser({ + const updateResult = await passwordlessRecipe.recipeInterfaceImpl.updateUser({ recipeUserId, email, userContext, @@ -102,16 +98,15 @@ const updateEmailForRecipeId = async (recipeId, recipeUserId, email, tenantId, u }; } if (recipeId === "webauthn") { - let validationError = await recipe_3.default - .getInstanceOrThrowError() - .config.validateEmailAddress(email, tenantId, userContext); + const webauthnRecipe = stInstance.getRecipeInstanceOrThrow("webauthn"); + let validationError = await webauthnRecipe.config.validateEmailAddress(email, tenantId, userContext); if (validationError !== undefined) { return { status: "INVALID_EMAIL_ERROR", error: validationError, }; } - const emailUpdateResponse = await webauthn_1.default.updateUserEmail({ + const emailUpdateResponse = await webauthnRecipe.recipeInterfaceImpl.updateUserEmail({ email, recipeUserId: recipeUserId.getAsString(), tenantId, @@ -133,10 +128,11 @@ const updateEmailForRecipeId = async (recipeId, recipeUserId, email, tenantId, u */ throw new Error("Should never come here"); }; -const updatePhoneForRecipeId = async (recipeUserId, phone, tenantId, userContext) => { +const updatePhoneForRecipeId = async (stInstance, recipeUserId, phone, tenantId, userContext) => { let isValidPhone = true; let validationError = ""; - const passwordlessConfig = recipe_2.default.getInstanceOrThrowError().config; + const passwordlessRecipe = stInstance.getRecipeInstanceOrThrow("passwordless"); + const passwordlessConfig = passwordlessRecipe.config; if (passwordlessConfig.contactMethod === "EMAIL") { const validationResult = await (0, utils_2.defaultValidatePhoneNumber)(phone); if (validationResult !== undefined) { @@ -156,7 +152,7 @@ const updatePhoneForRecipeId = async (recipeUserId, phone, tenantId, userContext error: validationError, }; } - const updateResult = await passwordless_1.default.updateUser({ + const updateResult = await passwordlessRecipe.recipeInterfaceImpl.updateUser({ recipeUserId, phoneNumber: phone, userContext, @@ -179,7 +175,7 @@ const updatePhoneForRecipeId = async (recipeUserId, phone, tenantId, userContext status: "OK", }; }; -const userPut = async (_, tenantId, options, userContext) => { +const userPut = async ({ stInstance, tenantId, options, userContext }) => { const requestBody = await options.req.getJSONBody(); const recipeUserId = requestBody.recipeUserId; const recipeId = requestBody.recipeId; @@ -230,6 +226,7 @@ const userPut = async (_, tenantId, options, userContext) => { }); } let userResponse = await (0, utils_1.getUserForRecipeId)( + stInstance, new recipeUserId_1.default(recipeUserId), recipeId, userContext @@ -238,14 +235,8 @@ const userPut = async (_, tenantId, options, userContext) => { throw new Error("Should never come here"); } if (firstName.trim() !== "" || lastName.trim() !== "") { - let isRecipeInitialised = false; - try { - recipe_4.default.getInstanceOrThrowError(); - isRecipeInitialised = true; - } catch (_) { - // no op - } - if (isRecipeInitialised) { + let usermetadataRecipe = stInstance.getRecipeInstance("usermetadata"); + if (usermetadataRecipe) { let metaDataUpdate = {}; if (firstName.trim() !== "") { metaDataUpdate["first_name"] = firstName.trim(); @@ -253,11 +244,16 @@ const userPut = async (_, tenantId, options, userContext) => { if (lastName.trim() !== "") { metaDataUpdate["last_name"] = lastName.trim(); } - await usermetadata_1.default.updateUserMetadata(userResponse.user.id, metaDataUpdate, userContext); + await usermetadataRecipe.recipeInterfaceImpl.updateUserMetadata({ + userId: userResponse.user.id, + metadataUpdate: metaDataUpdate, + userContext, + }); } } if (email.trim() !== "") { const emailUpdateResponse = await updateEmailForRecipeId( + stInstance, userResponse.recipe, new recipeUserId_1.default(recipeUserId), email.trim(), @@ -276,6 +272,7 @@ const userPut = async (_, tenantId, options, userContext) => { } if (phone.trim() !== "") { const phoneUpdateResponse = await updatePhoneForRecipeId( + stInstance, new recipeUserId_1.default(recipeUserId), phone.trim(), tenantId, diff --git a/lib/build/recipe/dashboard/api/userdetails/userSessionsGet.js b/lib/build/recipe/dashboard/api/userdetails/userSessionsGet.js index 2528cf4ff..373fd9a1c 100644 --- a/lib/build/recipe/dashboard/api/userdetails/userSessionsGet.js +++ b/lib/build/recipe/dashboard/api/userdetails/userSessionsGet.js @@ -7,8 +7,8 @@ var __importDefault = Object.defineProperty(exports, "__esModule", { value: true }); exports.userSessionsGet = void 0; const error_1 = __importDefault(require("../../../../error")); -const session_1 = __importDefault(require("../../../session")); -const userSessionsGet = async (_, ___, options, userContext) => { +const constants_1 = require("../../../multitenancy/constants"); +const userSessionsGet = async ({ stInstance, options, userContext }) => { const userId = options.req.getKeyValueFromQuery("userId"); if (userId === undefined || userId === "") { throw new error_1.default({ @@ -16,14 +16,24 @@ const userSessionsGet = async (_, ___, options, userContext) => { type: error_1.default.BAD_INPUT_ERROR, }); } - const response = await session_1.default.getAllSessionHandlesForUser(userId, undefined, undefined, userContext); + const sessionRecipe = stInstance.getRecipeInstanceOrThrow("session"); + const response = await sessionRecipe.recipeInterfaceImpl.getAllSessionHandlesForUser({ + userId, + fetchSessionsForAllLinkedAccounts: true, + tenantId: constants_1.DEFAULT_TENANT_ID, + fetchAcrossAllTenants: true, + userContext, + }); let sessions = []; let sessionInfoPromises = []; for (let i = 0; i < response.length; i++) { sessionInfoPromises.push( new Promise(async (res, rej) => { try { - const sessionResponse = await session_1.default.getSessionInformation(response[i], userContext); + const sessionResponse = await sessionRecipe.recipeInterfaceImpl.getSessionInformation({ + sessionHandle: response[i], + userContext, + }); if (sessionResponse !== undefined) { const accessTokenPayload = sessionResponse.customClaimsInAccessTokenPayload; delete sessionResponse.customClaimsInAccessTokenPayload; diff --git a/lib/build/recipe/dashboard/api/userdetails/userSessionsPost.d.ts b/lib/build/recipe/dashboard/api/userdetails/userSessionsPost.d.ts index 2da7a484d..921ebb7e2 100644 --- a/lib/build/recipe/dashboard/api/userdetails/userSessionsPost.d.ts +++ b/lib/build/recipe/dashboard/api/userdetails/userSessionsPost.d.ts @@ -1,13 +1,11 @@ // @ts-nocheck -import { APIInterface, APIOptions } from "../../types"; -import { UserContext } from "../../../../types"; +import { APIFunction } from "../../types"; type Response = { status: "OK"; }; -export declare const userSessionsPost: ( - _: APIInterface, - ___: string, - options: APIOptions, - userContext: UserContext -) => Promise; +export declare const userSessionsPost: ({ + stInstance, + options, + userContext, +}: Parameters[0]) => Promise; export {}; diff --git a/lib/build/recipe/dashboard/api/userdetails/userSessionsPost.js b/lib/build/recipe/dashboard/api/userdetails/userSessionsPost.js index 51ab7f94a..9ad8854ce 100644 --- a/lib/build/recipe/dashboard/api/userdetails/userSessionsPost.js +++ b/lib/build/recipe/dashboard/api/userdetails/userSessionsPost.js @@ -7,8 +7,7 @@ var __importDefault = Object.defineProperty(exports, "__esModule", { value: true }); exports.userSessionsPost = void 0; const error_1 = __importDefault(require("../../../../error")); -const session_1 = __importDefault(require("../../../session")); -const userSessionsPost = async (_, ___, options, userContext) => { +const userSessionsPost = async ({ stInstance, options, userContext }) => { const requestBody = await options.req.getJSONBody(); const sessionHandles = requestBody.sessionHandles; if (sessionHandles === undefined || !Array.isArray(sessionHandles)) { @@ -17,7 +16,8 @@ const userSessionsPost = async (_, ___, options, userContext) => { type: error_1.default.BAD_INPUT_ERROR, }); } - await session_1.default.revokeMultipleSessions(sessionHandles, userContext); + const sessionRecipe = stInstance.getRecipeInstanceOrThrow("session"); + await sessionRecipe.recipeInterfaceImpl.revokeMultipleSessions({ sessionHandles, userContext }); return { status: "OK", }; diff --git a/lib/build/recipe/dashboard/api/userdetails/userUnlinkGet.d.ts b/lib/build/recipe/dashboard/api/userdetails/userUnlinkGet.d.ts index b7c3067df..fc2d92dce 100644 --- a/lib/build/recipe/dashboard/api/userdetails/userUnlinkGet.d.ts +++ b/lib/build/recipe/dashboard/api/userdetails/userUnlinkGet.d.ts @@ -1,13 +1,11 @@ // @ts-nocheck -import { APIInterface, APIOptions } from "../../types"; -import { UserContext } from "../../../../types"; +import { APIFunction } from "../../types"; type Response = { status: "OK"; }; -export declare const userUnlink: ( - _: APIInterface, - ___: string, - options: APIOptions, - userContext: UserContext -) => Promise; +export declare const userUnlink: ({ + stInstance, + options, + userContext, +}: Parameters[0]) => Promise; export {}; diff --git a/lib/build/recipe/dashboard/api/userdetails/userUnlinkGet.js b/lib/build/recipe/dashboard/api/userdetails/userUnlinkGet.js index 11283fce1..8d39f7b92 100644 --- a/lib/build/recipe/dashboard/api/userdetails/userUnlinkGet.js +++ b/lib/build/recipe/dashboard/api/userdetails/userUnlinkGet.js @@ -7,9 +7,8 @@ var __importDefault = Object.defineProperty(exports, "__esModule", { value: true }); exports.userUnlink = void 0; const error_1 = __importDefault(require("../../../../error")); -const accountlinking_1 = __importDefault(require("../../../accountlinking")); const recipeUserId_1 = __importDefault(require("../../../../recipeUserId")); -const userUnlink = async (_, ___, options, userContext) => { +const userUnlink = async ({ stInstance, options, userContext }) => { const recipeUserId = options.req.getKeyValueFromQuery("recipeUserId"); if (recipeUserId === undefined) { throw new error_1.default({ @@ -17,7 +16,9 @@ const userUnlink = async (_, ___, options, userContext) => { type: error_1.default.BAD_INPUT_ERROR, }); } - await accountlinking_1.default.unlinkAccount(new recipeUserId_1.default(recipeUserId), userContext); + await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.unlinkAccount({ recipeUserId: new recipeUserId_1.default(recipeUserId), userContext }); return { status: "OK", }; diff --git a/lib/build/recipe/dashboard/api/userroles/addRoleToUser.d.ts b/lib/build/recipe/dashboard/api/userroles/addRoleToUser.d.ts index 8485ed162..dd25782a6 100644 --- a/lib/build/recipe/dashboard/api/userroles/addRoleToUser.d.ts +++ b/lib/build/recipe/dashboard/api/userroles/addRoleToUser.d.ts @@ -1,11 +1,6 @@ // @ts-nocheck -import { APIInterface, APIOptions } from "../../types"; -declare const addRoleToUser: ( - _: APIInterface, - tenantId: string, - options: APIOptions, - __: any -) => Promise< +import { APIFunction } from "../../types"; +declare const addRoleToUser: ({ stInstance, tenantId, options, userContext }: Parameters[0]) => Promise< | { status: "OK"; didUserAlreadyHaveRole: boolean; diff --git a/lib/build/recipe/dashboard/api/userroles/addRoleToUser.js b/lib/build/recipe/dashboard/api/userroles/addRoleToUser.js index c7b1e0397..e16df6194 100644 --- a/lib/build/recipe/dashboard/api/userroles/addRoleToUser.js +++ b/lib/build/recipe/dashboard/api/userroles/addRoleToUser.js @@ -5,12 +5,11 @@ var __importDefault = return mod && mod.__esModule ? mod : { default: mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -const recipe_1 = __importDefault(require("../../../userroles/recipe")); -const userroles_1 = __importDefault(require("../../../userroles")); const error_1 = __importDefault(require("../../../../error")); -const addRoleToUser = async (_, tenantId, options, __) => { +const addRoleToUser = async ({ stInstance, tenantId, options, userContext }) => { + let userrolesRecipe = undefined; try { - recipe_1.default.getInstanceOrThrowError(); + userrolesRecipe = stInstance.getRecipeInstanceOrThrow("userroles"); } catch (_) { return { status: "FEATURE_NOT_ENABLED_ERROR", @@ -31,7 +30,7 @@ const addRoleToUser = async (_, tenantId, options, __) => { type: error_1.default.BAD_INPUT_ERROR, }); } - const response = await userroles_1.default.addRoleToUser(tenantId, userId, role); + const response = await userrolesRecipe.recipeInterfaceImpl.addRoleToUser({ userId, role, tenantId, userContext }); return response; }; exports.default = addRoleToUser; diff --git a/lib/build/recipe/dashboard/api/userroles/getRolesForUser.d.ts b/lib/build/recipe/dashboard/api/userroles/getRolesForUser.d.ts index 0de8b9c3e..2ab694c5f 100644 --- a/lib/build/recipe/dashboard/api/userroles/getRolesForUser.d.ts +++ b/lib/build/recipe/dashboard/api/userroles/getRolesForUser.d.ts @@ -1,11 +1,6 @@ // @ts-nocheck -import { APIInterface, APIOptions } from "../../types"; -declare const getRolesForUser: ( - _: APIInterface, - tenantId: string, - options: APIOptions, - __: any -) => Promise< +import { APIFunction } from "../../types"; +declare const getRolesForUser: ({ stInstance, tenantId, options, userContext }: Parameters[0]) => Promise< | { status: "OK"; roles: string[]; diff --git a/lib/build/recipe/dashboard/api/userroles/getRolesForUser.js b/lib/build/recipe/dashboard/api/userroles/getRolesForUser.js index be76ed593..b54df867a 100644 --- a/lib/build/recipe/dashboard/api/userroles/getRolesForUser.js +++ b/lib/build/recipe/dashboard/api/userroles/getRolesForUser.js @@ -5,13 +5,12 @@ var __importDefault = return mod && mod.__esModule ? mod : { default: mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -const userroles_1 = __importDefault(require("../../../userroles")); -const recipe_1 = __importDefault(require("../../../userroles/recipe")); const error_1 = __importDefault(require("../../../../error")); -const getRolesForUser = async (_, tenantId, options, __) => { +const getRolesForUser = async ({ stInstance, tenantId, options, userContext }) => { const userId = options.req.getKeyValueFromQuery("userId"); + let userrolesRecipe = undefined; try { - recipe_1.default.getInstanceOrThrowError(); + userrolesRecipe = stInstance.getRecipeInstanceOrThrow("userroles"); } catch (_) { return { status: "FEATURE_NOT_ENABLED_ERROR", @@ -23,7 +22,7 @@ const getRolesForUser = async (_, tenantId, options, __) => { type: error_1.default.BAD_INPUT_ERROR, }); } - const response = await userroles_1.default.getRolesForUser(tenantId, userId); + const response = await userrolesRecipe.recipeInterfaceImpl.getRolesForUser({ userId, tenantId, userContext }); return response; }; exports.default = getRolesForUser; diff --git a/lib/build/recipe/dashboard/api/userroles/permissions/getPermissionsForRole.d.ts b/lib/build/recipe/dashboard/api/userroles/permissions/getPermissionsForRole.d.ts index 206ddc1af..9b0718239 100644 --- a/lib/build/recipe/dashboard/api/userroles/permissions/getPermissionsForRole.d.ts +++ b/lib/build/recipe/dashboard/api/userroles/permissions/getPermissionsForRole.d.ts @@ -1,11 +1,6 @@ // @ts-nocheck -import { APIInterface, APIOptions } from "../../../types"; -declare const getPermissionsForRole: ( - _: APIInterface, - ___: string, - options: APIOptions, - __: any -) => Promise< +import { APIFunction } from "../../../types"; +declare const getPermissionsForRole: ({ stInstance, options, userContext }: Parameters[0]) => Promise< | { status: "OK"; permissions: string[]; diff --git a/lib/build/recipe/dashboard/api/userroles/permissions/getPermissionsForRole.js b/lib/build/recipe/dashboard/api/userroles/permissions/getPermissionsForRole.js index fac738710..da4031e82 100644 --- a/lib/build/recipe/dashboard/api/userroles/permissions/getPermissionsForRole.js +++ b/lib/build/recipe/dashboard/api/userroles/permissions/getPermissionsForRole.js @@ -5,12 +5,11 @@ var __importDefault = return mod && mod.__esModule ? mod : { default: mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -const recipe_1 = __importDefault(require("../../../../userroles/recipe")); -const userroles_1 = __importDefault(require("../../../../userroles")); const error_1 = __importDefault(require("../../../../../error")); -const getPermissionsForRole = async (_, ___, options, __) => { +const getPermissionsForRole = async ({ stInstance, options, userContext }) => { + let userrolesRecipe = undefined; try { - recipe_1.default.getInstanceOrThrowError(); + userrolesRecipe = stInstance.getRecipeInstanceOrThrow("userroles"); } catch (_) { return { status: "FEATURE_NOT_ENABLED_ERROR", @@ -23,7 +22,7 @@ const getPermissionsForRole = async (_, ___, options, __) => { type: error_1.default.BAD_INPUT_ERROR, }); } - const response = await userroles_1.default.getPermissionsForRole(role); + const response = await userrolesRecipe.recipeInterfaceImpl.getPermissionsForRole({ role, userContext }); return response; }; exports.default = getPermissionsForRole; diff --git a/lib/build/recipe/dashboard/api/userroles/permissions/removePermissions.d.ts b/lib/build/recipe/dashboard/api/userroles/permissions/removePermissions.d.ts index e4904b004..c594ab8dd 100644 --- a/lib/build/recipe/dashboard/api/userroles/permissions/removePermissions.d.ts +++ b/lib/build/recipe/dashboard/api/userroles/permissions/removePermissions.d.ts @@ -1,11 +1,6 @@ // @ts-nocheck -import { APIInterface, APIOptions } from "../../../types"; -declare const removePermissionsFromRole: ( - _: APIInterface, - ___: string, - options: APIOptions, - __: any -) => Promise<{ +import { APIFunction } from "../../../types"; +declare const removePermissionsFromRole: ({ stInstance, options, userContext }: Parameters[0]) => Promise<{ status: "OK" | "UNKNOWN_ROLE_ERROR" | "FEATURE_NOT_ENABLED_ERROR"; }>; export default removePermissionsFromRole; diff --git a/lib/build/recipe/dashboard/api/userroles/permissions/removePermissions.js b/lib/build/recipe/dashboard/api/userroles/permissions/removePermissions.js index cab2e0a91..b07d2cf17 100644 --- a/lib/build/recipe/dashboard/api/userroles/permissions/removePermissions.js +++ b/lib/build/recipe/dashboard/api/userroles/permissions/removePermissions.js @@ -5,12 +5,11 @@ var __importDefault = return mod && mod.__esModule ? mod : { default: mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -const recipe_1 = __importDefault(require("../../../../userroles/recipe")); -const userroles_1 = __importDefault(require("../../../../userroles")); const error_1 = __importDefault(require("../../../../../error")); -const removePermissionsFromRole = async (_, ___, options, __) => { +const removePermissionsFromRole = async ({ stInstance, options, userContext }) => { + let userrolesRecipe = undefined; try { - recipe_1.default.getInstanceOrThrowError(); + userrolesRecipe = stInstance.getRecipeInstanceOrThrow("userroles"); } catch (_) { return { status: "FEATURE_NOT_ENABLED_ERROR", @@ -32,7 +31,11 @@ const removePermissionsFromRole = async (_, ___, options, __) => { type: error_1.default.BAD_INPUT_ERROR, }); } - const response = await userroles_1.default.removePermissionsFromRole(role, permissions); + const response = await userrolesRecipe.recipeInterfaceImpl.removePermissionsFromRole({ + role, + permissions, + userContext, + }); return response; }; exports.default = removePermissionsFromRole; diff --git a/lib/build/recipe/dashboard/api/userroles/removeUserRole.d.ts b/lib/build/recipe/dashboard/api/userroles/removeUserRole.d.ts index bdf782e49..78baba0cc 100644 --- a/lib/build/recipe/dashboard/api/userroles/removeUserRole.d.ts +++ b/lib/build/recipe/dashboard/api/userroles/removeUserRole.d.ts @@ -1,11 +1,6 @@ // @ts-nocheck -import { APIInterface, APIOptions } from "../../types"; -declare const removeUserRole: ( - _: APIInterface, - tenantId: string, - options: APIOptions, - __: any -) => Promise< +import { APIFunction } from "../../types"; +declare const removeUserRole: ({ stInstance, tenantId, options, userContext }: Parameters[0]) => Promise< | { status: "OK"; didUserHaveRole: boolean; diff --git a/lib/build/recipe/dashboard/api/userroles/removeUserRole.js b/lib/build/recipe/dashboard/api/userroles/removeUserRole.js index 025c93fcd..683cf6762 100644 --- a/lib/build/recipe/dashboard/api/userroles/removeUserRole.js +++ b/lib/build/recipe/dashboard/api/userroles/removeUserRole.js @@ -5,12 +5,11 @@ var __importDefault = return mod && mod.__esModule ? mod : { default: mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -const recipe_1 = __importDefault(require("../../../userroles/recipe")); -const userroles_1 = __importDefault(require("../../../userroles")); const error_1 = __importDefault(require("../../../../error")); -const removeUserRole = async (_, tenantId, options, __) => { +const removeUserRole = async ({ stInstance, tenantId, options, userContext }) => { + let userrolesRecipe = undefined; try { - recipe_1.default.getInstanceOrThrowError(); + userrolesRecipe = stInstance.getRecipeInstanceOrThrow("userroles"); } catch (_) { return { status: "FEATURE_NOT_ENABLED_ERROR", @@ -30,7 +29,7 @@ const removeUserRole = async (_, tenantId, options, __) => { type: error_1.default.BAD_INPUT_ERROR, }); } - const response = await userroles_1.default.removeUserRole(tenantId, userId, role); + const response = await userrolesRecipe.recipeInterfaceImpl.removeUserRole({ userId, role, tenantId, userContext }); return response; }; exports.default = removeUserRole; diff --git a/lib/build/recipe/dashboard/api/userroles/roles/createRoleOrAddPermissions.d.ts b/lib/build/recipe/dashboard/api/userroles/roles/createRoleOrAddPermissions.d.ts index 75663bcb0..c40298e6b 100644 --- a/lib/build/recipe/dashboard/api/userroles/roles/createRoleOrAddPermissions.d.ts +++ b/lib/build/recipe/dashboard/api/userroles/roles/createRoleOrAddPermissions.d.ts @@ -1,11 +1,6 @@ // @ts-nocheck -import { APIInterface, APIOptions } from "../../../types"; -declare const createRoleOrAddPermissions: ( - _: APIInterface, - __: string, - options: APIOptions, - ___: any -) => Promise< +import { APIFunction } from "../../../types"; +declare const createRoleOrAddPermissions: ({ stInstance, options, userContext }: Parameters[0]) => Promise< | { status: "OK"; createdNewRole: boolean; diff --git a/lib/build/recipe/dashboard/api/userroles/roles/createRoleOrAddPermissions.js b/lib/build/recipe/dashboard/api/userroles/roles/createRoleOrAddPermissions.js index 1540fe51d..05b6ea08e 100644 --- a/lib/build/recipe/dashboard/api/userroles/roles/createRoleOrAddPermissions.js +++ b/lib/build/recipe/dashboard/api/userroles/roles/createRoleOrAddPermissions.js @@ -5,12 +5,11 @@ var __importDefault = return mod && mod.__esModule ? mod : { default: mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -const recipe_1 = __importDefault(require("../../../../userroles/recipe")); -const userroles_1 = __importDefault(require("../../../../userroles")); const error_1 = __importDefault(require("../../../../../error")); -const createRoleOrAddPermissions = async (_, __, options, ___) => { +const createRoleOrAddPermissions = async ({ stInstance, options, userContext }) => { + let userrolesRecipe = undefined; try { - recipe_1.default.getInstanceOrThrowError(); + userrolesRecipe = stInstance.getRecipeInstanceOrThrow("userroles"); } catch (_) { return { status: "FEATURE_NOT_ENABLED_ERROR", @@ -31,7 +30,11 @@ const createRoleOrAddPermissions = async (_, __, options, ___) => { type: error_1.default.BAD_INPUT_ERROR, }); } - const response = await userroles_1.default.createNewRoleOrAddPermissions(role, permissions); + const response = await userrolesRecipe.recipeInterfaceImpl.createNewRoleOrAddPermissions({ + role, + permissions, + userContext, + }); return response; }; exports.default = createRoleOrAddPermissions; diff --git a/lib/build/recipe/dashboard/api/userroles/roles/deleteRole.d.ts b/lib/build/recipe/dashboard/api/userroles/roles/deleteRole.d.ts index 14e5cf5b7..f5a936eb7 100644 --- a/lib/build/recipe/dashboard/api/userroles/roles/deleteRole.d.ts +++ b/lib/build/recipe/dashboard/api/userroles/roles/deleteRole.d.ts @@ -1,11 +1,6 @@ // @ts-nocheck -import { APIInterface, APIOptions } from "../../../types"; -declare const deleteRole: ( - _: APIInterface, - ___: string, - options: APIOptions, - __: any -) => Promise< +import { APIFunction } from "../../../types"; +declare const deleteRole: ({ stInstance, options, userContext }: Parameters[0]) => Promise< | { status: "OK"; didRoleExist: boolean; diff --git a/lib/build/recipe/dashboard/api/userroles/roles/deleteRole.js b/lib/build/recipe/dashboard/api/userroles/roles/deleteRole.js index 3814268fb..941f98ed1 100644 --- a/lib/build/recipe/dashboard/api/userroles/roles/deleteRole.js +++ b/lib/build/recipe/dashboard/api/userroles/roles/deleteRole.js @@ -5,12 +5,11 @@ var __importDefault = return mod && mod.__esModule ? mod : { default: mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -const recipe_1 = __importDefault(require("../../../../userroles/recipe")); -const userroles_1 = __importDefault(require("../../../../userroles")); const error_1 = __importDefault(require("../../../../../error")); -const deleteRole = async (_, ___, options, __) => { +const deleteRole = async ({ stInstance, options, userContext }) => { + let userrolesRecipe = undefined; try { - recipe_1.default.getInstanceOrThrowError(); + userrolesRecipe = stInstance.getRecipeInstanceOrThrow("userroles"); } catch (_) { return { status: "FEATURE_NOT_ENABLED_ERROR", @@ -23,7 +22,7 @@ const deleteRole = async (_, ___, options, __) => { type: error_1.default.BAD_INPUT_ERROR, }); } - const response = await userroles_1.default.deleteRole(role); + const response = await userrolesRecipe.recipeInterfaceImpl.deleteRole({ role, userContext }); return response; }; exports.default = deleteRole; diff --git a/lib/build/recipe/dashboard/api/userroles/roles/getAllRoles.js b/lib/build/recipe/dashboard/api/userroles/roles/getAllRoles.js index bce2b636d..7f27c0122 100644 --- a/lib/build/recipe/dashboard/api/userroles/roles/getAllRoles.js +++ b/lib/build/recipe/dashboard/api/userroles/roles/getAllRoles.js @@ -1,21 +1,15 @@ "use strict"; -var __importDefault = - (this && this.__importDefault) || - function (mod) { - return mod && mod.__esModule ? mod : { default: mod }; - }; Object.defineProperty(exports, "__esModule", { value: true }); -const userroles_1 = __importDefault(require("../../../../userroles")); -const recipe_1 = __importDefault(require("../../../../userroles/recipe")); -const getAllRoles = async (_, __, ____) => { +const getAllRoles = async ({ stInstance, userContext }) => { + let userrolesRecipe = undefined; try { - recipe_1.default.getInstanceOrThrowError(); + userrolesRecipe = stInstance.getRecipeInstanceOrThrow("userroles"); } catch (_) { return { status: "FEATURE_NOT_ENABLED_ERROR", }; } - const response = await userroles_1.default.getAllRoles(); + const response = await userrolesRecipe.recipeInterfaceImpl.getAllRoles({ userContext }); return { status: "OK", roles: response.roles, diff --git a/lib/build/recipe/dashboard/api/usersCountGet.d.ts b/lib/build/recipe/dashboard/api/usersCountGet.d.ts index 68e1efd3a..8296ee6ba 100644 --- a/lib/build/recipe/dashboard/api/usersCountGet.d.ts +++ b/lib/build/recipe/dashboard/api/usersCountGet.d.ts @@ -1,13 +1,11 @@ // @ts-nocheck -import { APIInterface, APIOptions } from "../types"; -import { UserContext } from "../../../types"; +import { APIFunction } from "../types"; export type Response = { status: "OK"; count: number; }; -export default function usersCountGet( - _: APIInterface, - tenantId: string, - __: APIOptions, - userContext: UserContext -): Promise; +export default function usersCountGet({ + stInstance, + tenantId, + userContext, +}: Parameters[0]): Promise; diff --git a/lib/build/recipe/dashboard/api/usersCountGet.js b/lib/build/recipe/dashboard/api/usersCountGet.js index 9068c3923..505177b04 100644 --- a/lib/build/recipe/dashboard/api/usersCountGet.js +++ b/lib/build/recipe/dashboard/api/usersCountGet.js @@ -13,16 +13,10 @@ * License for the specific language governing permissions and limitations * under the License. */ -var __importDefault = - (this && this.__importDefault) || - function (mod) { - return mod && mod.__esModule ? mod : { default: mod }; - }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = usersCountGet; -const supertokens_1 = __importDefault(require("../../../supertokens")); -async function usersCountGet(_, tenantId, __, userContext) { - const count = await supertokens_1.default.getInstanceOrThrowError().getUserCount(undefined, tenantId, userContext); +async function usersCountGet({ stInstance, tenantId, userContext }) { + const count = await stInstance.getUserCount(undefined, tenantId, userContext); return { status: "OK", count, diff --git a/lib/build/recipe/dashboard/api/usersGet.d.ts b/lib/build/recipe/dashboard/api/usersGet.d.ts index 9170759cc..a255ba7e3 100644 --- a/lib/build/recipe/dashboard/api/usersGet.d.ts +++ b/lib/build/recipe/dashboard/api/usersGet.d.ts @@ -1,11 +1,16 @@ // @ts-nocheck -import { APIInterface, APIOptions, UserWithFirstAndLastName } from "../types"; +import { APIFunction, UserWithFirstAndLastName } from "../types"; export type Response = { status: "OK"; nextPaginationToken?: string; users: UserWithFirstAndLastName[]; }; -export default function usersGet(_: APIInterface, tenantId: string, options: APIOptions): Promise; +export default function usersGet({ + stInstance, + tenantId, + options, + userContext, +}: Parameters[0]): Promise; export declare function getSearchParamsFromURL(path: string): { [key: string]: string; }; diff --git a/lib/build/recipe/dashboard/api/usersGet.js b/lib/build/recipe/dashboard/api/usersGet.js index 317655a75..732eed1c6 100644 --- a/lib/build/recipe/dashboard/api/usersGet.js +++ b/lib/build/recipe/dashboard/api/usersGet.js @@ -9,9 +9,7 @@ exports.default = usersGet; exports.getSearchParamsFromURL = getSearchParamsFromURL; const error_1 = __importDefault(require("../../../error")); const __1 = require("../../.."); -const recipe_1 = __importDefault(require("../../usermetadata/recipe")); -const usermetadata_1 = __importDefault(require("../../usermetadata")); -async function usersGet(_, tenantId, options) { +async function usersGet({ stInstance, tenantId, options, userContext }) { const req = options.req; const limit = options.req.getKeyValueFromQuery("limit"); if (limit === undefined) { @@ -46,9 +44,10 @@ async function usersGet(_, tenantId, options) { limit: parseInt(limit), paginationToken, }); + let usermetadataRecipe = undefined; // If the UserMetaData recipe has been initialised, fetch first and last name try { - recipe_1.default.getInstanceOrThrowError(); + usermetadataRecipe = stInstance.getRecipeInstanceOrThrow("usermetadata"); } catch (e) { // Recipe has not been initialised, return without first name and last name return { @@ -65,7 +64,10 @@ async function usersGet(_, tenantId, options) { () => new Promise(async (resolve, reject) => { try { - const userMetaDataResponse = await usermetadata_1.default.getUserMetadata(userObj.id); + const userMetaDataResponse = await usermetadataRecipe.recipeInterfaceImpl.getUserMetadata({ + userId: userObj.id, + userContext, + }); const { first_name, last_name } = userMetaDataResponse.metadata; updatedUsersArray[i] = Object.assign(Object.assign({}, userObj), { firstName: first_name, diff --git a/lib/build/recipe/dashboard/recipe.d.ts b/lib/build/recipe/dashboard/recipe.d.ts index 25343ea75..2fe77a21c 100644 --- a/lib/build/recipe/dashboard/recipe.d.ts +++ b/lib/build/recipe/dashboard/recipe.d.ts @@ -5,6 +5,7 @@ import { APIInterface, RecipeInterface, TypeInput, TypeNormalisedInput } from ". import NormalisedURLPath from "../../normalisedURLPath"; import type { BaseRequest, BaseResponse } from "../../framework"; import error from "../../error"; +import type SuperTokens from "../../supertokens"; export default class Recipe extends RecipeModule { private static instance; static RECIPE_ID: "dashboard"; @@ -12,7 +13,13 @@ export default class Recipe extends RecipeModule { recipeInterfaceImpl: RecipeInterface; apiImpl: APIInterface; isInServerlessEnv: boolean; - constructor(recipeId: string, appInfo: NormalisedAppinfo, isInServerlessEnv: boolean, config?: TypeInput); + constructor( + stInstance: SuperTokens, + recipeId: string, + appInfo: NormalisedAppinfo, + isInServerlessEnv: boolean, + config?: TypeInput + ); static getInstanceOrThrowError(): Recipe; static init(config?: TypeInput): RecipeListFunction; static reset(): void; diff --git a/lib/build/recipe/dashboard/recipe.js b/lib/build/recipe/dashboard/recipe.js index bc9f06981..5a6376c6c 100644 --- a/lib/build/recipe/dashboard/recipe.js +++ b/lib/build/recipe/dashboard/recipe.js @@ -71,8 +71,8 @@ const getThirdPartyConfig_1 = __importDefault(require("./api/multitenancy/getThi const utils_2 = require("../../utils"); const plugins_1 = require("../../plugins"); class Recipe extends recipeModule_1.default { - constructor(recipeId, appInfo, isInServerlessEnv, config) { - super(recipeId, appInfo); + constructor(stInstance, recipeId, appInfo, isInServerlessEnv, config) { + super(stInstance, recipeId, appInfo); // abstract instance functions below............... this.getAPIsHandled = () => { return [ @@ -444,10 +444,24 @@ class Recipe extends recipeModule_1.default { }; // For these APIs we dont need API key validation if (id === constants_1.DASHBOARD_API) { - return await (0, dashboard_1.default)(this.apiImpl, options, userContext); + return await (0, dashboard_1.default)({ + apiImplementation: this.apiImpl, + recipeInstance: this, + stInstance: this.stInstance, + tenantId, + options, + userContext, + }); } if (id === constants_1.SIGN_IN_API) { - return await (0, signIn_1.default)(this.apiImpl, options, userContext); + return await (0, signIn_1.default)({ + apiImplementation: this.apiImpl, + recipeInstance: this, + stInstance: this.stInstance, + tenantId, + options, + userContext, + }); } if (id === constants_1.VALIDATE_KEY_API) { return await (0, validateKey_1.default)(this.apiImpl, options, userContext); @@ -569,7 +583,14 @@ class Recipe extends recipeModule_1.default { if (apiFunction === undefined) { return false; } - return await (0, apiKeyProtector_1.default)(this.apiImpl, tenantId, options, apiFunction, userContext); + return await (0, apiKeyProtector_1.default)(apiFunction, { + apiImplementation: this.apiImpl, + recipeInstance: this, + stInstance: this.stInstance, + tenantId, + options, + userContext, + }); }; this.handleError = async (err, _, __) => { throw err; @@ -583,11 +604,11 @@ class Recipe extends recipeModule_1.default { this.config = (0, utils_1.validateAndNormaliseUserInput)(config); this.isInServerlessEnv = isInServerlessEnv; { - let builder = new supertokens_js_override_1.default((0, recipeImplementation_1.default)()); + let builder = new supertokens_js_override_1.default((0, recipeImplementation_1.default)(this.querier)); this.recipeInterfaceImpl = builder.override(this.config.override.functions).build(); } { - let builder = new supertokens_js_override_1.default((0, implementation_1.default)()); + let builder = new supertokens_js_override_1.default((0, implementation_1.default)(this.stInstance)); this.apiImpl = builder.override(this.config.override.apis).build(); } } @@ -598,9 +619,10 @@ class Recipe extends recipeModule_1.default { throw new Error("Initialisation not done. Did you forget to call the Dashboard.init function?"); } static init(config) { - return (appInfo, isInServerlessEnv, plugins) => { + return (stInstance, appInfo, isInServerlessEnv, plugins) => { if (Recipe.instance === undefined) { Recipe.instance = new Recipe( + stInstance, Recipe.RECIPE_ID, appInfo, isInServerlessEnv, diff --git a/lib/build/recipe/dashboard/recipeImplementation.d.ts b/lib/build/recipe/dashboard/recipeImplementation.d.ts index 881866f94..4062978a7 100644 --- a/lib/build/recipe/dashboard/recipeImplementation.d.ts +++ b/lib/build/recipe/dashboard/recipeImplementation.d.ts @@ -1,3 +1,4 @@ // @ts-nocheck +import { Querier } from "../../querier"; import { RecipeInterface } from "./types"; -export default function getRecipeImplementation(): RecipeInterface; +export default function getRecipeImplementation(querier: Querier): RecipeInterface; diff --git a/lib/build/recipe/dashboard/recipeImplementation.js b/lib/build/recipe/dashboard/recipeImplementation.js index f2e2a7ace..504596469 100644 --- a/lib/build/recipe/dashboard/recipeImplementation.js +++ b/lib/build/recipe/dashboard/recipeImplementation.js @@ -22,12 +22,11 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.default = getRecipeImplementation; const error_1 = __importDefault(require("./error")); const logger_1 = require("../../logger"); -const querier_1 = require("../../querier"); const utils_1 = require("../../utils"); const version_1 = require("../../version"); const constants_1 = require("./constants"); const utils_2 = require("./utils"); -function getRecipeImplementation() { +function getRecipeImplementation(querier) { return { getDashboardBundleLocation: async function () { return `https://cdn.jsdelivr.net/gh/supertokens/dashboard@v${version_1.dashboardVersion}/build/`; @@ -37,7 +36,6 @@ function getRecipeImplementation() { // For cases where we're not using the API key, the JWT is being used; we allow their access by default if (!input.config.apiKey) { // make the check for the API endpoint here with querier - let querier = querier_1.Querier.getNewInstanceOrThrowError(undefined); const authHeaderValue = (_a = input.req.getHeaderValue("authorization")) === null || _a === void 0 ? void 0 diff --git a/lib/build/recipe/dashboard/types.d.ts b/lib/build/recipe/dashboard/types.d.ts index d9ff21bec..76bc87f38 100644 --- a/lib/build/recipe/dashboard/types.d.ts +++ b/lib/build/recipe/dashboard/types.d.ts @@ -1,7 +1,9 @@ // @ts-nocheck import OverrideableBuilder from "supertokens-js-override"; import type { BaseRequest, BaseResponse } from "../../framework"; -import { NormalisedAppinfo, User, UserContext } from "../../types"; +import type { NormalisedAppinfo, User, UserContext } from "../../types"; +import type DashboardRecipe from "./recipe"; +import type SuperTokens from "../../supertokens"; export type TypeInput = { apiKey?: string; admins?: string[]; @@ -45,12 +47,14 @@ export type APIOptions = { export type APIInterface = { dashboardGET: undefined | ((input: { options: APIOptions; userContext: UserContext }) => Promise); }; -export type APIFunction = ( - apiImplementation: APIInterface, - tenantId: string, - options: APIOptions, - userContext: UserContext -) => Promise; +export type APIFunction = (input: { + apiImplementation: APIInterface; + recipeInstance: DashboardRecipe; + stInstance: SuperTokens; + tenantId: string; + options: APIOptions; + userContext: UserContext; +}) => Promise; export type RecipeIdForUser = "emailpassword" | "thirdparty" | "passwordless" | "webauthn"; export type AuthMode = "api-key" | "email-password"; export type UserWithFirstAndLastName = User & { diff --git a/lib/build/recipe/dashboard/utils.d.ts b/lib/build/recipe/dashboard/utils.d.ts index b5a295d0a..4e7b7ea9a 100644 --- a/lib/build/recipe/dashboard/utils.d.ts +++ b/lib/build/recipe/dashboard/utils.d.ts @@ -3,10 +3,12 @@ import type { BaseRequest, BaseResponse } from "../../framework"; import { RecipeIdForUser, TypeInput, TypeNormalisedInput, UserWithFirstAndLastName } from "./types"; import RecipeUserId from "../../recipeUserId"; import { UserContext } from "../../types"; +import type SuperTokens from "../../supertokens"; export declare function validateAndNormaliseUserInput(config?: TypeInput): TypeNormalisedInput; export declare function sendUnauthorisedAccess(res: BaseResponse): void; export declare function isValidRecipeId(recipeId: string): recipeId is RecipeIdForUser; export declare function getUserForRecipeId( + stInstance: SuperTokens, recipeUserId: RecipeUserId, recipeId: string, userContext: UserContext diff --git a/lib/build/recipe/dashboard/utils.js b/lib/build/recipe/dashboard/utils.js index fb9c8f3bb..9e90c34fe 100644 --- a/lib/build/recipe/dashboard/utils.js +++ b/lib/build/recipe/dashboard/utils.js @@ -13,11 +13,6 @@ * License for the specific language governing permissions and limitations * under the License. */ -var __importDefault = - (this && this.__importDefault) || - function (mod) { - return mod && mod.__esModule ? mod : { default: mod }; - }; Object.defineProperty(exports, "__esModule", { value: true }); exports.validateAndNormaliseUserInput = validateAndNormaliseUserInput; exports.sendUnauthorisedAccess = sendUnauthorisedAccess; @@ -27,11 +22,6 @@ exports.validateApiKey = validateApiKey; exports.getApiPathWithDashboardBase = getApiPathWithDashboardBase; const utils_1 = require("../../utils"); const constants_1 = require("./constants"); -const recipe_1 = __importDefault(require("../accountlinking/recipe")); -const recipe_2 = __importDefault(require("../emailpassword/recipe")); -const recipe_3 = __importDefault(require("../thirdparty/recipe")); -const recipe_4 = __importDefault(require("../passwordless/recipe")); -const recipe_5 = __importDefault(require("../webauthn/recipe")); const logger_1 = require("../../logger"); function validateAndNormaliseUserInput(config) { let override = Object.assign( @@ -68,8 +58,8 @@ function isValidRecipeId(recipeId) { recipeId === "webauthn" ); } -async function getUserForRecipeId(recipeUserId, recipeId, userContext) { - let userResponse = await _getUserForRecipeId(recipeUserId, recipeId, userContext); +async function getUserForRecipeId(stInstance, recipeUserId, recipeId, userContext) { + let userResponse = await _getUserForRecipeId(stInstance, recipeUserId, recipeId, userContext); let user = undefined; if (userResponse.user !== undefined) { user = Object.assign(Object.assign({}, userResponse.user), { firstName: "", lastName: "" }); @@ -79,9 +69,9 @@ async function getUserForRecipeId(recipeUserId, recipeId, userContext) { recipe: userResponse.recipe, }; } -async function _getUserForRecipeId(recipeUserId, recipeId, userContext) { +async function _getUserForRecipeId(stInstance, recipeUserId, recipeId, userContext) { let recipe; - const user = await recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl.getUser({ + const user = await stInstance.getRecipeInstanceOrThrow("accountlinking").recipeInterfaceImpl.getUser({ userId: recipeUserId.getAsString(), userContext, }); @@ -100,34 +90,25 @@ async function _getUserForRecipeId(recipeUserId, recipeId, userContext) { recipe: undefined, }; } - if (recipeId === recipe_2.default.RECIPE_ID) { - try { - // we detect if this recipe has been init or not.. - recipe_2.default.getInstanceOrThrowError(); + if (recipeId === "emailpassword") { + let emailpasswordRecipe = stInstance.getRecipeInstance("emailpassword"); + if (emailpasswordRecipe !== undefined) { recipe = "emailpassword"; - } catch (e) { - // No - op } - } else if (recipeId === recipe_3.default.RECIPE_ID) { - try { - recipe_3.default.getInstanceOrThrowError(); + } else if (recipeId === "thirdparty") { + let thirdpartyRecipe = stInstance.getRecipeInstance("thirdparty"); + if (thirdpartyRecipe !== undefined) { recipe = "thirdparty"; - } catch (e) { - // No - op } - } else if (recipeId === recipe_4.default.RECIPE_ID) { - try { - recipe_4.default.getInstanceOrThrowError(); + } else if (recipeId === "passwordless") { + let passwordlessRecipe = stInstance.getRecipeInstance("passwordless"); + if (passwordlessRecipe !== undefined) { recipe = "passwordless"; - } catch (e) { - // No - op } - } else if (recipeId === recipe_5.default.RECIPE_ID) { - try { - recipe_5.default.getInstanceOrThrowError(); + } else if (recipeId === "webauthn") { + let webauthnRecipe = stInstance.getRecipeInstance("webauthn"); + if (webauthnRecipe !== undefined) { recipe = "webauthn"; - } catch (e) { - // No - op } } return { diff --git a/lib/build/recipe/emailpassword/api/emailExists.d.ts b/lib/build/recipe/emailpassword/api/emailExists.d.ts index 2f55b6d3b..07001b920 100644 --- a/lib/build/recipe/emailpassword/api/emailExists.d.ts +++ b/lib/build/recipe/emailpassword/api/emailExists.d.ts @@ -1,5 +1,5 @@ // @ts-nocheck -import { APIInterface, APIOptions } from "../"; +import type { APIInterface, APIOptions } from "../types"; import { UserContext } from "../../../types"; export default function emailExists( apiImplementation: APIInterface, diff --git a/lib/build/recipe/emailpassword/api/implementation.d.ts b/lib/build/recipe/emailpassword/api/implementation.d.ts index 402db9918..ad401abfa 100644 --- a/lib/build/recipe/emailpassword/api/implementation.d.ts +++ b/lib/build/recipe/emailpassword/api/implementation.d.ts @@ -1,3 +1,4 @@ // @ts-nocheck import { APIInterface } from "../"; -export default function getAPIImplementation(): APIInterface; +import type SuperTokens from "../../../supertokens"; +export default function getAPIImplementation(stInstance: SuperTokens): APIInterface; diff --git a/lib/build/recipe/emailpassword/api/implementation.js b/lib/build/recipe/emailpassword/api/implementation.js index b59513ad3..e94e6cfe1 100644 --- a/lib/build/recipe/emailpassword/api/implementation.js +++ b/lib/build/recipe/emailpassword/api/implementation.js @@ -7,27 +7,26 @@ var __importDefault = Object.defineProperty(exports, "__esModule", { value: true }); exports.default = getAPIImplementation; const logger_1 = require("../../../logger"); -const __1 = require("../../../"); -const recipe_1 = __importDefault(require("../../accountlinking/recipe")); -const recipe_2 = __importDefault(require("../../emailverification/recipe")); const recipeUserId_1 = __importDefault(require("../../../recipeUserId")); const utils_1 = require("../utils"); const authUtils_1 = require("../../../authUtils"); const utils_2 = require("../../thirdparty/utils"); -function getAPIImplementation() { +function getAPIImplementation(stInstance) { return { emailExistsGET: async function ({ email, tenantId, userContext }) { // even if the above returns true, we still need to check if there // exists an email password user with the same email cause the function // above does not check for that. - let users = await recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl.listUsersByAccountInfo({ - tenantId, - accountInfo: { - email, - }, - doUnionOfAccountInfo: false, - userContext, - }); + let users = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.listUsersByAccountInfo({ + tenantId, + accountInfo: { + email, + }, + doUnionOfAccountInfo: false, + userContext, + }); let emailPasswordUserExists = users.find((u) => { return ( @@ -95,14 +94,16 @@ function getAPIImplementation() { /** * check if primaryUserId is linked with this email */ - let users = await recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl.listUsersByAccountInfo({ - tenantId, - accountInfo: { - email, - }, - doUnionOfAccountInfo: false, - userContext, - }); + let users = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.listUsersByAccountInfo({ + tenantId, + accountInfo: { + email, + }, + doUnionOfAccountInfo: false, + userContext, + }); // we find the recipe user ID of the email password account from the user's list // for later use. let emailPasswordAccount = undefined; @@ -146,8 +147,8 @@ function getAPIImplementation() { } email)` ); // Otherwise, we check if the user can become primary. - const shouldBecomePrimaryUser = await recipe_1.default - .getInstanceOrThrowError() + const shouldBecomePrimaryUser = await stInstance + .getRecipeInstanceOrThrow("accountlinking") .shouldBecomePrimaryUser(oldestUser, tenantId, undefined, userContext); (0, logger_1.logDebugMessage)( `generatePasswordResetTokenPOST: recipe level-linking candidate ${ @@ -236,8 +237,8 @@ function getAPIImplementation() { // extra security measure here to make sure that the input email in the primary user // is verified, and if not, we need to make sure that there is no other email / phone number // associated with the primary user account. If there is, then we do not proceed. - let shouldDoAccountLinkingResponse = await recipe_1.default - .getInstanceOrThrowError() + let shouldDoAccountLinkingResponse = await stInstance + .getRecipeInstanceOrThrow("accountlinking") .config.shouldDoAutomaticAccountLinking( emailPasswordAccount !== undefined ? emailPasswordAccount @@ -270,7 +271,7 @@ function getAPIImplementation() { status: "OK", }; } - let isSignUpAllowed = await recipe_1.default.getInstanceOrThrowError().isSignUpAllowed({ + let isSignUpAllowed = await stInstance.getRecipeInstanceOrThrow("accountlinking").isSignUpAllowed({ newUser: { recipeId: "emailpassword", email, @@ -309,7 +310,14 @@ function getAPIImplementation() { }, passwordResetPOST: async function ({ formFields, token, tenantId, options, userContext }) { async function markEmailAsVerified(recipeUserId, email) { - const emailVerificationInstance = recipe_2.default.getInstance(); + let emailVerificationInstance = undefined; + try { + emailVerificationInstance = stInstance.getRecipeInstanceOrThrow("emailverification"); + } catch (_) { + (0, logger_1.logDebugMessage)( + "email verification recipe not initialised, not marking email as verified" + ); + } if (emailVerificationInstance) { const tokenResponse = await emailVerificationInstance.recipeInterfaceImpl.createEmailVerificationToken({ @@ -367,10 +375,9 @@ function getAPIImplementation() { // If we verified (and linked) the existing user with the original password, User M would get access to the current user and any linked users. await markEmailAsVerified(recipeUserId, emailForWhomTokenWasGenerated); // We refresh the user information here, because the verification status may be updated, which is used during linking. - const updatedUserAfterEmailVerification = await (0, __1.getUser)( - recipeUserId.getAsString(), - userContext - ); + const updatedUserAfterEmailVerification = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: recipeUserId.getAsString(), userContext }); if (updatedUserAfterEmailVerification === undefined) { throw new Error("Should never happen - user deleted after during password reset"); } @@ -387,8 +394,8 @@ function getAPIImplementation() { // The function below will try and also create a primary user of the new account, this can happen if: // 1. the user was unverified and linking requires verification // We do not take try linking by session here, since this is supposed to be called without a session - const linkRes = await recipe_1.default - .getInstanceOrThrowError() + const linkRes = await stInstance + .getRecipeInstanceOrThrow("accountlinking") .tryLinkingByAccountInfoOrCreatePrimaryUser({ tenantId, inputUser: updatedUserAfterEmailVerification, @@ -423,7 +430,9 @@ function getAPIImplementation() { } let userIdForWhomTokenWasGenerated = tokenConsumptionResponse.userId; let emailForWhomTokenWasGenerated = tokenConsumptionResponse.email; - let existingUser = await (0, __1.getUser)(userIdForWhomTokenWasGenerated, userContext); + let existingUser = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: userIdForWhomTokenWasGenerated, userContext }); if (existingUser === undefined) { // This should happen only cause of a race condition where the user // might be deleted before token creation and consumption. @@ -524,7 +533,9 @@ function getAPIImplementation() { createUserResponse.user.loginMethods[0].recipeUserId, tokenConsumptionResponse.email ); - const updatedUser = await (0, __1.getUser)(createUserResponse.user.id, userContext); + const updatedUser = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: createUserResponse.user.id, userContext }); if (updatedUser === undefined) { throw new Error("Should never happen - user deleted after during password reset"); } @@ -535,8 +546,8 @@ function getAPIImplementation() { // email is shared. // We do not take try linking by session here, since this is supposed to be called without a session // Still, the session object is passed around because it is a required input for shouldDoAutomaticAccountLinking - const linkRes = await recipe_1.default - .getInstanceOrThrowError() + const linkRes = await stInstance + .getRecipeInstanceOrThrow("accountlinking") .tryLinkingByAccountInfoOrCreatePrimaryUser({ tenantId, inputUser: createUserResponse.user, @@ -609,6 +620,7 @@ function getAPIImplementation() { } const authenticatingUser = await authUtils_1.AuthUtils.getAuthenticatingUserAndAddToCurrentTenantIfRequired( { + stInstance, accountInfo: { email }, userContext, recipeId, @@ -628,6 +640,7 @@ function getAPIImplementation() { }; } const preAuthChecks = await authUtils_1.AuthUtils.preAuthChecks({ + stInstance, authenticatingAccountInfo: { recipeId, email, @@ -679,6 +692,7 @@ function getAPIImplementation() { ); } const postAuthChecks = await authUtils_1.AuthUtils.postAuthChecks({ + stInstance, authenticatedUser: signInResponse.user, recipeUserId: signInResponse.recipeUserId, isSignUp: false, @@ -740,6 +754,7 @@ function getAPIImplementation() { let email = emailAsUnknown; let password = passwordAsUnknown; const preAuthCheckRes = await authUtils_1.AuthUtils.preAuthChecks({ + stInstance, authenticatingAccountInfo: { recipeId: "emailpassword", email, @@ -756,8 +771,8 @@ function getAPIImplementation() { shouldTryLinkingWithSessionUser, }); if (preAuthCheckRes.status === "SIGN_UP_NOT_ALLOWED") { - const conflictingUsers = await recipe_1.default - .getInstanceOrThrowError() + const conflictingUsers = await stInstance + .getRecipeInstanceOrThrow("accountlinking") .recipeInterfaceImpl.listUsersByAccountInfo({ tenantId, accountInfo: { @@ -808,6 +823,7 @@ function getAPIImplementation() { ); } const postAuthChecks = await authUtils_1.AuthUtils.postAuthChecks({ + stInstance, authenticatedUser: signUpResponse.user, recipeUserId: signUpResponse.recipeUserId, isSignUp: true, diff --git a/lib/build/recipe/emailpassword/api/signin.d.ts b/lib/build/recipe/emailpassword/api/signin.d.ts index 4a712efbe..517ec7c13 100644 --- a/lib/build/recipe/emailpassword/api/signin.d.ts +++ b/lib/build/recipe/emailpassword/api/signin.d.ts @@ -1,7 +1,9 @@ // @ts-nocheck import { APIInterface, APIOptions } from "../"; import { UserContext } from "../../../types"; +import type SuperTokens from "../../../supertokens"; export default function signInAPI( + stInstance: SuperTokens, apiImplementation: APIInterface, tenantId: string, options: APIOptions, diff --git a/lib/build/recipe/emailpassword/api/signin.js b/lib/build/recipe/emailpassword/api/signin.js index bdd9a5798..4ab91a2df 100644 --- a/lib/build/recipe/emailpassword/api/signin.js +++ b/lib/build/recipe/emailpassword/api/signin.js @@ -18,7 +18,7 @@ exports.default = signInAPI; const utils_1 = require("../../../utils"); const utils_2 = require("./utils"); const authUtils_1 = require("../../../authUtils"); -async function signInAPI(apiImplementation, tenantId, options, userContext) { +async function signInAPI(stInstance, apiImplementation, tenantId, options, userContext) { // Logic as per https://github.com/supertokens/supertokens-node/issues/20#issuecomment-710346362 if (apiImplementation.signInPOST === undefined) { return false; @@ -36,6 +36,7 @@ async function signInAPI(apiImplementation, tenantId, options, userContext) { body ); const session = await authUtils_1.AuthUtils.loadSessionInAuthAPIIfNeeded( + stInstance, options.req, options.res, shouldTryLinkingWithSessionUser, diff --git a/lib/build/recipe/emailpassword/api/signup.d.ts b/lib/build/recipe/emailpassword/api/signup.d.ts index 1487513c1..bc9491841 100644 --- a/lib/build/recipe/emailpassword/api/signup.d.ts +++ b/lib/build/recipe/emailpassword/api/signup.d.ts @@ -1,7 +1,9 @@ // @ts-nocheck import { APIInterface, APIOptions } from "../"; import { UserContext } from "../../../types"; +import type SuperTokens from "../../../supertokens"; export default function signUpAPI( + stInstance: SuperTokens, apiImplementation: APIInterface, tenantId: string, options: APIOptions, diff --git a/lib/build/recipe/emailpassword/api/signup.js b/lib/build/recipe/emailpassword/api/signup.js index 32d877548..f0ee65d3f 100644 --- a/lib/build/recipe/emailpassword/api/signup.js +++ b/lib/build/recipe/emailpassword/api/signup.js @@ -24,7 +24,7 @@ const utils_1 = require("../../../utils"); const utils_2 = require("./utils"); const error_1 = __importDefault(require("../error")); const authUtils_1 = require("../../../authUtils"); -async function signUpAPI(apiImplementation, tenantId, options, userContext) { +async function signUpAPI(stInstance, apiImplementation, tenantId, options, userContext) { // Logic as per https://github.com/supertokens/supertokens-node/issues/21#issuecomment-710423536 if (apiImplementation.signUpPOST === undefined) { return false; @@ -42,6 +42,7 @@ async function signUpAPI(apiImplementation, tenantId, options, userContext) { requestBody ); const session = await authUtils_1.AuthUtils.loadSessionInAuthAPIIfNeeded( + stInstance, options.req, options.res, shouldTryLinkingWithSessionUser, diff --git a/lib/build/recipe/emailpassword/passwordResetFunctions.js b/lib/build/recipe/emailpassword/passwordResetFunctions.js index 183421a1e..e460df27c 100644 --- a/lib/build/recipe/emailpassword/passwordResetFunctions.js +++ b/lib/build/recipe/emailpassword/passwordResetFunctions.js @@ -16,12 +16,13 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.createAndSendEmailUsingSupertokensService = createAndSendEmailUsingSupertokensService; const utils_1 = require("../../utils"); +const querier_1 = require("../../querier"); async function createAndSendEmailUsingSupertokensService(appInfo, user, passwordResetURLWithToken) { // related issue: https://github.com/supertokens/supertokens-node/issues/38 if ((0, utils_1.isTestEnv)()) { return; } - await (0, utils_1.postWithFetch)( + await (0, querier_1.postWithFetch)( "https://api.supertokens.io/0/st/auth/password/reset", { "api-version": "0", diff --git a/lib/build/recipe/emailpassword/recipe.d.ts b/lib/build/recipe/emailpassword/recipe.d.ts index fad20ce0f..b443f97cf 100644 --- a/lib/build/recipe/emailpassword/recipe.d.ts +++ b/lib/build/recipe/emailpassword/recipe.d.ts @@ -7,6 +7,7 @@ import NormalisedURLPath from "../../normalisedURLPath"; import type { BaseRequest, BaseResponse } from "../../framework"; import EmailDeliveryIngredient from "../../ingredients/emaildelivery"; import { TypeEmailPasswordEmailDeliveryInput } from "./types"; +import type SuperTokens from "../../supertokens"; export default class Recipe extends RecipeModule { private static instance; static RECIPE_ID: "emailpassword"; @@ -16,6 +17,7 @@ export default class Recipe extends RecipeModule { isInServerlessEnv: boolean; emailDelivery: EmailDeliveryIngredient; constructor( + stInstance: SuperTokens, recipeId: string, appInfo: NormalisedAppinfo, isInServerlessEnv: boolean, diff --git a/lib/build/recipe/emailpassword/recipe.js b/lib/build/recipe/emailpassword/recipe.js index 78e8abcf0..bfe5dcdcb 100644 --- a/lib/build/recipe/emailpassword/recipe.js +++ b/lib/build/recipe/emailpassword/recipe.js @@ -33,17 +33,14 @@ const plugins_1 = require("../../plugins"); const emailExists_1 = __importDefault(require("./api/emailExists")); const recipeImplementation_1 = __importDefault(require("./recipeImplementation")); const implementation_1 = __importDefault(require("./api/implementation")); -const querier_1 = require("../../querier"); const supertokens_js_override_1 = __importDefault(require("supertokens-js-override")); const emaildelivery_1 = __importDefault(require("../../ingredients/emaildelivery")); const postSuperTokensInitCallbacks_1 = require("../../postSuperTokensInitCallbacks"); -const recipe_1 = __importDefault(require("../multifactorauth/recipe")); -const recipe_2 = __importDefault(require("../multitenancy/recipe")); const utils_3 = require("../thirdparty/utils"); const multifactorauth_1 = require("../multifactorauth"); class Recipe extends recipeModule_1.default { - constructor(recipeId, appInfo, isInServerlessEnv, config, ingredients) { - super(recipeId, appInfo); + constructor(stInstance, recipeId, appInfo, isInServerlessEnv, config, ingredients) { + super(stInstance, recipeId, appInfo); // abstract instance functions below............... this.getAPIsHandled = () => { return [ @@ -99,9 +96,9 @@ class Recipe extends recipeModule_1.default { appInfo: this.getAppInfo(), }; if (id === constants_1.SIGN_UP_API) { - return await (0, signup_1.default)(this.apiImpl, tenantId, options, userContext); + return await (0, signup_1.default)(this.stInstance, this.apiImpl, tenantId, options, userContext); } else if (id === constants_1.SIGN_IN_API) { - return await (0, signin_1.default)(this.apiImpl, tenantId, options, userContext); + return await (0, signin_1.default)(this.stInstance, this.apiImpl, tenantId, options, userContext); } else if (id === constants_1.GENERATE_PASSWORD_RESET_TOKEN_API) { return await (0, generatePasswordResetToken_1.default)(this.apiImpl, tenantId, options, userContext); } else if (id === constants_1.PASSWORD_RESET_API) { @@ -136,15 +133,12 @@ class Recipe extends recipeModule_1.default { { const getEmailPasswordConfig = () => this.config; let builder = new supertokens_js_override_1.default( - (0, recipeImplementation_1.default)( - querier_1.Querier.getNewInstanceOrThrowError(recipeId), - getEmailPasswordConfig - ) + (0, recipeImplementation_1.default)(this.stInstance, this.querier, getEmailPasswordConfig) ); this.recipeInterfaceImpl = builder.override(this.config.override.functions).build(); } { - let builder = new supertokens_js_override_1.default((0, implementation_1.default)()); + let builder = new supertokens_js_override_1.default((0, implementation_1.default)(this.stInstance)); this.apiImpl = builder.override(this.config.override.apis).build(); } /** @@ -156,7 +150,7 @@ class Recipe extends recipeModule_1.default { ? new emaildelivery_1.default(this.config.getEmailDeliveryConfig(this.isInServerlessEnv)) : ingredients.emailDelivery; postSuperTokensInitCallbacks_1.PostSuperTokensInitCallbacks.addPostInitCallback(() => { - const mfaInstance = recipe_1.default.getInstance(); + const mfaInstance = stInstance.getRecipeInstance("multifactorauth"); if (mfaInstance !== undefined) { mfaInstance.addFuncToGetAllAvailableSecondaryFactorIdsFromOtherRecipes(() => { return ["emailpassword"]; @@ -266,7 +260,7 @@ class Recipe extends recipeModule_1.default { }; }); } - const mtRecipe = recipe_2.default.getInstance(); + const mtRecipe = stInstance.getRecipeInstance("multitenancy"); if (mtRecipe !== undefined) { mtRecipe.allAvailableFirstFactors.push(multifactorauth_1.FactorIds.EMAILPASSWORD); } @@ -279,9 +273,10 @@ class Recipe extends recipeModule_1.default { throw new Error("Initialisation not done. Did you forget to call the Emailpassword.init function?"); } static init(config) { - return (appInfo, isInServerlessEnv, plugins) => { + return (stInstance, appInfo, isInServerlessEnv, plugins) => { if (Recipe.instance === undefined) { Recipe.instance = new Recipe( + stInstance, Recipe.RECIPE_ID, appInfo, isInServerlessEnv, diff --git a/lib/build/recipe/emailpassword/recipeImplementation.d.ts b/lib/build/recipe/emailpassword/recipeImplementation.d.ts index cfb8e6ad0..c9038a5fd 100644 --- a/lib/build/recipe/emailpassword/recipeImplementation.d.ts +++ b/lib/build/recipe/emailpassword/recipeImplementation.d.ts @@ -1,7 +1,9 @@ // @ts-nocheck import { RecipeInterface, TypeNormalisedInput } from "./types"; import { Querier } from "../../querier"; +import type SuperTokens from "../../supertokens"; export default function getRecipeInterface( + stInstance: SuperTokens, querier: Querier, getEmailPasswordConfig: () => TypeNormalisedInput ): RecipeInterface; diff --git a/lib/build/recipe/emailpassword/recipeImplementation.js b/lib/build/recipe/emailpassword/recipeImplementation.js index d8cb5c562..ff0932ea1 100644 --- a/lib/build/recipe/emailpassword/recipeImplementation.js +++ b/lib/build/recipe/emailpassword/recipeImplementation.js @@ -6,15 +6,12 @@ var __importDefault = }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = getRecipeInterface; -const recipe_1 = __importDefault(require("../accountlinking/recipe")); -const recipe_2 = __importDefault(require("../emailverification/recipe")); -const __1 = require("../.."); const constants_1 = require("./constants"); const recipeUserId_1 = __importDefault(require("../../recipeUserId")); const constants_2 = require("../multitenancy/constants"); const user_1 = require("../../user"); const authUtils_1 = require("../../authUtils"); -function getRecipeInterface(querier, getEmailPasswordConfig) { +function getRecipeInterface(stInstance, querier, getEmailPasswordConfig) { return { signUp: async function ({ email, password, tenantId, session, shouldTryLinkingWithSessionUser, userContext }) { const response = await this.createNewRecipeUser({ @@ -29,8 +26,9 @@ function getRecipeInterface(querier, getEmailPasswordConfig) { let updatedUser = response.user; const linkResult = await authUtils_1.AuthUtils.linkToSessionIfRequiredElseCreatePrimaryUserIdOrLinkByAccountInfo({ + stInstance, tenantId, - inputUser: response.user, + inputUser: updatedUser, recipeUserId: response.recipeUserId, session, shouldTryLinkingWithSessionUser, @@ -78,8 +76,8 @@ function getRecipeInterface(querier, getEmailPasswordConfig) { (lm) => lm.recipeUserId.getAsString() === response.recipeUserId.getAsString() ); if (!loginMethod.verified) { - await recipe_1.default - .getInstanceOrThrowError() + await stInstance + .getRecipeInstanceOrThrow("accountlinking") .verifyEmailForRecipeUserIfLinkedAccountsAreVerified({ user: response.user, recipeUserId: response.recipeUserId, @@ -96,10 +94,13 @@ function getRecipeInterface(querier, getEmailPasswordConfig) { // point of view who is calling the sign up recipe function. // We do this so that we get the updated user (in case the above // function updated the verification status) and can return that - response.user = await (0, __1.getUser)(response.recipeUserId.getAsString(), userContext); + response.user = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: response.recipeUserId.getAsString(), userContext }); } const linkResult = await authUtils_1.AuthUtils.linkToSessionIfRequiredElseCreatePrimaryUserIdOrLinkByAccountInfo({ + stInstance, tenantId, inputUser: response.user, recipeUserId: response.recipeUserId, @@ -170,13 +171,16 @@ function getRecipeInterface(querier, getEmailPasswordConfig) { ); }, updateEmailOrPassword: async function (input) { - const accountLinking = recipe_1.default.getInstanceOrThrowError(); + const accountLinking = stInstance.getRecipeInstanceOrThrow("accountlinking"); if (input.email) { - const user = await (0, __1.getUser)(input.recipeUserId.getAsString(), input.userContext); + const user = await stInstance.getRecipeInstanceOrThrow("accountlinking").recipeInterfaceImpl.getUser({ + userId: input.recipeUserId.getAsString(), + userContext: input.userContext, + }); if (user === undefined) { return { status: "UNKNOWN_USER_ID_ERROR" }; } - const evInstance = recipe_2.default.getInstance(); + const evInstance = stInstance.getRecipeInstance("emailverification"); let isEmailVerified = false; if (evInstance) { isEmailVerified = await evInstance.recipeInterfaceImpl.isEmailVerified({ @@ -236,18 +240,23 @@ function getRecipeInterface(querier, getEmailPasswordConfig) { input.userContext ); if (response.status === "OK") { - const user = await (0, __1.getUser)(input.recipeUserId.getAsString(), input.userContext); + const user = await stInstance.getRecipeInstanceOrThrow("accountlinking").recipeInterfaceImpl.getUser({ + userId: input.recipeUserId.getAsString(), + userContext: input.userContext, + }); if (user === undefined) { // This means that the user was deleted between the put and get requests return { status: "UNKNOWN_USER_ID_ERROR", }; } - await recipe_1.default.getInstanceOrThrowError().verifyEmailForRecipeUserIfLinkedAccountsAreVerified({ - user, - recipeUserId: input.recipeUserId, - userContext: input.userContext, - }); + await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .verifyEmailForRecipeUserIfLinkedAccountsAreVerified({ + user, + recipeUserId: input.recipeUserId, + userContext: input.userContext, + }); } return response; }, diff --git a/lib/build/recipe/emailpassword/types.d.ts b/lib/build/recipe/emailpassword/types.d.ts index cefc98baf..306c1e990 100644 --- a/lib/build/recipe/emailpassword/types.d.ts +++ b/lib/build/recipe/emailpassword/types.d.ts @@ -320,3 +320,9 @@ export type TypeEmailPasswordPasswordResetEmailDeliveryInput = { tenantId: string; }; export type TypeEmailPasswordEmailDeliveryInput = TypeEmailPasswordPasswordResetEmailDeliveryInput; +export type APIFunction = (input: { + apiImplementation: APIInterface; + tenantId: string; + options: APIOptions; + userContext: UserContext; +}) => Promise; diff --git a/lib/build/recipe/emailpassword/utils.d.ts b/lib/build/recipe/emailpassword/utils.d.ts index a62eb7fe7..39db997e1 100644 --- a/lib/build/recipe/emailpassword/utils.d.ts +++ b/lib/build/recipe/emailpassword/utils.d.ts @@ -2,7 +2,7 @@ import Recipe from "./recipe"; import { TypeInput, TypeNormalisedInput, NormalisedFormField, TypeInputFormField } from "./types"; import { NormalisedAppinfo, UserContext } from "../../types"; -import { BaseRequest } from "../../framework"; +import type { BaseRequest } from "../../framework"; export declare function validateAndNormaliseUserInput( recipeInstance: Recipe, appInfo: NormalisedAppinfo, @@ -21,7 +21,7 @@ export declare function defaultPasswordValidator( >; export declare function defaultEmailValidator( value: any -): Promise<"Development bug: Please make sure the email field yields a string" | "Email is invalid" | undefined>; +): Promise<"Email is invalid" | "Development bug: Please make sure the email field yields a string" | undefined>; export declare function getPasswordResetLink(input: { appInfo: NormalisedAppinfo; token: string; diff --git a/lib/build/recipe/emailverification/api/emailVerify.d.ts b/lib/build/recipe/emailverification/api/emailVerify.d.ts index 1f7b416c8..2d00f0d50 100644 --- a/lib/build/recipe/emailverification/api/emailVerify.d.ts +++ b/lib/build/recipe/emailverification/api/emailVerify.d.ts @@ -1,7 +1,9 @@ // @ts-nocheck import { APIInterface, APIOptions } from "../"; import { UserContext } from "../../../types"; +import SuperTokens from "../../../supertokens"; export default function emailVerify( + stInstance: SuperTokens, apiImplementation: APIInterface, tenantId: string, options: APIOptions, diff --git a/lib/build/recipe/emailverification/api/emailVerify.js b/lib/build/recipe/emailverification/api/emailVerify.js index 80e678119..ed37113ac 100644 --- a/lib/build/recipe/emailverification/api/emailVerify.js +++ b/lib/build/recipe/emailverification/api/emailVerify.js @@ -22,8 +22,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.default = emailVerify; const utils_1 = require("../../../utils"); const error_1 = __importDefault(require("../error")); -const session_1 = __importDefault(require("../../session")); -async function emailVerify(apiImplementation, tenantId, options, userContext) { +async function emailVerify(stInstance, apiImplementation, tenantId, options, userContext) { let result; if ((0, utils_1.normaliseHttpMethod)(options.req.getMethod()) === "post") { // Logic according to Logic as per https://github.com/supertokens/supertokens-node/issues/62#issuecomment-751616106 @@ -44,12 +43,12 @@ async function emailVerify(apiImplementation, tenantId, options, userContext) { message: "The email verification token must be a string", }); } - const session = await session_1.default.getSession( - options.req, - options.res, - { overrideGlobalClaimValidators: () => [], sessionRequired: false }, - userContext - ); + const session = await stInstance.getRecipeInstanceOrThrow("session").getSession({ + req: options.req, + res: options.res, + options: { overrideGlobalClaimValidators: () => [], sessionRequired: false }, + userContext, + }); let response = await apiImplementation.verifyEmailPOST({ token, tenantId, @@ -69,15 +68,15 @@ async function emailVerify(apiImplementation, tenantId, options, userContext) { if (apiImplementation.isEmailVerifiedGET === undefined) { return false; } - const session = await session_1.default.getSession( - options.req, - options.res, - { overrideGlobalClaimValidators: () => [] }, - userContext - ); + const session = await stInstance.getRecipeInstanceOrThrow("session").getSession({ + req: options.req, + res: options.res, + options: { overrideGlobalClaimValidators: () => [] }, + userContext, + }); result = await apiImplementation.isEmailVerifiedGET({ options, - session, + session: session, userContext, }); } diff --git a/lib/build/recipe/emailverification/api/generateEmailVerifyToken.d.ts b/lib/build/recipe/emailverification/api/generateEmailVerifyToken.d.ts index 487897d0e..4ac5da85e 100644 --- a/lib/build/recipe/emailverification/api/generateEmailVerifyToken.d.ts +++ b/lib/build/recipe/emailverification/api/generateEmailVerifyToken.d.ts @@ -1,7 +1,9 @@ // @ts-nocheck import { APIInterface, APIOptions } from "../"; import { UserContext } from "../../../types"; +import type SuperTokens from "../../../supertokens"; export default function generateEmailVerifyToken( + stInstance: SuperTokens, apiImplementation: APIInterface, options: APIOptions, userContext: UserContext diff --git a/lib/build/recipe/emailverification/api/generateEmailVerifyToken.js b/lib/build/recipe/emailverification/api/generateEmailVerifyToken.js index 0f7d1bdea..5b389893b 100644 --- a/lib/build/recipe/emailverification/api/generateEmailVerifyToken.js +++ b/lib/build/recipe/emailverification/api/generateEmailVerifyToken.js @@ -13,26 +13,20 @@ * License for the specific language governing permissions and limitations * under the License. */ -var __importDefault = - (this && this.__importDefault) || - function (mod) { - return mod && mod.__esModule ? mod : { default: mod }; - }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = generateEmailVerifyToken; const utils_1 = require("../../../utils"); -const session_1 = __importDefault(require("../../session")); -async function generateEmailVerifyToken(apiImplementation, options, userContext) { +async function generateEmailVerifyToken(stInstance, apiImplementation, options, userContext) { // Logic as per https://github.com/supertokens/supertokens-node/issues/62#issuecomment-751616106 if (apiImplementation.generateEmailVerifyTokenPOST === undefined) { return false; } - const session = await session_1.default.getSession( - options.req, - options.res, - { overrideGlobalClaimValidators: () => [] }, - userContext - ); + const session = await stInstance.getRecipeInstanceOrThrow("session").getSession({ + req: options.req, + res: options.res, + options: { overrideGlobalClaimValidators: () => [] }, + userContext, + }); const result = await apiImplementation.generateEmailVerifyTokenPOST({ options, session: session, diff --git a/lib/build/recipe/emailverification/api/implementation.d.ts b/lib/build/recipe/emailverification/api/implementation.d.ts index dd40e7025..d5395c7aa 100644 --- a/lib/build/recipe/emailverification/api/implementation.d.ts +++ b/lib/build/recipe/emailverification/api/implementation.d.ts @@ -1,3 +1,4 @@ // @ts-nocheck import { APIInterface } from "../"; -export default function getAPIInterface(): APIInterface; +import type SuperTokens from "../../../supertokens"; +export default function getAPIInterface(stInstance: SuperTokens): APIInterface; diff --git a/lib/build/recipe/emailverification/api/implementation.js b/lib/build/recipe/emailverification/api/implementation.js index a4493686c..8062776df 100644 --- a/lib/build/recipe/emailverification/api/implementation.js +++ b/lib/build/recipe/emailverification/api/implementation.js @@ -7,11 +7,10 @@ var __importDefault = Object.defineProperty(exports, "__esModule", { value: true }); exports.default = getAPIInterface; const logger_1 = require("../../../logger"); -const recipe_1 = __importDefault(require("../recipe")); const emailVerificationClaim_1 = require("../emailVerificationClaim"); const error_1 = __importDefault(require("../../session/error")); const utils_1 = require("../utils"); -function getAPIInterface() { +function getAPIInterface(stInstance) { return { verifyEmailPOST: async function ({ token, tenantId, session, options, userContext }) { const verifyTokenResponse = await options.recipeImplementation.verifyEmailUsingToken({ @@ -24,8 +23,8 @@ function getAPIInterface() { return verifyTokenResponse; } // status: "OK" - let newSession = await recipe_1.default - .getInstanceOrThrowError() + let newSession = await stInstance + .getRecipeInstanceOrThrow("emailverification") .updateSessionIfRequiredPostEmailVerification({ req: options.req, res: options.res, @@ -41,8 +40,8 @@ function getAPIInterface() { }, isEmailVerifiedGET: async function ({ userContext, session, options }) { // In this API, we will check if the session's recipe user id's email is verified or not. - const emailInfo = await recipe_1.default - .getInstanceOrThrowError() + const emailInfo = await stInstance + .getRecipeInstanceOrThrow("emailverification") .getEmailForRecipeUserId(undefined, session.getRecipeUserId(userContext), userContext); if (emailInfo.status === "OK") { const isVerified = await options.recipeImplementation.isEmailVerified({ @@ -56,8 +55,8 @@ function getAPIInterface() { // whilst the first browser is polling this API - in this case, // we want to have the same effect to the session as if the // email was opened on the original browser itself. - let newSession = await recipe_1.default - .getInstanceOrThrowError() + let newSession = await stInstance + .getRecipeInstanceOrThrow("emailverification") .updateSessionIfRequiredPostEmailVerification({ req: options.req, res: options.res, @@ -97,8 +96,8 @@ function getAPIInterface() { generateEmailVerifyTokenPOST: async function ({ options, userContext, session }) { // In this API, we generate the email verification token for session's recipe user ID. const tenantId = session.getTenantId(); - const emailInfo = await recipe_1.default - .getInstanceOrThrowError() + const emailInfo = await stInstance + .getRecipeInstanceOrThrow("emailverification") .getEmailForRecipeUserId(undefined, session.getRecipeUserId(userContext), userContext); if (emailInfo.status === "EMAIL_DOES_NOT_EXIST_ERROR") { (0, logger_1.logDebugMessage)( @@ -108,8 +107,8 @@ function getAPIInterface() { ); // this can happen if the user ID was found, but it has no email. In this // case, we treat it as a success case. - let newSession = await recipe_1.default - .getInstanceOrThrowError() + let newSession = await stInstance + .getRecipeInstanceOrThrow("emailverification") .updateSessionIfRequiredPostEmailVerification({ req: options.req, res: options.res, @@ -136,8 +135,8 @@ function getAPIInterface() { .getRecipeUserId(userContext) .getAsString()} because it is already verified.` ); - let newSession = await recipe_1.default - .getInstanceOrThrowError() + let newSession = await stInstance + .getRecipeInstanceOrThrow("emailverification") .updateSessionIfRequiredPostEmailVerification({ req: options.req, res: options.res, diff --git a/lib/build/recipe/emailverification/emailVerificationFunctions.js b/lib/build/recipe/emailverification/emailVerificationFunctions.js index ebeef238c..2c3121799 100644 --- a/lib/build/recipe/emailverification/emailVerificationFunctions.js +++ b/lib/build/recipe/emailverification/emailVerificationFunctions.js @@ -16,11 +16,12 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.createAndSendEmailUsingSupertokensService = createAndSendEmailUsingSupertokensService; const utils_1 = require("../../utils"); +const querier_1 = require("../../querier"); async function createAndSendEmailUsingSupertokensService(appInfo, user, emailVerifyURLWithToken) { if ((0, utils_1.isTestEnv)()) { return; } - await (0, utils_1.postWithFetch)( + await (0, querier_1.postWithFetch)( "https://api.supertokens.io/0/st/auth/email/verify", { "api-version": "0", diff --git a/lib/build/recipe/emailverification/recipe.d.ts b/lib/build/recipe/emailverification/recipe.d.ts index 6841e9797..eaa891f47 100644 --- a/lib/build/recipe/emailverification/recipe.d.ts +++ b/lib/build/recipe/emailverification/recipe.d.ts @@ -9,6 +9,7 @@ import EmailDeliveryIngredient from "../../ingredients/emaildelivery"; import { TypeEmailVerificationEmailDeliveryInput } from "./types"; import { SessionContainerInterface } from "../session/types"; import RecipeUserId from "../../recipeUserId"; +import type SuperTokens from "../../supertokens"; export default class Recipe extends RecipeModule { private static instance; static RECIPE_ID: "emailverification"; @@ -18,6 +19,7 @@ export default class Recipe extends RecipeModule { isInServerlessEnv: boolean; emailDelivery: EmailDeliveryIngredient; constructor( + stInstance: SuperTokens, recipeId: string, appInfo: NormalisedAppinfo, isInServerlessEnv: boolean, diff --git a/lib/build/recipe/emailverification/recipe.js b/lib/build/recipe/emailverification/recipe.js index 10c2eb798..018818e2c 100644 --- a/lib/build/recipe/emailverification/recipe.js +++ b/lib/build/recipe/emailverification/recipe.js @@ -28,21 +28,18 @@ const generateEmailVerifyToken_1 = __importDefault(require("./api/generateEmailV const emailVerify_1 = __importDefault(require("./api/emailVerify")); const recipeImplementation_1 = __importDefault(require("./recipeImplementation")); const implementation_1 = __importDefault(require("./api/implementation")); -const querier_1 = require("../../querier"); const supertokens_js_override_1 = __importDefault(require("supertokens-js-override")); const emaildelivery_1 = __importDefault(require("../../ingredients/emaildelivery")); const postSuperTokensInitCallbacks_1 = require("../../postSuperTokensInitCallbacks"); -const recipe_1 = __importDefault(require("../session/recipe")); const emailVerificationClaim_1 = require("./emailVerificationClaim"); const error_2 = __importDefault(require("../session/error")); const session_1 = __importDefault(require("../session")); -const __1 = require("../.."); const logger_1 = require("../../logger"); const utils_2 = require("../../utils"); const plugins_1 = require("../../plugins"); class Recipe extends recipeModule_1.default { - constructor(recipeId, appInfo, isInServerlessEnv, config, ingredients) { - super(recipeId, appInfo); + constructor(stInstance, recipeId, appInfo, isInServerlessEnv, config, ingredients) { + super(stInstance, recipeId, appInfo); // abstract instance functions below............... this.getAPIsHandled = () => { return [ @@ -80,9 +77,14 @@ class Recipe extends recipeModule_1.default { appInfo: this.getAppInfo(), }; if (id === constants_1.GENERATE_EMAIL_VERIFY_TOKEN_API) { - return await (0, generateEmailVerifyToken_1.default)(this.apiImpl, options, userContext); + return await (0, generateEmailVerifyToken_1.default)( + this.stInstance, + this.apiImpl, + options, + userContext + ); } else { - return await (0, emailVerify_1.default)(this.apiImpl, tenantId, options, userContext); + return await (0, emailVerify_1.default)(this.stInstance, this.apiImpl, tenantId, options, userContext); } }; this.handleError = async (err, _, __) => { @@ -102,7 +104,9 @@ class Recipe extends recipeModule_1.default { } } if (user === undefined) { - user = await (0, __1.getUser)(recipeUserId.getAsString(), userContext); + user = await this.stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: recipeUserId.getAsString(), userContext }); if (user === undefined) { return { status: "UNKNOWN_USER_ID_ERROR", @@ -140,7 +144,9 @@ class Recipe extends recipeModule_1.default { // so that the consumer of the getUser function does not read the email // from the primaryUser. Hence, this function only returns the string ID // and nothing else from the primaryUser. - let primaryUser = await (0, __1.getUser)(recipeUserId.getAsString(), userContext); + let primaryUser = await this.stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: recipeUserId.getAsString(), userContext }); if (primaryUser === undefined) { // This can come here if the user is using session + email verification // recipe with a user ID that is not known to supertokens. In this case, @@ -260,15 +266,12 @@ class Recipe extends recipeModule_1.default { this.isInServerlessEnv = isInServerlessEnv; { let builder = new supertokens_js_override_1.default( - (0, recipeImplementation_1.default)( - querier_1.Querier.getNewInstanceOrThrowError(recipeId), - this.getEmailForRecipeUserId - ) + (0, recipeImplementation_1.default)(this.stInstance, this.querier, this.getEmailForRecipeUserId) ); this.recipeInterfaceImpl = builder.override(this.config.override.functions).build(); } { - let builder = new supertokens_js_override_1.default((0, implementation_1.default)()); + let builder = new supertokens_js_override_1.default((0, implementation_1.default)(this.stInstance)); this.apiImpl = builder.override(this.config.override.apis).build(); } /** @@ -290,9 +293,10 @@ class Recipe extends recipeModule_1.default { return Recipe.instance; } static init(config) { - return (appInfo, isInServerlessEnv, plugins) => { + return (stInstance, appInfo, isInServerlessEnv, plugins) => { if (Recipe.instance === undefined) { Recipe.instance = new Recipe( + stInstance, Recipe.RECIPE_ID, appInfo, isInServerlessEnv, @@ -306,12 +310,12 @@ class Recipe extends recipeModule_1.default { } ); postSuperTokensInitCallbacks_1.PostSuperTokensInitCallbacks.addPostInitCallback(() => { - recipe_1.default - .getInstanceOrThrowError() + stInstance + .getRecipeInstanceOrThrow("session") .addClaimFromOtherRecipe(emailVerificationClaim_1.EmailVerificationClaim); if (config.mode === "REQUIRED") { - recipe_1.default - .getInstanceOrThrowError() + stInstance + .getRecipeInstanceOrThrow("session") .addClaimValidatorFromOtherRecipe( emailVerificationClaim_1.EmailVerificationClaim.validators.isVerified() ); diff --git a/lib/build/recipe/emailverification/recipeImplementation.d.ts b/lib/build/recipe/emailverification/recipeImplementation.d.ts index 625b1087e..00be2c828 100644 --- a/lib/build/recipe/emailverification/recipeImplementation.d.ts +++ b/lib/build/recipe/emailverification/recipeImplementation.d.ts @@ -2,7 +2,9 @@ import { RecipeInterface } from "./"; import { Querier } from "../../querier"; import { GetEmailForRecipeUserIdFunc } from "./types"; +import SuperTokens from "../../supertokens"; export default function getRecipeInterface( + stInstance: SuperTokens, querier: Querier, getEmailForRecipeUserId: GetEmailForRecipeUserIdFunc ): RecipeInterface; diff --git a/lib/build/recipe/emailverification/recipeImplementation.js b/lib/build/recipe/emailverification/recipeImplementation.js index cc6b0e878..9f5aa8268 100644 --- a/lib/build/recipe/emailverification/recipeImplementation.js +++ b/lib/build/recipe/emailverification/recipeImplementation.js @@ -7,8 +7,7 @@ var __importDefault = Object.defineProperty(exports, "__esModule", { value: true }); exports.default = getRecipeInterface; const recipeUserId_1 = __importDefault(require("../../recipeUserId")); -const __1 = require("../.."); -function getRecipeInterface(querier, getEmailForRecipeUserId) { +function getRecipeInterface(stInstance, querier, getEmailForRecipeUserId) { return { createEmailVerificationToken: async function ({ recipeUserId, email, tenantId, userContext }) { let response = await querier.sendPostRequest( @@ -53,7 +52,9 @@ function getRecipeInterface(querier, getEmailForRecipeUserId) { const recipeUserId = new recipeUserId_1.default(response.userId); if (attemptAccountLinking) { // TODO: this should ideally come from the api response - const updatedUser = await (0, __1.getUser)(recipeUserId.getAsString()); + const updatedUser = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: recipeUserId.getAsString(), userContext }); if (updatedUser) { // before attempting this, we must check that the email that got verified // from the ID is the one that is currently associated with the ID (since @@ -61,15 +62,14 @@ function getRecipeInterface(querier, getEmailForRecipeUserId) { // and not necessarily the email that is currently associated with the ID) let emailInfo = await getEmailForRecipeUserId(updatedUser, recipeUserId, userContext); if (emailInfo.status === "OK" && emailInfo.email === response.email) { - // we do this here to prevent cyclic dependencies. - // TODO: Fix this. - let AccountLinking = require("../accountlinking/recipe").default.getInstanceOrThrowError(); - await AccountLinking.tryLinkingByAccountInfoOrCreatePrimaryUser({ - tenantId, - inputUser: updatedUser, - session: undefined, - userContext, - }); + await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .tryLinkingByAccountInfoOrCreatePrimaryUser({ + tenantId, + inputUser: updatedUser, + session: undefined, + userContext, + }); } } } diff --git a/lib/build/recipe/emailverification/utils.d.ts b/lib/build/recipe/emailverification/utils.d.ts index 60043dc8a..468049845 100644 --- a/lib/build/recipe/emailverification/utils.d.ts +++ b/lib/build/recipe/emailverification/utils.d.ts @@ -2,7 +2,7 @@ import Recipe from "./recipe"; import { TypeInput, TypeNormalisedInput } from "./types"; import { NormalisedAppinfo, UserContext } from "../../types"; -import { BaseRequest } from "../../framework"; +import type { BaseRequest } from "../../framework"; export declare function validateAndNormaliseUserInput( _: Recipe, appInfo: NormalisedAppinfo, diff --git a/lib/build/recipe/jwt/recipe.d.ts b/lib/build/recipe/jwt/recipe.d.ts index 0f0a948c3..fec3df322 100644 --- a/lib/build/recipe/jwt/recipe.d.ts +++ b/lib/build/recipe/jwt/recipe.d.ts @@ -5,6 +5,7 @@ import normalisedURLPath from "../../normalisedURLPath"; import RecipeModule from "../../recipeModule"; import { APIHandled, HTTPMethod, NormalisedAppinfo, RecipeListFunction, UserContext } from "../../types"; import { APIInterface, RecipeInterface, TypeInput, TypeNormalisedInput } from "./types"; +import type SuperTokens from "../../supertokens"; export default class Recipe extends RecipeModule { static RECIPE_ID: "jwt"; private static instance; @@ -12,7 +13,13 @@ export default class Recipe extends RecipeModule { recipeInterfaceImpl: RecipeInterface; apiImpl: APIInterface; isInServerlessEnv: boolean; - constructor(recipeId: string, appInfo: NormalisedAppinfo, isInServerlessEnv: boolean, config?: TypeInput); + constructor( + stInstance: SuperTokens, + recipeId: string, + appInfo: NormalisedAppinfo, + isInServerlessEnv: boolean, + config?: TypeInput + ); static getInstanceOrThrowError(): Recipe; static init(config?: TypeInput): RecipeListFunction; static reset(): void; diff --git a/lib/build/recipe/jwt/recipe.js b/lib/build/recipe/jwt/recipe.js index 7d6b6ab8d..4f5ef1c0a 100644 --- a/lib/build/recipe/jwt/recipe.js +++ b/lib/build/recipe/jwt/recipe.js @@ -21,7 +21,6 @@ var __importDefault = Object.defineProperty(exports, "__esModule", { value: true }); const error_1 = __importDefault(require("../../error")); const normalisedURLPath_1 = __importDefault(require("../../normalisedURLPath")); -const querier_1 = require("../../querier"); const recipeModule_1 = __importDefault(require("../../recipeModule")); const utils_1 = require("../../utils"); const plugins_1 = require("../../plugins"); @@ -32,8 +31,8 @@ const recipeImplementation_1 = __importDefault(require("./recipeImplementation") const utils_2 = require("./utils"); const supertokens_js_override_1 = __importDefault(require("supertokens-js-override")); class Recipe extends recipeModule_1.default { - constructor(recipeId, appInfo, isInServerlessEnv, config) { - super(recipeId, appInfo); + constructor(stInstance, recipeId, appInfo, isInServerlessEnv, config) { + super(stInstance, recipeId, appInfo); this.handleAPIRequest = async (_id, _tenantId, req, res, _path, _method, userContext) => { let options = { config: this.config, @@ -49,11 +48,7 @@ class Recipe extends recipeModule_1.default { this.isInServerlessEnv = isInServerlessEnv; { let builder = new supertokens_js_override_1.default( - (0, recipeImplementation_1.default)( - querier_1.Querier.getNewInstanceOrThrowError(recipeId), - this.config, - appInfo - ) + (0, recipeImplementation_1.default)(this.querier, this.config, appInfo) ); this.recipeInterfaceImpl = builder.override(this.config.override.functions).build(); } @@ -70,9 +65,10 @@ class Recipe extends recipeModule_1.default { throw new Error("Initialisation not done. Did you forget to call the Jwt.init function?"); } static init(config) { - return (appInfo, isInServerlessEnv, plugins) => { + return (stInstance, appInfo, isInServerlessEnv, plugins) => { if (Recipe.instance === undefined) { Recipe.instance = new Recipe( + stInstance, Recipe.RECIPE_ID, appInfo, isInServerlessEnv, diff --git a/lib/build/recipe/multifactorauth/api/implementation.d.ts b/lib/build/recipe/multifactorauth/api/implementation.d.ts index dd40e7025..3dce578ce 100644 --- a/lib/build/recipe/multifactorauth/api/implementation.d.ts +++ b/lib/build/recipe/multifactorauth/api/implementation.d.ts @@ -1,3 +1,8 @@ // @ts-nocheck import { APIInterface } from "../"; -export default function getAPIInterface(): APIInterface; +import type SuperTokens from "../../../supertokens"; +import { MultiFactorAuthClaimClass } from "../multiFactorAuthClaim"; +export default function getAPIInterface( + stInstance: SuperTokens, + multiFactorAuthClaim: MultiFactorAuthClaimClass +): APIInterface; diff --git a/lib/build/recipe/multifactorauth/api/implementation.js b/lib/build/recipe/multifactorauth/api/implementation.js index 7dad0fd4b..49ada2b84 100644 --- a/lib/build/recipe/multifactorauth/api/implementation.js +++ b/lib/build/recipe/multifactorauth/api/implementation.js @@ -20,15 +20,14 @@ var __importDefault = }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = getAPIInterface; -const multiFactorAuthClaim_1 = require("../multiFactorAuthClaim"); const error_1 = __importDefault(require("../../session/error")); const utils_1 = require("../utils"); -const multitenancy_1 = __importDefault(require("../../multitenancy")); -const __1 = require("../../.."); -function getAPIInterface() { +function getAPIInterface(stInstance, multiFactorAuthClaim) { return { resyncSessionAndFetchMFAInfoPUT: async ({ options, session, userContext }) => { - const sessionUser = await (0, __1.getUser)(session.getUserId(), userContext); + const sessionUser = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: session.getUserId(), userContext }); if (sessionUser === undefined) { throw new error_1.default({ type: error_1.default.UNAUTHORISED, @@ -37,13 +36,16 @@ function getAPIInterface() { } const mfaInfo = await (0, utils_1.updateAndGetMFARelatedInfoInSession)({ session, + stInstance, userContext, }); const factorsSetUpForUser = await options.recipeImplementation.getFactorsSetupForUser({ user: sessionUser, userContext, }); - const tenantInfo = await multitenancy_1.default.getTenant(session.getTenantId(userContext), userContext); + const tenantInfo = await stInstance + .getRecipeInstanceOrThrow("multitenancy") + .recipeInterfaceImpl.getTenant({ tenantId: session.getTenantId(userContext), userContext }); if (tenantInfo === undefined) { throw new error_1.default({ type: error_1.default.UNAUTHORISED, @@ -73,11 +75,10 @@ function getAPIInterface() { // ignore claims error and not add to the list of factors allowed to be set up } } - const nextSetOfUnsatisfiedFactors = - multiFactorAuthClaim_1.MultiFactorAuthClaim.getNextSetOfUnsatisfiedFactors( - mfaInfo.completedFactors, - mfaInfo.mfaRequirementsForAuth - ); + const nextSetOfUnsatisfiedFactors = multiFactorAuthClaim.getNextSetOfUnsatisfiedFactors( + mfaInfo.completedFactors, + mfaInfo.mfaRequirementsForAuth + ); let getEmailsForFactorsResult = options.recipeInstance.getEmailsForFactors( sessionUser, session.getRecipeUserId(userContext) diff --git a/lib/build/recipe/multifactorauth/api/resyncSessionAndFetchMFAInfo.d.ts b/lib/build/recipe/multifactorauth/api/resyncSessionAndFetchMFAInfo.d.ts index 081461387..82c5780dc 100644 --- a/lib/build/recipe/multifactorauth/api/resyncSessionAndFetchMFAInfo.d.ts +++ b/lib/build/recipe/multifactorauth/api/resyncSessionAndFetchMFAInfo.d.ts @@ -1,7 +1,9 @@ // @ts-nocheck import { APIInterface, APIOptions } from ".."; import { UserContext } from "../../../types"; +import SuperTokens from "../../../supertokens"; export default function resyncSessionAndFetchMFAInfo( + stInstance: SuperTokens, apiImplementation: APIInterface, options: APIOptions, userContext: UserContext diff --git a/lib/build/recipe/multifactorauth/api/resyncSessionAndFetchMFAInfo.js b/lib/build/recipe/multifactorauth/api/resyncSessionAndFetchMFAInfo.js index 594f2ac70..e9cb30d13 100644 --- a/lib/build/recipe/multifactorauth/api/resyncSessionAndFetchMFAInfo.js +++ b/lib/build/recipe/multifactorauth/api/resyncSessionAndFetchMFAInfo.js @@ -13,28 +13,22 @@ * License for the specific language governing permissions and limitations * under the License. */ -var __importDefault = - (this && this.__importDefault) || - function (mod) { - return mod && mod.__esModule ? mod : { default: mod }; - }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = resyncSessionAndFetchMFAInfo; const utils_1 = require("../../../utils"); -const session_1 = __importDefault(require("../../session")); -async function resyncSessionAndFetchMFAInfo(apiImplementation, options, userContext) { +async function resyncSessionAndFetchMFAInfo(stInstance, apiImplementation, options, userContext) { if (apiImplementation.resyncSessionAndFetchMFAInfoPUT === undefined) { return false; } - const session = await session_1.default.getSession( - options.req, - options.res, - { overrideGlobalClaimValidators: () => [], sessionRequired: true }, - userContext - ); + const session = await stInstance.getRecipeInstanceOrThrow("session").getSession({ + req: options.req, + res: options.res, + options: { overrideGlobalClaimValidators: () => [], sessionRequired: true }, + userContext, + }); let response = await apiImplementation.resyncSessionAndFetchMFAInfoPUT({ options, - session, + session: session, userContext, }); (0, utils_1.send200Response)(options.res, response); diff --git a/lib/build/recipe/multifactorauth/index.d.ts b/lib/build/recipe/multifactorauth/index.d.ts index b2d06cd51..d4654c352 100644 --- a/lib/build/recipe/multifactorauth/index.d.ts +++ b/lib/build/recipe/multifactorauth/index.d.ts @@ -1,12 +1,12 @@ // @ts-nocheck import Recipe from "./recipe"; import { RecipeInterface, APIOptions, APIInterface } from "./types"; -import { MultiFactorAuthClaim } from "./multiFactorAuthClaim"; import { SessionContainerInterface } from "../session/types"; import { FactorIds } from "./types"; +import { MultiFactorAuthClaimClass } from "./multiFactorAuthClaim"; export default class Wrapper { static init: typeof Recipe.init; - static MultiFactorAuthClaim: import("./multiFactorAuthClaim").MultiFactorAuthClaimClass; + static MultiFactorAuthClaim: MultiFactorAuthClaimClass; static FactorIds: { EMAILPASSWORD: string; WEBAUTHN: string; @@ -52,6 +52,6 @@ export declare let getRequiredSecondaryFactorsForUser: typeof Wrapper.getRequire export declare let getMFARequirementsForAuth: typeof Wrapper.getMFARequirementsForAuth; export declare const addToRequiredSecondaryFactorsForUser: typeof Wrapper.addToRequiredSecondaryFactorsForUser; export declare const removeFromRequiredSecondaryFactorsForUser: typeof Wrapper.removeFromRequiredSecondaryFactorsForUser; -export { MultiFactorAuthClaim }; +export declare const MultiFactorAuthClaim: MultiFactorAuthClaimClass; export { FactorIds }; export type { RecipeInterface, APIOptions, APIInterface }; diff --git a/lib/build/recipe/multifactorauth/index.js b/lib/build/recipe/multifactorauth/index.js index 489b0c655..1bea724a3 100644 --- a/lib/build/recipe/multifactorauth/index.js +++ b/lib/build/recipe/multifactorauth/index.js @@ -31,13 +31,6 @@ exports.FactorIds = exports.init = void 0; const recipe_1 = __importDefault(require("./recipe")); -const multiFactorAuthClaim_1 = require("./multiFactorAuthClaim"); -Object.defineProperty(exports, "MultiFactorAuthClaim", { - enumerable: true, - get: function () { - return multiFactorAuthClaim_1.MultiFactorAuthClaim; - }, -}); const __1 = require("../.."); const utils_1 = require("../../utils"); const utils_2 = require("./utils"); @@ -48,31 +41,19 @@ Object.defineProperty(exports, "FactorIds", { return types_1.FactorIds; }, }); +const supertokens_1 = __importDefault(require("../../supertokens")); +const multiFactorAuthClaim_1 = require("./multiFactorAuthClaim"); class Wrapper { static async assertAllowedToSetupFactorElseThrowInvalidClaimError(session, factorId, userContext) { let ctx = (0, utils_1.getUserContext)(userContext); - const mfaInfo = await (0, utils_2.updateAndGetMFARelatedInfoInSession)({ - session, - userContext: ctx, - }); - const factorsSetUpForUser = await Wrapper.getFactorsSetupForUser(session.getUserId(), ctx); await recipe_1.default .getInstanceOrThrowError() - .recipeInterfaceImpl.assertAllowedToSetupFactorElseThrowInvalidClaimError({ - session, - factorId, - get factorsSetUpForUser() { - return Promise.resolve(factorsSetUpForUser); - }, - get mfaRequirementsForAuth() { - return Promise.resolve(mfaInfo.mfaRequirementsForAuth); - }, - userContext: ctx, - }); + .assertAllowedToSetupFactorElseThrowInvalidClaimError(session, factorId, ctx); } static async getMFARequirementsForAuth(session, userContext) { let ctx = (0, utils_1.getUserContext)(userContext); const mfaInfo = await (0, utils_2.updateAndGetMFARelatedInfoInSession)({ + stInstance: supertokens_1.default.getInstanceOrThrowError(), session, userContext: ctx, }); @@ -118,7 +99,9 @@ class Wrapper { } } Wrapper.init = recipe_1.default.init; -Wrapper.MultiFactorAuthClaim = multiFactorAuthClaim_1.MultiFactorAuthClaim; +Wrapper.MultiFactorAuthClaim = new multiFactorAuthClaim_1.MultiFactorAuthClaimClass(() => + supertokens_1.default.getInstanceOrThrowError() +); Wrapper.FactorIds = types_1.FactorIds; exports.default = Wrapper; exports.init = Wrapper.init; @@ -130,3 +113,4 @@ exports.getRequiredSecondaryFactorsForUser = Wrapper.getRequiredSecondaryFactors exports.getMFARequirementsForAuth = Wrapper.getMFARequirementsForAuth; exports.addToRequiredSecondaryFactorsForUser = Wrapper.addToRequiredSecondaryFactorsForUser; exports.removeFromRequiredSecondaryFactorsForUser = Wrapper.removeFromRequiredSecondaryFactorsForUser; +exports.MultiFactorAuthClaim = Wrapper.MultiFactorAuthClaim; diff --git a/lib/build/recipe/multifactorauth/multiFactorAuthClaim.d.ts b/lib/build/recipe/multifactorauth/multiFactorAuthClaim.d.ts index 9a64cba0e..4813da321 100644 --- a/lib/build/recipe/multifactorauth/multiFactorAuthClaim.d.ts +++ b/lib/build/recipe/multifactorauth/multiFactorAuthClaim.d.ts @@ -5,11 +5,13 @@ import { SessionClaim } from "../session/claims"; import { JSONObject } from "../usermetadata"; import { MFAClaimValue, MFARequirementList } from "./types"; import { UserContext } from "../../types"; +import type SuperTokens from "../../supertokens"; /** * We include "Class" in the class name, because it makes it easier to import the right thing (the instance) instead of this. * */ export declare class MultiFactorAuthClaimClass extends SessionClaim { - constructor(key?: string); + private readonly stInstanceGetter; + constructor(stInstanceGetter: () => SuperTokens, key?: string); validators: { hasCompletedMFARequirementsForAuth: (id?: string) => SessionClaimValidator; hasCompletedRequirementList(requirementList: MFARequirementList, id?: string): SessionClaimValidator; @@ -58,4 +60,3 @@ export declare class MultiFactorAuthClaimClass extends SessionClaim MFAClaimValue; } -export declare const MultiFactorAuthClaim: MultiFactorAuthClaimClass; diff --git a/lib/build/recipe/multifactorauth/multiFactorAuthClaim.js b/lib/build/recipe/multifactorauth/multiFactorAuthClaim.js index 0fb1b6eab..2608f55c8 100644 --- a/lib/build/recipe/multifactorauth/multiFactorAuthClaim.js +++ b/lib/build/recipe/multifactorauth/multiFactorAuthClaim.js @@ -14,17 +14,19 @@ * under the License. */ Object.defineProperty(exports, "__esModule", { value: true }); -exports.MultiFactorAuthClaim = exports.MultiFactorAuthClaimClass = void 0; +exports.MultiFactorAuthClaimClass = void 0; const claims_1 = require("../session/claims"); const utils_1 = require("./utils"); /** * We include "Class" in the class name, because it makes it easier to import the right thing (the instance) instead of this. * */ class MultiFactorAuthClaimClass extends claims_1.SessionClaim { - constructor(key) { + constructor(stInstanceGetter, key) { super(key !== null && key !== void 0 ? key : "st-mfa"); + this.stInstanceGetter = stInstanceGetter; this.fetchValue = async (_userId, recipeUserId, tenantId, currentPayload, userContext) => { const mfaInfo = await (0, utils_1.updateAndGetMFARelatedInfoInSession)({ + stInstance: this.stInstanceGetter(), sessionRecipeUserId: recipeUserId, tenantId, accessTokenPayload: currentPayload, @@ -198,4 +200,3 @@ class MultiFactorAuthClaimClass extends claims_1.SessionClaim { } } exports.MultiFactorAuthClaimClass = MultiFactorAuthClaimClass; -exports.MultiFactorAuthClaim = new MultiFactorAuthClaimClass(); diff --git a/lib/build/recipe/multifactorauth/recipe.d.ts b/lib/build/recipe/multifactorauth/recipe.d.ts index b8661a8a7..3b8c699ec 100644 --- a/lib/build/recipe/multifactorauth/recipe.d.ts +++ b/lib/build/recipe/multifactorauth/recipe.d.ts @@ -1,9 +1,10 @@ // @ts-nocheck -import { BaseRequest, BaseResponse } from "../../framework"; +import type { BaseRequest, BaseResponse } from "../../framework"; import NormalisedURLPath from "../../normalisedURLPath"; import RecipeModule from "../../recipeModule"; import STError from "../../error"; import { APIHandled, HTTPMethod, NormalisedAppinfo, RecipeListFunction, UserContext } from "../../types"; +import { MultiFactorAuthClaimClass } from "./multiFactorAuthClaim"; import { APIInterface, GetAllAvailableSecondaryFactorIdsFromOtherRecipesFunc, @@ -16,10 +17,12 @@ import { } from "./types"; import { User } from "../../user"; import RecipeUserId from "../../recipeUserId"; -import { Querier } from "../../querier"; import { TenantConfig } from "../multitenancy/types"; +import type SuperTokens from "../../supertokens"; +import { SessionContainerInterface } from "../session/types"; export default class Recipe extends RecipeModule { private static instance; + multiFactorAuthClaim: MultiFactorAuthClaimClass; static RECIPE_ID: "multifactorauth"; getFactorsSetupForUserFromOtherRecipesFuncs: GetFactorsSetupForUserFromOtherRecipesFunc[]; getAllAvailableSecondaryFactorIdsFromOtherRecipesFuncs: GetAllAvailableSecondaryFactorIdsFromOtherRecipesFunc[]; @@ -30,8 +33,13 @@ export default class Recipe extends RecipeModule { recipeInterfaceImpl: RecipeInterface; apiImpl: APIInterface; isInServerlessEnv: boolean; - querier: Querier; - constructor(recipeId: string, appInfo: NormalisedAppinfo, isInServerlessEnv: boolean, config?: TypeInput); + constructor( + stInstance: SuperTokens, + recipeId: string, + appInfo: NormalisedAppinfo, + isInServerlessEnv: boolean, + config?: TypeInput + ); static getInstanceOrThrowError(): Recipe; static getInstance(): Recipe | undefined; static init(config?: TypeInput): RecipeListFunction; @@ -78,4 +86,9 @@ export default class Recipe extends RecipeModule { | { status: "UNKNOWN_SESSION_RECIPE_USER_ID"; }; + assertAllowedToSetupFactorElseThrowInvalidClaimError( + session: SessionContainerInterface, + factorId: string, + userContext: UserContext + ): Promise; } diff --git a/lib/build/recipe/multifactorauth/recipe.js b/lib/build/recipe/multifactorauth/recipe.js index fd0f5d4a1..8ea684db3 100644 --- a/lib/build/recipe/multifactorauth/recipe.js +++ b/lib/build/recipe/multifactorauth/recipe.js @@ -29,16 +29,13 @@ const constants_1 = require("./constants"); const multiFactorAuthClaim_1 = require("./multiFactorAuthClaim"); const utils_1 = require("./utils"); const resyncSessionAndFetchMFAInfo_1 = __importDefault(require("./api/resyncSessionAndFetchMFAInfo")); -const recipe_1 = __importDefault(require("../session/recipe")); const postSuperTokensInitCallbacks_1 = require("../../postSuperTokensInitCallbacks"); -const recipe_2 = __importDefault(require("../multitenancy/recipe")); -const querier_1 = require("../../querier"); const utils_2 = require("../../utils"); const plugins_1 = require("../../plugins"); class Recipe extends recipeModule_1.default { - constructor(recipeId, appInfo, isInServerlessEnv, config) { + constructor(stInstance, recipeId, appInfo, isInServerlessEnv, config) { var _a; - super(recipeId, appInfo); + super(stInstance, recipeId, appInfo); this.getFactorsSetupForUserFromOtherRecipesFuncs = []; this.getAllAvailableSecondaryFactorIdsFromOtherRecipesFuncs = []; this.getEmailsForFactorFromOtherRecipesFunc = []; @@ -68,7 +65,12 @@ class Recipe extends recipeModule_1.default { res, }; if (id === constants_1.RESYNC_SESSION_AND_FETCH_MFA_INFO) { - return await (0, resyncSessionAndFetchMFAInfo_1.default)(this.apiImpl, options, userContext); + return await (0, resyncSessionAndFetchMFAInfo_1.default)( + this.stInstance, + this.apiImpl, + options, + userContext + ); } throw new Error("should never come here"); }; @@ -145,8 +147,9 @@ class Recipe extends recipeModule_1.default { }; this.config = (0, utils_1.validateAndNormaliseUserInput)(config); this.isInServerlessEnv = isInServerlessEnv; + this.multiFactorAuthClaim = new multiFactorAuthClaim_1.MultiFactorAuthClaimClass(() => stInstance); { - let originalImpl = (0, recipeImplementation_1.default)(this); + let originalImpl = (0, recipeImplementation_1.default)(stInstance, this); let builder = new supertokens_js_override_1.default(originalImpl); this.recipeInterfaceImpl = builder.override(this.config.override.functions).build(); if ( @@ -158,24 +161,25 @@ class Recipe extends recipeModule_1.default { } } { - let builder = new supertokens_js_override_1.default((0, implementation_1.default)()); + let builder = new supertokens_js_override_1.default( + (0, implementation_1.default)(this.stInstance, this.multiFactorAuthClaim) + ); this.apiImpl = builder.override(this.config.override.apis).build(); } postSuperTokensInitCallbacks_1.PostSuperTokensInitCallbacks.addPostInitCallback(() => { - const mtRecipe = recipe_2.default.getInstance(); + const mtRecipe = stInstance.getRecipeInstance("multitenancy"); if (mtRecipe !== undefined) { mtRecipe.staticFirstFactors = this.config.firstFactors; } // We don't add MultiFactorAuthClaim as a global claim because the values are populated // on factor setup / completion any way (in the sign in / up APIs). // SessionRecipe.getInstanceOrThrowError().addClaimFromOtherRecipe(MultiFactorAuthClaim); - recipe_1.default - .getInstanceOrThrowError() + stInstance + .getRecipeInstanceOrThrow("session") .addClaimValidatorFromOtherRecipe( - multiFactorAuthClaim_1.MultiFactorAuthClaim.validators.hasCompletedMFARequirementsForAuth() + this.multiFactorAuthClaim.validators.hasCompletedMFARequirementsForAuth() ); }); - this.querier = querier_1.Querier.getNewInstanceOrThrowError(recipeId); } static getInstanceOrThrowError() { if (Recipe.instance !== undefined) { @@ -187,9 +191,10 @@ class Recipe extends recipeModule_1.default { return Recipe.instance; } static init(config) { - return (appInfo, isInServerlessEnv, plugins) => { + return (stInstance, appInfo, isInServerlessEnv, plugins) => { if (Recipe.instance === undefined) { Recipe.instance = new Recipe( + stInstance, Recipe.RECIPE_ID, appInfo, isInServerlessEnv, @@ -213,6 +218,34 @@ class Recipe extends recipeModule_1.default { } Recipe.instance = undefined; } + async assertAllowedToSetupFactorElseThrowInvalidClaimError(session, factorId, userContext) { + const user = await this.stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: session.getUserId(), userContext }); + if (!user) { + throw new Error("Unknown user id"); + } + const mfaInfo = await (0, utils_1.updateAndGetMFARelatedInfoInSession)({ + stInstance: this.stInstance, + session, + userContext, + }); + const factorsSetUpForUser = await this.recipeInterfaceImpl.getFactorsSetupForUser({ + user, + userContext, + }); + await this.recipeInterfaceImpl.assertAllowedToSetupFactorElseThrowInvalidClaimError({ + session, + factorId, + get factorsSetUpForUser() { + return Promise.resolve(factorsSetUpForUser); + }, + get mfaRequirementsForAuth() { + return Promise.resolve(mfaInfo.mfaRequirementsForAuth); + }, + userContext, + }); + } } Recipe.instance = undefined; Recipe.RECIPE_ID = "multifactorauth"; diff --git a/lib/build/recipe/multifactorauth/recipeImplementation.d.ts b/lib/build/recipe/multifactorauth/recipeImplementation.d.ts index fe6d93f74..eed2f1dc7 100644 --- a/lib/build/recipe/multifactorauth/recipeImplementation.d.ts +++ b/lib/build/recipe/multifactorauth/recipeImplementation.d.ts @@ -1,4 +1,8 @@ // @ts-nocheck import { RecipeInterface } from "./"; import type MultiFactorAuthRecipe from "./recipe"; -export default function getRecipeInterface(recipeInstance: MultiFactorAuthRecipe): RecipeInterface; +import type SuperTokens from "../../supertokens"; +export default function getRecipeInterface( + stInstance: SuperTokens, + recipeInstance: MultiFactorAuthRecipe +): RecipeInterface; diff --git a/lib/build/recipe/multifactorauth/recipeImplementation.js b/lib/build/recipe/multifactorauth/recipeImplementation.js index dd6ffe571..65e181acb 100644 --- a/lib/build/recipe/multifactorauth/recipeImplementation.js +++ b/lib/build/recipe/multifactorauth/recipeImplementation.js @@ -21,10 +21,9 @@ var __importDefault = Object.defineProperty(exports, "__esModule", { value: true }); exports.default = getRecipeInterface; const usermetadata_1 = __importDefault(require("../usermetadata")); -const multiFactorAuthClaim_1 = require("./multiFactorAuthClaim"); const logger_1 = require("../../logger"); const utils_1 = require("./utils"); -function getRecipeInterface(recipeInstance) { +function getRecipeInterface(stInstance, recipeInstance) { return { getFactorsSetupForUser: async function ({ user, userContext }) { // factors setup for user are provided by each of the initialized recipes @@ -72,14 +71,14 @@ function getRecipeInterface(recipeInstance) { // We allow when the next set of unsatisfied factors only contains factors that are not setup for the user // because the user will not be able to complete the MFA requirements for auth otherwise. const validator = { - id: multiFactorAuthClaim_1.MultiFactorAuthClaim.key, - claim: multiFactorAuthClaim_1.MultiFactorAuthClaim, + id: recipeInstance.multiFactorAuthClaim.key, + claim: recipeInstance.multiFactorAuthClaim, shouldRefetch: (payload) => { - const value = multiFactorAuthClaim_1.MultiFactorAuthClaim.getValueFromPayload(payload); + const value = recipeInstance.multiFactorAuthClaim.getValueFromPayload(payload); return value === undefined; }, validate: async (payload) => { - const claimVal = multiFactorAuthClaim_1.MultiFactorAuthClaim.getValueFromPayload(payload); + const claimVal = recipeInstance.multiFactorAuthClaim.getValueFromPayload(payload); if (!claimVal) { throw new Error("should never happen"); } @@ -89,11 +88,10 @@ function getRecipeInterface(recipeInstance) { ); return { isValid: true }; } - const setOfUnsatisfiedFactors = - multiFactorAuthClaim_1.MultiFactorAuthClaim.getNextSetOfUnsatisfiedFactors( - claimVal.c, - await input.mfaRequirementsForAuth - ); + const setOfUnsatisfiedFactors = recipeInstance.multiFactorAuthClaim.getNextSetOfUnsatisfiedFactors( + claimVal.c, + await input.mfaRequirementsForAuth + ); const factorsSetUpForUserRes = await input.factorsSetUpForUser; if (setOfUnsatisfiedFactors.factorIds.some((id) => factorsSetUpForUserRes.includes(id))) { (0, logger_1.logDebugMessage)( @@ -143,6 +141,7 @@ function getRecipeInterface(recipeInstance) { }, markFactorAsCompleteInSession: async function ({ session, factorId, userContext }) { await (0, utils_1.updateAndGetMFARelatedInfoInSession)({ + stInstance: stInstance, session, updatedFactorId: factorId, userContext, diff --git a/lib/build/recipe/multifactorauth/types.d.ts b/lib/build/recipe/multifactorauth/types.d.ts index f35ef7e3a..846a7b2af 100644 --- a/lib/build/recipe/multifactorauth/types.d.ts +++ b/lib/build/recipe/multifactorauth/types.d.ts @@ -1,5 +1,5 @@ // @ts-nocheck -import { BaseRequest, BaseResponse } from "../../framework"; +import type { BaseRequest, BaseResponse } from "../../framework"; import OverrideableBuilder from "supertokens-js-override"; import { GeneralErrorResponse, JSONObject, UserContext } from "../../types"; import { User } from "../../user"; diff --git a/lib/build/recipe/multifactorauth/utils.d.ts b/lib/build/recipe/multifactorauth/utils.d.ts index 97f09f4e9..7e1c8c3ce 100644 --- a/lib/build/recipe/multifactorauth/utils.d.ts +++ b/lib/build/recipe/multifactorauth/utils.d.ts @@ -3,6 +3,7 @@ import { TypeInput, TypeNormalisedInput, MFAClaimValue, MFARequirementList } fro import { UserContext } from "../../types"; import { SessionContainerInterface } from "../session/types"; import { RecipeUserId } from "../.."; +import type SuperTokens from "../../supertokens"; export declare function validateAndNormaliseUserInput(config?: TypeInput): TypeNormalisedInput; export declare const updateAndGetMFARelatedInfoInSession: ( input: ( @@ -16,6 +17,7 @@ export declare const updateAndGetMFARelatedInfoInSession: ( } ) & { updatedFactorId?: string; + stInstance: SuperTokens; userContext: UserContext; } ) => Promise<{ diff --git a/lib/build/recipe/multifactorauth/utils.js b/lib/build/recipe/multifactorauth/utils.js index 9586be8fe..f133ca32d 100644 --- a/lib/build/recipe/multifactorauth/utils.js +++ b/lib/build/recipe/multifactorauth/utils.js @@ -21,11 +21,6 @@ var __importDefault = Object.defineProperty(exports, "__esModule", { value: true }); exports.updateAndGetMFARelatedInfoInSession = void 0; exports.validateAndNormaliseUserInput = validateAndNormaliseUserInput; -const multitenancy_1 = __importDefault(require("../multitenancy")); -const __1 = require("../.."); -const recipe_1 = __importDefault(require("./recipe")); -const multiFactorAuthClaim_1 = require("./multiFactorAuthClaim"); -const session_1 = __importDefault(require("../session")); const error_1 = __importDefault(require("../session/error")); const types_1 = require("./types"); const utils_1 = require("../multitenancy/utils"); @@ -66,7 +61,9 @@ const updateAndGetMFARelatedInfoInSession = async function (input) { sessionHandle = accessTokenPayload.sessionHandle; } let updatedClaimVal = false; - let mfaClaimValue = multiFactorAuthClaim_1.MultiFactorAuthClaim.getValueFromPayload(accessTokenPayload); + let mfaClaimValue = input.stInstance + .getRecipeInstanceOrThrow("multifactorauth") + .multiFactorAuthClaim.getValueFromPayload(accessTokenPayload); if (input.updatedFactorId) { if (mfaClaimValue === undefined) { updatedClaimVal = true; @@ -83,7 +80,9 @@ const updateAndGetMFARelatedInfoInSession = async function (input) { } if (mfaClaimValue === undefined) { // it should be fine to get the user multiple times since the caching will de-duplicate these requests - const sessionUser = await (0, __1.getUser)(sessionRecipeUserId.getAsString(), input.userContext); + const sessionUser = await input.stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: sessionRecipeUserId.getAsString(), userContext: input.userContext }); if (sessionUser === undefined) { throw new error_1.default({ type: error_1.default.UNAUTHORISED, @@ -92,7 +91,9 @@ const updateAndGetMFARelatedInfoInSession = async function (input) { } // This can happen with older session, because we did not add MFA claims previously. // We try to determine best possible factorId based on the session's recipe user id. - const sessionInfo = await session_1.default.getSessionInformation(sessionHandle, input.userContext); + const sessionInfo = await input.stInstance + .getRecipeInstanceOrThrow("session") + .recipeInterfaceImpl.getSessionInformation({ sessionHandle, userContext: input.userContext }); if (sessionInfo === undefined) { throw new error_1.default({ type: error_1.default.UNAUTHORISED, @@ -105,6 +106,7 @@ const updateAndGetMFARelatedInfoInSession = async function (input) { if (lM.recipeUserId.getAsString() === sessionRecipeUserId.getAsString()) { if (lM.recipeId === "emailpassword") { let validRes = await (0, utils_1.isValidFirstFactor)( + input.stInstance, tenantId, types_1.FactorIds.EMAILPASSWORD, input.userContext @@ -120,6 +122,7 @@ const updateAndGetMFARelatedInfoInSession = async function (input) { } } else if (lM.recipeId === "thirdparty") { let validRes = await (0, utils_1.isValidFirstFactor)( + input.stInstance, tenantId, types_1.FactorIds.THIRDPARTY, input.userContext @@ -144,7 +147,12 @@ const updateAndGetMFARelatedInfoInSession = async function (input) { factorsToCheck.push(types_1.FactorIds.OTP_PHONE); } for (const factorId of factorsToCheck) { - let validRes = await (0, utils_1.isValidFirstFactor)(tenantId, factorId, input.userContext); + let validRes = await (0, utils_1.isValidFirstFactor)( + input.stInstance, + tenantId, + factorId, + input.userContext + ); if (validRes.status === "TENANT_NOT_FOUND_ERROR") { throw new error_1.default({ type: error_1.default.UNAUTHORISED, @@ -181,19 +189,22 @@ const updateAndGetMFARelatedInfoInSession = async function (input) { if (userProm) { return userProm; } - userProm = (0, __1.getUser)(sessionRecipeUserId.getAsString(), input.userContext).then((sessionUser) => { - if (sessionUser === undefined) { - throw new error_1.default({ - type: error_1.default.UNAUTHORISED, - message: "Session user not found", - }); - } - return sessionUser; - }); + userProm = input.stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: sessionRecipeUserId.getAsString(), userContext: input.userContext }) + .then((sessionUser) => { + if (sessionUser === undefined) { + throw new error_1.default({ + type: error_1.default.UNAUTHORISED, + message: "Session user not found", + }); + } + return sessionUser; + }); return userProm; } - const mfaRequirementsForAuth = await recipe_1.default - .getInstanceOrThrowError() + const mfaRequirementsForAuth = await input.stInstance + .getRecipeInstanceOrThrow("multifactorauth") .recipeInterfaceImpl.getMFARequirementsForAuth({ accessTokenPayload, tenantId, @@ -202,10 +213,12 @@ const updateAndGetMFARelatedInfoInSession = async function (input) { }, get factorsSetUpForUser() { return userGetter().then((user) => - recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl.getFactorsSetupForUser({ - user, - userContext: input.userContext, - }) + input.stInstance + .getRecipeInstanceOrThrow("multifactorauth") + .recipeInterfaceImpl.getFactorsSetupForUser({ + user, + userContext: input.userContext, + }) ); }, get requiredSecondaryFactorsForUser() { @@ -216,8 +229,8 @@ const updateAndGetMFARelatedInfoInSession = async function (input) { message: "Session user not found", }); } - return recipe_1.default - .getInstanceOrThrowError() + return input.stInstance + .getRecipeInstanceOrThrow("multifactorauth") .recipeInterfaceImpl.getRequiredSecondaryFactorsForUser({ userId: sessionUser.id, userContext: input.userContext, @@ -225,32 +238,35 @@ const updateAndGetMFARelatedInfoInSession = async function (input) { }); }, get requiredSecondaryFactorsForTenant() { - return multitenancy_1.default.getTenant(tenantId, input.userContext).then((tenantInfo) => { - var _a; - if (tenantInfo === undefined) { - throw new error_1.default({ - type: error_1.default.UNAUTHORISED, - message: "Tenant not found", - }); - } - return (_a = tenantInfo.requiredSecondaryFactors) !== null && _a !== void 0 ? _a : []; - }); + return input.stInstance + .getRecipeInstanceOrThrow("multitenancy") + .recipeInterfaceImpl.getTenant({ tenantId, userContext: input.userContext }) + .then((tenantInfo) => { + var _a; + if (tenantInfo === undefined) { + throw new error_1.default({ + type: error_1.default.UNAUTHORISED, + message: "Tenant not found", + }); + } + return (_a = tenantInfo.requiredSecondaryFactors) !== null && _a !== void 0 ? _a : []; + }); }, completedFactors, userContext: input.userContext, }); const areAuthReqsComplete = - multiFactorAuthClaim_1.MultiFactorAuthClaim.getNextSetOfUnsatisfiedFactors( - completedFactors, - mfaRequirementsForAuth - ).factorIds.length === 0; + input.stInstance + .getRecipeInstanceOrThrow("multifactorauth") + .multiFactorAuthClaim.getNextSetOfUnsatisfiedFactors(completedFactors, mfaRequirementsForAuth).factorIds + .length === 0; if (mfaClaimValue.v !== areAuthReqsComplete) { updatedClaimVal = true; mfaClaimValue.v = areAuthReqsComplete; } if ("session" in input && updatedClaimVal) { await input.session.setClaimValue( - multiFactorAuthClaim_1.MultiFactorAuthClaim, + input.stInstance.getRecipeInstanceOrThrow("multifactorauth").multiFactorAuthClaim, mfaClaimValue, input.userContext ); diff --git a/lib/build/recipe/multitenancy/allowedDomainsClaim.d.ts b/lib/build/recipe/multitenancy/allowedDomainsClaim.d.ts index 4edd418db..89ec78f16 100644 --- a/lib/build/recipe/multitenancy/allowedDomainsClaim.d.ts +++ b/lib/build/recipe/multitenancy/allowedDomainsClaim.d.ts @@ -1,9 +1,9 @@ // @ts-nocheck import { PrimitiveArrayClaim } from "../session/claims"; +import type Recipe from "./recipe"; /** * We include "Class" in the class name, because it makes it easier to import the right thing (the instance) instead of this. * */ export declare class AllowedDomainsClaimClass extends PrimitiveArrayClaim { - constructor(); + constructor(getRecipe: () => Recipe); } -export declare const AllowedDomainsClaim: AllowedDomainsClaimClass; diff --git a/lib/build/recipe/multitenancy/allowedDomainsClaim.js b/lib/build/recipe/multitenancy/allowedDomainsClaim.js index 582ea517f..a7221f4aa 100644 --- a/lib/build/recipe/multitenancy/allowedDomainsClaim.js +++ b/lib/build/recipe/multitenancy/allowedDomainsClaim.js @@ -1,29 +1,22 @@ "use strict"; -var __importDefault = - (this && this.__importDefault) || - function (mod) { - return mod && mod.__esModule ? mod : { default: mod }; - }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.AllowedDomainsClaim = exports.AllowedDomainsClaimClass = void 0; +exports.AllowedDomainsClaimClass = void 0; const claims_1 = require("../session/claims"); -const recipe_1 = __importDefault(require("./recipe")); /** * We include "Class" in the class name, because it makes it easier to import the right thing (the instance) instead of this. * */ class AllowedDomainsClaimClass extends claims_1.PrimitiveArrayClaim { - constructor() { + constructor(getRecipe) { super({ key: "st-t-dmns", async fetchValue(_userId, _recipeUserId, tenantId, _currentPayload, userContext) { - const recipe = recipe_1.default.getInstanceOrThrowError(); - if (recipe.getAllowedDomainsForTenantId === undefined) { + let getAllowedDomainsForTenantId = getRecipe().getAllowedDomainsForTenantId; + if (getAllowedDomainsForTenantId === undefined) { return undefined; // User did not provide a function to get allowed domains, but is using a validator. So we don't allow any domains by default } - return await recipe.getAllowedDomainsForTenantId(tenantId, userContext); + return await getAllowedDomainsForTenantId(tenantId, userContext); }, }); } } exports.AllowedDomainsClaimClass = AllowedDomainsClaimClass; -exports.AllowedDomainsClaim = new AllowedDomainsClaimClass(); diff --git a/lib/build/recipe/multitenancy/api/implementation.d.ts b/lib/build/recipe/multitenancy/api/implementation.d.ts index dd40e7025..d5395c7aa 100644 --- a/lib/build/recipe/multitenancy/api/implementation.d.ts +++ b/lib/build/recipe/multitenancy/api/implementation.d.ts @@ -1,3 +1,4 @@ // @ts-nocheck import { APIInterface } from "../"; -export default function getAPIInterface(): APIInterface; +import type SuperTokens from "../../../supertokens"; +export default function getAPIInterface(stInstance: SuperTokens): APIInterface; diff --git a/lib/build/recipe/multitenancy/api/implementation.js b/lib/build/recipe/multitenancy/api/implementation.js index 60c609ae0..ab8e8856c 100644 --- a/lib/build/recipe/multitenancy/api/implementation.js +++ b/lib/build/recipe/multitenancy/api/implementation.js @@ -4,7 +4,7 @@ exports.default = getAPIInterface; const utils_1 = require("../../multitenancy/utils"); const configUtils_1 = require("../../thirdparty/providers/configUtils"); const constants_1 = require("../constants"); -function getAPIInterface() { +function getAPIInterface(stInstance) { return { loginMethodsGET: async function ({ tenantId, clientType, options, userContext }) { const tenantConfigRes = await options.recipeImplementation.getTenant({ @@ -60,7 +60,7 @@ function getAPIInterface() { // enabled recipes in all cases irrespective of whether they are using MFA or not let validFirstFactors = []; for (const factorId of firstFactors) { - let validRes = await (0, utils_1.isValidFirstFactor)(tenantId, factorId, userContext); + let validRes = await (0, utils_1.isValidFirstFactor)(stInstance, tenantId, factorId, userContext); if (validRes.status === "OK") { validFirstFactors.push(factorId); } diff --git a/lib/build/recipe/multitenancy/index.d.ts b/lib/build/recipe/multitenancy/index.d.ts index d592eb4be..f22e5afb4 100644 --- a/lib/build/recipe/multitenancy/index.d.ts +++ b/lib/build/recipe/multitenancy/index.d.ts @@ -2,10 +2,11 @@ import Recipe from "./recipe"; import { RecipeInterface, APIOptions, APIInterface, TenantConfig } from "./types"; import { ProviderConfig } from "../thirdparty/types"; -import { AllowedDomainsClaim } from "./allowedDomainsClaim"; +import { AllowedDomainsClaimClass } from "./allowedDomainsClaim"; import RecipeUserId from "../../recipeUserId"; export default class Wrapper { static init: typeof Recipe.init; + static AllowedDomainsClaim: AllowedDomainsClaimClass; static createOrUpdateTenant( tenantId: string, config?: { @@ -98,5 +99,5 @@ export declare let createOrUpdateThirdPartyConfig: typeof Wrapper.createOrUpdate export declare let deleteThirdPartyConfig: typeof Wrapper.deleteThirdPartyConfig; export declare let associateUserToTenant: typeof Wrapper.associateUserToTenant; export declare let disassociateUserFromTenant: typeof Wrapper.disassociateUserFromTenant; -export { AllowedDomainsClaim }; +export declare const AllowedDomainsClaim: AllowedDomainsClaimClass; export type { RecipeInterface, APIOptions, APIInterface }; diff --git a/lib/build/recipe/multitenancy/index.js b/lib/build/recipe/multitenancy/index.js index 12ce7bd31..6c24d27bb 100644 --- a/lib/build/recipe/multitenancy/index.js +++ b/lib/build/recipe/multitenancy/index.js @@ -32,12 +32,6 @@ exports.AllowedDomainsClaim = void 0; const recipe_1 = __importDefault(require("./recipe")); const allowedDomainsClaim_1 = require("./allowedDomainsClaim"); -Object.defineProperty(exports, "AllowedDomainsClaim", { - enumerable: true, - get: function () { - return allowedDomainsClaim_1.AllowedDomainsClaim; - }, -}); const utils_1 = require("../../utils"); class Wrapper { static async createOrUpdateTenant(tenantId, config, userContext) { @@ -103,6 +97,9 @@ class Wrapper { } } Wrapper.init = recipe_1.default.init; +Wrapper.AllowedDomainsClaim = new allowedDomainsClaim_1.AllowedDomainsClaimClass(() => + recipe_1.default.getInstanceOrThrowError() +); exports.default = Wrapper; exports.init = Wrapper.init; exports.createOrUpdateTenant = Wrapper.createOrUpdateTenant; @@ -113,3 +110,4 @@ exports.createOrUpdateThirdPartyConfig = Wrapper.createOrUpdateThirdPartyConfig; exports.deleteThirdPartyConfig = Wrapper.deleteThirdPartyConfig; exports.associateUserToTenant = Wrapper.associateUserToTenant; exports.disassociateUserFromTenant = Wrapper.disassociateUserFromTenant; +exports.AllowedDomainsClaim = Wrapper.AllowedDomainsClaim; diff --git a/lib/build/recipe/multitenancy/recipe.d.ts b/lib/build/recipe/multitenancy/recipe.d.ts index 0de41b877..43de92a49 100644 --- a/lib/build/recipe/multitenancy/recipe.d.ts +++ b/lib/build/recipe/multitenancy/recipe.d.ts @@ -1,13 +1,16 @@ // @ts-nocheck -import { BaseRequest, BaseResponse } from "../../framework"; +import type { BaseRequest, BaseResponse } from "../../framework"; import NormalisedURLPath from "../../normalisedURLPath"; import RecipeModule from "../../recipeModule"; import STError from "../../error"; import { APIHandled, HTTPMethod, NormalisedAppinfo, RecipeListFunction, UserContext } from "../../types"; import { ProviderInput } from "../thirdparty/types"; import { APIInterface, RecipeInterface, TypeInput, TypeNormalisedInput } from "./types"; +import type SuperTokens from "../../supertokens"; +import { AllowedDomainsClaimClass } from "./allowedDomainsClaim"; export default class Recipe extends RecipeModule { private static instance; + allowedDomainsClaim: AllowedDomainsClaimClass; static RECIPE_ID: "multitenancy"; config: TypeNormalisedInput; recipeInterfaceImpl: RecipeInterface; @@ -17,7 +20,13 @@ export default class Recipe extends RecipeModule { allAvailableFirstFactors: string[]; staticFirstFactors: string[] | undefined; getAllowedDomainsForTenantId?: (tenantId: string, userContext: UserContext) => Promise; - constructor(recipeId: string, appInfo: NormalisedAppinfo, isInServerlessEnv: boolean, config?: TypeInput); + constructor( + stInstance: SuperTokens, + recipeId: string, + appInfo: NormalisedAppinfo, + isInServerlessEnv: boolean, + config?: TypeInput + ); static getInstanceOrThrowError(): Recipe; static getInstance(): Recipe | undefined; static init(config?: TypeInput): RecipeListFunction; diff --git a/lib/build/recipe/multitenancy/recipe.js b/lib/build/recipe/multitenancy/recipe.js index d0b172d7c..b7a795041 100644 --- a/lib/build/recipe/multitenancy/recipe.js +++ b/lib/build/recipe/multitenancy/recipe.js @@ -22,21 +22,19 @@ Object.defineProperty(exports, "__esModule", { value: true }); const supertokens_js_override_1 = __importDefault(require("supertokens-js-override")); const normalisedURLPath_1 = __importDefault(require("../../normalisedURLPath")); const postSuperTokensInitCallbacks_1 = require("../../postSuperTokensInitCallbacks"); -const querier_1 = require("../../querier"); const recipeModule_1 = __importDefault(require("../../recipeModule")); const error_1 = __importDefault(require("../../error")); const recipeImplementation_1 = __importDefault(require("./recipeImplementation")); const implementation_1 = __importDefault(require("./api/implementation")); -const recipe_1 = __importDefault(require("../session/recipe")); const constants_1 = require("./constants"); -const allowedDomainsClaim_1 = require("./allowedDomainsClaim"); const utils_1 = require("./utils"); const loginMethods_1 = __importDefault(require("./api/loginMethods")); const utils_2 = require("../../utils"); const plugins_1 = require("../../plugins"); +const allowedDomainsClaim_1 = require("./allowedDomainsClaim"); class Recipe extends recipeModule_1.default { - constructor(recipeId, appInfo, isInServerlessEnv, config) { - super(recipeId, appInfo); + constructor(stInstance, recipeId, appInfo, isInServerlessEnv, config) { + super(stInstance, recipeId, appInfo); this.staticThirdPartyProviders = []; this.allAvailableFirstFactors = []; this.staticFirstFactors = undefined; @@ -79,14 +77,13 @@ class Recipe extends recipeModule_1.default { }; this.config = (0, utils_1.validateAndNormaliseUserInput)(config); this.isInServerlessEnv = isInServerlessEnv; + this.allowedDomainsClaim = new allowedDomainsClaim_1.AllowedDomainsClaimClass(() => this); { - let builder = new supertokens_js_override_1.default( - (0, recipeImplementation_1.default)(querier_1.Querier.getNewInstanceOrThrowError(recipeId)) - ); + let builder = new supertokens_js_override_1.default((0, recipeImplementation_1.default)(this.querier)); this.recipeInterfaceImpl = builder.override(this.config.override.functions).build(); } { - let builder = new supertokens_js_override_1.default((0, implementation_1.default)()); + let builder = new supertokens_js_override_1.default((0, implementation_1.default)(this.stInstance)); this.apiImpl = builder.override(this.config.override.apis).build(); } this.getAllowedDomainsForTenantId = this.config.getAllowedDomainsForTenantId; @@ -101,9 +98,10 @@ class Recipe extends recipeModule_1.default { return Recipe.instance; } static init(config) { - return (appInfo, isInServerlessEnv, plugins) => { + return (stInstance, appInfo, isInServerlessEnv, plugins) => { if (Recipe.instance === undefined) { Recipe.instance = new Recipe( + stInstance, Recipe.RECIPE_ID, appInfo, isInServerlessEnv, @@ -116,9 +114,9 @@ class Recipe extends recipeModule_1.default { if (Recipe.instance.getAllowedDomainsForTenantId !== undefined) { postSuperTokensInitCallbacks_1.PostSuperTokensInitCallbacks.addPostInitCallback(() => { try { - recipe_1.default - .getInstanceOrThrowError() - .addClaimFromOtherRecipe(allowedDomainsClaim_1.AllowedDomainsClaim); + stInstance + .getRecipeInstanceOrThrow("session") + .addClaimFromOtherRecipe(Recipe.instance.allowedDomainsClaim); } catch (_a) { // Skip adding claims if session recipe is not initialised } diff --git a/lib/build/recipe/multitenancy/types.d.ts b/lib/build/recipe/multitenancy/types.d.ts index 0daa5853c..1eabe90e7 100644 --- a/lib/build/recipe/multitenancy/types.d.ts +++ b/lib/build/recipe/multitenancy/types.d.ts @@ -1,5 +1,5 @@ // @ts-nocheck -import { BaseRequest, BaseResponse } from "../../framework"; +import type { BaseRequest, BaseResponse } from "../../framework"; import OverrideableBuilder from "supertokens-js-override"; import { ProviderConfig, ProviderInput } from "../thirdparty/types"; import { GeneralErrorResponse, UserContext } from "../../types"; diff --git a/lib/build/recipe/multitenancy/utils.d.ts b/lib/build/recipe/multitenancy/utils.d.ts index 3bc6e2abc..538d144e7 100644 --- a/lib/build/recipe/multitenancy/utils.d.ts +++ b/lib/build/recipe/multitenancy/utils.d.ts @@ -1,8 +1,10 @@ // @ts-nocheck import { TypeInput, TypeNormalisedInput, TenantConfig } from "./types"; import { UserContext } from "../../types"; +import type SuperTokens from "../../supertokens"; export declare function validateAndNormaliseUserInput(config?: TypeInput): TypeNormalisedInput; export declare const isValidFirstFactor: ( + stInstance: SuperTokens, tenantId: string, factorId: string, userContext: UserContext diff --git a/lib/build/recipe/multitenancy/utils.js b/lib/build/recipe/multitenancy/utils.js index 5bb70e415..0648d51c8 100644 --- a/lib/build/recipe/multitenancy/utils.js +++ b/lib/build/recipe/multitenancy/utils.js @@ -24,16 +24,10 @@ var __rest = } return t; }; -var __importDefault = - (this && this.__importDefault) || - function (mod) { - return mod && mod.__esModule ? mod : { default: mod }; - }; Object.defineProperty(exports, "__esModule", { value: true }); exports.isValidFirstFactor = void 0; exports.validateAndNormaliseUserInput = validateAndNormaliseUserInput; exports.isFactorConfiguredForTenant = isFactorConfiguredForTenant; -const recipe_1 = __importDefault(require("./recipe")); const logger_1 = require("../../logger"); const types_1 = require("../multifactorauth/types"); function validateAndNormaliseUserInput(config) { @@ -50,9 +44,9 @@ function validateAndNormaliseUserInput(config) { override, }; } -const isValidFirstFactor = async function (tenantId, factorId, userContext) { +const isValidFirstFactor = async function (stInstance, tenantId, factorId, userContext) { var _a; - const mtRecipe = recipe_1.default.getInstance(); + const mtRecipe = stInstance.getRecipeInstanceOrThrow("multitenancy"); if (mtRecipe === undefined) { throw new Error("Should never happen"); } diff --git a/lib/build/recipe/oauth2provider/api/auth.d.ts b/lib/build/recipe/oauth2provider/api/auth.d.ts index 059876918..b276ce8e0 100644 --- a/lib/build/recipe/oauth2provider/api/auth.d.ts +++ b/lib/build/recipe/oauth2provider/api/auth.d.ts @@ -1,7 +1,9 @@ // @ts-nocheck import { APIInterface, APIOptions } from ".."; import { UserContext } from "../../../types"; +import type SuperTokens from "../../../supertokens"; export default function authGET( + stInstance: SuperTokens, apiImplementation: APIInterface, options: APIOptions, userContext: UserContext diff --git a/lib/build/recipe/oauth2provider/api/auth.js b/lib/build/recipe/oauth2provider/api/auth.js index 1f45d2ae2..b29379b8b 100644 --- a/lib/build/recipe/oauth2provider/api/auth.js +++ b/lib/build/recipe/oauth2provider/api/auth.js @@ -22,9 +22,8 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.default = authGET; const utils_1 = require("../../../utils"); const set_cookie_parser_1 = __importDefault(require("set-cookie-parser")); -const session_1 = __importDefault(require("../../session")); const error_1 = __importDefault(require("../../../recipe/session/error")); -async function authGET(apiImplementation, options, userContext) { +async function authGET(stInstance, apiImplementation, options, userContext) { var _a; if (apiImplementation.authGET === undefined) { return false; @@ -34,7 +33,12 @@ async function authGET(apiImplementation, options, userContext) { const params = new URLSearchParams(splitURL[1]); let session, shouldTryRefresh; try { - session = await session_1.default.getSession(options.req, options.res, { sessionRequired: false }, userContext); + session = await stInstance.getRecipeInstanceOrThrow("session").getSession({ + req: options.req, + res: options.res, + options: { sessionRequired: false }, + userContext, + }); shouldTryRefresh = false; } catch (error) { session = undefined; @@ -50,7 +54,7 @@ async function authGET(apiImplementation, options, userContext) { options, params: Object.fromEntries(params.entries()), cookie: options.req.getHeaderValue("cookie"), - session, + session: session, shouldTryRefresh, userContext, }); diff --git a/lib/build/recipe/oauth2provider/api/endSession.d.ts b/lib/build/recipe/oauth2provider/api/endSession.d.ts index 1f454cbd0..cfac877d9 100644 --- a/lib/build/recipe/oauth2provider/api/endSession.d.ts +++ b/lib/build/recipe/oauth2provider/api/endSession.d.ts @@ -1,12 +1,15 @@ // @ts-nocheck import { APIInterface, APIOptions } from ".."; import { UserContext } from "../../../types"; +import type SuperTokens from "../../../supertokens"; export declare function endSessionGET( + stInstance: SuperTokens, apiImplementation: APIInterface, options: APIOptions, userContext: UserContext ): Promise; export declare function endSessionPOST( + stInstance: SuperTokens, apiImplementation: APIInterface, options: APIOptions, userContext: UserContext diff --git a/lib/build/recipe/oauth2provider/api/endSession.js b/lib/build/recipe/oauth2provider/api/endSession.js index a31e329d5..b6538eef0 100644 --- a/lib/build/recipe/oauth2provider/api/endSession.js +++ b/lib/build/recipe/oauth2provider/api/endSession.js @@ -22,10 +22,9 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.endSessionGET = endSessionGET; exports.endSessionPOST = endSessionPOST; const utils_1 = require("../../../utils"); -const session_1 = __importDefault(require("../../session")); const error_1 = __importDefault(require("../../../error")); const error_2 = __importDefault(require("../../../recipe/session/error")); -async function endSessionGET(apiImplementation, options, userContext) { +async function endSessionGET(stInstance, apiImplementation, options, userContext) { if (apiImplementation.endSessionGET === undefined) { return false; } @@ -33,27 +32,33 @@ async function endSessionGET(apiImplementation, options, userContext) { const splitURL = origURL.split("?"); const params = new URLSearchParams(splitURL[1]); return endSessionCommon( + stInstance, Object.fromEntries(params.entries()), apiImplementation.endSessionGET, options, userContext ); } -async function endSessionPOST(apiImplementation, options, userContext) { +async function endSessionPOST(stInstance, apiImplementation, options, userContext) { if (apiImplementation.endSessionPOST === undefined) { return false; } const params = await options.req.getBodyAsJSONOrFormData(); - return endSessionCommon(params, apiImplementation.endSessionPOST, options, userContext); + return endSessionCommon(stInstance, params, apiImplementation.endSessionPOST, options, userContext); } -async function endSessionCommon(params, apiImplementation, options, userContext) { +async function endSessionCommon(stInstance, params, apiImplementation, options, userContext) { var _a; if (apiImplementation === undefined) { return false; } let session, shouldTryRefresh; try { - session = await session_1.default.getSession(options.req, options.res, { sessionRequired: false }, userContext); + session = await stInstance.getRecipeInstanceOrThrow("session").getSession({ + req: options.req, + res: options.res, + options: { sessionRequired: false }, + userContext, + }); shouldTryRefresh = false; } catch (error) { // We can handle this as if the session is not present, because then we redirect to the frontend, diff --git a/lib/build/recipe/oauth2provider/api/implementation.d.ts b/lib/build/recipe/oauth2provider/api/implementation.d.ts index 0218549fa..409eec4a7 100644 --- a/lib/build/recipe/oauth2provider/api/implementation.d.ts +++ b/lib/build/recipe/oauth2provider/api/implementation.d.ts @@ -1,3 +1,4 @@ // @ts-nocheck +import type SuperTokens from "../../../supertokens"; import { APIInterface } from "../types"; -export default function getAPIImplementation(): APIInterface; +export default function getAPIImplementation(stInstance: SuperTokens): APIInterface; diff --git a/lib/build/recipe/oauth2provider/api/implementation.js b/lib/build/recipe/oauth2provider/api/implementation.js index 89de95c3d..19f158142 100644 --- a/lib/build/recipe/oauth2provider/api/implementation.js +++ b/lib/build/recipe/oauth2provider/api/implementation.js @@ -16,10 +16,11 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.default = getAPIImplementation; const utils_1 = require("./utils"); -function getAPIImplementation() { +function getAPIImplementation(stInstance) { return { loginGET: async ({ loginChallenge, options, session, shouldTryRefresh, userContext }) => { const response = await (0, utils_1.loginGET)({ + stInstance, recipeImplementation: options.recipeImplementation, loginChallenge, session, @@ -31,6 +32,7 @@ function getAPIImplementation() { return response; } const respAfterInternalRedirects = await (0, utils_1.handleLoginInternalRedirects)({ + stInstance, response, cookie: options.req.getHeaderValue("cookie"), recipeImplementation: options.recipeImplementation, @@ -57,6 +59,7 @@ function getAPIImplementation() { return response; } return (0, utils_1.handleLoginInternalRedirects)({ + stInstance, response, recipeImplementation: options.recipeImplementation, cookie, @@ -139,6 +142,7 @@ function getAPIImplementation() { return response; } return (0, utils_1.handleLogoutInternalRedirects)({ + stInstance, response, session, recipeImplementation: options.recipeImplementation, @@ -156,6 +160,7 @@ function getAPIImplementation() { return response; } return (0, utils_1.handleLogoutInternalRedirects)({ + stInstance, response, session, recipeImplementation: options.recipeImplementation, @@ -174,6 +179,7 @@ function getAPIImplementation() { return response; } const res = await (0, utils_1.handleLogoutInternalRedirects)({ + stInstance, response, recipeImplementation: options.recipeImplementation, userContext, diff --git a/lib/build/recipe/oauth2provider/api/login.d.ts b/lib/build/recipe/oauth2provider/api/login.d.ts index 6f4253cef..94736a92f 100644 --- a/lib/build/recipe/oauth2provider/api/login.d.ts +++ b/lib/build/recipe/oauth2provider/api/login.d.ts @@ -1,7 +1,9 @@ // @ts-nocheck import { APIInterface, APIOptions } from ".."; import { UserContext } from "../../../types"; +import type SuperTokens from "../../../supertokens"; export default function login( + stInstance: SuperTokens, apiImplementation: APIInterface, options: APIOptions, userContext: UserContext diff --git a/lib/build/recipe/oauth2provider/api/login.js b/lib/build/recipe/oauth2provider/api/login.js index f67decc1f..be83705dd 100644 --- a/lib/build/recipe/oauth2provider/api/login.js +++ b/lib/build/recipe/oauth2provider/api/login.js @@ -22,17 +22,21 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.default = login; const set_cookie_parser_1 = __importDefault(require("set-cookie-parser")); const utils_1 = require("../../../utils"); -const session_1 = __importDefault(require("../../session")); const error_1 = __importDefault(require("../../../error")); const error_2 = __importDefault(require("../../../recipe/session/error")); -async function login(apiImplementation, options, userContext) { +async function login(stInstance, apiImplementation, options, userContext) { var _a, _b; if (apiImplementation.loginGET === undefined) { return false; } let session, shouldTryRefresh; try { - session = await session_1.default.getSession(options.req, options.res, { sessionRequired: false }, userContext); + session = await stInstance.getRecipeInstanceOrThrow("session").getSession({ + req: options.req, + res: options.res, + options: { sessionRequired: false }, + userContext, + }); shouldTryRefresh = false; } catch (error) { // We can handle this as if the session is not present, because then we redirect to the frontend, diff --git a/lib/build/recipe/oauth2provider/api/logout.d.ts b/lib/build/recipe/oauth2provider/api/logout.d.ts index 339a73e77..1b5cf26cf 100644 --- a/lib/build/recipe/oauth2provider/api/logout.d.ts +++ b/lib/build/recipe/oauth2provider/api/logout.d.ts @@ -1,7 +1,9 @@ // @ts-nocheck import { APIInterface, APIOptions } from ".."; import { UserContext } from "../../../types"; +import type SuperTokens from "../../../supertokens"; export declare function logoutPOST( + stInstance: SuperTokens, apiImplementation: APIInterface, options: APIOptions, userContext: UserContext diff --git a/lib/build/recipe/oauth2provider/api/logout.js b/lib/build/recipe/oauth2provider/api/logout.js index a7fcc83ac..382da1896 100644 --- a/lib/build/recipe/oauth2provider/api/logout.js +++ b/lib/build/recipe/oauth2provider/api/logout.js @@ -21,16 +21,20 @@ var __importDefault = Object.defineProperty(exports, "__esModule", { value: true }); exports.logoutPOST = logoutPOST; const utils_1 = require("../../../utils"); -const session_1 = __importDefault(require("../../session")); const error_1 = __importDefault(require("../../../error")); -async function logoutPOST(apiImplementation, options, userContext) { +async function logoutPOST(stInstance, apiImplementation, options, userContext) { var _a; if (apiImplementation.logoutPOST === undefined) { return false; } let session; try { - session = await session_1.default.getSession(options.req, options.res, { sessionRequired: false }, userContext); + session = await stInstance.getRecipeInstanceOrThrow("session").getSession({ + req: options.req, + res: options.res, + options: { sessionRequired: false }, + userContext, + }); } catch (_b) { session = undefined; } diff --git a/lib/build/recipe/oauth2provider/api/userInfo.d.ts b/lib/build/recipe/oauth2provider/api/userInfo.d.ts index d0b8cdf4e..daa7376c4 100644 --- a/lib/build/recipe/oauth2provider/api/userInfo.d.ts +++ b/lib/build/recipe/oauth2provider/api/userInfo.d.ts @@ -1,7 +1,9 @@ // @ts-nocheck import { APIInterface, APIOptions } from ".."; import { UserContext } from "../../../types"; +import SuperTokens from "../../../supertokens"; export default function userInfoGET( + stInstance: SuperTokens, apiImplementation: APIInterface, tenantId: string, options: APIOptions, diff --git a/lib/build/recipe/oauth2provider/api/userInfo.js b/lib/build/recipe/oauth2provider/api/userInfo.js index acea3a256..76c713577 100644 --- a/lib/build/recipe/oauth2provider/api/userInfo.js +++ b/lib/build/recipe/oauth2provider/api/userInfo.js @@ -13,17 +13,10 @@ * License for the specific language governing permissions and limitations * under the License. */ -var __importDefault = - (this && this.__importDefault) || - function (mod) { - return mod && mod.__esModule ? mod : { default: mod }; - }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = userInfoGET; -const recipe_1 = __importDefault(require("../recipe")); const utils_1 = require("../../../utils"); -const __1 = require("../../.."); -async function userInfoGET(apiImplementation, tenantId, options, userContext) { +async function userInfoGET(stInstance, apiImplementation, tenantId, options, userContext) { if (apiImplementation.userInfoGET === undefined) { return false; } @@ -35,12 +28,10 @@ async function userInfoGET(apiImplementation, tenantId, options, userContext) { const accessToken = authHeader.replace(/^Bearer /, "").trim(); let accessTokenPayload; try { - const validateTokenResponse = await recipe_1.default - .getInstanceOrThrowError() - .recipeInterfaceImpl.validateOAuth2AccessToken({ - token: accessToken, - userContext, - }); + const validateTokenResponse = await options.recipeImplementation.validateOAuth2AccessToken({ + token: accessToken, + userContext, + }); accessTokenPayload = validateTokenResponse.payload; } catch (error) { options.res.setHeader("WWW-Authenticate", 'Bearer error="invalid_token"', false); @@ -60,7 +51,9 @@ async function userInfoGET(apiImplementation, tenantId, options, userContext) { return true; } const userId = accessTokenPayload.sub; - const user = await (0, __1.getUser)(userId, userContext); + const user = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId, userContext }); if (user === undefined) { options.res.setHeader("WWW-Authenticate", 'Bearer error="invalid_token"', false); options.res.setHeader("Access-Control-Expose-Headers", "WWW-Authenticate", true); diff --git a/lib/build/recipe/oauth2provider/api/utils.d.ts b/lib/build/recipe/oauth2provider/api/utils.d.ts index be94270dc..99d43aeea 100644 --- a/lib/build/recipe/oauth2provider/api/utils.d.ts +++ b/lib/build/recipe/oauth2provider/api/utils.d.ts @@ -1,8 +1,10 @@ // @ts-nocheck +import type SuperTokens from "../../../supertokens"; import { UserContext } from "../../../types"; import { SessionContainerInterface } from "../../session/types"; import { ErrorOAuth2, RecipeInterface } from "../types"; export declare function loginGET({ + stInstance, recipeImplementation, loginChallenge, shouldTryRefresh, @@ -11,6 +13,7 @@ export declare function loginGET({ isDirectCall, userContext, }: { + stInstance: SuperTokens; recipeImplementation: RecipeInterface; loginChallenge: string; session?: SessionContainerInterface; @@ -32,6 +35,7 @@ export declare function loginGET({ } >; export declare function handleLoginInternalRedirects({ + stInstance, response, recipeImplementation, session, @@ -39,6 +43,7 @@ export declare function handleLoginInternalRedirects({ cookie, userContext, }: { + stInstance: SuperTokens; response: { redirectTo: string; cookies?: string[]; @@ -56,11 +61,13 @@ export declare function handleLoginInternalRedirects({ | ErrorOAuth2 >; export declare function handleLogoutInternalRedirects({ + stInstance, response, recipeImplementation, session, userContext, }: { + stInstance: SuperTokens; response: { redirectTo: string; }; diff --git a/lib/build/recipe/oauth2provider/api/utils.js b/lib/build/recipe/oauth2provider/api/utils.js index c09d53f99..2aef4ce87 100644 --- a/lib/build/recipe/oauth2provider/api/utils.js +++ b/lib/build/recipe/oauth2provider/api/utils.js @@ -8,14 +8,13 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.loginGET = loginGET; exports.handleLoginInternalRedirects = handleLoginInternalRedirects; exports.handleLogoutInternalRedirects = handleLogoutInternalRedirects; -const supertokens_1 = __importDefault(require("../../../supertokens")); const constants_1 = require("../../multitenancy/constants"); -const session_1 = require("../../session"); const constants_2 = require("../constants"); const set_cookie_parser_1 = __importDefault(require("set-cookie-parser")); // API implementation for the loginGET function. // Extracted for use in both apiImplementation and handleInternalRedirects. async function loginGET({ + stInstance, recipeImplementation, loginChallenge, shouldTryRefresh, @@ -34,9 +33,10 @@ async function loginGET({ } const sessionInfo = session !== undefined - ? await (0, session_1.getSessionInformation)( - session === null || session === void 0 ? void 0 : session.getHandle() - ) + ? await stInstance.getRecipeInstanceOrThrow("session").recipeInterfaceImpl.getSessionInformation({ + sessionHandle: session === null || session === void 0 ? void 0 : session.getHandle(), + userContext, + }) : undefined; if (!sessionInfo) { session = undefined; @@ -190,13 +190,13 @@ function mergeSetCookieHeaders(setCookie1, setCookie2) { } return [...setCookie1, ...setCookie2]; } -function isLoginInternalRedirect(redirectTo) { - const { apiDomain, apiBasePath } = supertokens_1.default.getInstanceOrThrowError().appInfo; +function isLoginInternalRedirect(stInstance, redirectTo) { + const { apiDomain, apiBasePath } = stInstance.appInfo; const basePath = `${apiDomain.getAsStringDangerous()}${apiBasePath.getAsStringDangerous()}`; return [constants_2.LOGIN_PATH, constants_2.AUTH_PATH].some((path) => redirectTo.startsWith(`${basePath}${path}`)); } -function isLogoutInternalRedirect(redirectTo) { - const { apiDomain, apiBasePath } = supertokens_1.default.getInstanceOrThrowError().appInfo; +function isLogoutInternalRedirect(stInstance, redirectTo) { + const { apiDomain, apiBasePath } = stInstance.appInfo; const basePath = `${apiDomain.getAsStringDangerous()}${apiBasePath.getAsStringDangerous()}`; return redirectTo.startsWith(`${basePath}${constants_2.END_SESSION_PATH}`); } @@ -204,6 +204,7 @@ function isLogoutInternalRedirect(redirectTo) { // If an internal redirect is identified, it's handled directly by this function. // Currently, we only need to handle redirects to /oauth/login and /oauth/auth endpoints in the login flow. async function handleLoginInternalRedirects({ + stInstance, response, recipeImplementation, session, @@ -212,14 +213,14 @@ async function handleLoginInternalRedirects({ userContext, }) { var _a; - if (!isLoginInternalRedirect(response.redirectTo)) { + if (!isLoginInternalRedirect(stInstance, response.redirectTo)) { return response; } // Typically, there are no more than 2 internal redirects per API call but we are allowing upto 10. // This safety net prevents infinite redirect loops in case there are more redirects than expected. const maxRedirects = 10; let redirectCount = 0; - while (redirectCount < maxRedirects && isLoginInternalRedirect(response.redirectTo)) { + while (redirectCount < maxRedirects && isLoginInternalRedirect(stInstance, response.redirectTo)) { cookie = getMergedCookies({ origCookies: cookie, newCookies: response.cookies }); const queryString = response.redirectTo.split("?")[1]; const params = new URLSearchParams(queryString); @@ -230,6 +231,7 @@ async function handleLoginInternalRedirects({ throw new Error(`Expected loginChallenge in ${response.redirectTo}`); } const loginRes = await loginGET({ + stInstance, recipeImplementation, loginChallenge, session, @@ -269,15 +271,15 @@ async function handleLoginInternalRedirects({ // In the OAuth2 flow, we do several internal redirects. These redirects don't require a frontend-to-api-server round trip. // If an internal redirect is identified, it's handled directly by this function. // Currently, we only need to handle redirects to /oauth/end_session endpoint in the logout flow. -async function handleLogoutInternalRedirects({ response, recipeImplementation, session, userContext }) { - if (!isLogoutInternalRedirect(response.redirectTo)) { +async function handleLogoutInternalRedirects({ stInstance, response, recipeImplementation, session, userContext }) { + if (!isLogoutInternalRedirect(stInstance, response.redirectTo)) { return response; } // Typically, there are no more than 2 internal redirects per API call but we are allowing upto 10. // This safety net prevents infinite redirect loops in case there are more redirects than expected. const maxRedirects = 10; let redirectCount = 0; - while (redirectCount < maxRedirects && isLogoutInternalRedirect(response.redirectTo)) { + while (redirectCount < maxRedirects && isLogoutInternalRedirect(stInstance, response.redirectTo)) { const queryString = response.redirectTo.split("?")[1]; const params = new URLSearchParams(queryString); if (response.redirectTo.includes(constants_2.END_SESSION_PATH)) { diff --git a/lib/build/recipe/oauth2provider/recipe.d.ts b/lib/build/recipe/oauth2provider/recipe.d.ts index 6afd8ddcc..9b03831a9 100644 --- a/lib/build/recipe/oauth2provider/recipe.d.ts +++ b/lib/build/recipe/oauth2provider/recipe.d.ts @@ -14,6 +14,7 @@ import { UserInfoBuilderFunction, } from "./types"; import { User } from "../../user"; +import type SuperTokens from "../../supertokens"; export default class Recipe extends RecipeModule { static RECIPE_ID: "oauth2provider"; private static instance; @@ -24,7 +25,13 @@ export default class Recipe extends RecipeModule { recipeInterfaceImpl: RecipeInterface; apiImpl: APIInterface; isInServerlessEnv: boolean; - constructor(recipeId: string, appInfo: NormalisedAppinfo, isInServerlessEnv: boolean, config?: TypeInput); + constructor( + stInstance: SuperTokens, + recipeId: string, + appInfo: NormalisedAppinfo, + isInServerlessEnv: boolean, + config?: TypeInput + ); static getInstance(): Recipe | undefined; static getInstanceOrThrowError(): Recipe; static init(config?: TypeInput): RecipeListFunction; diff --git a/lib/build/recipe/oauth2provider/recipe.js b/lib/build/recipe/oauth2provider/recipe.js index 42efe686a..65db9e5d7 100644 --- a/lib/build/recipe/oauth2provider/recipe.js +++ b/lib/build/recipe/oauth2provider/recipe.js @@ -21,7 +21,6 @@ var __importDefault = Object.defineProperty(exports, "__esModule", { value: true }); const error_1 = __importDefault(require("../../error")); const normalisedURLPath_1 = __importDefault(require("../../normalisedURLPath")); -const querier_1 = require("../../querier"); const recipeModule_1 = __importDefault(require("../../recipeModule")); const auth_1 = __importDefault(require("./api/auth")); const implementation_1 = __importDefault(require("./api/implementation")); @@ -40,8 +39,8 @@ const endSession_1 = require("./api/endSession"); const logout_1 = require("./api/logout"); const plugins_1 = require("../../plugins"); class Recipe extends recipeModule_1.default { - constructor(recipeId, appInfo, isInServerlessEnv, config) { - super(recipeId, appInfo); + constructor(stInstance, recipeId, appInfo, isInServerlessEnv, config) { + super(stInstance, recipeId, appInfo); this.accessTokenBuilders = []; this.idTokenBuilders = []; this.userInfoBuilders = []; @@ -64,19 +63,19 @@ class Recipe extends recipeModule_1.default { res, }; if (id === constants_1.LOGIN_PATH) { - return (0, login_1.default)(this.apiImpl, options, userContext); + return (0, login_1.default)(this.stInstance, this.apiImpl, options, userContext); } if (id === constants_1.TOKEN_PATH) { return (0, token_1.default)(this.apiImpl, options, userContext); } if (id === constants_1.AUTH_PATH) { - return (0, auth_1.default)(this.apiImpl, options, userContext); + return (0, auth_1.default)(this.stInstance, this.apiImpl, options, userContext); } if (id === constants_1.LOGIN_INFO_PATH) { return (0, loginInfo_1.default)(this.apiImpl, options, userContext); } if (id === constants_1.USER_INFO_PATH) { - return (0, userInfo_1.default)(this.apiImpl, tenantId, options, userContext); + return (0, userInfo_1.default)(this.stInstance, this.apiImpl, tenantId, options, userContext); } if (id === constants_1.REVOKE_TOKEN_PATH) { return (0, revokeToken_1.default)(this.apiImpl, options, userContext); @@ -85,13 +84,13 @@ class Recipe extends recipeModule_1.default { return (0, introspectToken_1.default)(this.apiImpl, options, userContext); } if (id === constants_1.END_SESSION_PATH && method === "get") { - return (0, endSession_1.endSessionGET)(this.apiImpl, options, userContext); + return (0, endSession_1.endSessionGET)(this.stInstance, this.apiImpl, options, userContext); } if (id === constants_1.END_SESSION_PATH && method === "post") { - return (0, endSession_1.endSessionPOST)(this.apiImpl, options, userContext); + return (0, endSession_1.endSessionPOST)(this.stInstance, this.apiImpl, options, userContext); } if (id === constants_1.LOGOUT_PATH && method === "post") { - return (0, logout_1.logoutPOST)(this.apiImpl, options, userContext); + return (0, logout_1.logoutPOST)(this.stInstance, this.apiImpl, options, userContext); } throw new Error("Should never come here: handleAPIRequest called with unknown id"); }; @@ -100,7 +99,8 @@ class Recipe extends recipeModule_1.default { { let builder = new supertokens_js_override_1.default( (0, recipeImplementation_1.default)( - querier_1.Querier.getNewInstanceOrThrowError(recipeId), + this.stInstance, + this.querier, this.config, appInfo, this.getDefaultAccessTokenPayload.bind(this), @@ -111,7 +111,7 @@ class Recipe extends recipeModule_1.default { this.recipeInterfaceImpl = builder.override(this.config.override.functions).build(); } { - let builder = new supertokens_js_override_1.default((0, implementation_1.default)()); + let builder = new supertokens_js_override_1.default((0, implementation_1.default)(this.stInstance)); this.apiImpl = builder.override(this.config.override.apis).build(); } } @@ -126,9 +126,10 @@ class Recipe extends recipeModule_1.default { throw new Error("Initialisation not done. Did you forget to call the Jwt.init function?"); } static init(config) { - return (appInfo, isInServerlessEnv, plugins) => { + return (stInstance, appInfo, isInServerlessEnv, plugins) => { if (Recipe.instance === undefined) { Recipe.instance = new Recipe( + stInstance, Recipe.RECIPE_ID, appInfo, isInServerlessEnv, diff --git a/lib/build/recipe/oauth2provider/recipeImplementation.d.ts b/lib/build/recipe/oauth2provider/recipeImplementation.d.ts index 4ecaeef69..091c84a8c 100644 --- a/lib/build/recipe/oauth2provider/recipeImplementation.d.ts +++ b/lib/build/recipe/oauth2provider/recipeImplementation.d.ts @@ -2,7 +2,9 @@ import { Querier } from "../../querier"; import { NormalisedAppinfo } from "../../types"; import { RecipeInterface, TypeNormalisedInput, PayloadBuilderFunction, UserInfoBuilderFunction } from "./types"; +import type SuperTokens from "../../supertokens"; export default function getRecipeInterface( + stInstance: SuperTokens, querier: Querier, _config: TypeNormalisedInput, appInfo: NormalisedAppinfo, diff --git a/lib/build/recipe/oauth2provider/recipeImplementation.js b/lib/build/recipe/oauth2provider/recipeImplementation.js index 185c966c9..a45fa92a3 100644 --- a/lib/build/recipe/oauth2provider/recipeImplementation.js +++ b/lib/build/recipe/oauth2provider/recipeImplementation.js @@ -65,19 +65,11 @@ var __importStar = return result; }; })(); -var __importDefault = - (this && this.__importDefault) || - function (mod) { - return mod && mod.__esModule ? mod : { default: mod }; - }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = getRecipeInterface; const jose = __importStar(require("jose")); const OAuth2Client_1 = require("./OAuth2Client"); -const __1 = require("../.."); const combinedRemoteJWKSet_1 = require("../../combinedRemoteJWKSet"); -const recipe_1 = __importDefault(require("../session/recipe")); -const recipe_2 = __importDefault(require("../openid/recipe")); const constants_1 = require("../multitenancy/constants"); const utils_1 = require("../../utils"); function getUpdatedRedirectTo(appInfo, redirectTo) { @@ -94,6 +86,7 @@ function copyAndCleanRequestBodyInput(input) { return result; } function getRecipeInterface( + stInstance, querier, _config, appInfo, @@ -206,7 +199,7 @@ function getRecipeInterface( grantAccessTokenAudience: input.grantAccessTokenAudience, grantScope: input.grantScope, handledAt: input.handledAt, - iss: await recipe_2.default.getIssuer(input.userContext), + iss: await stInstance.getRecipeInstanceOrThrow("openid").getIssuer(input.userContext), tId: input.tenantId, rsub: input.rsub, sessionHandle: input.sessionHandle, @@ -289,7 +282,9 @@ function getRecipeInterface( }; } const client = clientInfo.client; - const user = await (0, __1.getUser)(input.session.getUserId()); + const user = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: input.session.getUserId(), userContext: input.userContext }); if (!user) { return { status: "ERROR", @@ -329,7 +324,7 @@ function getRecipeInterface( "/recipe/oauth/auth", { params: Object.assign(Object.assign({}, input.params), { scope: scopes.join(" ") }), - iss: await recipe_2.default.getIssuer(input.userContext), + iss: await stInstance.getRecipeInstanceOrThrow("openid").getIssuer(input.userContext), cookies: input.cookies, session: payloads, }, @@ -392,7 +387,7 @@ function getRecipeInterface( inputBody: input.body, authorizationHeader: input.authorizationHeader, }; - body.iss = await recipe_2.default.getIssuer(input.userContext); + body.iss = await stInstance.getRecipeInstanceOrThrow("openid").getIssuer(input.userContext); if (input.body.grant_type === "password") { return { status: "ERROR", @@ -487,7 +482,12 @@ function getRecipeInterface( }; } const client = clientInfo.client; - const user = await (0, __1.getUser)(tokenInfo.sub); + const user = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ + userId: tokenInfo.sub, + userContext: input.userContext, + }); if (!user) { return { status: "ERROR", @@ -691,7 +691,10 @@ function getRecipeInterface( const payload = ( await jose.jwtVerify( input.token, - (0, combinedRemoteJWKSet_1.getCombinedJWKS)(recipe_1.default.getInstanceOrThrowError().config) + (0, combinedRemoteJWKSet_1.getCombinedJWKS)( + querier, + stInstance.getRecipeInstanceOrThrow("session").config + ) ) ).payload; if (payload.stt !== 1) { diff --git a/lib/build/recipe/openid/recipe.d.ts b/lib/build/recipe/openid/recipe.d.ts index fd2505e28..54e8fa848 100644 --- a/lib/build/recipe/openid/recipe.d.ts +++ b/lib/build/recipe/openid/recipe.d.ts @@ -5,17 +5,18 @@ import normalisedURLPath from "../../normalisedURLPath"; import RecipeModule from "../../recipeModule"; import { APIHandled, HTTPMethod, NormalisedAppinfo, RecipeListFunction, UserContext } from "../../types"; import { APIInterface, RecipeInterface, TypeInput, TypeNormalisedInput } from "./types"; +import type SuperTokens from "../../supertokens"; export default class OpenIdRecipe extends RecipeModule { static RECIPE_ID: "openid"; private static instance; config: TypeNormalisedInput; recipeImplementation: RecipeInterface; apiImpl: APIInterface; - constructor(recipeId: string, appInfo: NormalisedAppinfo, config?: TypeInput); + constructor(stInstance: SuperTokens, recipeId: string, appInfo: NormalisedAppinfo, config?: TypeInput); static getInstanceOrThrowError(): OpenIdRecipe; static init(config?: TypeInput): RecipeListFunction; static reset(): void; - static getIssuer(userContext: UserContext): Promise; + getIssuer(userContext: UserContext): Promise; getAPIsHandled: () => APIHandled[]; handleAPIRequest: ( id: string, diff --git a/lib/build/recipe/openid/recipe.js b/lib/build/recipe/openid/recipe.js index 3949bb7d6..be78802c3 100644 --- a/lib/build/recipe/openid/recipe.js +++ b/lib/build/recipe/openid/recipe.js @@ -31,8 +31,8 @@ const getOpenIdDiscoveryConfiguration_1 = __importDefault(require("./api/getOpen const utils_2 = require("../../utils"); const plugins_1 = require("../../plugins"); class OpenIdRecipe extends recipeModule_1.default { - constructor(recipeId, appInfo, config) { - super(recipeId, appInfo); + constructor(stInstance, recipeId, appInfo, config) { + super(stInstance, recipeId, appInfo); this.getAPIsHandled = () => { return [ { @@ -67,7 +67,7 @@ class OpenIdRecipe extends recipeModule_1.default { return error_1.default.isErrorFromSuperTokens(err) && err.fromRecipe === OpenIdRecipe.RECIPE_ID; }; this.config = (0, utils_1.validateAndNormaliseUserInput)(config); - let builder = new supertokens_js_override_1.default((0, recipeImplementation_1.default)(appInfo)); + let builder = new supertokens_js_override_1.default((0, recipeImplementation_1.default)(stInstance, appInfo)); this.recipeImplementation = builder.override(this.config.override.functions).build(); let apiBuilder = new supertokens_js_override_1.default((0, implementation_1.default)()); this.apiImpl = apiBuilder.override(this.config.override.apis).build(); @@ -79,9 +79,10 @@ class OpenIdRecipe extends recipeModule_1.default { throw new Error("Initialisation not done. Did you forget to call the Openid.init function?"); } static init(config) { - return (appInfo, _isInServerlessEnv, plugins) => { + return (stInstance, appInfo, _isInServerlessEnv, plugins) => { if (OpenIdRecipe.instance === undefined) { OpenIdRecipe.instance = new OpenIdRecipe( + stInstance, OpenIdRecipe.RECIPE_ID, appInfo, (0, plugins_1.applyPlugins)( @@ -102,10 +103,8 @@ class OpenIdRecipe extends recipeModule_1.default { } OpenIdRecipe.instance = undefined; } - static async getIssuer(userContext) { - return ( - await this.getInstanceOrThrowError().recipeImplementation.getOpenIdDiscoveryConfiguration({ userContext }) - ).issuer; + async getIssuer(userContext) { + return (await this.recipeImplementation.getOpenIdDiscoveryConfiguration({ userContext })).issuer; } } OpenIdRecipe.RECIPE_ID = "openid"; diff --git a/lib/build/recipe/openid/recipeImplementation.d.ts b/lib/build/recipe/openid/recipeImplementation.d.ts index 07ebf044c..a98a0dc48 100644 --- a/lib/build/recipe/openid/recipeImplementation.d.ts +++ b/lib/build/recipe/openid/recipeImplementation.d.ts @@ -1,4 +1,5 @@ // @ts-nocheck import { RecipeInterface } from "./types"; import { NormalisedAppinfo } from "../../types"; -export default function getRecipeInterface(appInfo: NormalisedAppinfo): RecipeInterface; +import type SuperTokens from "../../supertokens"; +export default function getRecipeInterface(stInstance: SuperTokens, appInfo: NormalisedAppinfo): RecipeInterface; diff --git a/lib/build/recipe/openid/recipeImplementation.js b/lib/build/recipe/openid/recipeImplementation.js index 6af6994ec..e8a580df0 100644 --- a/lib/build/recipe/openid/recipeImplementation.js +++ b/lib/build/recipe/openid/recipeImplementation.js @@ -6,11 +6,10 @@ var __importDefault = }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = getRecipeInterface; -const recipe_1 = __importDefault(require("../jwt/recipe")); const normalisedURLPath_1 = __importDefault(require("../../normalisedURLPath")); const constants_1 = require("../jwt/constants"); const constants_2 = require("../oauth2provider/constants"); -function getRecipeInterface(appInfo) { +function getRecipeInterface(stInstance, appInfo) { return { getOpenIdDiscoveryConfiguration: async function () { let issuer = appInfo.apiDomain.getAsStringDangerous() + appInfo.apiBasePath.getAsStringDangerous(); @@ -38,7 +37,7 @@ function getRecipeInterface(appInfo) { createJWT: async function ({ payload, validitySeconds, useStaticSigningKey, userContext }) { payload = payload === undefined || payload === null ? {} : payload; let issuer = (await this.getOpenIdDiscoveryConfiguration({ userContext })).issuer; - return await recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl.createJWT({ + return await stInstance.getRecipeInstanceOrThrow("jwt").recipeInterfaceImpl.createJWT({ payload: Object.assign({ iss: issuer }, payload), useStaticSigningKey, validitySeconds, diff --git a/lib/build/recipe/passwordless/api/consumeCode.d.ts b/lib/build/recipe/passwordless/api/consumeCode.d.ts index a07ff159f..7a9751a15 100644 --- a/lib/build/recipe/passwordless/api/consumeCode.d.ts +++ b/lib/build/recipe/passwordless/api/consumeCode.d.ts @@ -1,7 +1,9 @@ // @ts-nocheck import { APIInterface, APIOptions } from ".."; import { UserContext } from "../../../types"; +import type SuperTokens from "../../../supertokens"; export default function consumeCode( + stInstance: SuperTokens, apiImplementation: APIInterface, tenantId: string, options: APIOptions, diff --git a/lib/build/recipe/passwordless/api/consumeCode.js b/lib/build/recipe/passwordless/api/consumeCode.js index 783f9c134..0a750fb36 100644 --- a/lib/build/recipe/passwordless/api/consumeCode.js +++ b/lib/build/recipe/passwordless/api/consumeCode.js @@ -23,7 +23,7 @@ exports.default = consumeCode; const utils_1 = require("../../../utils"); const error_1 = __importDefault(require("../error")); const authUtils_1 = require("../../../authUtils"); -async function consumeCode(apiImplementation, tenantId, options, userContext) { +async function consumeCode(stInstance, apiImplementation, tenantId, options, userContext) { if (apiImplementation.consumeCodePOST === undefined) { return false; } @@ -62,6 +62,7 @@ async function consumeCode(apiImplementation, tenantId, options, userContext) { body ); const session = await authUtils_1.AuthUtils.loadSessionInAuthAPIIfNeeded( + stInstance, options.req, options.res, shouldTryLinkingWithSessionUser, diff --git a/lib/build/recipe/passwordless/api/createCode.d.ts b/lib/build/recipe/passwordless/api/createCode.d.ts index 1d2619c75..d27ca0e12 100644 --- a/lib/build/recipe/passwordless/api/createCode.d.ts +++ b/lib/build/recipe/passwordless/api/createCode.d.ts @@ -1,7 +1,9 @@ // @ts-nocheck import { APIInterface, APIOptions } from ".."; import { UserContext } from "../../../types"; +import type SuperTokens from "../../../supertokens"; export default function createCode( + stInstance: SuperTokens, apiImplementation: APIInterface, tenantId: string, options: APIOptions, diff --git a/lib/build/recipe/passwordless/api/createCode.js b/lib/build/recipe/passwordless/api/createCode.js index 791d55810..4522a1ef7 100644 --- a/lib/build/recipe/passwordless/api/createCode.js +++ b/lib/build/recipe/passwordless/api/createCode.js @@ -24,7 +24,7 @@ const utils_1 = require("../../../utils"); const error_1 = __importDefault(require("../error")); const max_1 = __importDefault(require("libphonenumber-js/max")); const authUtils_1 = require("../../../authUtils"); -async function createCode(apiImplementation, tenantId, options, userContext) { +async function createCode(stInstance, apiImplementation, tenantId, options, userContext) { if (apiImplementation.createCodePOST === undefined) { return false; } @@ -90,6 +90,7 @@ async function createCode(apiImplementation, tenantId, options, userContext) { body ); const session = await authUtils_1.AuthUtils.loadSessionInAuthAPIIfNeeded( + stInstance, options.req, options.res, shouldTryLinkingWithSessionUser, diff --git a/lib/build/recipe/passwordless/api/implementation.d.ts b/lib/build/recipe/passwordless/api/implementation.d.ts index 402db9918..ad401abfa 100644 --- a/lib/build/recipe/passwordless/api/implementation.d.ts +++ b/lib/build/recipe/passwordless/api/implementation.d.ts @@ -1,3 +1,4 @@ // @ts-nocheck import { APIInterface } from "../"; -export default function getAPIImplementation(): APIInterface; +import type SuperTokens from "../../../supertokens"; +export default function getAPIImplementation(stInstance: SuperTokens): APIInterface; diff --git a/lib/build/recipe/passwordless/api/implementation.js b/lib/build/recipe/passwordless/api/implementation.js index f70d23444..1bb963f4c 100644 --- a/lib/build/recipe/passwordless/api/implementation.js +++ b/lib/build/recipe/passwordless/api/implementation.js @@ -9,12 +9,9 @@ exports.default = getAPIImplementation; const logger_1 = require("../../../logger"); const authUtils_1 = require("../../../authUtils"); const multifactorauth_1 = require("../../multifactorauth"); -const recipe_1 = __importDefault(require("../../accountlinking/recipe")); -const recipe_2 = __importDefault(require("../../emailverification/recipe")); const utils_1 = require("../utils"); -const __1 = require("../../.."); const error_1 = __importDefault(require("../../session/error")); -function getAPIImplementation() { +function getAPIImplementation(stInstance) { return { consumeCodePOST: async function (input) { var _a, _b, _c; @@ -78,6 +75,7 @@ function getAPIImplementation() { }; const authenticatingUser = await authUtils_1.AuthUtils.getAuthenticatingUserAndAddToCurrentTenantIfRequired( { + stInstance, accountInfo, recipeId, userContext: input.userContext, @@ -86,7 +84,7 @@ function getAPIImplementation() { checkCredentialsOnTenant: checkCredentials, } ); - const emailVerificationInstance = recipe_2.default.getInstance(); + const emailVerificationInstance = stInstance.getRecipeInstance("emailverification"); // If we have a session and emailverification was initialized plus this code was sent to an email // then we check if we can/should verify this email address for the session user. // This helps in usecases like phone-password and emailverification-with-otp where we only want to allow linking @@ -100,7 +98,9 @@ function getAPIImplementation() { ) { // We first load the session user, so we can check if verification is required // We do this first, it is better for caching if we group the post calls together (verifyIng the code and the email address) - const sessionUser = await (0, __1.getUser)(input.session.getUserId(), input.userContext); + const sessionUser = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: input.session.getUserId(), userContext: input.userContext }); if (sessionUser === undefined) { throw new error_1.default({ type: error_1.default.UNAUTHORISED, @@ -157,6 +157,7 @@ function getAPIImplementation() { } const isSignUp = authenticatingUser === undefined; const preAuthChecks = await authUtils_1.AuthUtils.preAuthChecks({ + stInstance, authenticatingAccountInfo: { recipeId: "passwordless", email: deviceInfo.email, @@ -238,6 +239,7 @@ function getAPIImplementation() { // of the user), it's OK to do this check here cause the preAuthChecks already checks // conditions related to account linking const postAuthChecks = await authUtils_1.AuthUtils.postAuthChecks({ + stInstance, factorId, isSignUp, authenticatedUser: (_b = response.user) !== null && _b !== void 0 ? _b : authenticatingUser.user, @@ -286,7 +288,7 @@ function getAPIImplementation() { // 1. At this point we have no way to check credentials // 2. We do not want to associate the relevant recipe user with the current tenant (yet) const userWithMatchingLoginMethod = await getPasswordlessUserByAccountInfo( - Object.assign(Object.assign({}, input), { accountInfo }) + Object.assign(Object.assign({}, input), { accountInfo, stInstance }) ); let factorIds; if (input.session !== undefined) { @@ -308,6 +310,7 @@ function getAPIImplementation() { } } const preAuthChecks = await authUtils_1.AuthUtils.preAuthChecks({ + stInstance, authenticatingAccountInfo: Object.assign(Object.assign({}, accountInfo), { recipeId: "passwordless" }), isSignUp: userWithMatchingLoginMethod === undefined, authenticatingUser: @@ -448,14 +451,16 @@ function getAPIImplementation() { }; }, emailExistsGET: async function (input) { - const users = await recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl.listUsersByAccountInfo({ - tenantId: input.tenantId, - accountInfo: { - email: input.email, - }, - doUnionOfAccountInfo: false, - userContext: input.userContext, - }); + const users = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.listUsersByAccountInfo({ + tenantId: input.tenantId, + accountInfo: { + email: input.email, + }, + doUnionOfAccountInfo: false, + userContext: input.userContext, + }); const userExists = users.some((u) => u.loginMethods.some((lm) => lm.recipeId === "passwordless" && lm.hasSameEmailAs(input.email)) ); @@ -465,15 +470,16 @@ function getAPIImplementation() { }; }, phoneNumberExistsGET: async function (input) { - let users = await (0, __1.listUsersByAccountInfo)( - input.tenantId, - { - phoneNumber: input.phoneNumber, - // tenantId: input.tenantId, - }, - false, - input.userContext - ); + let users = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.listUsersByAccountInfo({ + tenantId: input.tenantId, + accountInfo: { + phoneNumber: input.phoneNumber, + }, + doUnionOfAccountInfo: false, + userContext: input.userContext, + }); return { exists: users.length > 0, status: "OK", @@ -499,9 +505,10 @@ function getAPIImplementation() { }; } const userWithMatchingLoginMethod = await getPasswordlessUserByAccountInfo( - Object.assign(Object.assign({}, input), { accountInfo: deviceInfo }) + Object.assign(Object.assign({}, input), { accountInfo: deviceInfo, stInstance: stInstance }) ); const authTypeInfo = await authUtils_1.AuthUtils.checkAuthTypeAndLinkingStatus( + stInstance, input.session, input.shouldTryLinkingWithSessionUser, { @@ -566,6 +573,7 @@ function getAPIImplementation() { } else { factorIds = (0, utils_1.getEnabledPwlessFactors)(input.options.config); factorIds = await authUtils_1.AuthUtils.filterOutInvalidFirstFactorsOrThrowIfAllAreInvalid( + stInstance, factorIds, input.tenantId, false, @@ -644,12 +652,14 @@ function getAPIImplementation() { }; } async function getPasswordlessUserByAccountInfo(input) { - const existingUsers = await recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl.listUsersByAccountInfo({ - tenantId: input.tenantId, - accountInfo: input.accountInfo, - doUnionOfAccountInfo: false, - userContext: input.userContext, - }); + const existingUsers = await input.stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.listUsersByAccountInfo({ + tenantId: input.tenantId, + accountInfo: input.accountInfo, + doUnionOfAccountInfo: false, + userContext: input.userContext, + }); (0, logger_1.logDebugMessage)( `getPasswordlessUserByAccountInfo got ${existingUsers.length} from core resp ${JSON.stringify( input.accountInfo diff --git a/lib/build/recipe/passwordless/api/resendCode.d.ts b/lib/build/recipe/passwordless/api/resendCode.d.ts index d6fd98191..9585c2c9b 100644 --- a/lib/build/recipe/passwordless/api/resendCode.d.ts +++ b/lib/build/recipe/passwordless/api/resendCode.d.ts @@ -1,7 +1,9 @@ // @ts-nocheck import { APIInterface, APIOptions } from ".."; import { UserContext } from "../../../types"; +import type SuperTokens from "../../../supertokens"; export default function resendCode( + stInstance: SuperTokens, apiImplementation: APIInterface, tenantId: string, options: APIOptions, diff --git a/lib/build/recipe/passwordless/api/resendCode.js b/lib/build/recipe/passwordless/api/resendCode.js index 019213f41..a60a19f50 100644 --- a/lib/build/recipe/passwordless/api/resendCode.js +++ b/lib/build/recipe/passwordless/api/resendCode.js @@ -23,7 +23,7 @@ exports.default = resendCode; const utils_1 = require("../../../utils"); const error_1 = __importDefault(require("../error")); const authUtils_1 = require("../../../authUtils"); -async function resendCode(apiImplementation, tenantId, options, userContext) { +async function resendCode(stInstance, apiImplementation, tenantId, options, userContext) { if (apiImplementation.resendCodePOST === undefined) { return false; } @@ -47,6 +47,7 @@ async function resendCode(apiImplementation, tenantId, options, userContext) { body ); const session = await authUtils_1.AuthUtils.loadSessionInAuthAPIIfNeeded( + stInstance, options.req, options.res, shouldTryLinkingWithSessionUser, diff --git a/lib/build/recipe/passwordless/emaildelivery/services/backwardCompatibility/index.js b/lib/build/recipe/passwordless/emaildelivery/services/backwardCompatibility/index.js index 7ca9d976e..741e50c56 100644 --- a/lib/build/recipe/passwordless/emaildelivery/services/backwardCompatibility/index.js +++ b/lib/build/recipe/passwordless/emaildelivery/services/backwardCompatibility/index.js @@ -1,11 +1,12 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const utils_1 = require("../../../../../utils"); +const querier_1 = require("../../../../../querier"); async function createAndSendEmailUsingSupertokensService(input) { if ((0, utils_1.isTestEnv)()) { return; } - const result = await (0, utils_1.postWithFetch)( + const result = await (0, querier_1.postWithFetch)( "https://api.supertokens.io/0/st/auth/passwordless/login", { "api-version": "0", diff --git a/lib/build/recipe/passwordless/recipe.d.ts b/lib/build/recipe/passwordless/recipe.d.ts index 903121051..ffc9b8c50 100644 --- a/lib/build/recipe/passwordless/recipe.d.ts +++ b/lib/build/recipe/passwordless/recipe.d.ts @@ -9,6 +9,7 @@ import EmailDeliveryIngredient from "../../ingredients/emaildelivery"; import { TypePasswordlessEmailDeliveryInput, TypePasswordlessSmsDeliveryInput } from "./types"; import SmsDeliveryIngredient from "../../ingredients/smsdelivery"; import { SessionContainerInterface } from "../session/types"; +import type SuperTokens from "../../supertokens"; export default class Recipe extends RecipeModule { private static instance; static RECIPE_ID: "passwordless"; @@ -19,6 +20,7 @@ export default class Recipe extends RecipeModule { emailDelivery: EmailDeliveryIngredient; smsDelivery: SmsDeliveryIngredient; constructor( + stInstance: SuperTokens, recipeId: string, appInfo: NormalisedAppinfo, isInServerlessEnv: boolean, diff --git a/lib/build/recipe/passwordless/recipe.js b/lib/build/recipe/passwordless/recipe.js index 8d57a3f40..27b1c946d 100644 --- a/lib/build/recipe/passwordless/recipe.js +++ b/lib/build/recipe/passwordless/recipe.js @@ -25,7 +25,6 @@ const utils_1 = require("./utils"); const normalisedURLPath_1 = __importDefault(require("../../normalisedURLPath")); const recipeImplementation_1 = __importDefault(require("./recipeImplementation")); const implementation_1 = __importDefault(require("./api/implementation")); -const querier_1 = require("../../querier"); const supertokens_js_override_1 = __importDefault(require("supertokens-js-override")); const consumeCode_1 = __importDefault(require("./api/consumeCode")); const createCode_1 = __importDefault(require("./api/createCode")); @@ -36,15 +35,13 @@ const constants_1 = require("./constants"); const emaildelivery_1 = __importDefault(require("../../ingredients/emaildelivery")); const smsdelivery_1 = __importDefault(require("../../ingredients/smsdelivery")); const postSuperTokensInitCallbacks_1 = require("../../postSuperTokensInitCallbacks"); -const recipe_1 = __importDefault(require("../multifactorauth/recipe")); -const recipe_2 = __importDefault(require("../multitenancy/recipe")); const utils_2 = require("../thirdparty/utils"); const multifactorauth_1 = require("../multifactorauth"); const utils_3 = require("../../utils"); const plugins_1 = require("../../plugins"); class Recipe extends recipeModule_1.default { - constructor(recipeId, appInfo, isInServerlessEnv, config, ingredients) { - super(recipeId, appInfo); + constructor(stInstance, recipeId, appInfo, isInServerlessEnv, config, ingredients) { + super(stInstance, recipeId, appInfo); // abstract instance functions below............... this.getAPIsHandled = () => { return [ @@ -107,9 +104,9 @@ class Recipe extends recipeModule_1.default { appInfo: this.getAppInfo(), }; if (id === constants_1.CONSUME_CODE_API) { - return await (0, consumeCode_1.default)(this.apiImpl, tenantId, options, userContext); + return await (0, consumeCode_1.default)(this.stInstance, this.apiImpl, tenantId, options, userContext); } else if (id === constants_1.CREATE_CODE_API) { - return await (0, createCode_1.default)(this.apiImpl, tenantId, options, userContext); + return await (0, createCode_1.default)(this.stInstance, this.apiImpl, tenantId, options, userContext); } else if (id === constants_1.DOES_EMAIL_EXIST_API || id === constants_1.DOES_EMAIL_EXIST_API_OLD) { return await (0, emailExists_1.default)(this.apiImpl, tenantId, options, userContext); } else if ( @@ -118,7 +115,7 @@ class Recipe extends recipeModule_1.default { ) { return await (0, phoneNumberExists_1.default)(this.apiImpl, tenantId, options, userContext); } else { - return await (0, resendCode_1.default)(this.apiImpl, tenantId, options, userContext); + return await (0, resendCode_1.default)(this.stInstance, this.apiImpl, tenantId, options, userContext); } }; this.handleError = async (err, _, __) => { @@ -232,12 +229,12 @@ class Recipe extends recipeModule_1.default { this.config = (0, utils_1.validateAndNormaliseUserInput)(this, appInfo, config); { let builder = new supertokens_js_override_1.default( - (0, recipeImplementation_1.default)(querier_1.Querier.getNewInstanceOrThrowError(recipeId)) + (0, recipeImplementation_1.default)(this.stInstance, this.querier) ); this.recipeInterfaceImpl = builder.override(this.config.override.functions).build(); } { - let builder = new supertokens_js_override_1.default((0, implementation_1.default)()); + let builder = new supertokens_js_override_1.default((0, implementation_1.default)(this.stInstance)); this.apiImpl = builder.override(this.config.override.apis).build(); } /** @@ -254,7 +251,7 @@ class Recipe extends recipeModule_1.default { : ingredients.smsDelivery; let allFactors = (0, utils_1.getEnabledPwlessFactors)(this.config); postSuperTokensInitCallbacks_1.PostSuperTokensInitCallbacks.addPostInitCallback(() => { - const mfaInstance = recipe_1.default.getInstance(); + const mfaInstance = stInstance.getRecipeInstance("multifactorauth"); if (mfaInstance !== undefined) { mfaInstance.addFuncToGetAllAvailableSecondaryFactorIdsFromOtherRecipes(() => { return allFactors; @@ -543,7 +540,7 @@ class Recipe extends recipeModule_1.default { }; }); } - const mtRecipe = recipe_2.default.getInstance(); + const mtRecipe = stInstance.getRecipeInstance("multitenancy"); if (mtRecipe !== undefined) { for (const factorId of allFactors) { mtRecipe.allAvailableFirstFactors.push(factorId); @@ -558,9 +555,10 @@ class Recipe extends recipeModule_1.default { throw new Error("Initialisation not done. Did you forget to call the Passwordless.init function?"); } static init(config) { - return (appInfo, isInServerlessEnv, plugins) => { + return (stInstance, appInfo, isInServerlessEnv, plugins) => { if (Recipe.instance === undefined) { Recipe.instance = new Recipe( + stInstance, Recipe.RECIPE_ID, appInfo, isInServerlessEnv, diff --git a/lib/build/recipe/passwordless/recipeImplementation.d.ts b/lib/build/recipe/passwordless/recipeImplementation.d.ts index 86bf78a27..32690fdd8 100644 --- a/lib/build/recipe/passwordless/recipeImplementation.d.ts +++ b/lib/build/recipe/passwordless/recipeImplementation.d.ts @@ -1,4 +1,5 @@ // @ts-nocheck import { RecipeInterface } from "./types"; import { Querier } from "../../querier"; -export default function getRecipeInterface(querier: Querier): RecipeInterface; +import type SuperTokens from "../../supertokens"; +export default function getRecipeInterface(stInstance: SuperTokens, querier: Querier): RecipeInterface; diff --git a/lib/build/recipe/passwordless/recipeImplementation.js b/lib/build/recipe/passwordless/recipeImplementation.js index e520bafc9..4e0f5709d 100644 --- a/lib/build/recipe/passwordless/recipeImplementation.js +++ b/lib/build/recipe/passwordless/recipeImplementation.js @@ -6,14 +6,11 @@ var __importDefault = }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = getRecipeInterface; -const recipe_1 = __importDefault(require("../accountlinking/recipe")); -const recipe_2 = __importDefault(require("../emailverification/recipe")); const logger_1 = require("../../logger"); const user_1 = require("../../user"); -const __1 = require("../.."); const recipeUserId_1 = __importDefault(require("../../recipeUserId")); const authUtils_1 = require("../../authUtils"); -function getRecipeInterface(querier) { +function getRecipeInterface(stInstance, querier) { function copyAndRemoveUserContextAndTenantId(input) { let result = Object.assign({}, input); delete result.userContext; @@ -46,6 +43,7 @@ function getRecipeInterface(querier) { let updatedUser = userAsObj; const linkResult = await authUtils_1.AuthUtils.linkToSessionIfRequiredElseCreatePrimaryUserIdOrLinkByAccountInfo({ + stInstance, tenantId: input.tenantId, inputUser: userAsObj, recipeUserId: recipeUserIdAsObj, @@ -188,13 +186,16 @@ function getRecipeInterface(querier) { return { status: "OK" }; }, updateUser: async function (input) { - const accountLinking = recipe_1.default.getInstanceOrThrowError(); + const accountLinking = stInstance.getRecipeInstanceOrThrow("accountlinking"); if (input.email) { - const user = await (0, __1.getUser)(input.recipeUserId.getAsString(), input.userContext); + const user = await stInstance.getRecipeInstanceOrThrow("accountlinking").recipeInterfaceImpl.getUser({ + userId: input.recipeUserId.getAsString(), + userContext: input.userContext, + }); if (user === undefined) { return { status: "UNKNOWN_USER_ID_ERROR" }; } - const evInstance = recipe_2.default.getInstance(); + const evInstance = stInstance.getRecipeInstance("emailverification"); let isEmailVerified = false; if (evInstance) { isEmailVerified = await evInstance.recipeInterfaceImpl.isEmailVerified({ @@ -229,18 +230,23 @@ function getRecipeInterface(querier) { if (response.status !== "OK") { return response; } - const user = await (0, __1.getUser)(input.recipeUserId.getAsString(), input.userContext); + const user = await stInstance.getRecipeInstanceOrThrow("accountlinking").recipeInterfaceImpl.getUser({ + userId: input.recipeUserId.getAsString(), + userContext: input.userContext, + }); if (user === undefined) { // This means that the user was deleted between the put and get requests return { status: "UNKNOWN_USER_ID_ERROR", }; } - await recipe_1.default.getInstanceOrThrowError().verifyEmailForRecipeUserIfLinkedAccountsAreVerified({ - user, - recipeUserId: input.recipeUserId, - userContext: input.userContext, - }); + await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .verifyEmailForRecipeUserIfLinkedAccountsAreVerified({ + user, + recipeUserId: input.recipeUserId, + userContext: input.userContext, + }); return response; }, }; diff --git a/lib/build/recipe/passwordless/smsdelivery/services/backwardCompatibility/index.js b/lib/build/recipe/passwordless/smsdelivery/services/backwardCompatibility/index.js index bca8dac47..ee2a567c9 100644 --- a/lib/build/recipe/passwordless/smsdelivery/services/backwardCompatibility/index.js +++ b/lib/build/recipe/passwordless/smsdelivery/services/backwardCompatibility/index.js @@ -7,11 +7,11 @@ var __importDefault = Object.defineProperty(exports, "__esModule", { value: true }); const supertokens_1 = require("../../../../../ingredients/smsdelivery/services/supertokens"); const supertokens_2 = __importDefault(require("../../../../../supertokens")); -const utils_1 = require("../../../../../utils"); +const querier_1 = require("../../../../../querier"); async function createAndSendSmsUsingSupertokensService(input) { let supertokens = supertokens_2.default.getInstanceOrThrowError(); let appName = supertokens.appInfo.appName; - const result = await (0, utils_1.postWithFetch)( + const result = await (0, querier_1.postWithFetch)( supertokens_1.SUPERTOKENS_SMS_SERVICE_URL, { "api-version": "0", diff --git a/lib/build/recipe/passwordless/smsdelivery/services/supertokens/index.js b/lib/build/recipe/passwordless/smsdelivery/services/supertokens/index.js index eb3d45066..b27362438 100644 --- a/lib/build/recipe/passwordless/smsdelivery/services/supertokens/index.js +++ b/lib/build/recipe/passwordless/smsdelivery/services/supertokens/index.js @@ -21,13 +21,13 @@ Object.defineProperty(exports, "__esModule", { value: true }); */ const supertokens_1 = require("../../../../../ingredients/smsdelivery/services/supertokens"); const supertokens_2 = __importDefault(require("../../../../../supertokens")); -const utils_1 = require("../../../../../utils"); +const querier_1 = require("../../../../../querier"); class SupertokensService { constructor(apiKey) { this.sendSms = async (input) => { let supertokens = supertokens_2.default.getInstanceOrThrowError(); let appName = supertokens.appInfo.appName; - const res = await (0, utils_1.postWithFetch)( + const res = await (0, querier_1.postWithFetch)( supertokens_1.SUPERTOKENS_SMS_SERVICE_URL, { "api-version": "0", diff --git a/lib/build/recipe/session/api/implementation.d.ts b/lib/build/recipe/session/api/implementation.d.ts index dd40e7025..f7295c4c6 100644 --- a/lib/build/recipe/session/api/implementation.d.ts +++ b/lib/build/recipe/session/api/implementation.d.ts @@ -1,3 +1,5 @@ // @ts-nocheck import { APIInterface } from "../"; -export default function getAPIInterface(): APIInterface; +import type SessionRecipe from "../recipe"; +import type SuperTokens from "../../../supertokens"; +export default function getAPIInterface(stInstance: SuperTokens, recipeInstance: SessionRecipe): APIInterface; diff --git a/lib/build/recipe/session/api/implementation.js b/lib/build/recipe/session/api/implementation.js index 0afc6aa1a..d3d80ec64 100644 --- a/lib/build/recipe/session/api/implementation.js +++ b/lib/build/recipe/session/api/implementation.js @@ -9,7 +9,7 @@ exports.default = getAPIInterface; const utils_1 = require("../../../utils"); const normalisedURLPath_1 = __importDefault(require("../../../normalisedURLPath")); const sessionRequestFunctions_1 = require("../sessionRequestFunctions"); -function getAPIInterface() { +function getAPIInterface(stInstance, recipeInstance) { return { refreshPOST: async function ({ options, userContext }) { return (0, sessionRequestFunctions_1.refreshSessionInRequest)({ @@ -18,6 +18,7 @@ function getAPIInterface() { userContext, config: options.config, recipeInterfaceImpl: options.recipeImplementation, + stInstance, }); }, verifySession: async function ({ verifySessionOptions, options, userContext }) { @@ -34,6 +35,7 @@ function getAPIInterface() { userContext, config: options.config, recipeInterfaceImpl: options.recipeImplementation, + stInstance, }); } else { return (0, sessionRequestFunctions_1.getSessionFromRequest)({ @@ -42,6 +44,8 @@ function getAPIInterface() { options: verifySessionOptions, config: options.config, recipeInterfaceImpl: options.recipeImplementation, + recipeInstance, + stInstance, userContext, }); } diff --git a/lib/build/recipe/session/api/signout.d.ts b/lib/build/recipe/session/api/signout.d.ts index 758ce9ed6..9a85fec53 100644 --- a/lib/build/recipe/session/api/signout.d.ts +++ b/lib/build/recipe/session/api/signout.d.ts @@ -1,7 +1,9 @@ // @ts-nocheck import { APIInterface, APIOptions } from "../"; import { UserContext } from "../../../types"; +import type SuperTokens from "../../../supertokens"; export default function signOutAPI( + stInstance: SuperTokens, apiImplementation: APIInterface, options: APIOptions, userContext: UserContext diff --git a/lib/build/recipe/session/api/signout.js b/lib/build/recipe/session/api/signout.js index 60e1cce8c..681f810f8 100644 --- a/lib/build/recipe/session/api/signout.js +++ b/lib/build/recipe/session/api/signout.js @@ -17,7 +17,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.default = signOutAPI; const utils_1 = require("../../../utils"); const sessionRequestFunctions_1 = require("../sessionRequestFunctions"); -async function signOutAPI(apiImplementation, options, userContext) { +async function signOutAPI(stInstance, apiImplementation, options, userContext) { // Logic as per https://github.com/supertokens/supertokens-node/issues/34#issuecomment-717958537 if (apiImplementation.signOutPOST === undefined) { return false; @@ -25,8 +25,10 @@ async function signOutAPI(apiImplementation, options, userContext) { const session = await (0, sessionRequestFunctions_1.getSessionFromRequest)({ req: options.req, res: options.res, + stInstance, config: options.config, recipeInterfaceImpl: options.recipeImplementation, + recipeInstance: stInstance.getRecipeInstanceOrThrow("session"), options: { sessionRequired: true, overrideGlobalClaimValidators: () => [], diff --git a/lib/build/recipe/session/framework/custom.d.ts b/lib/build/recipe/session/framework/custom.d.ts index 1c554414c..c73ab62e9 100644 --- a/lib/build/recipe/session/framework/custom.d.ts +++ b/lib/build/recipe/session/framework/custom.d.ts @@ -1,7 +1,7 @@ // @ts-nocheck import type { VerifySessionOptions } from ".."; -import { BaseRequest, BaseResponse } from "../../../framework"; -import { NextFunction } from "../../../framework/custom/framework"; +import type { BaseRequest, BaseResponse } from "../../../framework"; +import type { NextFunction } from "../../../framework/custom/framework"; import { SessionContainerInterface } from "../types"; export declare function verifySession< T extends BaseRequest & { diff --git a/lib/build/recipe/session/index.js b/lib/build/recipe/session/index.js index dff4e12f0..66e4cc9a7 100644 --- a/lib/build/recipe/session/index.js +++ b/lib/build/recipe/session/index.js @@ -47,12 +47,12 @@ const error_1 = __importDefault(require("./error")); const recipe_1 = __importDefault(require("./recipe")); const recipe_2 = __importDefault(require("../openid/recipe")); const recipe_3 = __importDefault(require("../jwt/recipe")); -const utils_1 = require("./utils"); const sessionRequestFunctions_1 = require("./sessionRequestFunctions"); const __1 = require("../.."); const constants_1 = require("../multitenancy/constants"); const constants_2 = require("./constants"); -const utils_2 = require("../../utils"); +const utils_1 = require("../../utils"); +const supertokens_1 = __importDefault(require("../../supertokens")); class SessionWrapper { static async createNewSession( req, @@ -64,23 +64,12 @@ class SessionWrapper { userContext ) { const recipeInstance = recipe_1.default.getInstanceOrThrowError(); - const config = recipeInstance.config; - const appInfo = recipeInstance.getAppInfo(); - let user = await (0, __1.getUser)(recipeUserId.getAsString(), userContext); - let userId = recipeUserId.getAsString(); - if (user !== undefined) { - userId = user.id; - } - return await (0, sessionRequestFunctions_1.createNewSessionInRequest)({ + return await recipeInstance.createNewSession({ req, res, - userContext: (0, utils_2.getUserContext)(userContext), - recipeInstance, + userContext: (0, utils_1.getUserContext)(userContext), accessTokenPayload, - userId, recipeUserId, - config, - appInfo, sessionDataInDatabase, tenantId, }); @@ -93,10 +82,10 @@ class SessionWrapper { disableAntiCsrf = false, userContext ) { - const ctx = (0, utils_2.getUserContext)(userContext); + const ctx = (0, utils_1.getUserContext)(userContext); const recipeInstance = recipe_1.default.getInstanceOrThrowError(); const claimsAddedByOtherRecipes = recipeInstance.getClaimsAddedByOtherRecipes(); - const issuer = await recipe_2.default.getIssuer(ctx); + const issuer = await recipe_2.default.getInstanceOrThrowError().getIssuer(ctx); let finalAccessTokenPayload = Object.assign(Object.assign({}, accessTokenPayload), { iss: issuer }); for (const prop of constants_2.protectedProps) { delete finalAccessTokenPayload[prop]; @@ -121,7 +110,7 @@ class SessionWrapper { }); } static async validateClaimsForSessionHandle(sessionHandle, overrideGlobalClaimValidators, userContext) { - const ctx = (0, utils_2.getUserContext)(userContext); + const ctx = (0, utils_1.getUserContext)(userContext); const recipeImpl = recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl; const sessionInfo = await recipeImpl.getSessionInformation({ sessionHandle, @@ -173,19 +162,15 @@ class SessionWrapper { } static async getSession(req, res, options, userContext) { const recipeInstance = recipe_1.default.getInstanceOrThrowError(); - const config = recipeInstance.config; - const recipeInterfaceImpl = recipeInstance.recipeInterfaceImpl; - return (0, sessionRequestFunctions_1.getSessionFromRequest)({ + return await recipeInstance.getSession({ req, res, - recipeInterfaceImpl, - config, options, - userContext: (0, utils_2.getUserContext)(userContext), // userContext is normalized inside the function + userContext: (0, utils_1.getUserContext)(userContext), }); } static async getSessionWithoutRequestResponse(accessToken, antiCsrfToken, options, userContext) { - const ctx = (0, utils_2.getUserContext)(userContext); + const ctx = (0, utils_1.getUserContext)(userContext); const recipeInterfaceImpl = recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl; const session = await recipeInterfaceImpl.getSession({ accessToken, @@ -194,11 +179,13 @@ class SessionWrapper { userContext: ctx, }); if (session !== undefined) { - const claimValidators = await (0, utils_1.getRequiredClaimValidators)( - session, - options === null || options === void 0 ? void 0 : options.overrideGlobalClaimValidators, - ctx - ); + const claimValidators = await recipe_1.default + .getInstanceOrThrowError() + .getRequiredClaimValidators( + session, + options === null || options === void 0 ? void 0 : options.overrideGlobalClaimValidators, + ctx + ); await session.assertClaims(claimValidators, ctx); } return session; @@ -206,7 +193,7 @@ class SessionWrapper { static getSessionInformation(sessionHandle, userContext) { return recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl.getSessionInformation({ sessionHandle, - userContext: (0, utils_2.getUserContext)(userContext), + userContext: (0, utils_1.getUserContext)(userContext), }); } static refreshSession(req, res, userContext) { @@ -216,7 +203,8 @@ class SessionWrapper { return (0, sessionRequestFunctions_1.refreshSessionInRequest)({ res, req, - userContext: (0, utils_2.getUserContext)(userContext), + stInstance: supertokens_1.default.getInstanceOrThrowError(), + userContext: (0, utils_1.getUserContext)(userContext), config, recipeInterfaceImpl, }); @@ -226,7 +214,7 @@ class SessionWrapper { refreshToken, disableAntiCsrf, antiCsrfToken, - userContext: (0, utils_2.getUserContext)(userContext), + userContext: (0, utils_1.getUserContext)(userContext), }); } static revokeAllSessionsForUser(userId, revokeSessionsForLinkedAccounts = true, tenantId, userContext) { @@ -235,7 +223,7 @@ class SessionWrapper { tenantId: tenantId === undefined ? constants_1.DEFAULT_TENANT_ID : tenantId, revokeAcrossAllTenants: tenantId === undefined, revokeSessionsForLinkedAccounts, - userContext: (0, utils_2.getUserContext)(userContext), + userContext: (0, utils_1.getUserContext)(userContext), }); } static getAllSessionHandlesForUser(userId, fetchSessionsForAllLinkedAccounts = true, tenantId, userContext) { @@ -244,33 +232,33 @@ class SessionWrapper { tenantId: tenantId === undefined ? constants_1.DEFAULT_TENANT_ID : tenantId, fetchAcrossAllTenants: tenantId === undefined, fetchSessionsForAllLinkedAccounts, - userContext: (0, utils_2.getUserContext)(userContext), + userContext: (0, utils_1.getUserContext)(userContext), }); } static revokeSession(sessionHandle, userContext) { return recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl.revokeSession({ sessionHandle, - userContext: (0, utils_2.getUserContext)(userContext), + userContext: (0, utils_1.getUserContext)(userContext), }); } static revokeMultipleSessions(sessionHandles, userContext) { return recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl.revokeMultipleSessions({ sessionHandles, - userContext: (0, utils_2.getUserContext)(userContext), + userContext: (0, utils_1.getUserContext)(userContext), }); } static updateSessionDataInDatabase(sessionHandle, newSessionData, userContext) { return recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl.updateSessionDataInDatabase({ sessionHandle, newSessionData, - userContext: (0, utils_2.getUserContext)(userContext), + userContext: (0, utils_1.getUserContext)(userContext), }); } static mergeIntoAccessTokenPayload(sessionHandle, accessTokenPayloadUpdate, userContext) { return recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl.mergeIntoAccessTokenPayload({ sessionHandle, accessTokenPayloadUpdate, - userContext: (0, utils_2.getUserContext)(userContext), + userContext: (0, utils_1.getUserContext)(userContext), }); } static createJWT(payload, validitySeconds, useStaticSigningKey, userContext) { @@ -278,24 +266,24 @@ class SessionWrapper { payload, validitySeconds, useStaticSigningKey, - userContext: (0, utils_2.getUserContext)(userContext), + userContext: (0, utils_1.getUserContext)(userContext), }); } static getJWKS(userContext) { return recipe_3.default.getInstanceOrThrowError().recipeInterfaceImpl.getJWKS({ - userContext: (0, utils_2.getUserContext)(userContext), + userContext: (0, utils_1.getUserContext)(userContext), }); } static getOpenIdDiscoveryConfiguration(userContext) { return recipe_2.default.getInstanceOrThrowError().recipeImplementation.getOpenIdDiscoveryConfiguration({ - userContext: (0, utils_2.getUserContext)(userContext), + userContext: (0, utils_1.getUserContext)(userContext), }); } static fetchAndSetClaim(sessionHandle, claim, userContext) { return recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl.fetchAndSetClaim({ sessionHandle, claim, - userContext: (0, utils_2.getUserContext)(userContext), + userContext: (0, utils_1.getUserContext)(userContext), }); } static setClaimValue(sessionHandle, claim, value, userContext) { @@ -303,21 +291,21 @@ class SessionWrapper { sessionHandle, claim, value, - userContext: (0, utils_2.getUserContext)(userContext), + userContext: (0, utils_1.getUserContext)(userContext), }); } static getClaimValue(sessionHandle, claim, userContext) { return recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl.getClaimValue({ sessionHandle, claim, - userContext: (0, utils_2.getUserContext)(userContext), + userContext: (0, utils_1.getUserContext)(userContext), }); } static removeClaim(sessionHandle, claim, userContext) { return recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl.removeClaim({ sessionHandle, claim, - userContext: (0, utils_2.getUserContext)(userContext), + userContext: (0, utils_1.getUserContext)(userContext), }); } } diff --git a/lib/build/recipe/session/recipe.d.ts b/lib/build/recipe/session/recipe.d.ts index b0c7fe68a..d377bb67c 100644 --- a/lib/build/recipe/session/recipe.d.ts +++ b/lib/build/recipe/session/recipe.d.ts @@ -8,11 +8,14 @@ import { VerifySessionOptions, SessionClaimValidator, SessionClaim, + SessionContainerInterface, } from "./types"; import STError from "./error"; import { NormalisedAppinfo, RecipeListFunction, APIHandled, HTTPMethod, UserContext } from "../../types"; import NormalisedURLPath from "../../normalisedURLPath"; import type { BaseRequest, BaseResponse } from "../../framework"; +import type SuperTokens from "../../supertokens"; +import { RecipeUserId } from "../.."; export default class SessionRecipe extends RecipeModule { private static instance; static RECIPE_ID: "session"; @@ -22,7 +25,13 @@ export default class SessionRecipe extends RecipeModule { recipeInterfaceImpl: RecipeInterface; apiImpl: APIInterface; isInServerlessEnv: boolean; - constructor(recipeId: string, appInfo: NormalisedAppinfo, isInServerlessEnv: boolean, config?: TypeInput); + constructor( + stInstance: SuperTokens, + recipeId: string, + appInfo: NormalisedAppinfo, + isInServerlessEnv: boolean, + config?: TypeInput + ); static getInstanceOrThrowError(): SessionRecipe; static init(config?: TypeInput): RecipeListFunction; static reset(): void; @@ -53,5 +62,25 @@ export default class SessionRecipe extends RecipeModule { request: BaseRequest, response: BaseResponse, userContext: UserContext - ) => Promise; + ) => Promise; + getRequiredClaimValidators: ( + session: SessionContainerInterface, + overrideGlobalClaimValidators: VerifySessionOptions["overrideGlobalClaimValidators"], + userContext: UserContext + ) => Promise; + createNewSession: (input: { + req: any; + res: any; + tenantId: string; + recipeUserId: RecipeUserId; + accessTokenPayload: any; + sessionDataInDatabase: any; + userContext: UserContext; + }) => Promise; + getSession: (input: { + req: any; + res: any; + options?: VerifySessionOptions; + userContext: UserContext; + }) => Promise; } diff --git a/lib/build/recipe/session/recipe.js b/lib/build/recipe/session/recipe.js index 914b6f8a0..7f4d937c2 100644 --- a/lib/build/recipe/session/recipe.js +++ b/lib/build/recipe/session/recipe.js @@ -28,17 +28,17 @@ const constants_1 = require("./constants"); const normalisedURLPath_1 = __importDefault(require("../../normalisedURLPath")); const cookieAndHeaders_1 = require("./cookieAndHeaders"); const recipeImplementation_1 = __importDefault(require("./recipeImplementation")); -const querier_1 = require("../../querier"); const implementation_1 = __importDefault(require("./api/implementation")); const supertokens_js_override_1 = __importDefault(require("supertokens-js-override")); const logger_1 = require("../../logger"); const combinedRemoteJWKSet_1 = require("../../combinedRemoteJWKSet"); const utils_2 = require("../../utils"); const plugins_1 = require("../../plugins"); +const sessionRequestFunctions_1 = require("./sessionRequestFunctions"); // For Express class SessionRecipe extends recipeModule_1.default { - constructor(recipeId, appInfo, isInServerlessEnv, config) { - super(recipeId, appInfo); + constructor(stInstance, recipeId, appInfo, isInServerlessEnv, config) { + super(stInstance, recipeId, appInfo); this.claimsAddedByOtherRecipes = []; this.claimValidatorsAddedByOtherRecipes = []; this.addClaimFromOtherRecipe = (claim) => { @@ -89,7 +89,7 @@ class SessionRecipe extends recipeModule_1.default { if (id === constants_1.REFRESH_API_PATH) { return await (0, refresh_1.default)(this.apiImpl, options, userContext); } else if (id === constants_1.SIGNOUT_API_PATH) { - return await (0, signout_1.default)(this.apiImpl, options, userContext); + return await (0, signout_1.default)(this.stInstance, this.apiImpl, options, userContext); } else { return false; } @@ -181,6 +181,55 @@ class SessionRecipe extends recipeModule_1.default { userContext, }); }; + this.getRequiredClaimValidators = async (session, overrideGlobalClaimValidators, userContext) => { + const claimValidatorsAddedByOtherRecipes = this.getClaimValidatorsAddedByOtherRecipes(); + const globalClaimValidators = await this.recipeInterfaceImpl.getGlobalClaimValidators({ + userId: session.getUserId(userContext), + recipeUserId: session.getRecipeUserId(userContext), + tenantId: session.getTenantId(userContext), + claimValidatorsAddedByOtherRecipes, + userContext, + }); + return overrideGlobalClaimValidators !== undefined + ? await overrideGlobalClaimValidators(globalClaimValidators, session, userContext) + : globalClaimValidators; + }; + this.createNewSession = async (input) => { + let user = await this.stInstance.getRecipeInstanceOrThrow("accountlinking").recipeInterfaceImpl.getUser({ + userId: input.recipeUserId.getAsString(), + userContext: input.userContext, + }); + let userId = input.recipeUserId.getAsString(); + if (user !== undefined) { + userId = user.id; + } + return await (0, sessionRequestFunctions_1.createNewSessionInRequest)({ + req: input.req, + res: input.res, + userContext: input.userContext, + recipeInstance: this, + stInstance: this.stInstance, + accessTokenPayload: input.accessTokenPayload, + userId, + recipeUserId: input.recipeUserId, + config: this.config, + appInfo: this.stInstance.appInfo, + sessionDataInDatabase: input.sessionDataInDatabase, + tenantId: input.tenantId, + }); + }; + this.getSession = async (input) => { + return (0, sessionRequestFunctions_1.getSessionFromRequest)({ + req: input.req, + res: input.res, + recipeInterfaceImpl: this.recipeInterfaceImpl, + recipeInstance: this, + stInstance: this.stInstance, + config: this.config, + options: input.options, + userContext: input.userContext, // userContext is normalized inside the function + }); + }; this.config = (0, utils_1.validateAndNormaliseUserInput)(this, appInfo, config); const antiCsrfToLog = typeof this.config.antiCsrfFunctionOrString === "string" @@ -201,7 +250,7 @@ class SessionRecipe extends recipeModule_1.default { this.isInServerlessEnv = isInServerlessEnv; let builder = new supertokens_js_override_1.default( (0, recipeImplementation_1.default)( - querier_1.Querier.getNewInstanceOrThrowError(recipeId), + this.querier, this.config, this.getAppInfo(), () => this.recipeInterfaceImpl @@ -209,7 +258,7 @@ class SessionRecipe extends recipeModule_1.default { ); this.recipeInterfaceImpl = builder.override(this.config.override.functions).build(); { - let builder = new supertokens_js_override_1.default((0, implementation_1.default)()); + let builder = new supertokens_js_override_1.default((0, implementation_1.default)(this.stInstance, this)); this.apiImpl = builder.override(this.config.override.apis).build(); } } @@ -222,9 +271,10 @@ class SessionRecipe extends recipeModule_1.default { ); } static init(config) { - return (appInfo, isInServerlessEnv, plugins) => { + return (stInstance, appInfo, isInServerlessEnv, plugins) => { if (SessionRecipe.instance === undefined) { SessionRecipe.instance = new SessionRecipe( + stInstance, SessionRecipe.RECIPE_ID, appInfo, isInServerlessEnv, diff --git a/lib/build/recipe/session/sessionFunctions.js b/lib/build/recipe/session/sessionFunctions.js index 0ffcef93e..0f4e3fc47 100644 --- a/lib/build/recipe/session/sessionFunctions.js +++ b/lib/build/recipe/session/sessionFunctions.js @@ -111,7 +111,7 @@ async function getSession( */ accessTokenInfo = await (0, accessToken_1.getInfoFromAccessToken)( parsedAccessToken, - (0, combinedRemoteJWKSet_1.getCombinedJWKS)(config), + (0, combinedRemoteJWKSet_1.getCombinedJWKS)(helpers.querier, config), helpers.config.antiCsrfFunctionOrString === "VIA_TOKEN" && doAntiCsrfCheck ); } catch (err) { diff --git a/lib/build/recipe/session/sessionRequestFunctions.d.ts b/lib/build/recipe/session/sessionRequestFunctions.d.ts index 46796682e..efc9898bd 100644 --- a/lib/build/recipe/session/sessionRequestFunctions.d.ts +++ b/lib/build/recipe/session/sessionRequestFunctions.d.ts @@ -1,5 +1,4 @@ // @ts-nocheck -import Recipe from "./recipe"; import { VerifySessionOptions, RecipeInterface, @@ -7,14 +6,18 @@ import { TypeNormalisedInput, SessionContainerInterface, } from "./types"; +import type SuperTokens from "../../supertokens"; import { ParsedJWTInfo } from "./jwt"; import { NormalisedAppinfo, UserContext } from "../../types"; import RecipeUserId from "../../recipeUserId"; +import type SessionRecipe from "./recipe"; export declare function getSessionFromRequest({ req, res, config, recipeInterfaceImpl, + recipeInstance, + stInstance, options, userContext, }: { @@ -22,6 +25,8 @@ export declare function getSessionFromRequest({ res: any; config: TypeNormalisedInput; recipeInterfaceImpl: RecipeInterface; + recipeInstance: SessionRecipe; + stInstance: SuperTokens; options?: VerifySessionOptions; userContext: UserContext; }): Promise; @@ -41,18 +46,21 @@ export declare function refreshSessionInRequest({ userContext, config, recipeInterfaceImpl, + stInstance, }: { res: any; req: any; userContext: UserContext; config: TypeNormalisedInput; recipeInterfaceImpl: RecipeInterface; + stInstance: SuperTokens; }): Promise; export declare function createNewSessionInRequest({ req, res, userContext, recipeInstance, + stInstance, accessTokenPayload, userId, recipeUserId, @@ -64,7 +72,8 @@ export declare function createNewSessionInRequest({ req: any; res: any; userContext: UserContext; - recipeInstance: Recipe; + recipeInstance: SessionRecipe; + stInstance: SuperTokens; accessTokenPayload: any; userId: string; recipeUserId: RecipeUserId; diff --git a/lib/build/recipe/session/sessionRequestFunctions.js b/lib/build/recipe/session/sessionRequestFunctions.js index 08e5f4e45..eafd8836c 100644 --- a/lib/build/recipe/session/sessionRequestFunctions.js +++ b/lib/build/recipe/session/sessionRequestFunctions.js @@ -10,21 +10,28 @@ exports.getAccessTokenFromRequest = getAccessTokenFromRequest; exports.refreshSessionInRequest = refreshSessionInRequest; exports.createNewSessionInRequest = createNewSessionInRequest; const framework_1 = __importDefault(require("../../framework")); -const supertokens_1 = __importDefault(require("../../supertokens")); -const recipe_1 = __importDefault(require("../openid/recipe")); -const utils_1 = require("./utils"); -const utils_2 = require("../../utils"); +const utils_1 = require("../../utils"); const logger_1 = require("../../logger"); const constants_1 = require("./constants"); const cookieAndHeaders_1 = require("./cookieAndHeaders"); const jwt_1 = require("./jwt"); const accessToken_1 = require("./accessToken"); const error_1 = __importDefault(require("./error")); +const normalisedURLDomain_1 = require("../../normalisedURLDomain"); // We are defining this here (and not exporting it) to reduce the scope of legacy code const LEGACY_ID_REFRESH_TOKEN_COOKIE_NAME = "sIdRefreshToken"; -async function getSessionFromRequest({ req, res, config, recipeInterfaceImpl, options, userContext }) { +async function getSessionFromRequest({ + req, + res, + config, + recipeInterfaceImpl, + recipeInstance, + stInstance, + options, + userContext, +}) { (0, logger_1.logDebugMessage)("getSession: Started"); - const configuredFramework = supertokens_1.default.getInstanceOrThrowError().framework; + const configuredFramework = stInstance.framework; if (configuredFramework !== "custom") { if (!req.wrapperUsed) { req = framework_1.default[configuredFramework].wrapRequest(req); @@ -33,7 +40,7 @@ async function getSessionFromRequest({ req, res, config, recipeInterfaceImpl, op res = framework_1.default[configuredFramework].wrapResponse(res); } } - userContext = (0, utils_2.setRequestInUserContextIfNotDefined)(userContext, req); + userContext = (0, utils_1.setRequestInUserContextIfNotDefined)(userContext, req); (0, logger_1.logDebugMessage)("getSession: Wrapping done"); // This token isn't handled by getToken to limit the scope of this legacy/migration code if (req.getCookieValue(LEGACY_ID_REFRESH_TOKEN_COOKIE_NAME) !== undefined) { @@ -62,7 +69,7 @@ async function getSessionFromRequest({ req, res, config, recipeInterfaceImpl, op let antiCsrfToken = (0, cookieAndHeaders_1.getAntiCsrfTokenFromHeaders)(req); let doAntiCsrfCheck = options !== undefined ? options.antiCsrfCheck : undefined; if (doAntiCsrfCheck === undefined) { - doAntiCsrfCheck = (0, utils_2.normaliseHttpMethod)(req.getMethod()) !== "get"; + doAntiCsrfCheck = (0, utils_1.normaliseHttpMethod)(req.getMethod()) !== "get"; } if (requestTransferMethod === "header") { doAntiCsrfCheck = false; @@ -81,7 +88,7 @@ async function getSessionFromRequest({ req, res, config, recipeInterfaceImpl, op } if (doAntiCsrfCheck && antiCsrf === "VIA_CUSTOM_HEADER") { if (antiCsrf === "VIA_CUSTOM_HEADER") { - if ((0, utils_2.getRidFromHeader)(req) === undefined) { + if ((0, utils_1.getRidFromHeader)(req) === undefined) { (0, logger_1.logDebugMessage)( "getSession: Returning TRY_REFRESH_TOKEN because custom header (rid) was not passed" ); @@ -103,7 +110,7 @@ async function getSessionFromRequest({ req, res, config, recipeInterfaceImpl, op userContext, }); if (session !== undefined) { - const claimValidators = await (0, utils_1.getRequiredClaimValidators)( + const claimValidators = await recipeInstance.getRequiredClaimValidators( session, options === null || options === void 0 ? void 0 : options.overrideGlobalClaimValidators, userContext @@ -189,9 +196,9 @@ function getAccessTokenFromRequest(config, req, allowedTransferMethod, userConte In all cases: if sIdRefreshToken token exists (so it's a legacy session) we clear it. Check http://localhost:3002/docs/contribute/decisions/session/0008 for further details and a table of expected behaviours */ -async function refreshSessionInRequest({ res, req, userContext, config, recipeInterfaceImpl }) { +async function refreshSessionInRequest({ res, req, userContext, config, recipeInterfaceImpl, stInstance }) { (0, logger_1.logDebugMessage)("refreshSession: Started"); - const configuredFramework = supertokens_1.default.getInstanceOrThrowError().framework; + const configuredFramework = stInstance.framework; if (configuredFramework !== "custom") { if (!req.wrapperUsed) { req = framework_1.default[configuredFramework].wrapRequest(req); @@ -200,7 +207,7 @@ async function refreshSessionInRequest({ res, req, userContext, config, recipeIn res = framework_1.default[configuredFramework].wrapResponse(res); } } - userContext = (0, utils_2.setRequestInUserContextIfNotDefined)(userContext, req); + userContext = (0, utils_1.setRequestInUserContextIfNotDefined)(userContext, req); (0, logger_1.logDebugMessage)("refreshSession: Wrapping done"); (0, cookieAndHeaders_1.clearSessionCookiesFromOlderCookieDomain)({ req, res, config, userContext }); const refreshTokens = {}; @@ -295,7 +302,7 @@ async function refreshSessionInRequest({ res, req, userContext, config, recipeIn }); } if (antiCsrf === "VIA_CUSTOM_HEADER" && !disableAntiCsrf) { - if ((0, utils_2.getRidFromHeader)(req) === undefined) { + if ((0, utils_1.getRidFromHeader)(req) === undefined) { (0, logger_1.logDebugMessage)( "refreshSession: Returning UNAUTHORISED because custom header (rid) was not passed" ); @@ -379,6 +386,7 @@ async function createNewSessionInRequest({ res, userContext, recipeInstance, + stInstance, accessTokenPayload, userId, recipeUserId, @@ -388,7 +396,7 @@ async function createNewSessionInRequest({ tenantId, }) { (0, logger_1.logDebugMessage)("createNewSession: Started"); - const configuredFramework = supertokens_1.default.getInstanceOrThrowError().framework; + const configuredFramework = stInstance.framework; if (configuredFramework !== "custom") { if (!req.wrapperUsed) { req = framework_1.default[configuredFramework].wrapRequest(req); @@ -398,9 +406,9 @@ async function createNewSessionInRequest({ } } (0, logger_1.logDebugMessage)("createNewSession: Wrapping done"); - userContext = (0, utils_2.setRequestInUserContextIfNotDefined)(userContext, req); + userContext = (0, utils_1.setRequestInUserContextIfNotDefined)(userContext, req); const claimsAddedByOtherRecipes = recipeInstance.getClaimsAddedByOtherRecipes(); - const issuer = await recipe_1.default.getIssuer(userContext); + const issuer = await stInstance.getRecipeInstanceOrThrow("openid").getIssuer(userContext); let finalAccessTokenPayload = Object.assign(Object.assign({}, accessTokenPayload), { iss: issuer }); for (const prop of constants_1.protectedProps) { delete finalAccessTokenPayload[prop]; @@ -429,12 +437,13 @@ async function createNewSessionInRequest({ }) === "none" && !config.cookieSecure && !( - (appInfo.topLevelAPIDomain === "localhost" || (0, utils_2.isAnIpAddress)(appInfo.topLevelAPIDomain)) && + (appInfo.topLevelAPIDomain === "localhost" || + (0, normalisedURLDomain_1.isAnIpAddress)(appInfo.topLevelAPIDomain)) && (appInfo.getTopLevelWebsiteDomain({ request: req, userContext, }) === "localhost" || - (0, utils_2.isAnIpAddress)( + (0, normalisedURLDomain_1.isAnIpAddress)( appInfo.getTopLevelWebsiteDomain({ request: req, userContext, diff --git a/lib/build/recipe/session/utils.d.ts b/lib/build/recipe/session/utils.d.ts index 02fa11722..aca325d00 100644 --- a/lib/build/recipe/session/utils.d.ts +++ b/lib/build/recipe/session/utils.d.ts @@ -4,12 +4,10 @@ import { TypeNormalisedInput, ClaimValidationError, SessionClaimValidator, - SessionContainerInterface, - VerifySessionOptions, TokenTransferMethod, TokenType, } from "./types"; -import SessionRecipe from "./recipe"; +import type SessionRecipe from "./recipe"; import { NormalisedAppinfo, UserContext } from "../../types"; import type { BaseRequest, BaseResponse } from "../../framework"; import RecipeUserId from "../../recipeUserId"; @@ -60,11 +58,6 @@ export declare function setAccessTokenInResponse( req: BaseRequest, userContext: UserContext ): void; -export declare function getRequiredClaimValidators( - session: SessionContainerInterface, - overrideGlobalClaimValidators: VerifySessionOptions["overrideGlobalClaimValidators"], - userContext: UserContext -): Promise; export declare function validateClaimsInPayload( claimValidators: SessionClaimValidator[], newAccessTokenPayload: any, diff --git a/lib/build/recipe/session/utils.js b/lib/build/recipe/session/utils.js index 20c44a3dc..8a8d7b3ee 100644 --- a/lib/build/recipe/session/utils.js +++ b/lib/build/recipe/session/utils.js @@ -28,17 +28,16 @@ exports.getURLProtocol = getURLProtocol; exports.validateAndNormaliseUserInput = validateAndNormaliseUserInput; exports.normaliseSameSiteOrThrowError = normaliseSameSiteOrThrowError; exports.setAccessTokenInResponse = setAccessTokenInResponse; -exports.getRequiredClaimValidators = getRequiredClaimValidators; exports.validateClaimsInPayload = validateClaimsInPayload; exports.getCookieNameForTokenType = getCookieNameForTokenType; exports.getResponseHeaderNameForTokenType = getResponseHeaderNameForTokenType; const cookieAndHeaders_1 = require("./cookieAndHeaders"); -const recipe_1 = __importDefault(require("./recipe")); const constants_1 = require("./constants"); const normalisedURLPath_1 = __importDefault(require("../../normalisedURLPath")); const utils_1 = require("../../utils"); const utils_2 = require("../../utils"); const logger_1 = require("../../logger"); +const normalisedURLDomain_1 = require("../../normalisedURLDomain"); async function sendTryRefreshTokenResponse(recipeInstance, _, __, response, ___) { (0, utils_2.sendNon200ResponseWithMessage)( response, @@ -86,7 +85,7 @@ function normaliseSessionScopeOrThrowError(sessionScope) { } } let noDotNormalised = helper(sessionScope); - if (noDotNormalised === "localhost" || (0, utils_1.isAnIpAddress)(noDotNormalised)) { + if (noDotNormalised === "localhost" || (0, normalisedURLDomain_1.isAnIpAddress)(noDotNormalised)) { return noDotNormalised; } if (sessionScope.startsWith(".")) { @@ -298,23 +297,6 @@ function setAccessTokenInResponse(res, accessToken, frontToken, config, transfer ); } } -async function getRequiredClaimValidators(session, overrideGlobalClaimValidators, userContext) { - const claimValidatorsAddedByOtherRecipes = recipe_1.default - .getInstanceOrThrowError() - .getClaimValidatorsAddedByOtherRecipes(); - const globalClaimValidators = await recipe_1.default - .getInstanceOrThrowError() - .recipeInterfaceImpl.getGlobalClaimValidators({ - userId: session.getUserId(userContext), - recipeUserId: session.getRecipeUserId(userContext), - tenantId: session.getTenantId(userContext), - claimValidatorsAddedByOtherRecipes, - userContext, - }); - return overrideGlobalClaimValidators !== undefined - ? await overrideGlobalClaimValidators(globalClaimValidators, session, userContext) - : globalClaimValidators; -} async function validateClaimsInPayload(claimValidators, newAccessTokenPayload, userContext) { const validationErrors = []; for (const validator of claimValidators) { diff --git a/lib/build/recipe/thirdparty/api/implementation.d.ts b/lib/build/recipe/thirdparty/api/implementation.d.ts index dd40e7025..d5395c7aa 100644 --- a/lib/build/recipe/thirdparty/api/implementation.d.ts +++ b/lib/build/recipe/thirdparty/api/implementation.d.ts @@ -1,3 +1,4 @@ // @ts-nocheck import { APIInterface } from "../"; -export default function getAPIInterface(): APIInterface; +import type SuperTokens from "../../../supertokens"; +export default function getAPIInterface(stInstance: SuperTokens): APIInterface; diff --git a/lib/build/recipe/thirdparty/api/implementation.js b/lib/build/recipe/thirdparty/api/implementation.js index 89684ce03..bafc4fd47 100644 --- a/lib/build/recipe/thirdparty/api/implementation.js +++ b/lib/build/recipe/thirdparty/api/implementation.js @@ -1,17 +1,10 @@ "use strict"; -var __importDefault = - (this && this.__importDefault) || - function (mod) { - return mod && mod.__esModule ? mod : { default: mod }; - }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = getAPIInterface; -const emailverification_1 = __importDefault(require("../../emailverification")); -const recipe_1 = __importDefault(require("../../emailverification/recipe")); const authUtils_1 = require("../../../authUtils"); const logger_1 = require("../../../logger"); const utils_1 = require("../../../utils"); -function getAPIInterface() { +function getAPIInterface(stInstance) { return { authorisationUrlGET: async function ({ provider, redirectURIOnProviderDashboard, userContext }) { const authUrl = await provider.getAuthorisationRedirectURL({ @@ -73,6 +66,7 @@ function getAPIInterface() { }; const authenticatingUser = await authUtils_1.AuthUtils.getAuthenticatingUserAndAddToCurrentTenantIfRequired( { + stInstance, accountInfo: { thirdParty: { userId: userInfo.thirdPartyUserId, @@ -99,15 +93,17 @@ function getAPIInterface() { // is verified on the user's account via supertokens on a previous sign in / up. // So we just check that as well before calling isEmailChangeAllowed const recipeUserId = authenticatingUser.loginMethod.recipeUserId; - if (!emailInfo.isVerified && recipe_1.default.getInstance() !== undefined) { - emailInfo.isVerified = await emailverification_1.default.isEmailVerified( - recipeUserId, - emailInfo.id, - userContext - ); + const emailVerificationRecipe = stInstance.getRecipeInstance("emailverification"); + if (!emailInfo.isVerified && emailVerificationRecipe !== undefined) { + emailInfo.isVerified = await emailVerificationRecipe.recipeInterfaceImpl.isEmailVerified({ + recipeUserId: recipeUserId, + email: emailInfo.id, + userContext, + }); } } const preAuthChecks = await authUtils_1.AuthUtils.preAuthChecks({ + stInstance, authenticatingAccountInfo: { recipeId, email: emailInfo.id, @@ -177,6 +173,7 @@ function getAPIInterface() { // of the user), it's OK to do this check here cause the preAuthChecks checks // conditions related to account linking const postAuthChecks = await authUtils_1.AuthUtils.postAuthChecks({ + stInstance, factorId: "thirdparty", isSignUp, authenticatedUser: response.user, diff --git a/lib/build/recipe/thirdparty/api/signinup.d.ts b/lib/build/recipe/thirdparty/api/signinup.d.ts index 06f84bb63..2156d58ae 100644 --- a/lib/build/recipe/thirdparty/api/signinup.d.ts +++ b/lib/build/recipe/thirdparty/api/signinup.d.ts @@ -1,7 +1,9 @@ // @ts-nocheck import { APIInterface, APIOptions } from "../"; import { UserContext } from "../../../types"; +import type SuperTokens from "../../../supertokens"; export default function signInUpAPI( + stInstance: SuperTokens, apiImplementation: APIInterface, tenantId: string, options: APIOptions, diff --git a/lib/build/recipe/thirdparty/api/signinup.js b/lib/build/recipe/thirdparty/api/signinup.js index ecf9310bf..ecc5802e2 100644 --- a/lib/build/recipe/thirdparty/api/signinup.js +++ b/lib/build/recipe/thirdparty/api/signinup.js @@ -23,7 +23,7 @@ exports.default = signInUpAPI; const error_1 = __importDefault(require("../error")); const utils_1 = require("../../../utils"); const authUtils_1 = require("../../../authUtils"); -async function signInUpAPI(apiImplementation, tenantId, options, userContext) { +async function signInUpAPI(stInstance, apiImplementation, tenantId, options, userContext) { if (apiImplementation.signInUpPOST === undefined) { return false; } @@ -72,6 +72,7 @@ async function signInUpAPI(apiImplementation, tenantId, options, userContext) { bodyParams ); const session = await authUtils_1.AuthUtils.loadSessionInAuthAPIIfNeeded( + stInstance, options.req, options.res, shouldTryLinkingWithSessionUser, diff --git a/lib/build/recipe/thirdparty/providers/configUtils.d.ts b/lib/build/recipe/thirdparty/providers/configUtils.d.ts index c4e9bbe88..b192f467c 100644 --- a/lib/build/recipe/thirdparty/providers/configUtils.d.ts +++ b/lib/build/recipe/thirdparty/providers/configUtils.d.ts @@ -1,16 +1,6 @@ // @ts-nocheck import { UserContext } from "../../../types"; -import { - ProviderClientConfig, - ProviderConfig, - ProviderConfigForClientType, - ProviderInput, - TypeProvider, -} from "../types"; -export declare function getProviderConfigForClient( - providerConfig: ProviderConfig, - clientConfig: ProviderClientConfig -): ProviderConfigForClientType; +import { ProviderConfig, ProviderInput, TypeProvider } from "../types"; export declare function findAndCreateProviderInstance( providers: ProviderInput[], thirdPartyId: string, diff --git a/lib/build/recipe/thirdparty/providers/configUtils.js b/lib/build/recipe/thirdparty/providers/configUtils.js index 830afb4b6..28a1517b7 100644 --- a/lib/build/recipe/thirdparty/providers/configUtils.js +++ b/lib/build/recipe/thirdparty/providers/configUtils.js @@ -5,16 +5,12 @@ var __importDefault = return mod && mod.__esModule ? mod : { default: mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.getProviderConfigForClient = getProviderConfigForClient; exports.findAndCreateProviderInstance = findAndCreateProviderInstance; exports.mergeConfig = mergeConfig; exports.mergeProvidersFromCoreAndStatic = mergeProvidersFromCoreAndStatic; const _1 = require("."); const custom_1 = __importDefault(require("./custom")); const utils_1 = require("./utils"); -function getProviderConfigForClient(providerConfig, clientConfig) { - return Object.assign(Object.assign({}, providerConfig), clientConfig); -} async function fetchAndSetConfig(provider, clientType, userContext) { let config = await provider.getConfigForClientType({ clientType, userContext }); await (0, utils_1.discoverOIDCEndpoints)(config); diff --git a/lib/build/recipe/thirdparty/providers/custom.js b/lib/build/recipe/thirdparty/providers/custom.js index 439999764..be39e69ff 100644 --- a/lib/build/recipe/thirdparty/providers/custom.js +++ b/lib/build/recipe/thirdparty/providers/custom.js @@ -12,7 +12,6 @@ exports.default = NewProvider; const thirdpartyUtils_1 = require("../../../thirdpartyUtils"); const utils_1 = require("../../../utils"); const pkce_challenge_1 = __importDefault(require("pkce-challenge")); -const configUtils_1 = require("./configUtils"); const jose_1 = require("jose"); const logger_1 = require("../../../logger"); const DEV_OAUTH_AUTHORIZATION_URL = "https://supertokens.io/dev/oauth/redirect-to-provider"; @@ -26,6 +25,9 @@ const DEV_KEY_IDENTIFIER = "4398792-"; function isUsingDevelopmentClientId(client_id) { return client_id.startsWith(DEV_KEY_IDENTIFIER) || DEV_OAUTH_CLIENT_IDS.includes(client_id); } +function getProviderConfigForClient(providerConfig, clientConfig) { + return Object.assign(Object.assign({}, providerConfig), clientConfig); +} function getActualClientIdFromDevelopmentClientId(client_id) { if (client_id.startsWith(DEV_KEY_IDENTIFIER)) { return client_id.split(DEV_KEY_IDENTIFIER)[1]; @@ -167,12 +169,12 @@ function NewProvider(input) { if (input.config.clients === undefined || input.config.clients.length !== 1) { throw new Error("please provide exactly one client config or pass clientType or tenantId"); } - return (0, configUtils_1.getProviderConfigForClient)(input.config, input.config.clients[0]); + return getProviderConfigForClient(input.config, input.config.clients[0]); } if (input.config.clients !== undefined) { for (const client of input.config.clients) { if (client.clientType === clientType) { - return (0, configUtils_1.getProviderConfigForClient)(input.config, client); + return getProviderConfigForClient(input.config, client); } } } diff --git a/lib/build/recipe/thirdparty/providers/utils.js b/lib/build/recipe/thirdparty/providers/utils.js index 377f57c55..2172cea1b 100644 --- a/lib/build/recipe/thirdparty/providers/utils.js +++ b/lib/build/recipe/thirdparty/providers/utils.js @@ -67,7 +67,7 @@ const thirdpartyUtils_1 = require("../../../thirdpartyUtils"); const normalisedURLDomain_1 = __importDefault(require("../../../normalisedURLDomain")); const normalisedURLPath_1 = __importDefault(require("../../../normalisedURLPath")); const logger_1 = require("../../../logger"); -const utils_1 = require("../../../utils"); +const querier_1 = require("../../../querier"); async function doGetRequest(url, queryParams, headers) { (0, logger_1.logDebugMessage)( `GET request to ${url}, with query params ${JSON.stringify(queryParams)} and headers ${JSON.stringify(headers)}` @@ -77,7 +77,7 @@ async function doGetRequest(url, queryParams, headers) { } const finalURL = new URL(url); finalURL.search = new URLSearchParams(queryParams).toString(); - let response = await (0, utils_1.doFetch)(finalURL.toString(), { + let response = await (0, querier_1.doFetch)(finalURL.toString(), { headers: headers, }); const stringResponse = await response.text(); @@ -102,7 +102,7 @@ async function doPostRequest(url, params, headers) { `POST request to ${url}, with params ${JSON.stringify(params)} and headers ${JSON.stringify(headers)}` ); const body = new URLSearchParams(params).toString(); - let response = await (0, utils_1.doFetch)(url, { + let response = await (0, querier_1.doFetch)(url, { method: "POST", body, headers, diff --git a/lib/build/recipe/thirdparty/recipe.d.ts b/lib/build/recipe/thirdparty/recipe.d.ts index 163ba5523..993a1f01a 100644 --- a/lib/build/recipe/thirdparty/recipe.d.ts +++ b/lib/build/recipe/thirdparty/recipe.d.ts @@ -5,6 +5,7 @@ import { TypeInput, TypeNormalisedInput, RecipeInterface, APIInterface, Provider import STError from "./error"; import NormalisedURLPath from "../../normalisedURLPath"; import type { BaseRequest, BaseResponse } from "../../framework"; +import type SuperTokens from "../../supertokens"; export default class Recipe extends RecipeModule { private static instance; static RECIPE_ID: "thirdparty"; @@ -14,6 +15,7 @@ export default class Recipe extends RecipeModule { apiImpl: APIInterface; isInServerlessEnv: boolean; constructor( + stInstance: SuperTokens, recipeId: string, appInfo: NormalisedAppinfo, isInServerlessEnv: boolean, diff --git a/lib/build/recipe/thirdparty/recipe.js b/lib/build/recipe/thirdparty/recipe.js index fd805cdc1..3070c3018 100644 --- a/lib/build/recipe/thirdparty/recipe.js +++ b/lib/build/recipe/thirdparty/recipe.js @@ -21,7 +21,6 @@ var __importDefault = Object.defineProperty(exports, "__esModule", { value: true }); const recipeModule_1 = __importDefault(require("../../recipeModule")); const utils_1 = require("./utils"); -const recipe_1 = __importDefault(require("../multitenancy/recipe")); const error_1 = __importDefault(require("./error")); const constants_1 = require("./constants"); const normalisedURLPath_1 = __importDefault(require("../../normalisedURLPath")); @@ -29,7 +28,6 @@ const signinup_1 = __importDefault(require("./api/signinup")); const authorisationUrl_1 = __importDefault(require("./api/authorisationUrl")); const recipeImplementation_1 = __importDefault(require("./recipeImplementation")); const implementation_1 = __importDefault(require("./api/implementation")); -const querier_1 = require("../../querier"); const appleRedirect_1 = __importDefault(require("./api/appleRedirect")); const supertokens_js_override_1 = __importDefault(require("supertokens-js-override")); const postSuperTokensInitCallbacks_1 = require("../../postSuperTokensInitCallbacks"); @@ -37,8 +35,8 @@ const multifactorauth_1 = require("../multifactorauth"); const utils_2 = require("../../utils"); const plugins_1 = require("../../plugins"); class Recipe extends recipeModule_1.default { - constructor(recipeId, appInfo, isInServerlessEnv, config, _recipes, _ingredients) { - super(recipeId, appInfo); + constructor(stInstance, recipeId, appInfo, isInServerlessEnv, config, _recipes, _ingredients) { + super(stInstance, recipeId, appInfo); this.getAPIsHandled = () => { return [ { @@ -73,7 +71,7 @@ class Recipe extends recipeModule_1.default { appInfo: this.getAppInfo(), }; if (id === constants_1.SIGN_IN_UP_API) { - return await (0, signinup_1.default)(this.apiImpl, tenantId, options, userContext); + return await (0, signinup_1.default)(this.stInstance, this.apiImpl, tenantId, options, userContext); } else if (id === constants_1.AUTHORISATION_API) { return await (0, authorisationUrl_1.default)(this.apiImpl, tenantId, options, userContext); } else if (id === constants_1.APPLE_REDIRECT_HANDLER) { @@ -95,19 +93,16 @@ class Recipe extends recipeModule_1.default { this.providers = this.config.signInAndUpFeature.providers; { let builder = new supertokens_js_override_1.default( - (0, recipeImplementation_1.default)( - querier_1.Querier.getNewInstanceOrThrowError(recipeId), - this.providers - ) + (0, recipeImplementation_1.default)(this.stInstance, this.querier, this.providers) ); this.recipeInterfaceImpl = builder.override(this.config.override.functions).build(); } { - let builder = new supertokens_js_override_1.default((0, implementation_1.default)()); + let builder = new supertokens_js_override_1.default((0, implementation_1.default)(stInstance)); this.apiImpl = builder.override(this.config.override.apis).build(); } postSuperTokensInitCallbacks_1.PostSuperTokensInitCallbacks.addPostInitCallback(() => { - const mtRecipe = recipe_1.default.getInstance(); + const mtRecipe = stInstance.getRecipeInstance("multitenancy"); if (mtRecipe !== undefined) { mtRecipe.staticThirdPartyProviders = this.config.signInAndUpFeature.providers; mtRecipe.allAvailableFirstFactors.push(multifactorauth_1.FactorIds.THIRDPARTY); @@ -115,9 +110,10 @@ class Recipe extends recipeModule_1.default { }); } static init(config) { - return (appInfo, isInServerlessEnv, plugins) => { + return (stInstance, appInfo, isInServerlessEnv, plugins) => { if (Recipe.instance === undefined) { Recipe.instance = new Recipe( + stInstance, Recipe.RECIPE_ID, appInfo, isInServerlessEnv, diff --git a/lib/build/recipe/thirdparty/recipeImplementation.d.ts b/lib/build/recipe/thirdparty/recipeImplementation.d.ts index 5a45b7285..3cf58cc20 100644 --- a/lib/build/recipe/thirdparty/recipeImplementation.d.ts +++ b/lib/build/recipe/thirdparty/recipeImplementation.d.ts @@ -1,4 +1,9 @@ // @ts-nocheck import { RecipeInterface, ProviderInput } from "./types"; import { Querier } from "../../querier"; -export default function getRecipeImplementation(querier: Querier, providers: ProviderInput[]): RecipeInterface; +import type SuperTokens from "../../supertokens"; +export default function getRecipeImplementation( + stInstance: SuperTokens, + querier: Querier, + providers: ProviderInput[] +): RecipeInterface; diff --git a/lib/build/recipe/thirdparty/recipeImplementation.js b/lib/build/recipe/thirdparty/recipeImplementation.js index 90ed9a2b0..5538570a0 100644 --- a/lib/build/recipe/thirdparty/recipeImplementation.js +++ b/lib/build/recipe/thirdparty/recipeImplementation.js @@ -7,14 +7,11 @@ var __importDefault = Object.defineProperty(exports, "__esModule", { value: true }); exports.default = getRecipeImplementation; const configUtils_1 = require("./providers/configUtils"); -const recipe_1 = __importDefault(require("../accountlinking/recipe")); -const recipe_2 = __importDefault(require("../multitenancy/recipe")); const recipeUserId_1 = __importDefault(require("../../recipeUserId")); -const __1 = require("../.."); const user_1 = require("../../user"); const authUtils_1 = require("../../authUtils"); const constants_1 = require("../multitenancy/constants"); -function getRecipeImplementation(querier, providers) { +function getRecipeImplementation(stInstance, querier, providers) { return { manuallyCreateOrUpdateUser: async function ({ thirdPartyId, @@ -26,13 +23,13 @@ function getRecipeImplementation(querier, providers) { shouldTryLinkingWithSessionUser, userContext, }) { - const accountLinking = recipe_1.default.getInstanceOrThrowError(); - const users = await (0, __1.listUsersByAccountInfo)( + const accountLinking = stInstance.getRecipeInstanceOrThrow("accountlinking"); + const users = await accountLinking.recipeInterfaceImpl.listUsersByAccountInfo({ tenantId, - { thirdParty: { id: thirdPartyId, userId: thirdPartyUserId } }, - false, - userContext - ); + accountInfo: { thirdParty: { id: thirdPartyId, userId: thirdPartyUserId } }, + doUnionOfAccountInfo: false, + userContext, + }); const user = users[0]; if (user !== undefined) { const isEmailChangeAllowed = await accountLinking.isEmailChangeAllowed({ @@ -71,16 +68,20 @@ function getRecipeImplementation(querier, providers) { } let userAsObj = user_1.User.fromApi(response.user); const recipeUserIdAsObj = new recipeUserId_1.default(response.recipeUserId); - await recipe_1.default.getInstanceOrThrowError().verifyEmailForRecipeUserIfLinkedAccountsAreVerified({ + await accountLinking.verifyEmailForRecipeUserIfLinkedAccountsAreVerified({ user: userAsObj, recipeUserId: recipeUserIdAsObj, userContext, }); // we do this so that we get the updated user (in case the above // function updated the verification status) and can return that - userAsObj = await (0, __1.getUser)(recipeUserIdAsObj.getAsString(), userContext); + userAsObj = await accountLinking.recipeInterfaceImpl.getUser({ + userId: recipeUserIdAsObj.getAsString(), + userContext, + }); const linkResult = await authUtils_1.AuthUtils.linkToSessionIfRequiredElseCreatePrimaryUserIdOrLinkByAccountInfo({ + stInstance, tenantId, shouldTryLinkingWithSessionUser, inputUser: userAsObj, @@ -135,7 +136,7 @@ function getRecipeImplementation(querier, providers) { return response; }, getProvider: async function ({ thirdPartyId, tenantId, clientType, userContext }) { - const mtRecipe = recipe_2.default.getInstanceOrThrowError(); + const mtRecipe = stInstance.getRecipeInstanceOrThrow("multitenancy"); const tenantConfig = await mtRecipe.recipeInterfaceImpl.getTenant({ tenantId, userContext }); if (tenantConfig === undefined) { throw new Error("Tenant not found"); diff --git a/lib/build/recipe/totp/api/createDevice.d.ts b/lib/build/recipe/totp/api/createDevice.d.ts index aaa135298..c60e135b0 100644 --- a/lib/build/recipe/totp/api/createDevice.d.ts +++ b/lib/build/recipe/totp/api/createDevice.d.ts @@ -1,7 +1,9 @@ // @ts-nocheck import { APIInterface, APIOptions } from ".."; import { UserContext } from "../../../types"; +import type SuperTokens from "../../../supertokens"; export default function createDeviceAPI( + stInstance: SuperTokens, apiImplementation: APIInterface, options: APIOptions, userContext: UserContext diff --git a/lib/build/recipe/totp/api/createDevice.js b/lib/build/recipe/totp/api/createDevice.js index 3527e4448..9ad620cef 100644 --- a/lib/build/recipe/totp/api/createDevice.js +++ b/lib/build/recipe/totp/api/createDevice.js @@ -13,25 +13,19 @@ * License for the specific language governing permissions and limitations * under the License. */ -var __importDefault = - (this && this.__importDefault) || - function (mod) { - return mod && mod.__esModule ? mod : { default: mod }; - }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = createDeviceAPI; const utils_1 = require("../../../utils"); -const session_1 = __importDefault(require("../../session")); -async function createDeviceAPI(apiImplementation, options, userContext) { +async function createDeviceAPI(stInstance, apiImplementation, options, userContext) { if (apiImplementation.createDevicePOST === undefined) { return false; } - const session = await session_1.default.getSession( - options.req, - options.res, - { overrideGlobalClaimValidators: () => [], sessionRequired: true }, - userContext - ); + const session = await stInstance.getRecipeInstanceOrThrow("session").getSession({ + req: options.req, + res: options.res, + options: { overrideGlobalClaimValidators: () => [], sessionRequired: true }, + userContext, + }); const bodyParams = await options.req.getJSONBody(); const deviceName = bodyParams.deviceName; if (deviceName !== undefined && typeof deviceName !== "string") { @@ -40,7 +34,7 @@ async function createDeviceAPI(apiImplementation, options, userContext) { let response = await apiImplementation.createDevicePOST({ deviceName, options, - session, + session: session, userContext, }); (0, utils_1.send200Response)(options.res, response); diff --git a/lib/build/recipe/totp/api/implementation.d.ts b/lib/build/recipe/totp/api/implementation.d.ts index dd40e7025..d5395c7aa 100644 --- a/lib/build/recipe/totp/api/implementation.d.ts +++ b/lib/build/recipe/totp/api/implementation.d.ts @@ -1,3 +1,4 @@ // @ts-nocheck import { APIInterface } from "../"; -export default function getAPIInterface(): APIInterface; +import type SuperTokens from "../../../supertokens"; +export default function getAPIInterface(stInstance: SuperTokens): APIInterface; diff --git a/lib/build/recipe/totp/api/implementation.js b/lib/build/recipe/totp/api/implementation.js index f2869fe9d..8aa66cd25 100644 --- a/lib/build/recipe/totp/api/implementation.js +++ b/lib/build/recipe/totp/api/implementation.js @@ -13,58 +13,6 @@ * License for the specific language governing permissions and limitations * under the License. */ -var __createBinding = - (this && this.__createBinding) || - (Object.create - ? function (o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { - enumerable: true, - get: function () { - return m[k]; - }, - }; - } - Object.defineProperty(o, k2, desc); - } - : function (o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; - }); -var __setModuleDefault = - (this && this.__setModuleDefault) || - (Object.create - ? function (o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); - } - : function (o, v) { - o["default"] = v; - }); -var __importStar = - (this && this.__importStar) || - (function () { - var ownKeys = function (o) { - ownKeys = - Object.getOwnPropertyNames || - function (o) { - var ar = []; - for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; - return ar; - }; - return ownKeys(o); - }; - return function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) - for (var k = ownKeys(mod), i = 0; i < k.length; i++) - if (k[i] !== "default") __createBinding(result, mod, k[i]); - __setModuleDefault(result, mod); - return result; - }; - })(); var __importDefault = (this && this.__importDefault) || function (mod) { @@ -72,22 +20,16 @@ var __importDefault = }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = getAPIInterface; -const multifactorauth_1 = __importStar(require("../../multifactorauth")); -const recipe_1 = __importDefault(require("../../multifactorauth/recipe")); const error_1 = __importDefault(require("../../session/error")); -function getAPIInterface() { +function getAPIInterface(stInstance) { return { createDevicePOST: async function ({ deviceName, options, session, userContext }) { const userId = session.getUserId(); - let mfaInstance = recipe_1.default.getInstance(); + let mfaInstance = stInstance.getRecipeInstance("multifactorauth"); if (mfaInstance === undefined) { throw new Error("should never come here"); // If TOTP initialised, MFA is auto initialised. This should never happen. } - await multifactorauth_1.default.assertAllowedToSetupFactorElseThrowInvalidClaimError( - session, - "totp", - userContext - ); + await mfaInstance.assertAllowedToSetupFactorElseThrowInvalidClaimError(session, "totp", userContext); const createDeviceRes = await options.recipeImplementation.createDevice({ userId, deviceName: deviceName, @@ -117,7 +59,9 @@ function getAPIInterface() { }); if (deviceList.devices.some((device) => device.name === deviceName && device.verified)) { await session.assertClaims([ - multifactorauth_1.MultiFactorAuthClaim.validators.hasCompletedMFARequirementsForAuth(), + stInstance + .getRecipeInstanceOrThrow("multifactorauth") + .multiFactorAuthClaim.validators.hasCompletedMFARequirementsForAuth(), ]); } return await options.recipeImplementation.removeDevice({ @@ -129,15 +73,11 @@ function getAPIInterface() { verifyDevicePOST: async function ({ deviceName, totp, options, session, userContext }) { const userId = session.getUserId(); const tenantId = session.getTenantId(); - const mfaInstance = recipe_1.default.getInstance(); + const mfaInstance = stInstance.getRecipeInstance("multifactorauth"); if (mfaInstance === undefined) { throw new Error("should never come here"); // If TOTP initialised, MFA is auto initialised. This should never happen. } - await multifactorauth_1.default.assertAllowedToSetupFactorElseThrowInvalidClaimError( - session, - "totp", - userContext - ); + await mfaInstance.assertAllowedToSetupFactorElseThrowInvalidClaimError(session, "totp", userContext); const res = await options.recipeImplementation.verifyDevice({ tenantId, userId, @@ -157,7 +97,7 @@ function getAPIInterface() { verifyTOTPPOST: async function ({ totp, options, session, userContext }) { const userId = session.getUserId(); const tenantId = session.getTenantId(); - const mfaInstance = recipe_1.default.getInstance(); + const mfaInstance = stInstance.getRecipeInstance("multifactorauth"); if (mfaInstance === undefined) { throw new Error("should never come here"); // If TOTP initialised, MFA is auto initialised. This should never happen. } diff --git a/lib/build/recipe/totp/api/listDevices.d.ts b/lib/build/recipe/totp/api/listDevices.d.ts index d6ba65d69..ae9581f11 100644 --- a/lib/build/recipe/totp/api/listDevices.d.ts +++ b/lib/build/recipe/totp/api/listDevices.d.ts @@ -1,7 +1,9 @@ // @ts-nocheck import { APIInterface, APIOptions } from ".."; import { UserContext } from "../../../types"; +import type SuperTokens from "../../../supertokens"; export default function listDevicesAPI( + stInstance: SuperTokens, apiImplementation: APIInterface, options: APIOptions, userContext: UserContext diff --git a/lib/build/recipe/totp/api/listDevices.js b/lib/build/recipe/totp/api/listDevices.js index ba27614a0..f9fdb9df1 100644 --- a/lib/build/recipe/totp/api/listDevices.js +++ b/lib/build/recipe/totp/api/listDevices.js @@ -13,28 +13,22 @@ * License for the specific language governing permissions and limitations * under the License. */ -var __importDefault = - (this && this.__importDefault) || - function (mod) { - return mod && mod.__esModule ? mod : { default: mod }; - }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = listDevicesAPI; const utils_1 = require("../../../utils"); -const session_1 = __importDefault(require("../../session")); -async function listDevicesAPI(apiImplementation, options, userContext) { +async function listDevicesAPI(stInstance, apiImplementation, options, userContext) { if (apiImplementation.listDevicesGET === undefined) { return false; } - const session = await session_1.default.getSession( - options.req, - options.res, - { overrideGlobalClaimValidators: () => [], sessionRequired: true }, - userContext - ); + const session = await stInstance.getRecipeInstanceOrThrow("session").getSession({ + req: options.req, + res: options.res, + options: { overrideGlobalClaimValidators: () => [], sessionRequired: true }, + userContext, + }); let response = await apiImplementation.listDevicesGET({ options, - session, + session: session, userContext, }); (0, utils_1.send200Response)(options.res, response); diff --git a/lib/build/recipe/totp/api/removeDevice.d.ts b/lib/build/recipe/totp/api/removeDevice.d.ts index 047515bef..c67a7a4a5 100644 --- a/lib/build/recipe/totp/api/removeDevice.d.ts +++ b/lib/build/recipe/totp/api/removeDevice.d.ts @@ -1,7 +1,9 @@ // @ts-nocheck import { APIInterface, APIOptions } from ".."; import { UserContext } from "../../../types"; +import SuperTokens from "../../../supertokens"; export default function removeDeviceAPI( + stInstance: SuperTokens, apiImplementation: APIInterface, options: APIOptions, userContext: UserContext diff --git a/lib/build/recipe/totp/api/removeDevice.js b/lib/build/recipe/totp/api/removeDevice.js index 7493444ac..e2cffe919 100644 --- a/lib/build/recipe/totp/api/removeDevice.js +++ b/lib/build/recipe/totp/api/removeDevice.js @@ -13,28 +13,19 @@ * License for the specific language governing permissions and limitations * under the License. */ -var __importDefault = - (this && this.__importDefault) || - function (mod) { - return mod && mod.__esModule ? mod : { default: mod }; - }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = removeDeviceAPI; const utils_1 = require("../../../utils"); -const session_1 = __importDefault(require("../../session")); -async function removeDeviceAPI(apiImplementation, options, userContext) { +async function removeDeviceAPI(stInstance, apiImplementation, options, userContext) { if (apiImplementation.removeDevicePOST === undefined) { return false; } - const session = await session_1.default.getSession( - options.req, - options.res, - { - overrideGlobalClaimValidators: () => [], - sessionRequired: true, - }, - userContext - ); + const session = await stInstance.getRecipeInstanceOrThrow("session").getSession({ + req: options.req, + res: options.res, + options: { overrideGlobalClaimValidators: () => [], sessionRequired: true }, + userContext, + }); const bodyParams = await options.req.getJSONBody(); const deviceName = bodyParams.deviceName; if (deviceName === undefined || typeof deviceName !== "string" || deviceName.length === 0) { @@ -43,7 +34,7 @@ async function removeDeviceAPI(apiImplementation, options, userContext) { let response = await apiImplementation.removeDevicePOST({ deviceName, options, - session, + session: session, userContext, }); (0, utils_1.send200Response)(options.res, response); diff --git a/lib/build/recipe/totp/api/verifyDevice.d.ts b/lib/build/recipe/totp/api/verifyDevice.d.ts index d4de4bcc9..b0fabd8f1 100644 --- a/lib/build/recipe/totp/api/verifyDevice.d.ts +++ b/lib/build/recipe/totp/api/verifyDevice.d.ts @@ -1,7 +1,9 @@ // @ts-nocheck import { APIInterface, APIOptions } from ".."; import { UserContext } from "../../../types"; +import SuperTokens from "../../../supertokens"; export default function verifyDeviceAPI( + stInstance: SuperTokens, apiImplementation: APIInterface, options: APIOptions, userContext: UserContext diff --git a/lib/build/recipe/totp/api/verifyDevice.js b/lib/build/recipe/totp/api/verifyDevice.js index 0b1e41f24..66105ca8a 100644 --- a/lib/build/recipe/totp/api/verifyDevice.js +++ b/lib/build/recipe/totp/api/verifyDevice.js @@ -13,25 +13,19 @@ * License for the specific language governing permissions and limitations * under the License. */ -var __importDefault = - (this && this.__importDefault) || - function (mod) { - return mod && mod.__esModule ? mod : { default: mod }; - }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = verifyDeviceAPI; const utils_1 = require("../../../utils"); -const session_1 = __importDefault(require("../../session")); -async function verifyDeviceAPI(apiImplementation, options, userContext) { +async function verifyDeviceAPI(stInstance, apiImplementation, options, userContext) { if (apiImplementation.verifyDevicePOST === undefined) { return false; } - const session = await session_1.default.getSession( - options.req, - options.res, - { overrideGlobalClaimValidators: () => [], sessionRequired: true }, - userContext - ); + const session = await stInstance.getRecipeInstanceOrThrow("session").getSession({ + req: options.req, + res: options.res, + options: { overrideGlobalClaimValidators: () => [], sessionRequired: true }, + userContext, + }); const bodyParams = await options.req.getJSONBody(); const deviceName = bodyParams.deviceName; const totp = bodyParams.totp; @@ -45,7 +39,7 @@ async function verifyDeviceAPI(apiImplementation, options, userContext) { deviceName, totp, options, - session, + session: session, userContext, }); (0, utils_1.send200Response)(options.res, response); diff --git a/lib/build/recipe/totp/api/verifyTOTP.d.ts b/lib/build/recipe/totp/api/verifyTOTP.d.ts index 925a9f40a..292488518 100644 --- a/lib/build/recipe/totp/api/verifyTOTP.d.ts +++ b/lib/build/recipe/totp/api/verifyTOTP.d.ts @@ -1,7 +1,9 @@ // @ts-nocheck import { APIInterface, APIOptions } from ".."; import { UserContext } from "../../../types"; +import type SuperTokens from "../../../supertokens"; export default function verifyTOTPAPI( + stInstance: SuperTokens, apiImplementation: APIInterface, options: APIOptions, userContext: UserContext diff --git a/lib/build/recipe/totp/api/verifyTOTP.js b/lib/build/recipe/totp/api/verifyTOTP.js index 732e0e780..f3cc551e1 100644 --- a/lib/build/recipe/totp/api/verifyTOTP.js +++ b/lib/build/recipe/totp/api/verifyTOTP.js @@ -13,25 +13,19 @@ * License for the specific language governing permissions and limitations * under the License. */ -var __importDefault = - (this && this.__importDefault) || - function (mod) { - return mod && mod.__esModule ? mod : { default: mod }; - }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = verifyTOTPAPI; const utils_1 = require("../../../utils"); -const session_1 = __importDefault(require("../../session")); -async function verifyTOTPAPI(apiImplementation, options, userContext) { +async function verifyTOTPAPI(stInstance, apiImplementation, options, userContext) { if (apiImplementation.verifyTOTPPOST === undefined) { return false; } - const session = await session_1.default.getSession( - options.req, - options.res, - { overrideGlobalClaimValidators: () => [], sessionRequired: true }, - userContext - ); + const session = await stInstance.getRecipeInstanceOrThrow("session").getSession({ + req: options.req, + res: options.res, + options: { overrideGlobalClaimValidators: () => [], sessionRequired: true }, + userContext, + }); const bodyParams = await options.req.getJSONBody(); const totp = bodyParams.totp; if (totp === undefined || typeof totp !== "string") { @@ -40,7 +34,7 @@ async function verifyTOTPAPI(apiImplementation, options, userContext) { let response = await apiImplementation.verifyTOTPPOST({ totp, options, - session, + session: session, userContext, }); (0, utils_1.send200Response)(options.res, response); diff --git a/lib/build/recipe/totp/recipe.d.ts b/lib/build/recipe/totp/recipe.d.ts index 31a45bff8..c9f537702 100644 --- a/lib/build/recipe/totp/recipe.d.ts +++ b/lib/build/recipe/totp/recipe.d.ts @@ -1,10 +1,11 @@ // @ts-nocheck -import { BaseRequest, BaseResponse } from "../../framework"; +import type { BaseRequest, BaseResponse } from "../../framework"; import NormalisedURLPath from "../../normalisedURLPath"; import RecipeModule from "../../recipeModule"; import STError from "../../error"; import { APIHandled, HTTPMethod, NormalisedAppinfo, RecipeListFunction, UserContext } from "../../types"; import { APIInterface, RecipeInterface, TypeInput, TypeNormalisedInput } from "./types"; +import type SuperTokens from "../../supertokens"; export default class Recipe extends RecipeModule { private static instance; static RECIPE_ID: "totp"; @@ -12,7 +13,13 @@ export default class Recipe extends RecipeModule { recipeInterfaceImpl: RecipeInterface; apiImpl: APIInterface; isInServerlessEnv: boolean; - constructor(recipeId: string, appInfo: NormalisedAppinfo, isInServerlessEnv: boolean, config?: TypeInput); + constructor( + stInstance: SuperTokens, + recipeId: string, + appInfo: NormalisedAppinfo, + isInServerlessEnv: boolean, + config?: TypeInput + ); static getInstanceOrThrowError(): Recipe; static getInstance(): Recipe | undefined; static init(config?: TypeInput): RecipeListFunction; diff --git a/lib/build/recipe/totp/recipe.js b/lib/build/recipe/totp/recipe.js index 0d40021e9..5a6b198a7 100644 --- a/lib/build/recipe/totp/recipe.js +++ b/lib/build/recipe/totp/recipe.js @@ -21,7 +21,6 @@ var __importDefault = Object.defineProperty(exports, "__esModule", { value: true }); const supertokens_js_override_1 = __importDefault(require("supertokens-js-override")); const normalisedURLPath_1 = __importDefault(require("../../normalisedURLPath")); -const querier_1 = require("../../querier"); const recipeModule_1 = __importDefault(require("../../recipeModule")); const error_1 = __importDefault(require("../../error")); const recipeImplementation_1 = __importDefault(require("./recipeImplementation")); @@ -34,12 +33,11 @@ const verifyTOTP_1 = __importDefault(require("./api/verifyTOTP")); const listDevices_1 = __importDefault(require("./api/listDevices")); const removeDevice_1 = __importDefault(require("./api/removeDevice")); const postSuperTokensInitCallbacks_1 = require("../../postSuperTokensInitCallbacks"); -const recipe_1 = __importDefault(require("../multifactorauth/recipe")); const utils_2 = require("../../utils"); const plugins_1 = require("../../plugins"); class Recipe extends recipeModule_1.default { - constructor(recipeId, appInfo, isInServerlessEnv, config) { - super(recipeId, appInfo); + constructor(stInstance, recipeId, appInfo, isInServerlessEnv, config) { + super(stInstance, recipeId, appInfo); // abstract instance functions below............... this.getAPIsHandled = () => { return [ @@ -85,15 +83,15 @@ class Recipe extends recipeModule_1.default { res, }; if (id === constants_1.CREATE_TOTP_DEVICE) { - return await (0, createDevice_1.default)(this.apiImpl, options, userContext); + return await (0, createDevice_1.default)(this.stInstance, this.apiImpl, options, userContext); } else if (id === constants_1.LIST_TOTP_DEVICES) { - return await (0, listDevices_1.default)(this.apiImpl, options, userContext); + return await (0, listDevices_1.default)(this.stInstance, this.apiImpl, options, userContext); } else if (id === constants_1.REMOVE_TOTP_DEVICE) { - return await (0, removeDevice_1.default)(this.apiImpl, options, userContext); + return await (0, removeDevice_1.default)(this.stInstance, this.apiImpl, options, userContext); } else if (id === constants_1.VERIFY_TOTP_DEVICE) { - return await (0, verifyDevice_1.default)(this.apiImpl, options, userContext); + return await (0, verifyDevice_1.default)(this.stInstance, this.apiImpl, options, userContext); } else if (id === constants_1.VERIFY_TOTP) { - return await (0, verifyTOTP_1.default)(this.apiImpl, options, userContext); + return await (0, verifyTOTP_1.default)(this.stInstance, this.apiImpl, options, userContext); } throw new Error("should never come here"); }; @@ -110,22 +108,23 @@ class Recipe extends recipeModule_1.default { this.isInServerlessEnv = isInServerlessEnv; { let builder = new supertokens_js_override_1.default( - (0, recipeImplementation_1.default)(querier_1.Querier.getNewInstanceOrThrowError(recipeId), this.config) + (0, recipeImplementation_1.default)(this.stInstance, this.querier, this.config) ); this.recipeInterfaceImpl = builder.override(this.config.override.functions).build(); } { - let builder = new supertokens_js_override_1.default((0, implementation_1.default)()); + let builder = new supertokens_js_override_1.default((0, implementation_1.default)(this.stInstance)); this.apiImpl = builder.override(this.config.override.apis).build(); } + const instance = this; postSuperTokensInitCallbacks_1.PostSuperTokensInitCallbacks.addPostInitCallback(() => { - const mfaInstance = recipe_1.default.getInstance(); + const mfaInstance = this.stInstance.getRecipeInstance("multifactorauth"); if (mfaInstance !== undefined) { mfaInstance.addFuncToGetAllAvailableSecondaryFactorIdsFromOtherRecipes(() => { return ["totp"]; }); mfaInstance.addFuncToGetFactorsSetupForUserFromOtherRecipes(async (user, userContext) => { - const deviceRes = await Recipe.getInstanceOrThrowError().recipeInterfaceImpl.listDevices({ + const deviceRes = await instance.recipeInterfaceImpl.listDevices({ userId: user.id, userContext, }); @@ -149,9 +148,10 @@ class Recipe extends recipeModule_1.default { return Recipe.instance; } static init(config) { - return (appInfo, isInServerlessEnv, plugins) => { + return (stInstance, appInfo, isInServerlessEnv, plugins) => { if (Recipe.instance === undefined) { Recipe.instance = new Recipe( + stInstance, Recipe.RECIPE_ID, appInfo, isInServerlessEnv, diff --git a/lib/build/recipe/totp/recipeImplementation.d.ts b/lib/build/recipe/totp/recipeImplementation.d.ts index 05e5cc9ef..0a65a74c1 100644 --- a/lib/build/recipe/totp/recipeImplementation.d.ts +++ b/lib/build/recipe/totp/recipeImplementation.d.ts @@ -2,4 +2,9 @@ import { RecipeInterface } from "./"; import { Querier } from "../../querier"; import { TypeNormalisedInput } from "./types"; -export default function getRecipeInterface(querier: Querier, config: TypeNormalisedInput): RecipeInterface; +import SuperTokens from "../../supertokens"; +export default function getRecipeInterface( + stInstance: SuperTokens, + querier: Querier, + config: TypeNormalisedInput +): RecipeInterface; diff --git a/lib/build/recipe/totp/recipeImplementation.js b/lib/build/recipe/totp/recipeImplementation.js index db15b86a3..3fa298265 100644 --- a/lib/build/recipe/totp/recipeImplementation.js +++ b/lib/build/recipe/totp/recipeImplementation.js @@ -15,11 +15,12 @@ */ Object.defineProperty(exports, "__esModule", { value: true }); exports.default = getRecipeInterface; -const __1 = require("../.."); -function getRecipeInterface(querier, config) { +function getRecipeInterface(stInstance, querier, config) { return { getUserIdentifierInfoForUserId: async function ({ userId, userContext }) { - let user = await (0, __1.getUser)(userId, userContext); + let user = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId, userContext }); if (user === undefined) { return { status: "UNKNOWN_USER_ID_ERROR", diff --git a/lib/build/recipe/totp/types.d.ts b/lib/build/recipe/totp/types.d.ts index 84b38cd0d..adf5d3506 100644 --- a/lib/build/recipe/totp/types.d.ts +++ b/lib/build/recipe/totp/types.d.ts @@ -1,5 +1,5 @@ // @ts-nocheck -import { BaseRequest, BaseResponse } from "../../framework"; +import type { BaseRequest, BaseResponse } from "../../framework"; import OverrideableBuilder from "supertokens-js-override"; import { GeneralErrorResponse, UserContext } from "../../types"; import { SessionContainerInterface } from "../session/types"; diff --git a/lib/build/recipe/usermetadata/recipe.d.ts b/lib/build/recipe/usermetadata/recipe.d.ts index a588ea3b3..ae003de68 100644 --- a/lib/build/recipe/usermetadata/recipe.d.ts +++ b/lib/build/recipe/usermetadata/recipe.d.ts @@ -5,13 +5,20 @@ import normalisedURLPath from "../../normalisedURLPath"; import RecipeModule from "../../recipeModule"; import { APIHandled, HTTPMethod, NormalisedAppinfo, RecipeListFunction } from "../../types"; import { RecipeInterface, TypeInput, TypeNormalisedInput } from "./types"; +import type SuperTokens from "../../supertokens"; export default class Recipe extends RecipeModule { static RECIPE_ID: "usermetadata"; private static instance; config: TypeNormalisedInput; recipeInterfaceImpl: RecipeInterface; isInServerlessEnv: boolean; - constructor(recipeId: string, appInfo: NormalisedAppinfo, isInServerlessEnv: boolean, config?: TypeInput); + constructor( + stInstance: SuperTokens, + recipeId: string, + appInfo: NormalisedAppinfo, + isInServerlessEnv: boolean, + config?: TypeInput + ); static getInstanceOrThrowError(): Recipe; static init(config?: TypeInput): RecipeListFunction; static reset(): void; diff --git a/lib/build/recipe/usermetadata/recipe.js b/lib/build/recipe/usermetadata/recipe.js index c1b83556a..5d89f4c15 100644 --- a/lib/build/recipe/usermetadata/recipe.js +++ b/lib/build/recipe/usermetadata/recipe.js @@ -20,7 +20,6 @@ var __importDefault = }; Object.defineProperty(exports, "__esModule", { value: true }); const error_1 = __importDefault(require("../../error")); -const querier_1 = require("../../querier"); const recipeModule_1 = __importDefault(require("../../recipeModule")); const utils_1 = require("../../utils"); const plugins_1 = require("../../plugins"); @@ -28,8 +27,8 @@ const recipeImplementation_1 = __importDefault(require("./recipeImplementation") const utils_2 = require("./utils"); const supertokens_js_override_1 = __importDefault(require("supertokens-js-override")); class Recipe extends recipeModule_1.default { - constructor(recipeId, appInfo, isInServerlessEnv, config) { - super(recipeId, appInfo); + constructor(stInstance, recipeId, appInfo, isInServerlessEnv, config) { + super(stInstance, recipeId, appInfo); // This stub is required to implement RecipeModule this.handleAPIRequest = async (_, _tenantId, __, ___, ____, _____) => { throw new Error("Should never come here"); @@ -37,9 +36,7 @@ class Recipe extends recipeModule_1.default { this.config = (0, utils_2.validateAndNormaliseUserInput)(this, appInfo, config); this.isInServerlessEnv = isInServerlessEnv; { - let builder = new supertokens_js_override_1.default( - (0, recipeImplementation_1.default)(querier_1.Querier.getNewInstanceOrThrowError(recipeId)) - ); + let builder = new supertokens_js_override_1.default((0, recipeImplementation_1.default)(this.querier)); this.recipeInterfaceImpl = builder.override(this.config.override.functions).build(); } } @@ -53,9 +50,10 @@ class Recipe extends recipeModule_1.default { ); } static init(config) { - return (appInfo, isInServerlessEnv, plugins) => { + return (stInstance, appInfo, isInServerlessEnv, plugins) => { if (Recipe.instance === undefined) { Recipe.instance = new Recipe( + stInstance, Recipe.RECIPE_ID, appInfo, isInServerlessEnv, diff --git a/lib/build/recipe/userroles/recipe.d.ts b/lib/build/recipe/userroles/recipe.d.ts index 2e0f19f0e..25a1dc26e 100644 --- a/lib/build/recipe/userroles/recipe.d.ts +++ b/lib/build/recipe/userroles/recipe.d.ts @@ -5,13 +5,20 @@ import normalisedURLPath from "../../normalisedURLPath"; import RecipeModule from "../../recipeModule"; import { APIHandled, HTTPMethod, NormalisedAppinfo, RecipeListFunction } from "../../types"; import { RecipeInterface, TypeInput, TypeNormalisedInput } from "./types"; +import type SuperTokens from "../../supertokens"; export default class Recipe extends RecipeModule { static RECIPE_ID: "userroles"; private static instance; config: TypeNormalisedInput; recipeInterfaceImpl: RecipeInterface; isInServerlessEnv: boolean; - constructor(recipeId: string, appInfo: NormalisedAppinfo, isInServerlessEnv: boolean, config?: TypeInput); + constructor( + stInstance: SuperTokens, + recipeId: string, + appInfo: NormalisedAppinfo, + isInServerlessEnv: boolean, + config?: TypeInput + ); static getInstanceOrThrowError(): Recipe; static init(config?: TypeInput): RecipeListFunction; static reset(): void; diff --git a/lib/build/recipe/userroles/recipe.js b/lib/build/recipe/userroles/recipe.js index 4615de287..a63b75807 100644 --- a/lib/build/recipe/userroles/recipe.js +++ b/lib/build/recipe/userroles/recipe.js @@ -20,22 +20,19 @@ var __importDefault = }; Object.defineProperty(exports, "__esModule", { value: true }); const error_1 = __importDefault(require("../../error")); -const querier_1 = require("../../querier"); const recipeModule_1 = __importDefault(require("../../recipeModule")); const recipeImplementation_1 = __importDefault(require("./recipeImplementation")); const utils_1 = require("./utils"); const supertokens_js_override_1 = __importDefault(require("supertokens-js-override")); const postSuperTokensInitCallbacks_1 = require("../../postSuperTokensInitCallbacks"); -const recipe_1 = __importDefault(require("../session/recipe")); -const recipe_2 = __importDefault(require("../oauth2provider/recipe")); const userRoleClaim_1 = require("./userRoleClaim"); const permissionClaim_1 = require("./permissionClaim"); const session_1 = require("../session"); const utils_2 = require("../../utils"); const plugins_1 = require("../../plugins"); class Recipe extends recipeModule_1.default { - constructor(recipeId, appInfo, isInServerlessEnv, config) { - super(recipeId, appInfo); + constructor(stInstance, recipeId, appInfo, isInServerlessEnv, config) { + super(stInstance, recipeId, appInfo); // This stub is required to implement RecipeModule this.handleAPIRequest = async (_, _tenantId, __, ___, ____, _____) => { throw new Error("Should never come here"); @@ -43,17 +40,17 @@ class Recipe extends recipeModule_1.default { this.config = (0, utils_1.validateAndNormaliseUserInput)(this, appInfo, config); this.isInServerlessEnv = isInServerlessEnv; { - let builder = new supertokens_js_override_1.default( - (0, recipeImplementation_1.default)(querier_1.Querier.getNewInstanceOrThrowError(recipeId)) - ); + let builder = new supertokens_js_override_1.default((0, recipeImplementation_1.default)(this.querier)); this.recipeInterfaceImpl = builder.override(this.config.override.functions).build(); } postSuperTokensInitCallbacks_1.PostSuperTokensInitCallbacks.addPostInitCallback(() => { if (!this.config.skipAddingRolesToAccessToken) { - recipe_1.default.getInstanceOrThrowError().addClaimFromOtherRecipe(userRoleClaim_1.UserRoleClaim); + stInstance.getRecipeInstanceOrThrow("session").addClaimFromOtherRecipe(userRoleClaim_1.UserRoleClaim); } if (!this.config.skipAddingPermissionsToAccessToken) { - recipe_1.default.getInstanceOrThrowError().addClaimFromOtherRecipe(permissionClaim_1.PermissionClaim); + stInstance + .getRecipeInstanceOrThrow("session") + .addClaimFromOtherRecipe(permissionClaim_1.PermissionClaim); } const tokenPayloadBuilder = async (user, scopes, sessionHandle, userContext) => { let payload = {}; @@ -91,10 +88,12 @@ class Recipe extends recipeModule_1.default { } return payload; }; - recipe_2.default.getInstanceOrThrowError().addAccessTokenBuilderFromOtherRecipe(tokenPayloadBuilder); - recipe_2.default.getInstanceOrThrowError().addIdTokenBuilderFromOtherRecipe(tokenPayloadBuilder); - recipe_2.default - .getInstanceOrThrowError() + stInstance + .getRecipeInstanceOrThrow("oauth2provider") + .addAccessTokenBuilderFromOtherRecipe(tokenPayloadBuilder); + stInstance.getRecipeInstanceOrThrow("oauth2provider").addIdTokenBuilderFromOtherRecipe(tokenPayloadBuilder); + stInstance + .getRecipeInstanceOrThrow("oauth2provider") .addUserInfoBuilderFromOtherRecipe(async (user, _accessTokenPayload, scopes, tenantId, userContext) => { let userInfo = {}; let userRoles = []; @@ -142,9 +141,10 @@ class Recipe extends recipeModule_1.default { ); } static init(config) { - return (appInfo, isInServerlessEnv, plugins) => { + return (stInstance, appInfo, isInServerlessEnv, plugins) => { if (Recipe.instance === undefined) { Recipe.instance = new Recipe( + stInstance, Recipe.RECIPE_ID, appInfo, isInServerlessEnv, diff --git a/lib/build/recipe/webauthn/api/implementation.d.ts b/lib/build/recipe/webauthn/api/implementation.d.ts index 2f382b449..928c9aebd 100644 --- a/lib/build/recipe/webauthn/api/implementation.d.ts +++ b/lib/build/recipe/webauthn/api/implementation.d.ts @@ -1,3 +1,4 @@ // @ts-nocheck import { APIInterface } from ".."; -export default function getAPIImplementation(): APIInterface; +import type SuperTokens from "../../../supertokens"; +export default function getAPIImplementation(stInstance: SuperTokens): APIInterface; diff --git a/lib/build/recipe/webauthn/api/implementation.js b/lib/build/recipe/webauthn/api/implementation.js index 1bd6ba525..9a96bf17a 100644 --- a/lib/build/recipe/webauthn/api/implementation.js +++ b/lib/build/recipe/webauthn/api/implementation.js @@ -17,18 +17,14 @@ var __importDefault = }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = getAPIImplementation; -const recipe_1 = __importDefault(require("../../accountlinking/recipe")); -const recipe_2 = __importDefault(require("../../emailverification/recipe")); const authUtils_1 = require("../../../authUtils"); const utils_1 = require("../../thirdparty/utils"); const constants_1 = require("../constants"); const recipeUserId_1 = __importDefault(require("../../../recipeUserId")); const utils_2 = require("../utils"); const logger_1 = require("../../../logger"); -const __1 = require("../../.."); -const multifactorauth_1 = __importDefault(require("../../multifactorauth")); -const recipe_3 = __importDefault(require("../../multifactorauth/recipe")); -function getAPIImplementation() { +const types_1 = require("../../multifactorauth/types"); +function getAPIImplementation(stInstance) { return { registerOptionsPOST: async function (_a) { var { tenantId, options, userContext } = _a, @@ -173,11 +169,12 @@ function getAPIImplementation() { ); } const preAuthCheckRes = await authUtils_1.AuthUtils.preAuthChecks({ + stInstance, authenticatingAccountInfo: { recipeId: "webauthn", email, }, - factorIds: [multifactorauth_1.default.FactorIds.WEBAUTHN], + factorIds: [types_1.FactorIds.WEBAUTHN], isSignUp: true, isVerified: (0, utils_1.isFakeEmail)(email), signInVerifiesLoginMethod: false, @@ -189,8 +186,8 @@ function getAPIImplementation() { shouldTryLinkingWithSessionUser, }); if (preAuthCheckRes.status === "SIGN_UP_NOT_ALLOWED") { - const conflictingUsers = await recipe_1.default - .getInstanceOrThrowError() + const conflictingUsers = await stInstance + .getRecipeInstanceOrThrow("accountlinking") .recipeInterfaceImpl.listUsersByAccountInfo({ tenantId, accountInfo: { @@ -252,6 +249,7 @@ function getAPIImplementation() { ); } const postAuthChecks = await authUtils_1.AuthUtils.postAuthChecks({ + stInstance, authenticatedUser: signUpResponse.user, recipeUserId: signUpResponse.recipeUserId, isSignUp: true, @@ -329,6 +327,7 @@ function getAPIImplementation() { const accountInfo = { webauthn: { credentialId: credential.id } }; const authenticatingUser = await authUtils_1.AuthUtils.getAuthenticatingUserAndAddToCurrentTenantIfRequired( { + stInstance, accountInfo, userContext, recipeId, @@ -364,11 +363,12 @@ function getAPIImplementation() { throw new Error("This should never happen: webauthn user has no email"); } const preAuthChecks = await authUtils_1.AuthUtils.preAuthChecks({ + stInstance, authenticatingAccountInfo: { recipeId, email, }, - factorIds: [multifactorauth_1.default.FactorIds.WEBAUTHN], + factorIds: [types_1.FactorIds.WEBAUTHN], isSignUp: false, authenticatingUser: authenticatingUser === null || authenticatingUser === void 0 ? void 0 : authenticatingUser.user, @@ -425,6 +425,7 @@ function getAPIImplementation() { ); } const postAuthChecks = await authUtils_1.AuthUtils.postAuthChecks({ + stInstance, authenticatedUser: signInResponse.user, recipeUserId: signInResponse.recipeUserId, isSignUp: false, @@ -452,14 +453,16 @@ function getAPIImplementation() { // even if the above returns true, we still need to check if there // exists an webauthn user with the same email cause the function // above does not check for that. - const users = await recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl.listUsersByAccountInfo({ - tenantId, - accountInfo: { - email, - }, - doUnionOfAccountInfo: false, - userContext, - }); + const users = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.listUsersByAccountInfo({ + tenantId, + accountInfo: { + email, + }, + doUnionOfAccountInfo: false, + userContext, + }); const webauthnUserExists = users.find((u) => { return ( @@ -524,14 +527,16 @@ function getAPIImplementation() { }; } //check if primaryUserId is linked with this email - const users = await recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl.listUsersByAccountInfo({ - tenantId, - accountInfo: { - email, - }, - doUnionOfAccountInfo: false, - userContext, - }); + const users = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.listUsersByAccountInfo({ + tenantId, + accountInfo: { + email, + }, + doUnionOfAccountInfo: false, + userContext, + }); // we find the recipe user ID of the webauthn account from the user's list // for later use. let webauthnAccount = undefined; @@ -584,8 +589,8 @@ function getAPIImplementation() { reason: "Recover account link was not created because of account take over risk. Please contact support. (ERR_CODE_001)", }; } - const shouldDoAccountLinkingResponse = await recipe_1.default - .getInstanceOrThrowError() + const shouldDoAccountLinkingResponse = await stInstance + .getRecipeInstanceOrThrow("accountlinking") .config.shouldDoAutomaticAccountLinking( webauthnAccount !== undefined ? webauthnAccount @@ -618,7 +623,7 @@ function getAPIImplementation() { status: "OK", }; } - const isSignUpAllowed = await recipe_1.default.getInstanceOrThrowError().isSignUpAllowed({ + const isSignUpAllowed = await stInstance.getRecipeInstanceOrThrow("accountlinking").isSignUpAllowed({ newUser: { recipeId: "webauthn", email, @@ -704,7 +709,7 @@ function getAPIImplementation() { userContext, }) { async function markEmailAsVerified(recipeUserId, email) { - const emailVerificationInstance = recipe_2.default.getInstance(); + const emailVerificationInstance = stInstance.getRecipeInstance("emailverification"); if (emailVerificationInstance) { const tokenResponse = await emailVerificationInstance.recipeInterfaceImpl.createEmailVerificationToken({ @@ -759,10 +764,9 @@ function getAPIImplementation() { // If we verified (and linked) the existing user with the original credential, User M would get access to the current user and any linked users. await markEmailAsVerified(recipeUserId, emailForWhomTokenWasGenerated); // We refresh the user information here, because the verification status may be updated, which is used during linking. - const updatedUserAfterEmailVerification = await (0, __1.getUser)( - recipeUserId.getAsString(), - userContext - ); + const updatedUserAfterEmailVerification = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: recipeUserId.getAsString(), userContext }); if (updatedUserAfterEmailVerification === undefined) { throw new Error("Should never happen - user deleted after during recover account"); } @@ -780,8 +784,8 @@ function getAPIImplementation() { // 1. the user was unverified and linking requires verification // We do not take try linking by session here, since this is supposed to be called without a session // Still, the session object is passed around because it is a required input for shouldDoAutomaticAccountLinking - const linkRes = await recipe_1.default - .getInstanceOrThrowError() + const linkRes = await stInstance + .getRecipeInstanceOrThrow("accountlinking") .tryLinkingByAccountInfoOrCreatePrimaryUser({ tenantId, inputUser: updatedUserAfterEmailVerification, @@ -807,7 +811,9 @@ function getAPIImplementation() { } const userIdForWhomTokenWasGenerated = tokenConsumptionResponse.userId; const emailForWhomTokenWasGenerated = tokenConsumptionResponse.email; - const existingUser = await (0, __1.getUser)(tokenConsumptionResponse.userId, userContext); + const existingUser = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: tokenConsumptionResponse.userId, userContext }); if (existingUser === undefined) { // This should happen only cause of a race condition where the user // might be deleted before token creation and consumption. @@ -886,7 +892,9 @@ function getAPIImplementation() { createUserResponse.user.loginMethods[0].recipeUserId, tokenConsumptionResponse.email ); - const updatedUser = await (0, __1.getUser)(createUserResponse.user.id, userContext); + const updatedUser = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: createUserResponse.user.id, userContext }); if (updatedUser === undefined) { throw new Error("Should never happen - user deleted after during recover account"); } @@ -897,8 +905,8 @@ function getAPIImplementation() { // email is shared. // We do not take try linking by session here, since this is supposed to be called without a session // Still, the session object is passed around because it is a required input for shouldDoAutomaticAccountLinking - const linkRes = await recipe_1.default - .getInstanceOrThrowError() + const linkRes = await stInstance + .getRecipeInstanceOrThrow("accountlinking") .tryLinkingByAccountInfoOrCreatePrimaryUser({ tenantId, inputUser: createUserResponse.user, @@ -931,7 +939,9 @@ function getAPIImplementation() { }, listCredentialsGET: async function ({ options, userContext, session }) { var _a; - const existingUser = await (0, __1.getUser)(session.getUserId(), userContext); + const existingUser = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: session.getUserId(), userContext }); if (!existingUser) { return { status: "GENERAL_ERROR", @@ -977,15 +987,17 @@ function getAPIImplementation() { INVALID_CREDENTIALS_ERROR: "The credentials are incorrect. Please make sure you are using the correct credentials. (ERR_CODE_025)", }; - const mfaInstance = recipe_3.default.getInstance(); + const mfaInstance = stInstance.getRecipeInstance("multifactorauth"); if (mfaInstance) { - await multifactorauth_1.default.assertAllowedToSetupFactorElseThrowInvalidClaimError( + await mfaInstance.assertAllowedToSetupFactorElseThrowInvalidClaimError( session, - multifactorauth_1.default.FactorIds.WEBAUTHN, + types_1.FactorIds.WEBAUTHN, userContext ); } - const user = await (0, __1.getUser)(session.getUserId(), userContext); + const user = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: session.getUserId(), userContext }); if (!user) { return { status: "GENERAL_ERROR", @@ -1043,13 +1055,15 @@ function getAPIImplementation() { }, removeCredentialPOST: async function ({ webauthnCredentialId, options, userContext, session }) { var _a; - const mfaInstance = recipe_3.default.getInstance(); + const mfaInstance = stInstance.getRecipeInstance("multifactorauth"); if (mfaInstance) { await session.assertClaims([ - multifactorauth_1.default.MultiFactorAuthClaim.validators.hasCompletedMFARequirementsForAuth(), + mfaInstance.multiFactorAuthClaim.validators.hasCompletedMFARequirementsForAuth(), ]); } - const user = await (0, __1.getUser)(session.getUserId(), userContext); + const user = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: session.getUserId(), userContext }); if (!user) { return { status: "GENERAL_ERROR", diff --git a/lib/build/recipe/webauthn/api/listCredentials.d.ts b/lib/build/recipe/webauthn/api/listCredentials.d.ts index f2f241126..7a31775fa 100644 --- a/lib/build/recipe/webauthn/api/listCredentials.d.ts +++ b/lib/build/recipe/webauthn/api/listCredentials.d.ts @@ -1,7 +1,9 @@ // @ts-nocheck import { APIInterface, APIOptions } from ".."; import { UserContext } from "../../../types"; +import type SuperTokens from "../../../supertokens"; export default function listCredentialsAPI( + stInstance: SuperTokens, apiImplementation: APIInterface, _: string, options: APIOptions, diff --git a/lib/build/recipe/webauthn/api/listCredentials.js b/lib/build/recipe/webauthn/api/listCredentials.js index 8b0bcceb4..2ff835106 100644 --- a/lib/build/recipe/webauthn/api/listCredentials.js +++ b/lib/build/recipe/webauthn/api/listCredentials.js @@ -13,29 +13,23 @@ * License for the specific language governing permissions and limitations * under the License. */ -var __importDefault = - (this && this.__importDefault) || - function (mod) { - return mod && mod.__esModule ? mod : { default: mod }; - }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = listCredentialsAPI; const utils_1 = require("../../../utils"); -const session_1 = __importDefault(require("../../session")); -async function listCredentialsAPI(apiImplementation, _, options, userContext) { +async function listCredentialsAPI(stInstance, apiImplementation, _, options, userContext) { if (apiImplementation.listCredentialsGET === undefined) { return false; } - const session = await session_1.default.getSession( - options.req, - options.res, - { overrideGlobalClaimValidators: () => [], sessionRequired: true }, - userContext - ); + const session = await stInstance.getRecipeInstanceOrThrow("session").getSession({ + req: options.req, + res: options.res, + options: { overrideGlobalClaimValidators: () => [], sessionRequired: true }, + userContext, + }); const result = await apiImplementation.listCredentialsGET({ options, userContext: userContext, - session, + session: session, }); (0, utils_1.send200Response)(options.res, result); return true; diff --git a/lib/build/recipe/webauthn/api/registerCredential.d.ts b/lib/build/recipe/webauthn/api/registerCredential.d.ts index 4a29d2f16..0e286d090 100644 --- a/lib/build/recipe/webauthn/api/registerCredential.d.ts +++ b/lib/build/recipe/webauthn/api/registerCredential.d.ts @@ -1,7 +1,9 @@ // @ts-nocheck import { APIInterface, APIOptions } from ".."; import { UserContext } from "../../../types"; +import type SuperTokens from "../../../supertokens"; export default function registerCredentialAPI( + stInstance: SuperTokens, apiImplementation: APIInterface, tenantId: string, options: APIOptions, diff --git a/lib/build/recipe/webauthn/api/registerCredential.js b/lib/build/recipe/webauthn/api/registerCredential.js index cf42ba144..dfcefd8e0 100644 --- a/lib/build/recipe/webauthn/api/registerCredential.js +++ b/lib/build/recipe/webauthn/api/registerCredential.js @@ -22,18 +22,17 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.default = registerCredentialAPI; const utils_1 = require("../../../utils"); const utils_2 = require("./utils"); -const session_1 = __importDefault(require("../../session")); const error_1 = __importDefault(require("../../../error")); -async function registerCredentialAPI(apiImplementation, tenantId, options, userContext) { +async function registerCredentialAPI(stInstance, apiImplementation, tenantId, options, userContext) { if (apiImplementation.registerCredentialPOST === undefined) { return false; } - const session = await session_1.default.getSession( - options.req, - options.res, - { overrideGlobalClaimValidators: () => [], sessionRequired: true }, - userContext - ); + const session = await stInstance.getRecipeInstanceOrThrow("session").getSession({ + req: options.req, + res: options.res, + options: { overrideGlobalClaimValidators: () => [], sessionRequired: true }, + userContext, + }); const requestBody = await options.req.getJSONBody(); const webauthnGeneratedOptionsId = (0, utils_2.validateWebauthnGeneratedOptionsIdOrThrowError)( requestBody.webauthnGeneratedOptionsId @@ -53,7 +52,7 @@ async function registerCredentialAPI(apiImplementation, tenantId, options, userC tenantId, options, userContext: userContext, - session, + session: session, }); if (result.status === "OK") { (0, utils_1.send200Response)(options.res, { diff --git a/lib/build/recipe/webauthn/api/removeCredential.d.ts b/lib/build/recipe/webauthn/api/removeCredential.d.ts index 094df26b9..03b96d47d 100644 --- a/lib/build/recipe/webauthn/api/removeCredential.d.ts +++ b/lib/build/recipe/webauthn/api/removeCredential.d.ts @@ -1,7 +1,9 @@ // @ts-nocheck import { APIInterface, APIOptions } from ".."; import { UserContext } from "../../../types"; +import type SuperTokens from "../../../supertokens"; export default function removeCredentialAPI( + stInstance: SuperTokens, apiImplementation: APIInterface, _: string, options: APIOptions, diff --git a/lib/build/recipe/webauthn/api/removeCredential.js b/lib/build/recipe/webauthn/api/removeCredential.js index 4246340b8..dd5942cfc 100644 --- a/lib/build/recipe/webauthn/api/removeCredential.js +++ b/lib/build/recipe/webauthn/api/removeCredential.js @@ -22,17 +22,16 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.default = removeCredentialAPI; const utils_1 = require("../../../utils"); const error_1 = __importDefault(require("../error")); -const session_1 = __importDefault(require("../../session")); -async function removeCredentialAPI(apiImplementation, _, options, userContext) { +async function removeCredentialAPI(stInstance, apiImplementation, _, options, userContext) { if (apiImplementation.removeCredentialPOST === undefined) { return false; } - const session = await session_1.default.getSession( - options.req, - options.res, - { overrideGlobalClaimValidators: () => [], sessionRequired: true }, - userContext - ); + const session = await stInstance.getRecipeInstanceOrThrow("session").getSession({ + req: options.req, + res: options.res, + options: { overrideGlobalClaimValidators: () => [], sessionRequired: true }, + userContext, + }); const requestBody = await options.req.getJSONBody(); const webauthnCredentialId = requestBody.webauthnCredentialId; if (webauthnCredentialId === undefined) { @@ -45,7 +44,7 @@ async function removeCredentialAPI(apiImplementation, _, options, userContext) { webauthnCredentialId, options, userContext: userContext, - session, + session: session, }); (0, utils_1.send200Response)(options.res, result); return true; diff --git a/lib/build/recipe/webauthn/api/signin.d.ts b/lib/build/recipe/webauthn/api/signin.d.ts index 72cd6e46b..4f2de710a 100644 --- a/lib/build/recipe/webauthn/api/signin.d.ts +++ b/lib/build/recipe/webauthn/api/signin.d.ts @@ -1,7 +1,9 @@ // @ts-nocheck import { APIInterface, APIOptions } from ".."; import { UserContext } from "../../../types"; +import type SuperTokens from "../../../supertokens"; export default function signInAPI( + stInstance: SuperTokens, apiImplementation: APIInterface, tenantId: string, options: APIOptions, diff --git a/lib/build/recipe/webauthn/api/signin.js b/lib/build/recipe/webauthn/api/signin.js index aa8da7a2c..a0d47f015 100644 --- a/lib/build/recipe/webauthn/api/signin.js +++ b/lib/build/recipe/webauthn/api/signin.js @@ -18,7 +18,7 @@ exports.default = signInAPI; const utils_1 = require("../../../utils"); const utils_2 = require("./utils"); const authUtils_1 = require("../../../authUtils"); -async function signInAPI(apiImplementation, tenantId, options, userContext) { +async function signInAPI(stInstance, apiImplementation, tenantId, options, userContext) { if (apiImplementation.signInPOST === undefined) { return false; } @@ -32,6 +32,7 @@ async function signInAPI(apiImplementation, tenantId, options, userContext) { requestBody ); const session = await authUtils_1.AuthUtils.loadSessionInAuthAPIIfNeeded( + stInstance, options.req, options.res, shouldTryLinkingWithSessionUser, diff --git a/lib/build/recipe/webauthn/api/signup.d.ts b/lib/build/recipe/webauthn/api/signup.d.ts index afc748051..952aa0b96 100644 --- a/lib/build/recipe/webauthn/api/signup.d.ts +++ b/lib/build/recipe/webauthn/api/signup.d.ts @@ -1,7 +1,9 @@ // @ts-nocheck import { APIInterface, APIOptions } from ".."; import { UserContext } from "../../../types"; +import type SuperTokens from "../../../supertokens"; export default function signUpAPI( + stInstance: SuperTokens, apiImplementation: APIInterface, tenantId: string, options: APIOptions, diff --git a/lib/build/recipe/webauthn/api/signup.js b/lib/build/recipe/webauthn/api/signup.js index 3dc48747b..adf7ce558 100644 --- a/lib/build/recipe/webauthn/api/signup.js +++ b/lib/build/recipe/webauthn/api/signup.js @@ -18,7 +18,7 @@ exports.default = signUpAPI; const utils_1 = require("../../../utils"); const utils_2 = require("./utils"); const authUtils_1 = require("../../../authUtils"); -async function signUpAPI(apiImplementation, tenantId, options, userContext) { +async function signUpAPI(stInstance, apiImplementation, tenantId, options, userContext) { if (apiImplementation.signUpPOST === undefined) { return false; } @@ -32,6 +32,7 @@ async function signUpAPI(apiImplementation, tenantId, options, userContext) { requestBody ); const session = await authUtils_1.AuthUtils.loadSessionInAuthAPIIfNeeded( + stInstance, options.req, options.res, shouldTryLinkingWithSessionUser, diff --git a/lib/build/recipe/webauthn/emaildelivery/services/backwardCompatibility/index.js b/lib/build/recipe/webauthn/emaildelivery/services/backwardCompatibility/index.js index 7123561a8..e0a693432 100644 --- a/lib/build/recipe/webauthn/emaildelivery/services/backwardCompatibility/index.js +++ b/lib/build/recipe/webauthn/emaildelivery/services/backwardCompatibility/index.js @@ -1,11 +1,12 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const utils_1 = require("../../../../../utils"); +const querier_1 = require("../../../../../querier"); async function createAndSendEmailUsingSupertokensService(input) { if ((0, utils_1.isTestEnv)()) { return; } - const result = await (0, utils_1.postWithFetch)( + const result = await (0, querier_1.postWithFetch)( "https://api.supertokens.com/0/st/auth/webauthn/recover", { "api-version": "0", diff --git a/lib/build/recipe/webauthn/recipe.d.ts b/lib/build/recipe/webauthn/recipe.d.ts index d84d93786..b60802b2e 100644 --- a/lib/build/recipe/webauthn/recipe.d.ts +++ b/lib/build/recipe/webauthn/recipe.d.ts @@ -7,6 +7,7 @@ import NormalisedURLPath from "../../normalisedURLPath"; import type { BaseRequest, BaseResponse } from "../../framework"; import EmailDeliveryIngredient from "../../ingredients/emaildelivery"; import { TypeWebauthnEmailDeliveryInput } from "./types"; +import type SuperTokens from "../../supertokens"; export default class Recipe extends RecipeModule { private static instance; static RECIPE_ID: "webauthn"; @@ -16,6 +17,7 @@ export default class Recipe extends RecipeModule { isInServerlessEnv: boolean; emailDelivery: EmailDeliveryIngredient; constructor( + stInstance: SuperTokens, recipeId: string, appInfo: NormalisedAppinfo, isInServerlessEnv: boolean, diff --git a/lib/build/recipe/webauthn/recipe.js b/lib/build/recipe/webauthn/recipe.js index 099c5f4d5..64fbe86fa 100644 --- a/lib/build/recipe/webauthn/recipe.js +++ b/lib/build/recipe/webauthn/recipe.js @@ -38,17 +38,14 @@ const implementation_1 = __importDefault(require("./api/implementation")); const supertokens_js_override_1 = __importDefault(require("supertokens-js-override")); const emaildelivery_1 = __importDefault(require("../../ingredients/emaildelivery")); const postSuperTokensInitCallbacks_1 = require("../../postSuperTokensInitCallbacks"); -const recipe_1 = __importDefault(require("../multifactorauth/recipe")); -const recipe_2 = __importDefault(require("../multitenancy/recipe")); const utils_3 = require("../thirdparty/utils"); -const multifactorauth_1 = require("../multifactorauth"); -const querier_1 = require("../../querier"); +const types_1 = require("../multifactorauth/types"); const plugins_1 = require("../../plugins"); const listCredentials_1 = __importDefault(require("./api/listCredentials")); const removeCredential_1 = __importDefault(require("./api/removeCredential")); class Recipe extends recipeModule_1.default { - constructor(recipeId, appInfo, isInServerlessEnv, config, ingredients) { - super(recipeId, appInfo); + constructor(stInstance, recipeId, appInfo, isInServerlessEnv, config, ingredients) { + super(stInstance, recipeId, appInfo); this.getAPIsHandled = () => { return [ { @@ -131,9 +128,9 @@ class Recipe extends recipeModule_1.default { } else if (id === constants_1.SIGNIN_OPTIONS_API) { return await (0, signInOptions_1.default)(this.apiImpl, tenantId, options, userContext); } else if (id === constants_1.SIGN_UP_API) { - return await (0, signup_1.default)(this.apiImpl, tenantId, options, userContext); + return await (0, signup_1.default)(this.stInstance, this.apiImpl, tenantId, options, userContext); } else if (id === constants_1.SIGN_IN_API) { - return await (0, signin_1.default)(this.apiImpl, tenantId, options, userContext); + return await (0, signin_1.default)(this.stInstance, this.apiImpl, tenantId, options, userContext); } else if (id === constants_1.GENERATE_RECOVER_ACCOUNT_TOKEN_API) { return await (0, generateRecoverAccountToken_1.default)(this.apiImpl, tenantId, options, userContext); } else if (id === constants_1.RECOVER_ACCOUNT_API) { @@ -141,11 +138,29 @@ class Recipe extends recipeModule_1.default { } else if (id === constants_1.SIGNUP_EMAIL_EXISTS_API) { return await (0, emailExists_1.default)(this.apiImpl, tenantId, options, userContext); } else if (id === constants_1.REGISTER_CREDENTIAL_API) { - return await (0, registerCredential_1.default)(this.apiImpl, tenantId, options, userContext); + return await (0, registerCredential_1.default)( + this.stInstance, + this.apiImpl, + tenantId, + options, + userContext + ); } else if (id === constants_1.LIST_CREDENTIALS_API) { - return await (0, listCredentials_1.default)(this.apiImpl, tenantId, options, userContext); + return await (0, listCredentials_1.default)( + this.stInstance, + this.apiImpl, + tenantId, + options, + userContext + ); } else if (id === constants_1.REMOVE_CREDENTIAL_API) { - return await (0, removeCredential_1.default)(this.apiImpl, tenantId, options, userContext); + return await (0, removeCredential_1.default)( + this.stInstance, + this.apiImpl, + tenantId, + options, + userContext + ); } else return false; }; this.handleError = async (err, _request, _response) => { @@ -165,14 +180,13 @@ class Recipe extends recipeModule_1.default { this.config = (0, utils_1.validateAndNormaliseUserInput)(this, appInfo, config); { const getWebauthnConfig = () => this.config; - const querier = querier_1.Querier.getNewInstanceOrThrowError(recipeId); let builder = new supertokens_js_override_1.default( - (0, recipeImplementation_1.default)(querier, getWebauthnConfig) + (0, recipeImplementation_1.default)(stInstance, this.querier, getWebauthnConfig) ); this.recipeInterfaceImpl = builder.override(this.config.override.functions).build(); } { - let builder = new supertokens_js_override_1.default((0, implementation_1.default)()); + let builder = new supertokens_js_override_1.default((0, implementation_1.default)(stInstance)); this.apiImpl = builder.override(this.config.override.apis).build(); } /** @@ -184,7 +198,7 @@ class Recipe extends recipeModule_1.default { ? new emaildelivery_1.default(this.config.getEmailDeliveryConfig(this.isInServerlessEnv)) : ingredients.emailDelivery; postSuperTokensInitCallbacks_1.PostSuperTokensInitCallbacks.addPostInitCallback(() => { - const mfaInstance = recipe_1.default.getInstance(); + const mfaInstance = stInstance.getRecipeInstance("multifactorauth"); if (mfaInstance !== undefined) { mfaInstance.addFuncToGetAllAvailableSecondaryFactorIdsFromOtherRecipes(() => { return ["webauthn"]; @@ -287,9 +301,9 @@ class Recipe extends recipeModule_1.default { }; }); } - const mtRecipe = recipe_2.default.getInstance(); + const mtRecipe = stInstance.getRecipeInstance("multitenancy"); if (mtRecipe !== undefined) { - mtRecipe.allAvailableFirstFactors.push(multifactorauth_1.FactorIds.WEBAUTHN); + mtRecipe.allAvailableFirstFactors.push(types_1.FactorIds.WEBAUTHN); } }); } @@ -300,9 +314,10 @@ class Recipe extends recipeModule_1.default { throw new Error("Initialisation not done. Did you forget to call the Webauthn.init function?"); } static init(config) { - return (appInfo, isInServerlessEnv, plugins) => { + return (stInstance, appInfo, isInServerlessEnv, plugins) => { if (Recipe.instance === undefined) { Recipe.instance = new Recipe( + stInstance, Recipe.RECIPE_ID, appInfo, isInServerlessEnv, diff --git a/lib/build/recipe/webauthn/recipeImplementation.d.ts b/lib/build/recipe/webauthn/recipeImplementation.d.ts index b6421a667..d64cf175b 100644 --- a/lib/build/recipe/webauthn/recipeImplementation.d.ts +++ b/lib/build/recipe/webauthn/recipeImplementation.d.ts @@ -1,7 +1,9 @@ // @ts-nocheck import { RecipeInterface, TypeNormalisedInput } from "./types"; import { Querier } from "../../querier"; +import type SuperTokens from "../../supertokens"; export default function getRecipeInterface( + stInstance: SuperTokens, querier: Querier, getWebauthnConfig: () => TypeNormalisedInput ): RecipeInterface; diff --git a/lib/build/recipe/webauthn/recipeImplementation.js b/lib/build/recipe/webauthn/recipeImplementation.js index 8505b3505..0f1484f26 100644 --- a/lib/build/recipe/webauthn/recipeImplementation.js +++ b/lib/build/recipe/webauthn/recipeImplementation.js @@ -31,12 +31,10 @@ var __importDefault = }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = getRecipeInterface; -const recipe_1 = __importDefault(require("../accountlinking/recipe")); -const __1 = require("../.."); const recipeUserId_1 = __importDefault(require("../../recipeUserId")); const user_1 = require("../../user"); const authUtils_1 = require("../../authUtils"); -function getRecipeInterface(querier, getWebauthnConfig) { +function getRecipeInterface(stInstance, querier, getWebauthnConfig) { return { registerOptions: async function (_a) { var _b, _c; @@ -180,6 +178,7 @@ function getRecipeInterface(querier, getWebauthnConfig) { } const linkResult = await authUtils_1.AuthUtils.linkToSessionIfRequiredElseCreatePrimaryUserIdOrLinkByAccountInfo({ + stInstance, tenantId, inputUser: response.user, recipeUserId: response.recipeUserId, @@ -217,17 +216,22 @@ function getRecipeInterface(querier, getWebauthnConfig) { (lm) => lm.recipeUserId.getAsString() === response.recipeUserId.getAsString() ); if (!loginMethod.verified) { - await recipe_1.default.getInstanceOrThrowError().verifyEmailForRecipeUserIfLinkedAccountsAreVerified({ - user: response.user, - recipeUserId: response.recipeUserId, - userContext, - }); + await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .verifyEmailForRecipeUserIfLinkedAccountsAreVerified({ + user: response.user, + recipeUserId: response.recipeUserId, + userContext, + }); // We do this so that we get the updated user (in case the above // function updated the verification status) and can return that - response.user = await (0, __1.getUser)(response.recipeUserId.getAsString(), userContext); + response.user = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: response.recipeUserId.getAsString(), userContext }); } const linkResult = await authUtils_1.AuthUtils.linkToSessionIfRequiredElseCreatePrimaryUserIdOrLinkByAccountInfo({ + stInstance, tenantId, inputUser: response.user, recipeUserId: response.recipeUserId, diff --git a/lib/build/recipe/webauthn/utils.d.ts b/lib/build/recipe/webauthn/utils.d.ts index b37ca89ff..ffedb76bf 100644 --- a/lib/build/recipe/webauthn/utils.d.ts +++ b/lib/build/recipe/webauthn/utils.d.ts @@ -2,7 +2,7 @@ import Recipe from "./recipe"; import { TypeInput, TypeNormalisedInput } from "./types"; import { NormalisedAppinfo, UserContext } from "../../types"; -import { BaseRequest } from "../../framework"; +import type { BaseRequest } from "../../framework"; export declare function validateAndNormaliseUserInput( _: Recipe, appInfo: NormalisedAppinfo, @@ -10,7 +10,7 @@ export declare function validateAndNormaliseUserInput( ): TypeNormalisedInput; export declare function defaultEmailValidator( value: any -): Promise<"Development bug: Please make sure the email field yields a string" | "Email is invalid" | undefined>; +): Promise<"Email is invalid" | "Development bug: Please make sure the email field yields a string" | undefined>; export declare function getRecoverAccountLink(input: { appInfo: NormalisedAppinfo; token: string; diff --git a/lib/build/recipeIdToRecipeType.d.ts b/lib/build/recipeIdToRecipeType.d.ts new file mode 100644 index 000000000..0998afe35 --- /dev/null +++ b/lib/build/recipeIdToRecipeType.d.ts @@ -0,0 +1,35 @@ +// @ts-nocheck +import SessionRecipe from "./recipe/session/recipe"; +import JwtRecipe from "./recipe/jwt/recipe"; +import MultifactorAuthRecipe from "./recipe/multifactorauth/recipe"; +import MultitenancyRecipe from "./recipe/multitenancy/recipe"; +import OAuth2ProviderRecipe from "./recipe/oauth2provider/recipe"; +import OpenIdRecipe from "./recipe/openid/recipe"; +import PasswordlessRecipe from "./recipe/passwordless/recipe"; +import ThirdPartyRecipe from "./recipe/thirdparty/recipe"; +import TotpRecipe from "./recipe/totp/recipe"; +import UserMetadataRecipe from "./recipe/usermetadata/recipe"; +import UserRolesRecipe from "./recipe/userroles/recipe"; +import WebauthnRecipe from "./recipe/webauthn/recipe"; +import AccountLinkingRecipe from "./recipe/accountlinking/recipe"; +import DashboardRecipe from "./recipe/dashboard/recipe"; +import EmailPasswordRecipe from "./recipe/emailpassword/recipe"; +import EmailVerificationRecipe from "./recipe/emailverification/recipe"; +export type RecipeIdToRecipeTypeMap = { + [SessionRecipe.RECIPE_ID]: SessionRecipe; + [JwtRecipe.RECIPE_ID]: JwtRecipe; + [MultifactorAuthRecipe.RECIPE_ID]: MultifactorAuthRecipe; + [MultitenancyRecipe.RECIPE_ID]: MultitenancyRecipe; + [OAuth2ProviderRecipe.RECIPE_ID]: OAuth2ProviderRecipe; + [OpenIdRecipe.RECIPE_ID]: OpenIdRecipe; + [PasswordlessRecipe.RECIPE_ID]: PasswordlessRecipe; + [ThirdPartyRecipe.RECIPE_ID]: ThirdPartyRecipe; + [TotpRecipe.RECIPE_ID]: TotpRecipe; + [UserMetadataRecipe.RECIPE_ID]: UserMetadataRecipe; + [UserRolesRecipe.RECIPE_ID]: UserRolesRecipe; + [WebauthnRecipe.RECIPE_ID]: WebauthnRecipe; + [AccountLinkingRecipe.RECIPE_ID]: AccountLinkingRecipe; + [DashboardRecipe.RECIPE_ID]: DashboardRecipe; + [EmailPasswordRecipe.RECIPE_ID]: EmailPasswordRecipe; + [EmailVerificationRecipe.RECIPE_ID]: EmailVerificationRecipe; +}; diff --git a/lib/build/recipeIdToRecipeType.js b/lib/build/recipeIdToRecipeType.js new file mode 100644 index 000000000..11df12e51 --- /dev/null +++ b/lib/build/recipeIdToRecipeType.js @@ -0,0 +1,23 @@ +"use strict"; +var __importDefault = + (this && this.__importDefault) || + function (mod) { + return mod && mod.__esModule ? mod : { default: mod }; + }; +Object.defineProperty(exports, "__esModule", { value: true }); +const recipe_1 = __importDefault(require("./recipe/session/recipe")); +const recipe_2 = __importDefault(require("./recipe/jwt/recipe")); +const recipe_3 = __importDefault(require("./recipe/multifactorauth/recipe")); +const recipe_4 = __importDefault(require("./recipe/multitenancy/recipe")); +const recipe_5 = __importDefault(require("./recipe/oauth2provider/recipe")); +const recipe_6 = __importDefault(require("./recipe/openid/recipe")); +const recipe_7 = __importDefault(require("./recipe/passwordless/recipe")); +const recipe_8 = __importDefault(require("./recipe/thirdparty/recipe")); +const recipe_9 = __importDefault(require("./recipe/totp/recipe")); +const recipe_10 = __importDefault(require("./recipe/usermetadata/recipe")); +const recipe_11 = __importDefault(require("./recipe/userroles/recipe")); +const recipe_12 = __importDefault(require("./recipe/webauthn/recipe")); +const recipe_13 = __importDefault(require("./recipe/accountlinking/recipe")); +const recipe_14 = __importDefault(require("./recipe/dashboard/recipe")); +const recipe_15 = __importDefault(require("./recipe/emailpassword/recipe")); +const recipe_16 = __importDefault(require("./recipe/emailverification/recipe")); diff --git a/lib/build/recipeModule.d.ts b/lib/build/recipeModule.d.ts index e277192a9..2e84f586f 100644 --- a/lib/build/recipeModule.d.ts +++ b/lib/build/recipeModule.d.ts @@ -2,11 +2,15 @@ import STError from "./error"; import { NormalisedAppinfo, APIHandled, HTTPMethod, UserContext } from "./types"; import NormalisedURLPath from "./normalisedURLPath"; -import { BaseRequest, BaseResponse } from "./framework"; +import type { BaseRequest, BaseResponse } from "./framework"; +import { Querier } from "./querier"; +import type SuperTokens from "./supertokens"; export default abstract class RecipeModule { private recipeId; protected appInfo: NormalisedAppinfo; - constructor(recipeId: string, appInfo: NormalisedAppinfo); + protected stInstance: SuperTokens; + protected querier: Querier; + constructor(stInstance: SuperTokens, recipeId: string, appInfo: NormalisedAppinfo); getRecipeId: () => string; getAppInfo: () => NormalisedAppinfo; returnAPIIdIfCanHandleRequest: ( diff --git a/lib/build/recipeModule.js b/lib/build/recipeModule.js index 75c3219ae..3ee591bda 100644 --- a/lib/build/recipeModule.js +++ b/lib/build/recipeModule.js @@ -21,8 +21,9 @@ var __importDefault = Object.defineProperty(exports, "__esModule", { value: true }); const normalisedURLPath_1 = __importDefault(require("./normalisedURLPath")); const constants_1 = require("./recipe/multitenancy/constants"); +const querier_1 = require("./querier"); class RecipeModule { - constructor(recipeId, appInfo) { + constructor(stInstance, recipeId, appInfo) { this.getRecipeId = () => { return this.recipeId; }; @@ -41,11 +42,7 @@ class RecipeModule { tenantId = match[1]; remainingPath = new normalisedURLPath_1.default(match[2]); } - // Multitenancy recipe is an always initialized recipe and needs to be imported this way - // so that there is no circular dependency. Otherwise there would be cyclic dependency - // between `supertokens.ts` -> `recipeModule.ts` -> `multitenancy/recipe.ts` - let MultitenancyRecipe = require("./recipe/multitenancy/recipe").default; - const mtRecipe = MultitenancyRecipe.getInstanceOrThrowError(); + const mtRecipe = this.stInstance.getRecipeInstanceOrThrow("multitenancy"); for (let i = 0; i < apisHandled.length; i++) { let currAPI = apisHandled[i]; if (!currAPI.disabled && currAPI.method === method) { @@ -71,6 +68,8 @@ class RecipeModule { } return undefined; }; + this.stInstance = stInstance; + this.querier = querier_1.Querier.getNewInstanceOrThrowError(stInstance, recipeId); this.recipeId = recipeId; this.appInfo = appInfo; } diff --git a/lib/build/supertokens.d.ts b/lib/build/supertokens.d.ts index fab2d4a64..3c80e0863 100644 --- a/lib/build/supertokens.d.ts +++ b/lib/build/supertokens.d.ts @@ -12,6 +12,7 @@ import RecipeModule from "./recipeModule"; import NormalisedURLPath from "./normalisedURLPath"; import type { BaseRequest, BaseResponse } from "./framework"; import type { TypeFramework } from "./framework/types"; +import { RecipeIdToRecipeTypeMap } from "./recipeIdToRecipeType"; export default class SuperTokens { private static instance; framework: TypeFramework; @@ -95,4 +96,6 @@ export default class SuperTokens { middleware: (request: BaseRequest, response: BaseResponse, userContext: UserContext) => Promise; errorHandler: (err: any, request: BaseRequest, response: BaseResponse, userContext: UserContext) => Promise; getRequestFromUserContext: (userContext: UserContext | undefined) => BaseRequest | undefined; + getRecipeInstanceOrThrow: (recipeId: T) => RecipeIdToRecipeTypeMap[T]; + getRecipeInstance: (recipeId: T) => RecipeIdToRecipeTypeMap[T] | undefined; } diff --git a/lib/build/supertokens.js b/lib/build/supertokens.js index a1a2cf4a6..437dc34b4 100644 --- a/lib/build/supertokens.js +++ b/lib/build/supertokens.js @@ -81,7 +81,6 @@ const error_1 = __importStar(require("./error")); const logger_1 = require("./logger"); const postSuperTokensInitCallbacks_1 = require("./postSuperTokensInitCallbacks"); const constants_2 = require("./recipe/multitenancy/constants"); -const recipe_1 = __importDefault(require("./recipe/session/recipe")); class SuperTokens { constructor(config) { var _a, _b, _c, _d, _e, _f; @@ -101,7 +100,7 @@ class SuperTokens { return Array.from(headerSet); }; this.getUserCount = async (includeRecipeIds, tenantId, userContext) => { - let querier = querier_1.Querier.getNewInstanceOrThrowError(undefined); + let querier = querier_1.Querier.getNewInstanceOrThrowError(this); let apiVersion = await querier.getAPIVersion(userContext); if ((0, utils_1.maxVersion)(apiVersion, "2.7") === "2.7") { throw new Error( @@ -128,7 +127,7 @@ class SuperTokens { return Number(response.count); }; this.createUserIdMapping = async function (input) { - let querier = querier_1.Querier.getNewInstanceOrThrowError(undefined); + let querier = querier_1.Querier.getNewInstanceOrThrowError(this); let cdiVersion = await querier.getAPIVersion(input.userContext); if ((0, utils_1.maxVersion)("2.15", cdiVersion) === cdiVersion) { // create userId mapping is only available >= CDI 2.15 @@ -147,7 +146,7 @@ class SuperTokens { } }; this.getUserIdMapping = async function (input) { - let querier = querier_1.Querier.getNewInstanceOrThrowError(undefined); + let querier = querier_1.Querier.getNewInstanceOrThrowError(this); let cdiVersion = await querier.getAPIVersion(input.userContext); if ((0, utils_1.maxVersion)("2.15", cdiVersion) === cdiVersion) { // create userId mapping is only available >= CDI 2.15 @@ -165,7 +164,7 @@ class SuperTokens { } }; this.deleteUserIdMapping = async function (input) { - let querier = querier_1.Querier.getNewInstanceOrThrowError(undefined); + let querier = querier_1.Querier.getNewInstanceOrThrowError(this); let cdiVersion = await querier.getAPIVersion(input.userContext); if ((0, utils_1.maxVersion)("2.15", cdiVersion) === cdiVersion) { return await querier.sendPostRequest( @@ -182,7 +181,7 @@ class SuperTokens { } }; this.updateOrDeleteUserIdMappingInfo = async function (input) { - let querier = querier_1.Querier.getNewInstanceOrThrowError(undefined); + let querier = querier_1.Querier.getNewInstanceOrThrowError(this); let cdiVersion = await querier.getAPIVersion(input.userContext); if ((0, utils_1.maxVersion)("2.15", cdiVersion) === cdiVersion) { return await querier.sendPutRequest( @@ -211,9 +210,12 @@ class SuperTokens { if (handlerFromApis) { let session = undefined; if (handlerFromApis.verifySessionOptions !== undefined) { - session = await recipe_1.default - .getInstanceOrThrowError() - .verifySession(handlerFromApis.verifySessionOptions, request, response, userContext); + session = await this.getRecipeInstanceOrThrow("session").verifySession( + handlerFromApis.verifySessionOptions, + request, + response, + userContext + ); } (0, logger_1.logDebugMessage)( "middleware: Request being handled by plugin. ID is: " + handlerFromApis.pluginId @@ -427,6 +429,22 @@ class SuperTokens { } return userContext._default.request; }; + this.getRecipeInstanceOrThrow = (recipeId) => { + const recipe = this.recipeModules.find((recipe) => recipe.getRecipeId() === recipeId); + if (recipe === undefined) { + throw new Error( + `Recipe ${recipeId} not initialised. Did you forget to call the add it to the recipe list?` + ); + } + return recipe; + }; + this.getRecipeInstance = (recipeId) => { + const recipe = this.recipeModules.find((recipe) => recipe.getRecipeId() === recipeId); + if (recipe === undefined) { + return undefined; + } + return recipe; + }; this.appInfo = (0, utils_1.normaliseInputAppInfoOrThrowError)(config.appInfo); const { config: _config, @@ -505,7 +523,7 @@ class SuperTokens { let jwtRecipe = require("./recipe/jwt/recipe").default; let AccountLinkingRecipe = require("./recipe/accountlinking/recipe").default; this.recipeModules = config.recipeList.map((func) => { - const recipeModule = func(this.appInfo, this.isInServerlessEnv, this.pluginOverrideMaps); + const recipeModule = func(this, this.appInfo, this.isInServerlessEnv, this.pluginOverrideMaps); if (recipeModule.getRecipeId() === MultitenancyRecipe.RECIPE_ID) { multitenancyFound = true; } else if (recipeModule.getRecipeId() === UserMetadataRecipe.RECIPE_ID) { @@ -527,18 +545,22 @@ class SuperTokens { }); if (!accountLinkingFound) { this.recipeModules.push( - AccountLinkingRecipe.init()(this.appInfo, this.isInServerlessEnv, this.pluginOverrideMaps) + AccountLinkingRecipe.init()(this, this.appInfo, this.isInServerlessEnv, this.pluginOverrideMaps) ); } if (!jwtFound) { - this.recipeModules.push(jwtRecipe.init()(this.appInfo, this.isInServerlessEnv, this.pluginOverrideMaps)); + this.recipeModules.push( + jwtRecipe.init()(this, this.appInfo, this.isInServerlessEnv, this.pluginOverrideMaps) + ); } if (!openIdFound) { - this.recipeModules.push(OpenIdRecipe.init()(this.appInfo, this.isInServerlessEnv, this.pluginOverrideMaps)); + this.recipeModules.push( + OpenIdRecipe.init()(this, this.appInfo, this.isInServerlessEnv, this.pluginOverrideMaps) + ); } if (!multitenancyFound) { this.recipeModules.push( - MultitenancyRecipe.init()(this.appInfo, this.isInServerlessEnv, this.pluginOverrideMaps) + MultitenancyRecipe.init()(this, this.appInfo, this.isInServerlessEnv, this.pluginOverrideMaps) ); } if (totpFound && !multiFactorAuthFound) { @@ -548,7 +570,7 @@ class SuperTokens { // Initializing the user metadata recipe shouldn't cause any issues/side effects and it doesn't expose any APIs, // so we can just always initialize it this.recipeModules.push( - UserMetadataRecipe.init()(this.appInfo, this.isInServerlessEnv, this.pluginOverrideMaps) + UserMetadataRecipe.init()(this, this.appInfo, this.isInServerlessEnv, this.pluginOverrideMaps) ); } // While for many usecases account linking recipe also has to be initialized for MFA to function well, @@ -558,7 +580,7 @@ class SuperTokens { // We've decided to always initialize the OAuth2Provider recipe if (!oauth2Found) { this.recipeModules.push( - OAuth2ProviderRecipe.init()(this.appInfo, this.isInServerlessEnv, this.pluginOverrideMaps) + OAuth2ProviderRecipe.init()(this, this.appInfo, this.isInServerlessEnv, this.pluginOverrideMaps) ); } this.telemetryEnabled = config.telemetry === undefined ? !(0, utils_1.isTestEnv)() : config.telemetry; diff --git a/lib/build/thirdpartyUtils.js b/lib/build/thirdpartyUtils.js index cb3344cb5..838367d23 100644 --- a/lib/build/thirdpartyUtils.js +++ b/lib/build/thirdpartyUtils.js @@ -63,7 +63,7 @@ exports.verifyIdTokenFromJWKSEndpointAndGetPayload = verifyIdTokenFromJWKSEndpoi exports.getOIDCDiscoveryInfo = getOIDCDiscoveryInfo; const jose = __importStar(require("jose")); const logger_1 = require("./logger"); -const utils_1 = require("./utils"); +const querier_1 = require("./querier"); const normalisedURLDomain_1 = __importDefault(require("./normalisedURLDomain")); const normalisedURLPath_1 = __importDefault(require("./normalisedURLPath")); async function doGetRequest(url, queryParams, headers) { @@ -75,7 +75,7 @@ async function doGetRequest(url, queryParams, headers) { } const finalURL = new URL(url); finalURL.search = new URLSearchParams(queryParams).toString(); - let response = await (0, utils_1.doFetch)(finalURL.toString(), { + let response = await (0, querier_1.doFetch)(finalURL.toString(), { headers: headers, }); const stringResponse = await response.text(); @@ -100,7 +100,7 @@ async function doPostRequest(url, params, headers) { `POST request to ${url}, with params ${JSON.stringify(params)} and headers ${JSON.stringify(headers)}` ); const body = new URLSearchParams(params).toString(); - let response = await (0, utils_1.doFetch)(url, { + let response = await (0, querier_1.doFetch)(url, { method: "POST", body, headers, diff --git a/lib/build/types.d.ts b/lib/build/types.d.ts index c2d64731c..ef74b4979 100644 --- a/lib/build/types.d.ts +++ b/lib/build/types.d.ts @@ -2,9 +2,9 @@ import RecipeModule from "./recipeModule"; import NormalisedURLDomain from "./normalisedURLDomain"; import NormalisedURLPath from "./normalisedURLPath"; -import { TypeFramework } from "./framework/types"; +import type { TypeFramework } from "./framework/types"; import { RecipeLevelUser } from "./recipe/accountlinking/types"; -import { BaseRequest, BaseResponse } from "./framework"; +import type { BaseRequest, BaseResponse } from "./framework"; import type { TypeInput as AccountLinkingTypeInput } from "./recipe/accountlinking/types"; import type { TypeInput as DashboardTypeInput } from "./recipe/dashboard/types"; import type { TypeInput as EmailPasswordTypeInput } from "./recipe/emailpassword/types"; @@ -25,6 +25,7 @@ import type { TypeInput as TotpTypeInput } from "./recipe/totp/types"; import type { TypeInput as UserMetadataTypeInput } from "./recipe/usermetadata/types"; import type { TypeInput as UserRolesTypeInput } from "./recipe/userroles/types"; import type { TypeInput as WebauthnTypeInput } from "./recipe/webauthn/types"; +import type SuperTokens from "./supertokens"; declare const __brand: unique symbol; type Brand = { [__brand]: B; @@ -190,6 +191,7 @@ export interface HttpRequest { body?: any; } export type RecipeListFunction = ( + superTokens: SuperTokens, appInfo: NormalisedAppinfo, isInServerlessEnv: boolean, overrideMaps: NonNullable[] diff --git a/lib/build/utils.d.ts b/lib/build/utils.d.ts index 53bd8cd85..e56e3ae09 100644 --- a/lib/build/utils.d.ts +++ b/lib/build/utils.d.ts @@ -11,7 +11,6 @@ import type { import type { BaseRequest, BaseResponse } from "./framework"; import { User } from "./user"; import { SessionContainer } from "./recipe/session"; -export declare const doFetch: typeof fetch; export declare function getLargestVersionFromIntersection(v1: string[], v2: string[]): string | undefined; export declare function maxVersion(version1: string, version2: string): string; export declare function normaliseInputAppInfoOrThrowError(appInfo: AppInfo): NormalisedAppinfo; @@ -19,7 +18,6 @@ export declare function normaliseHttpMethod(method: string): HTTPMethod; export declare function sendNon200ResponseWithMessage(res: BaseResponse, message: string, statusCode: number): void; export declare function sendNon200Response(res: BaseResponse, statusCode: number, body: JSONObject): void; export declare function send200Response(res: BaseResponse, responseJson: any): void; -export declare function isAnIpAddress(ipaddress: string): boolean; export declare function getNormalisedShouldTryLinkingWithSessionUserFlag(req: BaseRequest, body: any): any; export declare function getBackwardsCompatibleUserInfo( req: BaseRequest, @@ -43,28 +41,6 @@ export declare function setRequestInUserContextIfNotDefined( ): UserContext; export declare function getTopLevelDomainForSameSiteResolution(url: string): string; export declare function getFromObjectCaseInsensitive(key: string, object: Record): T | undefined; -export declare function postWithFetch( - url: string, - headers: Record, - body: any, - { - successLog, - errorLogHeader, - }: { - successLog: string; - errorLogHeader: string; - } -): Promise< - | { - resp: { - status: number; - body: any; - }; - } - | { - error: any; - } ->; export declare function normaliseEmail(email: string): string; export declare function toCamelCase(str: string): string; export declare function toSnakeCase(str: string): string; diff --git a/lib/build/utils.js b/lib/build/utils.js index 3f00a2d0e..9039e7d88 100644 --- a/lib/build/utils.js +++ b/lib/build/utils.js @@ -1,4 +1,56 @@ "use strict"; +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { + enumerable: true, + get: function () { + return m[k]; + }, + }; + } + Object.defineProperty(o, k2, desc); + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); +var __setModuleDefault = + (this && this.__setModuleDefault) || + (Object.create + ? function (o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); + } + : function (o, v) { + o["default"] = v; + }); +var __importStar = + (this && this.__importStar) || + (function () { + var ownKeys = function (o) { + ownKeys = + Object.getOwnPropertyNames || + function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) + for (var k = ownKeys(mod), i = 0; i < k.length; i++) + if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; + })(); var __importDefault = (this && this.__importDefault) || function (mod) { @@ -11,7 +63,6 @@ exports.isBuffer = exports.isTestEnv = exports.getBuffer = exports.getProcess = - exports.doFetch = void 0; exports.getLargestVersionFromIntersection = getLargestVersionFromIntersection; exports.maxVersion = maxVersion; @@ -20,7 +71,6 @@ exports.normaliseHttpMethod = normaliseHttpMethod; exports.sendNon200ResponseWithMessage = sendNon200ResponseWithMessage; exports.sendNon200Response = sendNon200Response; exports.send200Response = send200Response; -exports.isAnIpAddress = isAnIpAddress; exports.getNormalisedShouldTryLinkingWithSessionUserFlag = getNormalisedShouldTryLinkingWithSessionUserFlag; exports.getBackwardsCompatibleUserInfo = getBackwardsCompatibleUserInfo; exports.getLatestFDIVersionFromFDIList = getLatestFDIVersionFromFDIList; @@ -33,7 +83,6 @@ exports.getUserContext = getUserContext; exports.setRequestInUserContextIfNotDefined = setRequestInUserContextIfNotDefined; exports.getTopLevelDomainForSameSiteResolution = getTopLevelDomainForSameSiteResolution; exports.getFromObjectCaseInsensitive = getFromObjectCaseInsensitive; -exports.postWithFetch = postWithFetch; exports.normaliseEmail = normaliseEmail; exports.toCamelCase = toCamelCase; exports.toSnakeCase = toSnakeCase; @@ -41,59 +90,10 @@ exports.transformObjectKeys = transformObjectKeys; exports.getPublicConfig = getPublicConfig; const tldts_1 = require("tldts"); const types_1 = require("./types"); -const normalisedURLDomain_1 = __importDefault(require("./normalisedURLDomain")); +const normalisedURLDomain_1 = __importStar(require("./normalisedURLDomain")); const normalisedURLPath_1 = __importDefault(require("./normalisedURLPath")); const logger_1 = require("./logger"); const constants_1 = require("./constants"); -const cross_fetch_1 = __importDefault(require("cross-fetch")); -const processState_1 = require("./processState"); -const doFetch = async (input, init) => { - // frameworks like nextJS cache fetch GET requests (https://nextjs.org/docs/app/building-your-application/caching#data-cache) - // we don't want that because it may lead to weird behaviour when querying the core. - if (init === undefined) { - processState_1.ProcessState.getInstance().addState( - processState_1.PROCESS_STATE.ADDING_NO_CACHE_HEADER_IN_FETCH - ); - init = { - cache: "no-store", - redirect: "manual", - }; - } else { - if (init.cache === undefined) { - processState_1.ProcessState.getInstance().addState( - processState_1.PROCESS_STATE.ADDING_NO_CACHE_HEADER_IN_FETCH - ); - init.cache = "no-store"; - init.redirect = "manual"; - } - } - // Remove the cache field if the runtime is Cloudflare Workers - // - // CF Workers did not support the cache field at all until Nov, 2024 - // when they added support for the `cache` field but it only supports - // `no-store`. - // - // The following check is to ensure that this doesn't error out in - // Cloudflare Workers where compatibility flag is set to an older version. - // - // Since there is no way for us to determine which compatibility flags are - // enabled, we are disabling the cache functionality for CF Workers altogether. - // Ref issue: https://github.com/cloudflare/workerd/issues/698 - if (isRunningInCloudflareWorker()) { - delete init.cache; - } - const fetchFunction = typeof fetch !== "undefined" ? fetch : cross_fetch_1.default; - try { - return await fetchFunction(input, init); - } catch (e) { - (0, logger_1.logDebugMessage)("Error fetching: " + e); - throw e; - } -}; -exports.doFetch = doFetch; -function isRunningInCloudflareWorker() { - return typeof navigator !== "undefined" && navigator.userAgent === "Cloudflare-Workers"; -} function getLargestVersionFromIntersection(v1, v2) { let intersection = v1.filter((value) => v2.indexOf(value) !== -1); if (intersection.length === 0) { @@ -216,11 +216,6 @@ function deepTransform(obj) { } return out; } -function isAnIpAddress(ipaddress) { - return /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test( - ipaddress - ); -} function getNormalisedShouldTryLinkingWithSessionUserFlag(req, body) { var _a; if (hasGreaterThanEqualToFDI(req, "3.1")) { @@ -348,7 +343,11 @@ function setRequestInUserContextIfNotDefined(userContext, request) { function getTopLevelDomainForSameSiteResolution(url) { let urlObj = new URL(url); let hostname = urlObj.hostname; - if (hostname.startsWith("localhost") || hostname.startsWith("localhost.org") || isAnIpAddress(hostname)) { + if ( + hostname.startsWith("localhost") || + hostname.startsWith("localhost.org") || + (0, normalisedURLDomain_1.isAnIpAddress)(hostname) + ) { // we treat these as the same TLDs since we can use sameSite lax for all of them. return "localhost"; } @@ -382,48 +381,6 @@ function getFromObjectCaseInsensitive(key, object) { } return object[matchedKeys[0]]; } -async function postWithFetch(url, headers, body, { successLog, errorLogHeader }) { - let error; - let resp; - try { - const fetchResp = await (0, exports.doFetch)(url, { - method: "POST", - body: JSON.stringify(body), - headers, - }); - const respText = await fetchResp.text(); - resp = { - status: fetchResp.status, - body: JSON.parse(respText), - }; - if (fetchResp.status < 300) { - (0, logger_1.logDebugMessage)(successLog); - return { resp }; - } - (0, logger_1.logDebugMessage)(errorLogHeader); - (0, logger_1.logDebugMessage)(`Error status: ${fetchResp.status}`); - (0, logger_1.logDebugMessage)(`Error response: ${respText}`); - } catch (caught) { - error = caught; - (0, logger_1.logDebugMessage)(errorLogHeader); - if (error instanceof Error) { - (0, logger_1.logDebugMessage)(`Error: ${error.message}`); - (0, logger_1.logDebugMessage)(`Stack: ${error.stack}`); - } else { - (0, logger_1.logDebugMessage)(`Error: ${JSON.stringify(error)}`); - } - } - (0, logger_1.logDebugMessage)("Logging the input below:"); - (0, logger_1.logDebugMessage)(JSON.stringify(body, null, 2)); - if (error !== undefined) { - return { - error, - }; - } - return { - resp: resp, - }; -} function normaliseEmail(email) { email = email.trim(); email = email.toLowerCase(); diff --git a/lib/ts/authUtils.ts b/lib/ts/authUtils.ts index 8f8ba9b3f..30c0e012b 100644 --- a/lib/ts/authUtils.ts +++ b/lib/ts/authUtils.ts @@ -1,8 +1,3 @@ -import AccountLinking from "./recipe/accountlinking/recipe"; -import Session from "./recipe/session"; -import MultiTenancy from "./recipe/multitenancy"; -import MultiFactorAuth from "./recipe/multifactorauth"; -import MultiFactorAuthRecipe from "./recipe/multifactorauth/recipe"; import { SessionContainerInterface } from "./recipe/session/types"; import { UserContext } from "./types"; import { LoginMethod, User } from "./user"; @@ -10,13 +5,14 @@ import RecipeUserId from "./recipeUserId"; import { updateAndGetMFARelatedInfoInSession } from "./recipe/multifactorauth/utils"; import { isValidFirstFactor } from "./recipe/multitenancy/utils"; import SessionError from "./recipe/session/error"; -import { Error as STError, getUser } from "."; +import { Error as STError } from "."; import { AccountInfoWithRecipeId } from "./recipe/accountlinking/types"; -import { BaseRequest, BaseResponse } from "./framework"; +import type { BaseRequest, BaseResponse } from "./framework"; import { logDebugMessage } from "./logger"; import { EmailVerificationClaim } from "./recipe/emailverification"; import SuperTokensError from "./error"; import { recipeInitDefinedShouldDoAutomaticAccountLinking } from "./recipe/accountlinking/utils"; +import type SuperTokens from "./supertokens"; export const AuthUtils = { /** @@ -72,6 +68,7 @@ export const AuthUtils = { * if the session user should become primary but we couldn't make it primary because of a conflicting primary user. */ preAuthChecks: async function ({ + stInstance, authenticatingAccountInfo, tenantId, isSignUp, @@ -84,6 +81,7 @@ export const AuthUtils = { shouldTryLinkingWithSessionUser, userContext, }: { + stInstance: SuperTokens; authenticatingAccountInfo: AccountInfoWithRecipeId; authenticatingUser: User | undefined; tenantId: string; @@ -118,6 +116,7 @@ export const AuthUtils = { // to decide if this is a first factor auth or not and if it'll link to the session user // We also load the session user here if it is available. const authTypeInfo = await AuthUtils.checkAuthTypeAndLinkingStatus( + stInstance, session, shouldTryLinkingWithSessionUser, authenticatingAccountInfo, @@ -141,6 +140,7 @@ export const AuthUtils = { // If the flowType for passwordless is USER_INPUT_CODE_AND_MAGIC_LINK and firstFactors for the tenant we only have otp-email // then we do not want to include a link in the email. const validFirstFactors = await AuthUtils.filterOutInvalidFirstFactorsOrThrowIfAllAreInvalid( + stInstance, factorIds, tenantId, session !== undefined, @@ -152,6 +152,7 @@ export const AuthUtils = { // In this case the app will try to link the session user and the authenticating user after auth, // so we need to check if this is allowed by the MFA recipe (if initialized). validFactorIds = await filterOutInvalidSecondFactorsOrThrowIfAllAreInvalid( + stInstance, factorIds, authTypeInfo.inputUserAlreadyLinkedToSessionUser, authTypeInfo.sessionUser, @@ -179,7 +180,7 @@ export const AuthUtils = { logDebugMessage("preAuthChecks checking if the user is allowed to sign up"); if ( - !(await AccountLinking.getInstanceOrThrowError().isSignUpAllowed({ + !(await stInstance.getRecipeInstanceOrThrow("accountlinking").isSignUpAllowed({ newUser: authenticatingAccountInfo, isVerified: isVerified || signInVerifiesLoginMethod || verifiedInSessionUser, tenantId, @@ -193,7 +194,7 @@ export const AuthUtils = { // for sign ins, this is checked after the credentials have been verified logDebugMessage("preAuthChecks checking if the user is allowed to sign in"); if ( - !(await AccountLinking.getInstanceOrThrowError().isSignInAllowed({ + !(await stInstance.getRecipeInstanceOrThrow("accountlinking").isSignInAllowed({ user: authenticatingUser, accountInfo: authenticatingAccountInfo, signInVerifiesLoginMethod, @@ -233,6 +234,7 @@ export const AuthUtils = { * if the session user should be primary but we couldn't make it primary because of a conflicting primary user. */ postAuthChecks: async function ({ + stInstance, authenticatedUser, recipeUserId, isSignUp, @@ -243,6 +245,7 @@ export const AuthUtils = { tenantId, userContext, }: { + stInstance: SuperTokens; authenticatedUser: User; recipeUserId: RecipeUserId; tenantId: string; @@ -259,7 +262,7 @@ export const AuthUtils = { } with ${factorId}` ); - const mfaInstance = MultiFactorAuthRecipe.getInstance(); + const mfaInstance = stInstance.getRecipeInstance("multifactorauth"); let respSession = session; if (session !== undefined) { @@ -272,24 +275,52 @@ export const AuthUtils = { logDebugMessage(`postAuthChecks marking factor as completed`); // if the authenticating user is linked to the current session user (it means that the factor got set up or completed), // we mark it as completed in the session. - await MultiFactorAuth.markFactorAsCompleteInSession(respSession!, factorId, userContext); + await mfaInstance.recipeInterfaceImpl.markFactorAsCompleteInSession({ + session: respSession!, + factorId, + userContext, + }); } } else { // If the new user wasn't linked to the current one, we overwrite the session // Note: we could also get here if MFA is enabled, but the app didn't want to link the user to the session user. - respSession = await Session.createNewSession(req, res, tenantId, recipeUserId, {}, {}, userContext); + respSession = await stInstance.getRecipeInstanceOrThrow("session").createNewSession({ + req, + res, + tenantId, + recipeUserId, + accessTokenPayload: {}, + sessionDataInDatabase: {}, + userContext, + }); if (mfaInstance !== undefined) { - await MultiFactorAuth.markFactorAsCompleteInSession(respSession!, factorId, userContext); + await mfaInstance.recipeInterfaceImpl.markFactorAsCompleteInSession({ + session: respSession!, + factorId, + userContext, + }); } } } else { logDebugMessage(`postAuthChecks creating session for first factor sign in/up`); // If there is no input session, we do not need to do anything other checks and create a new session - respSession = await Session.createNewSession(req, res, tenantId, recipeUserId, {}, {}, userContext); + respSession = await stInstance.getRecipeInstanceOrThrow("session").createNewSession({ + req, + res, + tenantId, + recipeUserId, + accessTokenPayload: {}, + sessionDataInDatabase: {}, + userContext, + }); // Here we can always mark the factor as completed, since we just created the session if (mfaInstance !== undefined) { - await MultiFactorAuth.markFactorAsCompleteInSession(respSession!, factorId, userContext); + await mfaInstance.recipeInterfaceImpl.markFactorAsCompleteInSession({ + session: respSession!, + factorId, + userContext, + }); } } return { status: "OK", session: respSession!, user: authenticatedUser }; @@ -306,6 +337,7 @@ export const AuthUtils = { * most importantly, this way all secondary factors are app-wide instead of mixing app-wide (totp) and tenant-wide (password) factors. */ getAuthenticatingUserAndAddToCurrentTenantIfRequired: async ({ + stInstance, recipeId, accountInfo, checkCredentialsOnTenant, @@ -313,6 +345,7 @@ export const AuthUtils = { session, userContext, }: { + stInstance: SuperTokens; recipeId: string; accountInfo: | { email: string; thirdParty?: undefined; phoneNumber?: undefined; webauthn?: undefined } @@ -339,8 +372,9 @@ export const AuthUtils = { logDebugMessage( `getAuthenticatingUserAndAddToCurrentTenantIfRequired called with ${JSON.stringify(accountInfo)}` ); - const existingUsers = - await AccountLinking.getInstanceOrThrowError().recipeInterfaceImpl.listUsersByAccountInfo({ + const existingUsers = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.listUsersByAccountInfo({ tenantId, accountInfo, doUnionOfAccountInfo: true, @@ -374,7 +408,9 @@ export const AuthUtils = { if (authenticatingUser === undefined && session !== undefined) { logDebugMessage(`getAuthenticatingUserAndAddToCurrentTenantIfRequired checking session user`); - const sessionUser = await getUser(session.getUserId(userContext), userContext); + const sessionUser = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: session.getUserId(userContext), userContext }); if (sessionUser === undefined) { throw new SessionError({ type: SessionError.UNAUTHORISED, @@ -425,11 +461,13 @@ export const AuthUtils = { logDebugMessage( `getAuthenticatingUserAndAddToCurrentTenantIfRequired associating user from ${lm.tenantIds[0]} with current tenant` ); - const associateRes = await MultiTenancy.associateUserToTenant( - tenantId, - lm.recipeUserId, - userContext - ); + const associateRes = await stInstance + .getRecipeInstanceOrThrow("multitenancy") + .recipeInterfaceImpl.associateUserToTenant({ + tenantId, + recipeUserId: lm.recipeUserId, + userContext, + }); logDebugMessage( `getAuthenticatingUserAndAddToCurrentTenantIfRequired associating returned ${associateRes.status}` ); @@ -488,6 +526,7 @@ export const AuthUtils = { * if the session user should be primary but we couldn't make it primary because of a conflicting primary user. */ checkAuthTypeAndLinkingStatus: async function ( + stInstance: SuperTokens, session: SessionContainerInterface | undefined, shouldTryLinkingWithSessionUser: boolean | undefined, accountInfo: AccountInfoWithRecipeId, @@ -532,14 +571,18 @@ export const AuthUtils = { return { status: "OK", isFirstFactor: true }; } - if (!recipeInitDefinedShouldDoAutomaticAccountLinking(AccountLinking.getInstanceOrThrowError().config)) { + if ( + !recipeInitDefinedShouldDoAutomaticAccountLinking( + stInstance.getRecipeInstanceOrThrow("accountlinking").config + ) + ) { if (shouldTryLinkingWithSessionUser === true) { throw new Error( "Please initialise the account linking recipe and define shouldDoAutomaticAccountLinking to enable MFA" ); } else { // This is the legacy case where shouldTryLinkingWithSessionUser is undefined - if (MultiFactorAuthRecipe.getInstance() !== undefined) { + if (stInstance.getRecipeInstance("multifactorauth") !== undefined) { throw new Error( "Please initialise the account linking recipe and define shouldDoAutomaticAccountLinking to enable MFA" ); @@ -578,6 +621,7 @@ export const AuthUtils = { ); // We have to load the session user in order to get the account linking info const sessionUserResult = await AuthUtils.tryAndMakeSessionUserIntoAPrimaryUser( + stInstance, session, skipSessionUserUpdateInCore, userContext @@ -608,13 +652,15 @@ export const AuthUtils = { // We check if the app intends to link these two accounts // Note: in some cases if the accountInfo already belongs to a primary user - const shouldLink = await AccountLinking.getInstanceOrThrowError().config.shouldDoAutomaticAccountLinking( - accountInfo, - sessionUser, - session, - session.getTenantId(), - userContext - ); + const shouldLink = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .config.shouldDoAutomaticAccountLinking( + accountInfo, + sessionUser, + session, + session.getTenantId(), + userContext + ); logDebugMessage( `checkAuthTypeAndLinkingStatus session user <-> input user shouldDoAutomaticAccountLinking returned ${JSON.stringify( shouldLink @@ -657,6 +703,7 @@ export const AuthUtils = { * if the session user should be primary but we couldn't make it primary because of a conflicting primary user. */ linkToSessionIfRequiredElseCreatePrimaryUserIdOrLinkByAccountInfo: async function ({ + stInstance, tenantId, inputUser, recipeUserId, @@ -664,6 +711,7 @@ export const AuthUtils = { shouldTryLinkingWithSessionUser, userContext, }: { + stInstance: SuperTokens; tenantId: string; inputUser: User; recipeUserId: RecipeUserId; @@ -685,6 +733,7 @@ export const AuthUtils = { const retry = () => { logDebugMessage("linkToSessionIfRequiredElseCreatePrimaryUserIdOrLinkByAccountInfo retrying...."); return AuthUtils.linkToSessionIfRequiredElseCreatePrimaryUserIdOrLinkByAccountInfo({ + stInstance, tenantId, inputUser: inputUser, session, @@ -706,6 +755,7 @@ export const AuthUtils = { } const authTypeRes = await AuthUtils.checkAuthTypeAndLinkingStatus( + stInstance, session, shouldTryLinkingWithSessionUser, authLoginMethod, @@ -719,7 +769,11 @@ export const AuthUtils = { } if (authTypeRes.isFirstFactor) { - if (!recipeInitDefinedShouldDoAutomaticAccountLinking(AccountLinking.getInstanceOrThrowError().config)) { + if ( + !recipeInitDefinedShouldDoAutomaticAccountLinking( + stInstance.getRecipeInstanceOrThrow("accountlinking").config + ) + ) { logDebugMessage( "linkToSessionIfRequiredElseCreatePrimaryUserIdOrLinkByAccountInfo skipping link by account info because this is a first factor auth and the app hasn't defined shouldDoAutomaticAccountLinking" ); @@ -730,12 +784,14 @@ export const AuthUtils = { ); // We try and list all users that can be linked to the input user based on the account info // later we can use these when trying to link or when checking if linking to the session user is possible. - const linkRes = await AccountLinking.getInstanceOrThrowError().tryLinkingByAccountInfoOrCreatePrimaryUser({ - inputUser: inputUser, - session, - tenantId, - userContext, - }); + const linkRes = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .tryLinkingByAccountInfoOrCreatePrimaryUser({ + inputUser: inputUser, + session, + tenantId, + userContext, + }); if (linkRes.status === "OK") { return { status: "OK", user: linkRes.user }; } @@ -756,6 +812,7 @@ export const AuthUtils = { "linkToSessionIfRequiredElseCreatePrimaryUserIdOrLinkByAccountInfo trying to link by session info" ); const sessionLinkingRes = await AuthUtils.tryLinkingBySession({ + stInstance, sessionUser: authTypeRes.sessionUser, authenticatedUser: inputUser, authLoginMethod, @@ -787,6 +844,7 @@ export const AuthUtils = { * It throws INVALID_CLAIM_ERROR if shouldDoAutomaticAccountLinking returned `{ shouldAutomaticallyLink: false }` but the email verification status was wrong */ tryAndMakeSessionUserIntoAPrimaryUser: async function ( + stInstance: SuperTokens, session: SessionContainerInterface, skipSessionUserUpdateInCore: boolean, userContext: UserContext @@ -796,7 +854,9 @@ export const AuthUtils = { | { status: "ACCOUNT_INFO_ALREADY_ASSOCIATED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR" } > { logDebugMessage(`tryAndMakeSessionUserIntoAPrimaryUser called`); - const sessionUser = await getUser(session.getUserId(), userContext); + const sessionUser = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: session.getUserId(), userContext }); if (sessionUser === undefined) { throw new SessionError({ type: SessionError.UNAUTHORISED, @@ -816,8 +876,9 @@ export const AuthUtils = { // We do this check here instead of using the shouldBecomePrimaryUser util, because // here we handle the shouldRequireVerification case differently - const shouldDoAccountLinking = - await AccountLinking.getInstanceOrThrowError().config.shouldDoAutomaticAccountLinking( + const shouldDoAccountLinking = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .config.shouldDoAutomaticAccountLinking( sessionUser.loginMethods[0], undefined, session, @@ -851,8 +912,9 @@ export const AuthUtils = { "This should never happen: email verification claim validator passed after setting value to false" ); } - const createPrimaryUserRes = - await AccountLinking.getInstanceOrThrowError().recipeInterfaceImpl.createPrimaryUser({ + const createPrimaryUserRes = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.createPrimaryUser({ recipeUserId: sessionUser.loginMethods[0].recipeUserId, userContext, }); @@ -894,12 +956,14 @@ export const AuthUtils = { * if the session user is not primary. This can be resolved by making it primary and retrying the call. */ tryLinkingBySession: async function ({ + stInstance, linkingToSessionUserRequiresVerification, authLoginMethod, authenticatedUser, sessionUser, userContext, }: { + stInstance: SuperTokens; authenticatedUser: User; linkingToSessionUserRequiresVerification: boolean; sessionUser: User; @@ -943,11 +1007,13 @@ export const AuthUtils = { // If we get here, it means that the session and the input user can be linked, so we try it. // Note that this function will not call shouldDoAutomaticAccountLinking and check the verification status before linking // it'll mark the freshly linked recipe user as verified if the email address was verified in the session user. - let linkAccountsResult = await AccountLinking.getInstanceOrThrowError().recipeInterfaceImpl.linkAccounts({ - recipeUserId: authenticatedUser.loginMethods[0].recipeUserId, - primaryUserId: sessionUser.id, - userContext, - }); + let linkAccountsResult = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.linkAccounts({ + recipeUserId: authenticatedUser.loginMethods[0].recipeUserId, + primaryUserId: sessionUser.id, + userContext, + }); if (linkAccountsResult.status === "OK") { logDebugMessage("tryLinkingBySession successfully linked input user to session user"); @@ -981,6 +1047,7 @@ export const AuthUtils = { }, filterOutInvalidFirstFactorsOrThrowIfAllAreInvalid: async function ( + stInstance: SuperTokens, factorIds: string[], tenantId: string, hasSession: boolean, @@ -989,7 +1056,7 @@ export const AuthUtils = { let validFactorIds = []; for (const id of factorIds) { // This util takes the tenant config into account (if it exists), then the MFA (static) config if it was initialized and set. - let validRes = await isValidFirstFactor(tenantId, id, userContext); + let validRes = await isValidFirstFactor(stInstance, tenantId, id, userContext); if (validRes.status === "TENANT_NOT_FOUND_ERROR") { if (hasSession) { @@ -1023,6 +1090,7 @@ export const AuthUtils = { return validFactorIds; }, loadSessionInAuthAPIIfNeeded: async function ( + stInstance: SuperTokens, req: BaseRequest, res: BaseResponse, shouldTryLinkingWithSessionUser: boolean | undefined, @@ -1032,17 +1100,17 @@ export const AuthUtils = { logDebugMessage( "loadSessionInAuthAPIIfNeeded: loading session because shouldTryLinkingWithSessionUser is not set to false so we may want to link later" ); - return await Session.getSession( + return await stInstance.getRecipeInstanceOrThrow("session").getSession({ req, res, - { + options: { // This is optional only if shouldTryLinkingWithSessionUser is undefined // in the (old) 3.0 FDI, this flag didn't exist and we linking was based on the session presence and shouldDoAutomaticAccountLinking sessionRequired: shouldTryLinkingWithSessionUser === true, overrideGlobalClaimValidators: () => [], }, - userContext - ); + userContext, + }); } logDebugMessage( @@ -1054,6 +1122,7 @@ export const AuthUtils = { }; async function filterOutInvalidSecondFactorsOrThrowIfAllAreInvalid( + stInstance: SuperTokens, factorIds: string[], inputUserAlreadyLinkedToSessionUser: boolean, sessionUser: User, @@ -1072,7 +1141,7 @@ async function filterOutInvalidSecondFactorsOrThrowIfAllAreInvalid( } logDebugMessage(`filterOutInvalidSecondFactorsOrThrowIfAllAreInvalid called for ${factorIds.join(", ")}`); - const mfaInstance = MultiFactorAuthRecipe.getInstance(); + const mfaInstance = stInstance.getRecipeInstance("multifactorauth"); if (mfaInstance !== undefined) { if (!inputUserAlreadyLinkedToSessionUser) { let factorsSetUpForUserProm: Promise | undefined; @@ -1096,6 +1165,7 @@ async function filterOutInvalidSecondFactorsOrThrowIfAllAreInvalid( return mfaInfoProm.then((res) => res.mfaRequirementsForAuth); } mfaInfoProm = updateAndGetMFARelatedInfoInSession({ + stInstance, session, userContext, }); diff --git a/lib/ts/combinedRemoteJWKSet.ts b/lib/ts/combinedRemoteJWKSet.ts index 063b243ac..174870ce7 100644 --- a/lib/ts/combinedRemoteJWKSet.ts +++ b/lib/ts/combinedRemoteJWKSet.ts @@ -1,6 +1,6 @@ import { createRemoteJWKSet } from "jose"; import { JWKCacheCooldownInMs } from "./recipe/session/constants"; -import { Querier } from "./querier"; +import type { Querier } from "./querier"; let combinedJWKS: ReturnType | undefined; @@ -21,9 +21,9 @@ export function resetCombinedJWKS() { Every core instance a backend is connected to is expected to connect to the same database and use the same key set for token verification. Otherwise, the result of session verification would depend on which core is currently available. */ -export function getCombinedJWKS(config: { jwksRefreshIntervalSec: number }) { +export function getCombinedJWKS(querier: Querier, config: { jwksRefreshIntervalSec: number }) { if (combinedJWKS === undefined) { - const JWKS: ReturnType[] = Querier.getNewInstanceOrThrowError(undefined) + const JWKS: ReturnType[] = querier .getAllCoreUrlsForPath("/.well-known/jwks.json") .map((url) => createRemoteJWKSet(new URL(url), { diff --git a/lib/ts/customFramework.ts b/lib/ts/customFramework.ts index e68ad6eaf..7ce969adc 100644 --- a/lib/ts/customFramework.ts +++ b/lib/ts/customFramework.ts @@ -7,13 +7,14 @@ import { serialize } from "cookie"; import { CollectingResponse, errorHandler, middleware, PreParsedRequest } from "./framework/custom"; import Session, { SessionContainer, VerifySessionOptions } from "./recipe/session"; -import SessionRecipe from "./recipe/session/recipe"; import { parseJWTWithoutSignatureVerification } from "./recipe/session/jwt"; import { JWTPayload } from "jose"; import { HTTPMethod } from "./types"; import { getInfoFromAccessToken } from "./recipe/session/accessToken"; import { getCombinedJWKS } from "./combinedRemoteJWKSet"; -import { BaseRequest } from "./framework"; +import type { BaseRequest } from "./framework"; +import { Querier } from "./querier"; +import SuperTokens from "./supertokens"; export interface ParsableRequest { url: string; @@ -137,8 +138,12 @@ export async function getSessionForSSRUsingAccessToken(accessToken: string | und }> { const hasToken = !!accessToken; try { - const sessionRecipe = SessionRecipe.getInstanceOrThrowError(); - const jwksToUse = getCombinedJWKS(sessionRecipe.config); + const sessionRecipe = SuperTokens.getInstanceOrThrowError().getRecipeInstanceOrThrow("session"); + const querier = Querier.getNewInstanceOrThrowError( + SuperTokens.getInstanceOrThrowError(), + sessionRecipe.getRecipeId() + ); + const jwksToUse = getCombinedJWKS(querier, sessionRecipe.config); try { if (accessToken) { diff --git a/lib/ts/index.ts b/lib/ts/index.ts index 9b6190d5d..1057fe9e3 100644 --- a/lib/ts/index.ts +++ b/lib/ts/index.ts @@ -16,7 +16,6 @@ import SuperTokens from "./supertokens"; import SuperTokensError, { SuperTokensPluginError } from "./error"; import { UserContext, User as UserType } from "./types"; -import AccountLinking from "./recipe/accountlinking/recipe"; import { AccountInfoInput } from "./recipe/accountlinking/types"; import RecipeUserId from "./recipeUserId"; import { User } from "./user"; @@ -63,11 +62,13 @@ export default class SuperTokensWrapper { users: UserType[]; nextPaginationToken?: string; }> { - return AccountLinking.getInstanceOrThrowError().recipeInterfaceImpl.getUsers({ - timeJoinedOrder: "ASC", - ...input, - userContext: getUserContext(input.userContext), - }); + return SuperTokens.getInstanceOrThrowError() + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUsers({ + timeJoinedOrder: "ASC", + ...input, + userContext: getUserContext(input.userContext), + }); } static getUsersNewestFirst(input: { @@ -81,11 +82,13 @@ export default class SuperTokensWrapper { users: UserType[]; nextPaginationToken?: string; }> { - return AccountLinking.getInstanceOrThrowError().recipeInterfaceImpl.getUsers({ - timeJoinedOrder: "DESC", - ...input, - userContext: getUserContext(input.userContext), - }); + return SuperTokens.getInstanceOrThrowError() + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUsers({ + timeJoinedOrder: "DESC", + ...input, + userContext: getUserContext(input.userContext), + }); } static createUserIdMapping(input: { @@ -137,10 +140,12 @@ export default class SuperTokensWrapper { } static async getUser(userId: string, userContext?: Record) { - return await AccountLinking.getInstanceOrThrowError().recipeInterfaceImpl.getUser({ - userId, - userContext: getUserContext(userContext), - }); + return await SuperTokens.getInstanceOrThrowError() + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ + userId, + userContext: getUserContext(userContext), + }); } static async listUsersByAccountInfo( @@ -149,23 +154,27 @@ export default class SuperTokensWrapper { doUnionOfAccountInfo: boolean = false, userContext?: Record ) { - return await AccountLinking.getInstanceOrThrowError().recipeInterfaceImpl.listUsersByAccountInfo({ - tenantId, - accountInfo, - doUnionOfAccountInfo, - userContext: getUserContext(userContext), - }); + return await SuperTokens.getInstanceOrThrowError() + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.listUsersByAccountInfo({ + tenantId, + accountInfo, + doUnionOfAccountInfo, + userContext: getUserContext(userContext), + }); } static async deleteUser( userId: string, removeAllLinkedAccounts: boolean = true, userContext?: Record ) { - return await AccountLinking.getInstanceOrThrowError().recipeInterfaceImpl.deleteUser({ - userId, - removeAllLinkedAccounts, - userContext: getUserContext(userContext), - }); + return await SuperTokens.getInstanceOrThrowError() + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.deleteUser({ + userId, + removeAllLinkedAccounts, + userContext: getUserContext(userContext), + }); } static convertToRecipeUserId(recipeUserId: string): RecipeUserId { return new RecipeUserId(recipeUserId); diff --git a/lib/ts/nextjs.ts b/lib/ts/nextjs.ts index 61f690f6f..a133c5e19 100644 --- a/lib/ts/nextjs.ts +++ b/lib/ts/nextjs.ts @@ -14,7 +14,7 @@ */ import { errorHandler } from "./framework/express"; -import { CollectingResponse, PreParsedRequest } from "./framework/custom"; +import type { CollectingResponse, PreParsedRequest } from "./framework/custom"; import { SessionContainer, VerifySessionOptions } from "./recipe/session"; import { JWTPayload } from "jose"; import { diff --git a/lib/ts/normalisedURLDomain.ts b/lib/ts/normalisedURLDomain.ts index eb229b05d..6f7b2849a 100644 --- a/lib/ts/normalisedURLDomain.ts +++ b/lib/ts/normalisedURLDomain.ts @@ -13,7 +13,11 @@ * under the License. */ -import { isAnIpAddress } from "./utils"; +export function isAnIpAddress(ipaddress: string) { + return /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test( + ipaddress + ); +} export default class NormalisedURLDomain { private value: string; diff --git a/lib/ts/querier.ts b/lib/ts/querier.ts index a71a4fccc..d19421400 100644 --- a/lib/ts/querier.ts +++ b/lib/ts/querier.ts @@ -12,7 +12,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -import { doFetch, getLargestVersionFromIntersection, isTestEnv } from "./utils"; +import { getLargestVersionFromIntersection, isTestEnv } from "./utils"; import { cdiSupported } from "./version"; import NormalisedURLDomain from "./normalisedURLDomain"; import NormalisedURLPath from "./normalisedURLPath"; @@ -21,10 +21,11 @@ import { RATE_LIMIT_STATUS_CODE } from "./constants"; import { logDebugMessage } from "./logger"; import { UserContext } from "./types"; import { NetworkInterceptor } from "./types"; -import SuperTokens from "./supertokens"; import { PathParam, RequestBody, ResponseBody } from "./core/types"; import { paths } from "./core/paths"; +import type SuperTokens from "./supertokens"; +import crossFetch from "cross-fetch"; export class Querier { private static initCalled = false; @@ -45,6 +46,7 @@ export class Querier { // we have rIdToCore so that recipes can force change the rId sent to core. This is a hack until the core is able // to support multiple rIds per API private constructor( + private stInstance: SuperTokens, hosts: { domain: NormalisedURLDomain; basePath: NormalisedURLPath }[] | undefined, rIdToCore?: string ) { @@ -57,10 +59,9 @@ export class Querier { return Querier.apiVersion; } ProcessState.getInstance().addState(PROCESS_STATE.CALLING_SERVICE_IN_GET_API_VERSION); - const st = SuperTokens.getInstanceOrThrowError(); - const appInfo = st.appInfo; + const appInfo = this.stInstance.appInfo; - const request = st.getRequestFromUserContext(userContext); + const request = this.stInstance.getRequestFromUserContext(userContext); const queryParamsObj: { apiDomain: string; websiteDomain: string; @@ -129,11 +130,11 @@ export class Querier { return Querier.hostsAliveForTesting; }; - static getNewInstanceOrThrowError(rIdToCore?: string): Querier { + static getNewInstanceOrThrowError(stInstance: SuperTokens, rIdToCore?: string): Querier { if (!Querier.initCalled) { throw Error("Please call the supertokens.init function before using SuperTokens"); } - return new Querier(Querier.hosts, rIdToCore); + return new Querier(stInstance, Querier.hosts, rIdToCore); } static init( @@ -695,3 +696,97 @@ export class Querier { } }; } + +export const doFetch: typeof fetch = async (input: RequestInfo | URL, init?: RequestInit | undefined) => { + // frameworks like nextJS cache fetch GET requests (https://nextjs.org/docs/app/building-your-application/caching#data-cache) + // we don't want that because it may lead to weird behaviour when querying the core. + if (init === undefined) { + ProcessState.getInstance().addState(PROCESS_STATE.ADDING_NO_CACHE_HEADER_IN_FETCH); + init = { + cache: "no-store", + redirect: "manual", + }; + } else { + if (init.cache === undefined) { + ProcessState.getInstance().addState(PROCESS_STATE.ADDING_NO_CACHE_HEADER_IN_FETCH); + init.cache = "no-store"; + init.redirect = "manual"; + } + } + + // Remove the cache field if the runtime is Cloudflare Workers + // + // CF Workers did not support the cache field at all until Nov, 2024 + // when they added support for the `cache` field but it only supports + // `no-store`. + // + // The following check is to ensure that this doesn't error out in + // Cloudflare Workers where compatibility flag is set to an older version. + // + // Since there is no way for us to determine which compatibility flags are + // enabled, we are disabling the cache functionality for CF Workers altogether. + // Ref issue: https://github.com/cloudflare/workerd/issues/698 + if (isRunningInCloudflareWorker()) { + delete init.cache; + } + + const fetchFunction = typeof fetch !== "undefined" ? fetch : crossFetch; + try { + return await fetchFunction(input, init); + } catch (e) { + logDebugMessage("Error fetching: " + e); + throw e; + } +}; + +function isRunningInCloudflareWorker() { + return typeof navigator !== "undefined" && navigator.userAgent === "Cloudflare-Workers"; +} + +export async function postWithFetch( + url: string, + headers: Record, + body: any, + { successLog, errorLogHeader }: { successLog: string; errorLogHeader: string } +): Promise<{ resp: { status: number; body: any } } | { error: any }> { + let error; + let resp: { status: number; body: any }; + try { + const fetchResp = await doFetch(url, { + method: "POST", + body: JSON.stringify(body), + headers, + }); + const respText = await fetchResp.text(); + resp = { + status: fetchResp.status, + body: JSON.parse(respText), + }; + if (fetchResp.status < 300) { + logDebugMessage(successLog); + return { resp }; + } + logDebugMessage(errorLogHeader); + logDebugMessage(`Error status: ${fetchResp.status}`); + logDebugMessage(`Error response: ${respText}`); + } catch (caught) { + error = caught; + logDebugMessage(errorLogHeader); + if (error instanceof Error) { + logDebugMessage(`Error: ${error.message}`); + logDebugMessage(`Stack: ${error.stack}`); + } else { + logDebugMessage(`Error: ${JSON.stringify(error)}`); + } + } + logDebugMessage("Logging the input below:"); + logDebugMessage(JSON.stringify(body, null, 2)); + if (error !== undefined) { + return { + error, + }; + } + return { + resp: resp!, + }; +} diff --git a/lib/ts/recipe/accountlinking/index.ts b/lib/ts/recipe/accountlinking/index.ts index 833977414..aa99a8730 100644 --- a/lib/ts/recipe/accountlinking/index.ts +++ b/lib/ts/recipe/accountlinking/index.ts @@ -16,7 +16,6 @@ import Recipe from "./recipe"; import type { RecipeInterface, AccountInfoWithRecipeId } from "./types"; import RecipeUserId from "../../recipeUserId"; -import { getUser } from "../.."; import { getUserContext } from "../../utils"; import { SessionContainerInterface } from "../session/types"; @@ -38,7 +37,11 @@ export default class Wrapper { session?: SessionContainerInterface, userContext?: Record ) { - const user = await getUser(recipeUserId.getAsString(), userContext); + const ctx = getUserContext(userContext); + const user = await Recipe.getInstanceOrThrowError().recipeInterfaceImpl.getUser({ + userId: recipeUserId.getAsString(), + userContext: ctx, + }); if (user === undefined) { // Should never really come here unless a programming error happened in the app throw new Error("Unknown recipeUserId"); @@ -47,7 +50,7 @@ export default class Wrapper { tenantId, inputUser: user, session, - userContext: getUserContext(userContext), + userContext: ctx, }); if (linkRes.status === "NO_LINK") { return user; @@ -69,7 +72,11 @@ export default class Wrapper { recipeUserId: RecipeUserId, userContext?: Record ) { - const user = await getUser(recipeUserId.getAsString(), userContext); + const ctx = getUserContext(userContext); + const user = await Recipe.getInstanceOrThrowError().recipeInterfaceImpl.getUser({ + userId: recipeUserId.getAsString(), + userContext: ctx, + }); if (user === undefined) { // Should never really come here unless a programming error happened in the app throw new Error("Unknown recipeUserId"); @@ -77,7 +84,7 @@ export default class Wrapper { return await Recipe.getInstanceOrThrowError().getPrimaryUserThatCanBeLinkedToRecipeUserId({ tenantId, user, - userContext: getUserContext(userContext), + userContext: ctx, }); } @@ -140,7 +147,11 @@ export default class Wrapper { session?: SessionContainerInterface, userContext?: Record ) { - const user = await getUser(recipeUserId.getAsString(), userContext); + const ctx = getUserContext(userContext); + const user = await Recipe.getInstanceOrThrowError().recipeInterfaceImpl.getUser({ + userId: recipeUserId.getAsString(), + userContext: ctx, + }); if (user === undefined) { // Should never really come here unless a programming error happened in the app throw new Error("Unknown recipeUserId"); @@ -152,7 +163,7 @@ export default class Wrapper { session, tenantId, signInVerifiesLoginMethod: false, - userContext: getUserContext(userContext), + userContext: ctx, }); } @@ -163,7 +174,11 @@ export default class Wrapper { session?: SessionContainerInterface, userContext?: Record ) { - const user = await getUser(recipeUserId.getAsString(), userContext); + const ctx = getUserContext(userContext); + const user = await Recipe.getInstanceOrThrowError().recipeInterfaceImpl.getUser({ + userId: recipeUserId.getAsString(), + userContext: ctx, + }); if (user === undefined) { throw new Error("Passed in recipe user id does not exist"); @@ -174,7 +189,7 @@ export default class Wrapper { newEmail, isVerified, session, - userContext: getUserContext(userContext), + userContext: ctx, }); return res.allowed; } diff --git a/lib/ts/recipe/accountlinking/recipe.ts b/lib/ts/recipe/accountlinking/recipe.ts index caf971a64..684cc8ec7 100644 --- a/lib/ts/recipe/accountlinking/recipe.ts +++ b/lib/ts/recipe/accountlinking/recipe.ts @@ -22,16 +22,15 @@ import type { TypeNormalisedInput, RecipeInterface, TypeInput, AccountInfoWithRe import { validateAndNormaliseUserInput } from "./utils"; import OverrideableBuilder from "supertokens-js-override"; import RecipeImplementation from "./recipeImplementation"; -import { Querier } from "../../querier"; import SuperTokensError from "../../error"; import RecipeUserId from "../../recipeUserId"; import { ProcessState, PROCESS_STATE } from "../../processState"; import { logDebugMessage } from "../../logger"; -import EmailVerificationRecipe from "../emailverification/recipe"; import { LoginMethod } from "../../user"; import { SessionContainerInterface } from "../session/types"; import { isTestEnv } from "../../utils"; import { applyPlugins } from "../../plugins"; +import type SuperTokens from "../../supertokens"; export default class Recipe extends RecipeModule { private static instance: Recipe | undefined = undefined; @@ -43,27 +42,27 @@ export default class Recipe extends RecipeModule { recipeInterfaceImpl: RecipeInterface; constructor( + stInstance: SuperTokens, recipeId: string, appInfo: NormalisedAppinfo, config: TypeInput | undefined, _recipes: {}, _ingredients: {} ) { - super(recipeId, appInfo); + super(stInstance, recipeId, appInfo); this.config = validateAndNormaliseUserInput(appInfo, config); { - let builder = new OverrideableBuilder( - RecipeImplementation(Querier.getNewInstanceOrThrowError(recipeId), this.config, this) - ); + let builder = new OverrideableBuilder(RecipeImplementation(this.querier, this.config, this)); this.recipeInterfaceImpl = builder.override(this.config.override.functions).build(); } } static init(config?: TypeInput): RecipeListFunction { - return (appInfo, _isInServerlessEnv, plugins) => { + return (stInstance, appInfo, _isInServerlessEnv, plugins) => { if (Recipe.instance === undefined) { Recipe.instance = new Recipe( + stInstance, Recipe.RECIPE_ID, appInfo, applyPlugins(Recipe.RECIPE_ID, config, plugins ?? []), @@ -690,9 +689,8 @@ export default class Recipe extends RecipeModule { recipeUserId: RecipeUserId; userContext: UserContext; }) => { - try { - EmailVerificationRecipe.getInstanceOrThrowError(); - } catch (ignored) { + let emailVerificationInstance = this.stInstance.getRecipeInstance("emailverification"); + if (emailVerificationInstance === undefined) { // if email verification recipe is not initialized, we do a no-op return; } @@ -727,30 +725,25 @@ export default class Recipe extends RecipeModule { }); if (shouldVerifyEmail) { - let resp = - await EmailVerificationRecipe.getInstanceOrThrowError().recipeInterfaceImpl.createEmailVerificationToken( - { - // While the token we create here is tenant specific, the verification status is not - // So we can use any tenantId the user is associated with here as long as we use the - // same in the verifyEmailUsingToken call - tenantId: input.user.tenantIds[0], - recipeUserId: input.recipeUserId, - email: recipeUserEmail, - userContext: input.userContext, - } - ); + let resp = await emailVerificationInstance.recipeInterfaceImpl.createEmailVerificationToken({ + // While the token we create here is tenant specific, the verification status is not + // So we can use any tenantId the user is associated with here as long as we use the + // same in the verifyEmailUsingToken call + tenantId: input.user.tenantIds[0], + recipeUserId: input.recipeUserId, + email: recipeUserEmail, + userContext: input.userContext, + }); if (resp.status === "OK") { // we purposely pass in false below cause we don't want account // linking to happen - await EmailVerificationRecipe.getInstanceOrThrowError().recipeInterfaceImpl.verifyEmailUsingToken( - { - // See comment about tenantId in the createEmailVerificationToken params - tenantId: input.user.tenantIds[0], - token: resp.token, - attemptAccountLinking: false, - userContext: input.userContext, - } - ); + await emailVerificationInstance.recipeInterfaceImpl.verifyEmailUsingToken({ + // See comment about tenantId in the createEmailVerificationToken params + tenantId: input.user.tenantIds[0], + token: resp.token, + attemptAccountLinking: false, + userContext: input.userContext, + }); } } } diff --git a/lib/ts/recipe/dashboard/api/analytics.ts b/lib/ts/recipe/dashboard/api/analytics.ts index 456264027..086425d99 100644 --- a/lib/ts/recipe/dashboard/api/analytics.ts +++ b/lib/ts/recipe/dashboard/api/analytics.ts @@ -13,26 +13,22 @@ * under the License. */ -import { APIInterface, APIOptions } from "../types"; -import SuperTokens from "../../../supertokens"; -import { Querier } from "../../../querier"; +import { APIFunction } from "../types"; +import { Querier, doFetch } from "../../../querier"; import { version as SDKVersion } from "../../../version"; import STError from "../../../error"; -import { doFetch } from "../../../utils"; -import { UserContext } from "../../../types"; export type Response = { status: "OK"; }; -export default async function analyticsPost( - _: APIInterface, - ___: string, - options: APIOptions, - userContext: UserContext -): Promise { +export default async function analyticsPost({ + stInstance, + options, + userContext, +}: Parameters[0]): Promise { // If telemetry is disabled, dont send any event - if (!SuperTokens.getInstanceOrThrowError().telemetryEnabled) { + if (!stInstance.telemetryEnabled) { return { status: "OK", }; @@ -57,13 +53,13 @@ export default async function analyticsPost( let telemetryId: string | undefined; let numberOfUsers: number; try { - let querier = Querier.getNewInstanceOrThrowError(options.recipeId); + let querier = Querier.getNewInstanceOrThrowError(stInstance); let response = await querier.sendGetRequest("/telemetry", {}, userContext); if (response.exists) { telemetryId = response.telemetryId; } - numberOfUsers = await SuperTokens.getInstanceOrThrowError().getUserCount(undefined, undefined, userContext); + numberOfUsers = await stInstance.getUserCount(undefined, undefined, userContext); } catch (_) { // If either telemetry id API or user count fetch fails, no event should be sent return { diff --git a/lib/ts/recipe/dashboard/api/apiKeyProtector.ts b/lib/ts/recipe/dashboard/api/apiKeyProtector.ts index ee2178b4d..bcc490674 100644 --- a/lib/ts/recipe/dashboard/api/apiKeyProtector.ts +++ b/lib/ts/recipe/dashboard/api/apiKeyProtector.ts @@ -12,18 +12,17 @@ * License for the specific language governing permissions and limitations * under the License. */ -import { UserContext } from "../../../types"; import RecipeError from "../error"; -import { APIFunction, APIInterface, APIOptions } from "../types"; +import { APIFunction } from "../types"; import { sendUnauthorisedAccess } from "../utils"; export default async function apiKeyProtector( - apiImplementation: APIInterface, - tenantId: string, - options: APIOptions, apiFunction: APIFunction, - userContext: UserContext + input: Parameters[0] ): Promise { + const options = input.options; + const userContext = input.userContext; + let shouldAllowAccess = false; try { @@ -49,7 +48,7 @@ export default async function apiKeyProtector( return true; } - const response = await apiFunction(apiImplementation, tenantId, options, userContext); + const response = await apiFunction(input); options.res.sendJSONResponse(response); return true; } diff --git a/lib/ts/recipe/dashboard/api/dashboard.ts b/lib/ts/recipe/dashboard/api/dashboard.ts index 82f484789..3c7b9e2f7 100644 --- a/lib/ts/recipe/dashboard/api/dashboard.ts +++ b/lib/ts/recipe/dashboard/api/dashboard.ts @@ -13,22 +13,17 @@ * under the License. */ -import { UserContext } from "../../../types"; -import { APIInterface, APIOptions } from "../types"; +import { APIFunction } from "../types"; -export default async function dashboard( - apiImplementation: APIInterface, - options: APIOptions, - userContext: UserContext -): Promise { - if (apiImplementation.dashboardGET === undefined) { +export default async function dashboard(input: Parameters[0]): Promise { + const options = input.options; + const userContext = input.userContext; + + if (input.apiImplementation?.dashboardGET === undefined) { return false; } - const htmlString = await apiImplementation.dashboardGET({ - options, - userContext, - }); + const htmlString = await input.apiImplementation.dashboardGET({ options, userContext }); options.res.sendHTMLResponse(htmlString); diff --git a/lib/ts/recipe/dashboard/api/implementation.ts b/lib/ts/recipe/dashboard/api/implementation.ts index 609c275c2..76a0b35b7 100644 --- a/lib/ts/recipe/dashboard/api/implementation.ts +++ b/lib/ts/recipe/dashboard/api/implementation.ts @@ -16,12 +16,12 @@ import NormalisedURLDomain from "../../../normalisedURLDomain"; import NormalisedURLPath from "../../../normalisedURLPath"; import { Querier } from "../../../querier"; -import SuperTokens from "../../../supertokens"; +import type SuperTokens from "../../../supertokens"; import { maxVersion } from "../../../utils"; import { DASHBOARD_API } from "../constants"; import { APIInterface, AuthMode } from "../types"; -export default function getAPIImplementation(): APIInterface { +export default function getAPIImplementation(stInstance: SuperTokens): APIInterface { return { dashboardGET: async function (input) { const bundleBasePathString = await input.options.recipeImplementation.getDashboardBundleLocation({ @@ -33,7 +33,7 @@ export default function getAPIImplementation(): APIInterface { new NormalisedURLPath(bundleBasePathString).getAsStringDangerous(); let connectionURI: string = ""; - const superTokensInstance = SuperTokens.getInstanceOrThrowError(); + const superTokensInstance = stInstance; const authMode: AuthMode = input.options.config.authMode; @@ -48,9 +48,10 @@ export default function getAPIImplementation(): APIInterface { } let isSearchEnabled = false; - const cdiVersion = await Querier.getNewInstanceOrThrowError(input.options.recipeId).getAPIVersion( - input.userContext - ); + const cdiVersion = await Querier.getNewInstanceOrThrowError( + stInstance, + input.options.recipeId + ).getAPIVersion(input.userContext); if (maxVersion("2.20", cdiVersion) === cdiVersion) { // Only enable search if CDI version is 2.20 or above isSearchEnabled = true; diff --git a/lib/ts/recipe/dashboard/api/multitenancy/createOrUpdateThirdPartyConfig.ts b/lib/ts/recipe/dashboard/api/multitenancy/createOrUpdateThirdPartyConfig.ts index c57cc7b0d..98e581432 100644 --- a/lib/ts/recipe/dashboard/api/multitenancy/createOrUpdateThirdPartyConfig.ts +++ b/lib/ts/recipe/dashboard/api/multitenancy/createOrUpdateThirdPartyConfig.ts @@ -12,10 +12,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -import { APIInterface, APIOptions } from "../../types"; -import Multitenancy from "../../../multitenancy"; -import MultitenancyRecipe from "../../../multitenancy/recipe"; -import { UserContext } from "../../../../types"; +import { APIFunction } from "../../types"; import NormalisedURLDomain from "../../../../normalisedURLDomain"; import NormalisedURLPath from "../../../../normalisedURLPath"; import { doPostRequest } from "../../../../thirdpartyUtils"; @@ -30,16 +27,17 @@ export type Response = | { status: "UNKNOWN_TENANT_ERROR" } | { status: "BOXY_ERROR"; message: string }; -export default async function createOrUpdateThirdPartyConfig( - _: APIInterface, - tenantId: string, - options: APIOptions, - userContext: UserContext -): Promise { +export default async function createOrUpdateThirdPartyConfig({ + stInstance, + tenantId, + options, + userContext, +}: Parameters[0]): Promise { const requestBody = await options.req.getJSONBody(); const { providerConfig } = requestBody; - let tenantRes = await Multitenancy.getTenant(tenantId, userContext); + let mtRecipe = stInstance.getRecipeInstanceOrThrow("multitenancy"); + let tenantRes = await mtRecipe.recipeInterfaceImpl.getTenant({ tenantId, userContext }); if (tenantRes === undefined) { return { @@ -49,19 +47,17 @@ export default async function createOrUpdateThirdPartyConfig( if (tenantRes.thirdParty.providers.length === 0) { // This means that the tenant was using the static list of providers, we need to add them all before adding the new one - const mtRecipe = MultitenancyRecipe.getInstance(); const staticProviders = mtRecipe?.staticThirdPartyProviders ?? []; for (const provider of staticProviders.filter( (provider) => provider.includeInNonPublicTenantsByDefault === true || tenantId === DEFAULT_TENANT_ID )) { - await Multitenancy.createOrUpdateThirdPartyConfig( + await mtRecipe.recipeInterfaceImpl.createOrUpdateThirdPartyConfig({ tenantId, - { + config: { thirdPartyId: provider.config.thirdPartyId, }, - undefined, - userContext - ); + userContext, + }); // delay after each provider to avoid rate limiting await new Promise((r) => setTimeout(r, 500)); // 500ms } @@ -129,12 +125,11 @@ export default async function createOrUpdateThirdPartyConfig( } } - const thirdPartyRes = await Multitenancy.createOrUpdateThirdPartyConfig( + const thirdPartyRes = await mtRecipe.recipeInterfaceImpl.createOrUpdateThirdPartyConfig({ tenantId, - providerConfig, - undefined, - userContext - ); + config: providerConfig, + userContext, + }); return thirdPartyRes; } diff --git a/lib/ts/recipe/dashboard/api/multitenancy/createTenant.ts b/lib/ts/recipe/dashboard/api/multitenancy/createTenant.ts index f246101bf..b76c047e0 100644 --- a/lib/ts/recipe/dashboard/api/multitenancy/createTenant.ts +++ b/lib/ts/recipe/dashboard/api/multitenancy/createTenant.ts @@ -12,10 +12,9 @@ * License for the specific language governing permissions and limitations * under the License. */ -import { APIInterface, APIOptions } from "../../types"; +import { APIFunction } from "../../types"; import Multitenancy from "../../../multitenancy"; import SuperTokensError from "../../../../error"; -import { UserContext } from "../../../../types"; export type Response = | { @@ -30,12 +29,7 @@ export type Response = message: string; }; -export default async function createTenant( - _: APIInterface, - __: string, - options: APIOptions, - userContext: UserContext -): Promise { +export default async function createTenant({ options, userContext }: Parameters[0]): Promise { const requestBody = await options.req.getJSONBody(); const { tenantId, ...config } = requestBody; diff --git a/lib/ts/recipe/dashboard/api/multitenancy/deleteTenant.ts b/lib/ts/recipe/dashboard/api/multitenancy/deleteTenant.ts index 95e2fc03c..8fdb40201 100644 --- a/lib/ts/recipe/dashboard/api/multitenancy/deleteTenant.ts +++ b/lib/ts/recipe/dashboard/api/multitenancy/deleteTenant.ts @@ -12,9 +12,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -import { APIInterface, APIOptions } from "../../types"; -import Multitenancy from "../../../multitenancy"; -import { UserContext } from "../../../../types"; +import { APIFunction } from "../../types"; export type Response = | { @@ -25,14 +23,15 @@ export type Response = status: "CANNOT_DELETE_PUBLIC_TENANT_ERROR"; }; -export default async function deleteTenant( - _: APIInterface, - tenantId: string, - __: APIOptions, - userContext: UserContext -): Promise { +export default async function deleteTenant({ + stInstance, + tenantId, + userContext, +}: Parameters[0]): Promise { try { - const deleteTenantRes = await Multitenancy.deleteTenant(tenantId, userContext); + const deleteTenantRes = await stInstance + .getRecipeInstanceOrThrow("multitenancy") + .recipeInterfaceImpl.deleteTenant({ tenantId, userContext }); return deleteTenantRes; } catch (err) { diff --git a/lib/ts/recipe/dashboard/api/multitenancy/deleteThirdPartyConfig.ts b/lib/ts/recipe/dashboard/api/multitenancy/deleteThirdPartyConfig.ts index c857377d8..4732acaa6 100644 --- a/lib/ts/recipe/dashboard/api/multitenancy/deleteThirdPartyConfig.ts +++ b/lib/ts/recipe/dashboard/api/multitenancy/deleteThirdPartyConfig.ts @@ -12,12 +12,9 @@ * License for the specific language governing permissions and limitations * under the License. */ -import { APIInterface, APIOptions } from "../../types"; -import Multitenancy from "../../../multitenancy"; -import MultitenancyRecipe from "../../../multitenancy/recipe"; +import { APIFunction } from "../../types"; import SuperTokensError from "../../../../error"; import { FactorIds } from "../../../multifactorauth"; -import { UserContext } from "../../../../types"; import { DEFAULT_TENANT_ID } from "../../../multitenancy/constants"; export type Response = @@ -29,12 +26,12 @@ export type Response = status: "UNKNOWN_TENANT_ERROR"; }; -export default async function deleteThirdPartyConfig( - _: APIInterface, - tenantId: string, - options: APIOptions, - userContext: UserContext -): Promise { +export default async function deleteThirdPartyConfig({ + stInstance, + tenantId, + options, + userContext, +}: Parameters[0]): Promise { const thirdPartyId = options.req.getKeyValueFromQuery("thirdPartyId"); if (typeof tenantId !== "string" || tenantId === "" || typeof thirdPartyId !== "string" || thirdPartyId === "") { @@ -44,7 +41,8 @@ export default async function deleteThirdPartyConfig( }); } - const tenantRes = await Multitenancy.getTenant(tenantId, userContext); + const mtRecipe = stInstance.getRecipeInstanceOrThrow("multitenancy"); + const tenantRes = await mtRecipe.recipeInterfaceImpl.getTenant({ tenantId, userContext }); if (tenantRes === undefined) { return { status: "UNKNOWN_TENANT_ERROR", @@ -55,44 +53,51 @@ export default async function deleteThirdPartyConfig( if (thirdPartyIdsFromCore.length === 0) { // this means that the tenant was using the static list of providers, we need to add them all before deleting one - const mtRecipe = MultitenancyRecipe.getInstance(); + const mtRecipe = stInstance.getRecipeInstanceOrThrow("multitenancy"); const staticProviders = mtRecipe?.staticThirdPartyProviders ?? []; for (const provider of staticProviders.filter( (provider) => provider.includeInNonPublicTenantsByDefault === true || tenantId === DEFAULT_TENANT_ID )) { const providerId = provider.config.thirdPartyId; - await Multitenancy.createOrUpdateThirdPartyConfig( + await mtRecipe.recipeInterfaceImpl.createOrUpdateThirdPartyConfig({ tenantId, - { + config: { thirdPartyId: providerId, }, - undefined, - userContext - ); + userContext, + }); // delay after each provider to avoid rate limiting await new Promise((r) => setTimeout(r, 500)); // 500ms } } else if (thirdPartyIdsFromCore.length === 1 && thirdPartyIdsFromCore[0] === thirdPartyId) { if (tenantRes.firstFactors === undefined) { // add all static first factors except thirdparty - await Multitenancy.createOrUpdateTenant(tenantId, { - firstFactors: [ - FactorIds.EMAILPASSWORD, - FactorIds.OTP_PHONE, - FactorIds.OTP_EMAIL, - FactorIds.LINK_PHONE, - FactorIds.LINK_EMAIL, - ], + await mtRecipe.recipeInterfaceImpl.createOrUpdateTenant({ + tenantId, + config: { + firstFactors: [ + FactorIds.EMAILPASSWORD, + FactorIds.OTP_PHONE, + FactorIds.OTP_EMAIL, + FactorIds.LINK_PHONE, + FactorIds.LINK_EMAIL, + ], + }, + userContext, }); } else if (tenantRes.firstFactors.includes("thirdparty")) { // add all static first factors except thirdparty const newFirstFactors = tenantRes.firstFactors.filter((factor) => factor !== "thirdparty"); - await Multitenancy.createOrUpdateTenant(tenantId, { - firstFactors: newFirstFactors, + await mtRecipe.recipeInterfaceImpl.createOrUpdateTenant({ + tenantId, + config: { + firstFactors: newFirstFactors, + }, + userContext, }); } } - return await Multitenancy.deleteThirdPartyConfig(tenantId, thirdPartyId, userContext); + return await mtRecipe.recipeInterfaceImpl.deleteThirdPartyConfig({ tenantId, thirdPartyId, userContext }); } diff --git a/lib/ts/recipe/dashboard/api/multitenancy/getTenantInfo.ts b/lib/ts/recipe/dashboard/api/multitenancy/getTenantInfo.ts index 56d137cf0..af1ea8b79 100644 --- a/lib/ts/recipe/dashboard/api/multitenancy/getTenantInfo.ts +++ b/lib/ts/recipe/dashboard/api/multitenancy/getTenantInfo.ts @@ -12,17 +12,13 @@ * License for the specific language governing permissions and limitations * under the License. */ -import { APIInterface, APIOptions, CoreConfigFieldInfo } from "../../types"; -import Multitenancy from "../../../multitenancy"; -import MultitenancyRecipe from "../../../multitenancy/recipe"; -import SuperTokens from "../../../../supertokens"; +import { APIFunction, CoreConfigFieldInfo } from "../../types"; import { getNormalisedFirstFactorsBasedOnTenantConfigFromCoreAndSDKInit } from "./utils"; import { findAndCreateProviderInstance, mergeProvidersFromCoreAndStatic, } from "../../../thirdparty/providers/configUtils"; import { Querier } from "../../../../querier"; -import { UserContext } from "../../../../types"; import { DEFAULT_TENANT_ID } from "../../../multitenancy/constants"; export type Response = @@ -43,13 +39,14 @@ export type Response = status: "UNKNOWN_TENANT_ERROR"; }; -export default async function getTenantInfo( - _: APIInterface, - tenantId: string, - options: APIOptions, - userContext: UserContext -): Promise { - let tenantRes = await Multitenancy.getTenant(tenantId, userContext); +export default async function getTenantInfo({ + stInstance, + tenantId, + options, + userContext, +}: Parameters[0]): Promise { + const mtRecipe = stInstance.getRecipeInstanceOrThrow("multitenancy"); + let tenantRes = await mtRecipe.recipeInterfaceImpl.getTenant({ tenantId, userContext }); if (tenantRes === undefined) { return { @@ -59,7 +56,7 @@ export default async function getTenantInfo( let { status, ...tenantConfig } = tenantRes; - let firstFactors = getNormalisedFirstFactorsBasedOnTenantConfigFromCoreAndSDKInit(tenantConfig); + let firstFactors = getNormalisedFirstFactorsBasedOnTenantConfigFromCoreAndSDKInit(stInstance, tenantConfig); if (tenantRes === undefined) { return { @@ -67,10 +64,9 @@ export default async function getTenantInfo( }; } - const userCount = await SuperTokens.getInstanceOrThrowError().getUserCount(undefined, tenantId, userContext); + const userCount = await stInstance.getUserCount(undefined, tenantId, userContext); const providersFromCore = tenantRes?.thirdParty?.providers; - const mtRecipe = MultitenancyRecipe.getInstance(); const staticProviders = mtRecipe?.staticThirdPartyProviders ?? []; const mergedProvidersFromCoreAndStatic = mergeProvidersFromCoreAndStatic( @@ -79,7 +75,7 @@ export default async function getTenantInfo( tenantId === DEFAULT_TENANT_ID ); - let querier = Querier.getNewInstanceOrThrowError(options.recipeId); + let querier = Querier.getNewInstanceOrThrowError(stInstance, options.recipeId); let coreConfig = await querier.sendGetRequest( { path: "//recipe/dashboard/tenant/core-config", diff --git a/lib/ts/recipe/dashboard/api/multitenancy/getThirdPartyConfig.ts b/lib/ts/recipe/dashboard/api/multitenancy/getThirdPartyConfig.ts index c11cdf26c..0cd1f68e3 100644 --- a/lib/ts/recipe/dashboard/api/multitenancy/getThirdPartyConfig.ts +++ b/lib/ts/recipe/dashboard/api/multitenancy/getThirdPartyConfig.ts @@ -12,15 +12,12 @@ * License for the specific language governing permissions and limitations * under the License. */ -import { APIInterface, APIOptions } from "../../types"; -import Multitenancy from "../../../multitenancy"; -import MultitenancyRecipe from "../../../multitenancy/recipe"; +import { APIFunction } from "../../types"; import { findAndCreateProviderInstance, mergeProvidersFromCoreAndStatic, } from "../../../thirdparty/providers/configUtils"; import { ProviderConfig } from "../../../thirdparty/types"; -import { UserContext } from "../../../../types"; import NormalisedURLDomain from "../../../../normalisedURLDomain"; import NormalisedURLPath from "../../../../normalisedURLPath"; import { doGetRequest } from "../../../../thirdpartyUtils"; @@ -38,13 +35,14 @@ export type Response = status: "UNKNOWN_TENANT_ERROR"; }; -export default async function getThirdPartyConfig( - _: APIInterface, - tenantId: string, - options: APIOptions, - userContext: UserContext -): Promise { - let tenantRes = await Multitenancy.getTenant(tenantId, userContext); +export default async function getThirdPartyConfig({ + stInstance, + tenantId, + options, + userContext, +}: Parameters[0]): Promise { + const mtRecipe = stInstance.getRecipeInstanceOrThrow("multitenancy"); + let tenantRes = await mtRecipe.recipeInterfaceImpl.getTenant({ tenantId, userContext }); if (tenantRes === undefined) { return { @@ -59,7 +57,6 @@ export default async function getThirdPartyConfig( } let providersFromCore = tenantRes?.thirdParty?.providers; - const mtRecipe = MultitenancyRecipe.getInstance(); let staticProviders = mtRecipe?.staticThirdPartyProviders ? mtRecipe.staticThirdPartyProviders.map((provider) => ({ ...provider })) : []; diff --git a/lib/ts/recipe/dashboard/api/multitenancy/listAllTenantsWithLoginMethods.ts b/lib/ts/recipe/dashboard/api/multitenancy/listAllTenantsWithLoginMethods.ts index 4230ca99f..dcc9b1bfd 100644 --- a/lib/ts/recipe/dashboard/api/multitenancy/listAllTenantsWithLoginMethods.ts +++ b/lib/ts/recipe/dashboard/api/multitenancy/listAllTenantsWithLoginMethods.ts @@ -12,9 +12,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -import { APIInterface, APIOptions } from "../../types"; -import MultitenancyRecipe from "../../../multitenancy/recipe"; -import { UserContext } from "../../../../types"; +import { APIFunction } from "../../types"; import { getNormalisedFirstFactorsBasedOnTenantConfigFromCoreAndSDKInit } from "./utils"; type TenantWithLoginMethods = { @@ -27,13 +25,12 @@ export type Response = { tenants: TenantWithLoginMethods[]; }; -export default async function listAllTenantsWithLoginMethods( - _: APIInterface, - __: string, - ___: APIOptions, - userContext: UserContext -): Promise { - const tenantsRes = await MultitenancyRecipe.getInstanceOrThrowError().recipeInterfaceImpl.listAllTenants({ +export default async function listAllTenantsWithLoginMethods({ + stInstance, + userContext, +}: Parameters[0]): Promise { + const mtRecipe = stInstance.getRecipeInstanceOrThrow("multitenancy"); + const tenantsRes = await mtRecipe.recipeInterfaceImpl.listAllTenants({ userContext, }); const finalTenants: TenantWithLoginMethods[] = []; @@ -41,7 +38,7 @@ export default async function listAllTenantsWithLoginMethods( for (let i = 0; i < tenantsRes.tenants.length; i++) { const currentTenant = tenantsRes.tenants[i]; - const loginMethods = getNormalisedFirstFactorsBasedOnTenantConfigFromCoreAndSDKInit(currentTenant); + const loginMethods = getNormalisedFirstFactorsBasedOnTenantConfigFromCoreAndSDKInit(stInstance, currentTenant); finalTenants.push({ tenantId: currentTenant.tenantId, diff --git a/lib/ts/recipe/dashboard/api/multitenancy/updateTenantCoreConfig.ts b/lib/ts/recipe/dashboard/api/multitenancy/updateTenantCoreConfig.ts index 0a317ba3f..42f61cff1 100644 --- a/lib/ts/recipe/dashboard/api/multitenancy/updateTenantCoreConfig.ts +++ b/lib/ts/recipe/dashboard/api/multitenancy/updateTenantCoreConfig.ts @@ -12,27 +12,25 @@ * License for the specific language governing permissions and limitations * under the License. */ -import { APIInterface, APIOptions } from "../../types"; -import MultitenancyRecipe from "../../../multitenancy/recipe"; -import { UserContext } from "../../../../types"; +import { APIFunction } from "../../types"; export type Response = | { status: "OK" } | { status: "UNKNOWN_TENANT_ERROR" } | { status: "INVALID_CONFIG_ERROR"; message: string }; -export default async function updateTenantCoreConfig( - _: APIInterface, - tenantId: string, - options: APIOptions, - userContext: UserContext -): Promise { +export default async function updateTenantCoreConfig({ + stInstance, + tenantId, + options, + userContext, +}: Parameters[0]): Promise { const requestBody = await options.req.getJSONBody(); const { name, value } = requestBody; - const mtRecipe = MultitenancyRecipe.getInstance(); + const mtRecipe = stInstance.getRecipeInstanceOrThrow("multitenancy"); - const tenantRes = await mtRecipe!.recipeInterfaceImpl.getTenant({ tenantId, userContext }); + const tenantRes = await mtRecipe.recipeInterfaceImpl.getTenant({ tenantId, userContext }); if (tenantRes === undefined) { return { status: "UNKNOWN_TENANT_ERROR", @@ -40,7 +38,7 @@ export default async function updateTenantCoreConfig( } try { - await mtRecipe!.recipeInterfaceImpl.createOrUpdateTenant({ + await mtRecipe.recipeInterfaceImpl.createOrUpdateTenant({ tenantId, config: { coreConfig: { diff --git a/lib/ts/recipe/dashboard/api/multitenancy/updateTenantFirstFactor.ts b/lib/ts/recipe/dashboard/api/multitenancy/updateTenantFirstFactor.ts index abb1ea6ac..9e93337fe 100644 --- a/lib/ts/recipe/dashboard/api/multitenancy/updateTenantFirstFactor.ts +++ b/lib/ts/recipe/dashboard/api/multitenancy/updateTenantFirstFactor.ts @@ -12,29 +12,27 @@ * License for the specific language governing permissions and limitations * under the License. */ -import { APIInterface, APIOptions } from "../../types"; -import MultitenancyRecipe from "../../../multitenancy/recipe"; +import { APIFunction } from "../../types"; import { getFactorNotAvailableMessage, getNormalisedFirstFactorsBasedOnTenantConfigFromCoreAndSDKInit } from "./utils"; -import { UserContext } from "../../../../types"; export type Response = | { status: "OK" } | { status: "RECIPE_NOT_CONFIGURED_ON_BACKEND_SDK_ERROR"; message: string } | { status: "UNKNOWN_TENANT_ERROR" }; -export default async function updateTenantFirstFactor( - _: APIInterface, - tenantId: string, - options: APIOptions, - userContext: UserContext -): Promise { +export default async function updateTenantFirstFactor({ + stInstance, + tenantId, + options, + userContext, +}: Parameters[0]): Promise { const requestBody = await options.req.getJSONBody(); const { factorId, enable } = requestBody; - const mtRecipe = MultitenancyRecipe.getInstance(); + const mtRecipe = stInstance.getRecipeInstanceOrThrow("multitenancy"); if (enable === true) { - if (!mtRecipe?.allAvailableFirstFactors.includes(factorId)) { + if (!mtRecipe.allAvailableFirstFactors.includes(factorId)) { return { status: "RECIPE_NOT_CONFIGURED_ON_BACKEND_SDK_ERROR", message: getFactorNotAvailableMessage(factorId, mtRecipe!.allAvailableFirstFactors), @@ -50,7 +48,7 @@ export default async function updateTenantFirstFactor( }; } - let firstFactors = getNormalisedFirstFactorsBasedOnTenantConfigFromCoreAndSDKInit(tenantRes); + let firstFactors = getNormalisedFirstFactorsBasedOnTenantConfigFromCoreAndSDKInit(stInstance, tenantRes); if (enable === true) { if (!firstFactors.includes(factorId)) { diff --git a/lib/ts/recipe/dashboard/api/multitenancy/updateTenantSecondaryFactor.ts b/lib/ts/recipe/dashboard/api/multitenancy/updateTenantSecondaryFactor.ts index f2c60d7db..e937e3294 100644 --- a/lib/ts/recipe/dashboard/api/multitenancy/updateTenantSecondaryFactor.ts +++ b/lib/ts/recipe/dashboard/api/multitenancy/updateTenantSecondaryFactor.ts @@ -12,14 +12,11 @@ * License for the specific language governing permissions and limitations * under the License. */ -import { APIInterface, APIOptions } from "../../types"; -import MultitenancyRecipe from "../../../multitenancy/recipe"; -import MultifactorAuthRecipe from "../../../multifactorauth/recipe"; +import { APIFunction } from "../../types"; import { getFactorNotAvailableMessage, getNormalisedRequiredSecondaryFactorsBasedOnTenantConfigFromCoreAndSDKInit, } from "./utils"; -import { UserContext } from "../../../../types"; export type Response = | { status: "OK"; isMFARequirementsForAuthOverridden: boolean } @@ -27,17 +24,17 @@ export type Response = | { status: "MFA_NOT_INITIALIZED_ERROR" } | { status: "UNKNOWN_TENANT_ERROR" }; -export default async function updateTenantSecondaryFactor( - _: APIInterface, - tenantId: string, - options: APIOptions, - userContext: UserContext -): Promise { +export default async function updateTenantSecondaryFactor({ + stInstance, + tenantId, + options, + userContext, +}: Parameters[0]): Promise { const requestBody = await options.req.getJSONBody(); const { factorId, enable } = requestBody; - const mtRecipe = MultitenancyRecipe.getInstance(); - const mfaInstance = MultifactorAuthRecipe.getInstance(); + const mtRecipe = stInstance.getRecipeInstanceOrThrow("multitenancy"); + const mfaInstance = stInstance.getRecipeInstanceOrThrow("multifactorauth"); if (mfaInstance === undefined) { return { @@ -64,7 +61,10 @@ export default async function updateTenantSecondaryFactor( } } - let secondaryFactors = getNormalisedRequiredSecondaryFactorsBasedOnTenantConfigFromCoreAndSDKInit(tenantRes); + let secondaryFactors = getNormalisedRequiredSecondaryFactorsBasedOnTenantConfigFromCoreAndSDKInit( + stInstance, + tenantRes + ); if (enable === true) { if (!secondaryFactors.includes(factorId)) { diff --git a/lib/ts/recipe/dashboard/api/multitenancy/utils.ts b/lib/ts/recipe/dashboard/api/multitenancy/utils.ts index 95d9224f7..99d0007c1 100644 --- a/lib/ts/recipe/dashboard/api/multitenancy/utils.ts +++ b/lib/ts/recipe/dashboard/api/multitenancy/utils.ts @@ -1,15 +1,15 @@ -import MultitenancyRecipe from "../../../multitenancy/recipe"; -import MultifactorAuthRecipe from "../../../multifactorauth/recipe"; import { isFactorConfiguredForTenant } from "../../../multitenancy/utils"; -import { TenantConfig } from "../../../multitenancy/types"; -import { FactorIds } from "../../../multifactorauth"; +import type { TenantConfig } from "../../../multitenancy/types"; +import { FactorIds } from "../../../multifactorauth/types"; +import type SuperTokens from "../../../../supertokens"; export function getNormalisedFirstFactorsBasedOnTenantConfigFromCoreAndSDKInit( + stInstance: SuperTokens, tenantDetailsFromCore: TenantConfig ): string[] { let firstFactors: string[]; - let mtInstance = MultitenancyRecipe.getInstanceOrThrowError(); + let mtInstance = stInstance.getRecipeInstanceOrThrow("multitenancy"); if (tenantDetailsFromCore.firstFactors !== undefined) { firstFactors = tenantDetailsFromCore.firstFactors; // highest priority, config from core } else if (mtInstance.staticFirstFactors !== undefined) { @@ -42,9 +42,10 @@ export function getNormalisedFirstFactorsBasedOnTenantConfigFromCoreAndSDKInit( } export function getNormalisedRequiredSecondaryFactorsBasedOnTenantConfigFromCoreAndSDKInit( + stInstance: SuperTokens, tenantDetailsFromCore: TenantConfig ): string[] { - const mfaInstance = MultifactorAuthRecipe.getInstance(); + const mfaInstance = stInstance.getRecipeInstanceOrThrow("multifactorauth"); if (mfaInstance === undefined) { return []; diff --git a/lib/ts/recipe/dashboard/api/search/tagsGet.ts b/lib/ts/recipe/dashboard/api/search/tagsGet.ts index 420b39654..4b002b794 100644 --- a/lib/ts/recipe/dashboard/api/search/tagsGet.ts +++ b/lib/ts/recipe/dashboard/api/search/tagsGet.ts @@ -13,19 +13,17 @@ * under the License. */ -import { APIInterface, APIOptions } from "../../types"; +import { APIFunction } from "../../types"; import { Querier } from "../../../../querier"; -import { UserContext } from "../../../../types"; type TagsResponse = { status: "OK"; tags: string[] }; -export const getSearchTags = async ( - _: APIInterface, - ___: string, - options: APIOptions, - userContext: UserContext -): Promise => { - let querier = Querier.getNewInstanceOrThrowError(options.recipeId); +export const getSearchTags = async ({ + stInstance, + options, + userContext, +}: Parameters[0]): Promise => { + let querier = Querier.getNewInstanceOrThrowError(stInstance, options.recipeId); let tagsResponse = await querier.sendGetRequest("/user/search/tags", {}, userContext); return tagsResponse; }; diff --git a/lib/ts/recipe/dashboard/api/signIn.ts b/lib/ts/recipe/dashboard/api/signIn.ts index e4067ce2a..57b3f3965 100644 --- a/lib/ts/recipe/dashboard/api/signIn.ts +++ b/lib/ts/recipe/dashboard/api/signIn.ts @@ -13,13 +13,14 @@ * under the License. */ -import { APIInterface, APIOptions } from "../types"; +import { APIFunction } from "../types"; import { send200Response } from "../../../utils"; import STError from "../../../error"; import { Querier } from "../../../querier"; -import { UserContext } from "../../../types"; -export default async function signIn(_: APIInterface, options: APIOptions, userContext: UserContext): Promise { +export default async function signIn(input: Parameters[0]): Promise { + const options = input.options; + const userContext = input.userContext; const { email, password } = await options.req.getJSONBody(); if (email === undefined) { @@ -36,7 +37,7 @@ export default async function signIn(_: APIInterface, options: APIOptions, userC }); } - let querier = Querier.getNewInstanceOrThrowError(undefined); + let querier = Querier.getNewInstanceOrThrowError(input.stInstance); const signInResponse = await querier.sendPostRequest( "/recipe/dashboard/signin", { diff --git a/lib/ts/recipe/dashboard/api/signOut.ts b/lib/ts/recipe/dashboard/api/signOut.ts index 7dc199d16..903fe6bd2 100644 --- a/lib/ts/recipe/dashboard/api/signOut.ts +++ b/lib/ts/recipe/dashboard/api/signOut.ts @@ -13,22 +13,20 @@ * under the License. */ -import { APIInterface, APIOptions } from "../types"; +import { APIFunction } from "../types"; import { send200Response } from "../../../utils"; import { Querier } from "../../../querier"; -import { UserContext } from "../../../types"; -export default async function signOut( - _: APIInterface, - ___: string, - options: APIOptions, - userContext: UserContext -): Promise { +export default async function signOut({ + stInstance, + options, + userContext, +}: Parameters[0]): Promise { if (options.config.authMode === "api-key") { send200Response(options.res, { status: "OK" }); } else { const sessionIdFormAuthHeader = options.req.getHeaderValue("authorization")?.split(" ")[1]; - let querier = Querier.getNewInstanceOrThrowError(undefined); + let querier = Querier.getNewInstanceOrThrowError(stInstance); const sessionDeleteResponse = await querier.sendDeleteRequest( "/recipe/dashboard/session", undefined, diff --git a/lib/ts/recipe/dashboard/api/user/create/emailpasswordUser.ts b/lib/ts/recipe/dashboard/api/user/create/emailpasswordUser.ts index 7191e0656..84ad03fa5 100644 --- a/lib/ts/recipe/dashboard/api/user/create/emailpasswordUser.ts +++ b/lib/ts/recipe/dashboard/api/user/create/emailpasswordUser.ts @@ -13,12 +13,11 @@ * under the License. */ -import { APIInterface, APIOptions } from "../../../types"; +import { APIFunction } from "../../../types"; import STError from "../../../../../error"; import EmailPassword from "../../../../emailpassword"; -import EmailPasswordRecipe from "../../../../emailpassword/recipe"; -import { User, UserContext } from "../../../../../types"; -import RecipeUserId from "../../../../../recipeUserId"; +import type { User } from "../../../../../types"; +import type RecipeUserId from "../../../../../recipeUserId"; type Response = | { @@ -38,15 +37,15 @@ type Response = message: string; }; -export const createEmailPasswordUser = async ( - _: APIInterface, - tenantId: string, - options: APIOptions, - userContext: UserContext -): Promise => { - let emailPassword: EmailPasswordRecipe | undefined = undefined; +export const createEmailPasswordUser = async ({ + stInstance, + tenantId, + options, + userContext, +}: Parameters[0]): Promise => { + let emailPassword = undefined; try { - emailPassword = EmailPasswordRecipe.getInstanceOrThrowError(); + emailPassword = stInstance.getRecipeInstanceOrThrow("emailpassword"); } catch (error) { return { status: "FEATURE_NOT_ENABLED_ERROR", diff --git a/lib/ts/recipe/dashboard/api/user/create/passwordlessUser.ts b/lib/ts/recipe/dashboard/api/user/create/passwordlessUser.ts index a5fc600c4..4586f77ed 100644 --- a/lib/ts/recipe/dashboard/api/user/create/passwordlessUser.ts +++ b/lib/ts/recipe/dashboard/api/user/create/passwordlessUser.ts @@ -13,12 +13,10 @@ * under the License. */ -import { APIInterface, APIOptions } from "../../../types"; +import { APIFunction } from "../../../types"; import STError from "../../../../../error"; -import Passwordless from "../../../../passwordless"; -import PasswordlessRecipe from "../../../../passwordless/recipe"; -import { User } from "../../../../../types"; -import RecipeUserId from "../../../../../recipeUserId"; +import type { User } from "../../../../../types"; +import type RecipeUserId from "../../../../../recipeUserId"; import { parsePhoneNumber } from "libphonenumber-js/max"; type Response = @@ -40,16 +38,16 @@ type Response = message: string; }; -export const createPasswordlessUser = async ( - _: APIInterface, - tenantId: string, - options: APIOptions, - __: any -): Promise => { - let passwordlessRecipe: PasswordlessRecipe | undefined = undefined; +export const createPasswordlessUser = async ({ + stInstance, + tenantId, + options, + userContext, +}: Parameters[0]): Promise => { + let passwordlessRecipe = undefined; try { - passwordlessRecipe = PasswordlessRecipe.getInstanceOrThrowError(); + passwordlessRecipe = stInstance.getRecipeInstanceOrThrow("passwordless"); } catch (_) { return { status: "FEATURE_NOT_ENABLED_ERROR", @@ -111,7 +109,7 @@ export const createPasswordlessUser = async ( } } - return await Passwordless.signInUp( - email !== undefined ? { email, tenantId } : { phoneNumber: phoneNumber!, tenantId } + return await passwordlessRecipe.signInUp( + email !== undefined ? { email, tenantId, userContext } : { phoneNumber: phoneNumber!, tenantId, userContext } ); }; diff --git a/lib/ts/recipe/dashboard/api/userdetails/userDelete.ts b/lib/ts/recipe/dashboard/api/userdetails/userDelete.ts index 10788198a..952dc6932 100644 --- a/lib/ts/recipe/dashboard/api/userdetails/userDelete.ts +++ b/lib/ts/recipe/dashboard/api/userdetails/userDelete.ts @@ -1,19 +1,22 @@ -import { APIInterface, APIOptions } from "../../types"; +import { APIFunction } from "../../types"; import STError from "../../../../error"; -import { deleteUser } from "../../../.."; type Response = { status: "OK"; }; -export const userDelete = async (_: APIInterface, ___: string, options: APIOptions, __: any): Promise => { +export const userDelete = async ({ + stInstance, + options, + userContext, +}: Parameters[0]): Promise => { const userId = options.req.getKeyValueFromQuery("userId"); let removeAllLinkedAccountsQueryValue = options.req.getKeyValueFromQuery("removeAllLinkedAccounts"); if (removeAllLinkedAccountsQueryValue !== undefined) { removeAllLinkedAccountsQueryValue = removeAllLinkedAccountsQueryValue.trim().toLowerCase(); } const removeAllLinkedAccounts = - removeAllLinkedAccountsQueryValue === undefined ? undefined : removeAllLinkedAccountsQueryValue === "true"; + removeAllLinkedAccountsQueryValue === undefined ? true : removeAllLinkedAccountsQueryValue === "true"; if (userId === undefined || userId === "") { throw new STError({ @@ -22,7 +25,9 @@ export const userDelete = async (_: APIInterface, ___: string, options: APIOptio }); } - await deleteUser(userId, removeAllLinkedAccounts); + await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.deleteUser({ userId, removeAllLinkedAccounts, userContext }); return { status: "OK", diff --git a/lib/ts/recipe/dashboard/api/userdetails/userEmailVerifyGet.ts b/lib/ts/recipe/dashboard/api/userdetails/userEmailVerifyGet.ts index fa24c9b63..31764a14f 100644 --- a/lib/ts/recipe/dashboard/api/userdetails/userEmailVerifyGet.ts +++ b/lib/ts/recipe/dashboard/api/userdetails/userEmailVerifyGet.ts @@ -1,9 +1,6 @@ -import { APIFunction, APIInterface, APIOptions } from "../../types"; +import { APIFunction } from "../../types"; import STError from "../../../../error"; -import EmailVerification from "../../../emailverification"; -import EmailVerificationRecipe from "../../../emailverification/recipe"; import RecipeUserId from "../../../../recipeUserId"; -import { UserContext } from "../../../../types"; type Response = | { @@ -14,12 +11,7 @@ type Response = status: "FEATURE_NOT_ENABLED_ERROR"; }; -export const userEmailVerifyGet: APIFunction = async ( - _: APIInterface, - ___: string, - options: APIOptions, - userContext: UserContext -): Promise => { +export const userEmailVerifyGet: APIFunction = async ({ stInstance, options, userContext }): Promise => { const req = options.req; const recipeUserId = req.getKeyValueFromQuery("recipeUserId"); @@ -30,15 +22,35 @@ export const userEmailVerifyGet: APIFunction = async ( }); } + let emailVerificationRecipe = undefined; try { - EmailVerificationRecipe.getInstanceOrThrowError(); + emailVerificationRecipe = stInstance.getRecipeInstanceOrThrow("emailverification"); } catch (e) { return { status: "FEATURE_NOT_ENABLED_ERROR", }; } - const response = await EmailVerification.isEmailVerified(new RecipeUserId(recipeUserId), undefined, userContext); + let email: string | undefined = undefined; + const emailInfo = await emailVerificationRecipe.getEmailForRecipeUserId( + undefined, + new RecipeUserId(recipeUserId), + userContext + ); + if (emailInfo.status === "OK") { + email = emailInfo.email; + } else { + throw new STError({ + message: "Failed to get email for recipe user id", + type: STError.BAD_INPUT_ERROR, + }); + } + + const response = await emailVerificationRecipe.recipeInterfaceImpl.isEmailVerified({ + recipeUserId: new RecipeUserId(recipeUserId), + email, + userContext, + }); return { status: "OK", isVerified: response, diff --git a/lib/ts/recipe/dashboard/api/userdetails/userEmailVerifyPut.ts b/lib/ts/recipe/dashboard/api/userdetails/userEmailVerifyPut.ts index d5f098b16..551e4e7ec 100644 --- a/lib/ts/recipe/dashboard/api/userdetails/userEmailVerifyPut.ts +++ b/lib/ts/recipe/dashboard/api/userdetails/userEmailVerifyPut.ts @@ -1,19 +1,18 @@ -import { APIInterface, APIOptions } from "../../types"; +import { APIFunction } from "../../types"; import STError from "../../../../error"; import EmailVerification from "../../../emailverification"; import RecipeUserId from "../../../../recipeUserId"; -import { UserContext } from "../../../../types"; type Response = { status: "OK"; }; -export const userEmailVerifyPut = async ( - _: APIInterface, - tenantId: string, - options: APIOptions, - userContext: UserContext -): Promise => { +export const userEmailVerifyPut = async ({ + stInstance, + tenantId, + options, + userContext, +}: Parameters[0]): Promise => { const requestBody = await options.req.getJSONBody(); const recipeUserId = requestBody.recipeUserId; const verified = requestBody.verified; @@ -31,14 +30,38 @@ export const userEmailVerifyPut = async ( type: STError.BAD_INPUT_ERROR, }); } + let emailVerificationRecipe = undefined; + try { + emailVerificationRecipe = stInstance.getRecipeInstanceOrThrow("emailverification"); + } catch (e) { + throw new STError({ + message: "Email verification recipe not initialised", + type: STError.BAD_INPUT_ERROR, + }); + } + + let email: string | undefined = undefined; + const emailInfo = await emailVerificationRecipe.getEmailForRecipeUserId( + undefined, + new RecipeUserId(recipeUserId), + userContext + ); + if (emailInfo.status === "OK") { + email = emailInfo.email; + } else { + throw new STError({ + message: "Failed to get email for recipe user id", + type: STError.BAD_INPUT_ERROR, + }); + } if (verified) { - const tokenResponse = await EmailVerification.createEmailVerificationToken( + const tokenResponse = await emailVerificationRecipe.recipeInterfaceImpl.createEmailVerificationToken({ + recipeUserId: new RecipeUserId(recipeUserId), + email: email, tenantId, - new RecipeUserId(recipeUserId), - undefined, - userContext - ); + userContext, + }); if (tokenResponse.status === "EMAIL_ALREADY_VERIFIED_ERROR") { return { diff --git a/lib/ts/recipe/dashboard/api/userdetails/userEmailVerifyTokenPost.ts b/lib/ts/recipe/dashboard/api/userdetails/userEmailVerifyTokenPost.ts index 6e30aa645..279a8146e 100644 --- a/lib/ts/recipe/dashboard/api/userdetails/userEmailVerifyTokenPost.ts +++ b/lib/ts/recipe/dashboard/api/userdetails/userEmailVerifyTokenPost.ts @@ -1,19 +1,18 @@ -import { APIInterface, APIOptions } from "../../types"; +import { APIFunction } from "../../types"; import STError from "../../../../error"; import EmailVerification from "../../../emailverification"; -import { convertToRecipeUserId, getUser } from "../../../.."; -import { UserContext } from "../../../../types"; +import { convertToRecipeUserId } from "../../../.."; type Response = { status: "OK" | "EMAIL_ALREADY_VERIFIED_ERROR"; }; -export const userEmailVerifyTokenPost = async ( - _: APIInterface, - tenantId: string, - options: APIOptions, - userContext: UserContext -): Promise => { +export const userEmailVerifyTokenPost = async ({ + stInstance, + tenantId, + options, + userContext, +}: Parameters[0]): Promise => { const requestBody = await options.req.getJSONBody(); const recipeUserId = requestBody.recipeUserId; @@ -23,7 +22,9 @@ export const userEmailVerifyTokenPost = async ( type: STError.BAD_INPUT_ERROR, }); } - const user = await getUser(recipeUserId, userContext); + const user = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: recipeUserId, userContext }); if (!user) { throw new STError({ diff --git a/lib/ts/recipe/dashboard/api/userdetails/userGet.ts b/lib/ts/recipe/dashboard/api/userdetails/userGet.ts index 6677057f8..bf22a1e9d 100644 --- a/lib/ts/recipe/dashboard/api/userdetails/userGet.ts +++ b/lib/ts/recipe/dashboard/api/userdetails/userGet.ts @@ -1,9 +1,6 @@ -import { APIFunction, APIInterface, APIOptions, UserWithFirstAndLastName } from "../../types"; +import { APIFunction, UserWithFirstAndLastName } from "../../types"; import STError from "../../../../error"; -import UserMetaDataRecipe from "../../../usermetadata/recipe"; -import UserMetaData from "../../../usermetadata"; -import { getUser } from "../../../.."; -import { User, UserContext } from "../../../../types"; +import { User } from "../../../../types"; type Response = | { @@ -14,12 +11,11 @@ type Response = user: UserWithFirstAndLastName; }; -export const userGet: APIFunction = async ( - _: APIInterface, - ___: string, - options: APIOptions, - userContext: UserContext -): Promise => { +export const userGet: APIFunction = async ({ + stInstance, + options, + userContext, +}: Parameters[0]): Promise => { const userId = options.req.getKeyValueFromQuery("userId"); if (userId === undefined || userId === "") { @@ -29,7 +25,9 @@ export const userGet: APIFunction = async ( }); } - let user: User | undefined = await getUser(userId, userContext); + let user: User | undefined = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId, userContext }); if (user === undefined) { return { @@ -37,9 +35,8 @@ export const userGet: APIFunction = async ( }; } - try { - UserMetaDataRecipe.getInstanceOrThrowError(); - } catch (_) { + let usermetadataRecipe = stInstance.getRecipeInstance("usermetadata"); + if (usermetadataRecipe === undefined) { return { status: "OK", user: { @@ -50,7 +47,7 @@ export const userGet: APIFunction = async ( }; } - const userMetaData = await UserMetaData.getUserMetadata(userId, userContext); + const userMetaData = await usermetadataRecipe.recipeInterfaceImpl.getUserMetadata({ userId, userContext }); const { first_name, last_name } = userMetaData.metadata; return { diff --git a/lib/ts/recipe/dashboard/api/userdetails/userMetadataGet.ts b/lib/ts/recipe/dashboard/api/userdetails/userMetadataGet.ts index ad750181b..fbfdf7d31 100644 --- a/lib/ts/recipe/dashboard/api/userdetails/userMetadataGet.ts +++ b/lib/ts/recipe/dashboard/api/userdetails/userMetadataGet.ts @@ -1,8 +1,5 @@ -import { APIFunction, APIInterface, APIOptions } from "../../types"; +import { APIFunction } from "../../types"; import STError from "../../../../error"; -import UserMetaDataRecipe from "../../../usermetadata/recipe"; -import UserMetaData from "../../../usermetadata"; -import { UserContext } from "../../../../types"; type Response = | { @@ -13,12 +10,11 @@ type Response = data: any; }; -export const userMetaDataGet: APIFunction = async ( - _: APIInterface, - ___: string, - options: APIOptions, - userContext: UserContext -): Promise => { +export const userMetaDataGet: APIFunction = async ({ + stInstance, + options, + userContext, +}: Parameters[0]): Promise => { const userId = options.req.getKeyValueFromQuery("userId"); if (userId === undefined || userId === "") { @@ -28,15 +24,16 @@ export const userMetaDataGet: APIFunction = async ( }); } + let usermetadataRecipe = undefined; try { - UserMetaDataRecipe.getInstanceOrThrowError(); + usermetadataRecipe = stInstance.getRecipeInstanceOrThrow("usermetadata"); } catch (e) { return { status: "FEATURE_NOT_ENABLED_ERROR", }; } - const metaDataResponse = UserMetaData.getUserMetadata(userId, userContext); + const metaDataResponse = usermetadataRecipe.recipeInterfaceImpl.getUserMetadata({ userId, userContext }); return { status: "OK", data: (await metaDataResponse).metadata, diff --git a/lib/ts/recipe/dashboard/api/userdetails/userMetadataPut.ts b/lib/ts/recipe/dashboard/api/userdetails/userMetadataPut.ts index 513b305f6..c19c8858e 100644 --- a/lib/ts/recipe/dashboard/api/userdetails/userMetadataPut.ts +++ b/lib/ts/recipe/dashboard/api/userdetails/userMetadataPut.ts @@ -1,25 +1,21 @@ -import { APIInterface, APIOptions } from "../../types"; -import UserMetadaRecipe from "../../../usermetadata/recipe"; -import UserMetaData from "../../../usermetadata"; +import { APIFunction } from "../../types"; import STError from "../../../../error"; -import { UserContext } from "../../../../types"; type Response = { status: "OK"; }; -export const userMetadataPut = async ( - _: APIInterface, - ___: string, - options: APIOptions, - userContext: UserContext -): Promise => { +export const userMetadataPut = async ({ + stInstance, + options, + userContext, +}: Parameters[0]): Promise => { const requestBody = await options.req.getJSONBody(); const userId = requestBody.userId; const data = requestBody.data; // This is to throw an error early in case the recipe has not been initialised - UserMetadaRecipe.getInstanceOrThrowError(); + const usermetadataRecipe = stInstance.getRecipeInstanceOrThrow("usermetadata"); if (userId === undefined || typeof userId !== "string") { throw new STError({ @@ -68,8 +64,12 @@ export const userMetadataPut = async ( * * Removing first ensures that the final data is exactly what the user wanted it to be */ - await UserMetaData.clearUserMetadata(userId, userContext); - await UserMetaData.updateUserMetadata(userId, JSON.parse(data), userContext); + await usermetadataRecipe.recipeInterfaceImpl.clearUserMetadata({ userId, userContext }); + await usermetadataRecipe.recipeInterfaceImpl.updateUserMetadata({ + userId, + metadataUpdate: JSON.parse(data), + userContext, + }); return { status: "OK", diff --git a/lib/ts/recipe/dashboard/api/userdetails/userPasswordPut.ts b/lib/ts/recipe/dashboard/api/userdetails/userPasswordPut.ts index df7d12f86..3bf1cf4de 100644 --- a/lib/ts/recipe/dashboard/api/userdetails/userPasswordPut.ts +++ b/lib/ts/recipe/dashboard/api/userdetails/userPasswordPut.ts @@ -1,8 +1,6 @@ -import { APIInterface, APIOptions } from "../../types"; +import { APIFunction } from "../../types"; import STError from "../../../../error"; -import EmailPassword from "../../../emailpassword"; import RecipeUserId from "../../../../recipeUserId"; -import { UserContext } from "../../../../types"; type Response = | { @@ -13,12 +11,12 @@ type Response = error: string; }; -export const userPasswordPut = async ( - _: APIInterface, - tenantId: string, - options: APIOptions, - userContext: UserContext -): Promise => { +export const userPasswordPut = async ({ + stInstance, + tenantId, + options, + userContext, +}: Parameters[0]): Promise => { const requestBody = await options.req.getJSONBody(); const recipeUserId = requestBody.recipeUserId; const newPassword = requestBody.newPassword; @@ -37,7 +35,8 @@ export const userPasswordPut = async ( }); } - const updateResponse = await EmailPassword.updateEmailOrPassword({ + const emailpasswordRecipe = stInstance.getRecipeInstanceOrThrow("emailpassword"); + const updateResponse = await emailpasswordRecipe.recipeInterfaceImpl.updateEmailOrPassword({ recipeUserId: new RecipeUserId(recipeUserId), password: newPassword, tenantIdForPasswordPolicy: tenantId, diff --git a/lib/ts/recipe/dashboard/api/userdetails/userPut.ts b/lib/ts/recipe/dashboard/api/userdetails/userPut.ts index 1252099d7..9d643ecb1 100644 --- a/lib/ts/recipe/dashboard/api/userdetails/userPut.ts +++ b/lib/ts/recipe/dashboard/api/userdetails/userPut.ts @@ -1,18 +1,11 @@ -import { APIInterface, APIOptions } from "../../types"; +import { APIFunction } from "../../types"; import STError from "../../../../error"; -import EmailPasswordRecipe from "../../../emailpassword/recipe"; -import PasswordlessRecipe from "../../../passwordless/recipe"; -import WebAuthnRecipe from "../../../webauthn/recipe"; -import EmailPassword from "../../../emailpassword"; -import Passwordless from "../../../passwordless"; -import WebAuthn from "../../../webauthn"; import { isValidRecipeId, getUserForRecipeId } from "../../utils"; -import UserMetadataRecipe from "../../../usermetadata/recipe"; -import UserMetadata from "../../../usermetadata"; import { FORM_FIELD_EMAIL_ID } from "../../../emailpassword/constants"; import { defaultValidateEmail, defaultValidatePhoneNumber } from "../../../passwordless/utils"; import RecipeUserId from "../../../../recipeUserId"; import { UserContext } from "../../../../types"; +import type SuperTokens from "../../../../supertokens"; type Response = | { @@ -42,6 +35,7 @@ type Response = }; const updateEmailForRecipeId = async ( + stInstance: SuperTokens, recipeId: "emailpassword" | "passwordless" | "thirdparty" | "webauthn", recipeUserId: RecipeUserId, email: string, @@ -64,9 +58,9 @@ const updateEmailForRecipeId = async ( } > => { if (recipeId === "emailpassword") { - let emailFormFields = EmailPasswordRecipe.getInstanceOrThrowError().config.signUpFeature.formFields.filter( - (field) => field.id === FORM_FIELD_EMAIL_ID - ); + let emailFormFields = stInstance + .getRecipeInstanceOrThrow("emailpassword") + .config.signUpFeature.formFields.filter((field) => field.id === FORM_FIELD_EMAIL_ID); let validationError = await emailFormFields[0].validate(email, tenantId, userContext); @@ -77,11 +71,14 @@ const updateEmailForRecipeId = async ( }; } - const emailUpdateResponse = await EmailPassword.updateEmailOrPassword({ - recipeUserId, - email, - userContext, - }); + const emailUpdateResponse = await stInstance + .getRecipeInstanceOrThrow("emailpassword") + .recipeInterfaceImpl.updateEmailOrPassword({ + recipeUserId, + email, + userContext, + tenantIdForPasswordPolicy: tenantId, + }); if (emailUpdateResponse.status === "EMAIL_ALREADY_EXISTS_ERROR") { return { @@ -105,7 +102,8 @@ const updateEmailForRecipeId = async ( let isValidEmail = true; let validationError = ""; - const passwordlessConfig = PasswordlessRecipe.getInstanceOrThrowError().config; + const passwordlessRecipe = stInstance.getRecipeInstanceOrThrow("passwordless"); + const passwordlessConfig = passwordlessRecipe.config; if (passwordlessConfig.contactMethod === "PHONE") { const validationResult = await defaultValidateEmail(email); @@ -130,7 +128,7 @@ const updateEmailForRecipeId = async ( }; } - const updateResult = await Passwordless.updateUser({ + const updateResult = await passwordlessRecipe.recipeInterfaceImpl.updateUser({ recipeUserId, email, userContext, @@ -162,11 +160,8 @@ const updateEmailForRecipeId = async ( } if (recipeId === "webauthn") { - let validationError = await WebAuthnRecipe.getInstanceOrThrowError().config.validateEmailAddress( - email, - tenantId, - userContext - ); + const webauthnRecipe = stInstance.getRecipeInstanceOrThrow("webauthn"); + let validationError = await webauthnRecipe.config.validateEmailAddress(email, tenantId, userContext); if (validationError !== undefined) { return { @@ -175,7 +170,7 @@ const updateEmailForRecipeId = async ( }; } - const emailUpdateResponse = await WebAuthn.updateUserEmail({ + const emailUpdateResponse = await webauthnRecipe.recipeInterfaceImpl.updateUserEmail({ email, recipeUserId: recipeUserId.getAsString(), tenantId, @@ -202,6 +197,7 @@ const updateEmailForRecipeId = async ( }; const updatePhoneForRecipeId = async ( + stInstance: SuperTokens, recipeUserId: RecipeUserId, phone: string, tenantId: string, @@ -225,7 +221,8 @@ const updatePhoneForRecipeId = async ( let isValidPhone = true; let validationError = ""; - const passwordlessConfig = PasswordlessRecipe.getInstanceOrThrowError().config; + const passwordlessRecipe = stInstance.getRecipeInstanceOrThrow("passwordless"); + const passwordlessConfig = passwordlessRecipe.config; if (passwordlessConfig.contactMethod === "EMAIL") { const validationResult = await defaultValidatePhoneNumber(phone); @@ -250,7 +247,7 @@ const updatePhoneForRecipeId = async ( }; } - const updateResult = await Passwordless.updateUser({ + const updateResult = await passwordlessRecipe.recipeInterfaceImpl.updateUser({ recipeUserId, phoneNumber: phone, userContext, @@ -277,12 +274,12 @@ const updatePhoneForRecipeId = async ( }; }; -export const userPut = async ( - _: APIInterface, - tenantId: string, - options: APIOptions, - userContext: UserContext -): Promise => { +export const userPut = async ({ + stInstance, + tenantId, + options, + userContext, +}: Parameters[0]): Promise => { const requestBody = await options.req.getJSONBody(); const recipeUserId = requestBody.recipeUserId; const recipeId = requestBody.recipeId; @@ -340,22 +337,16 @@ export const userPut = async ( }); } - let userResponse = await getUserForRecipeId(new RecipeUserId(recipeUserId), recipeId, userContext); + let userResponse = await getUserForRecipeId(stInstance, new RecipeUserId(recipeUserId), recipeId, userContext); if (userResponse.user === undefined || userResponse.recipe === undefined) { throw new Error("Should never come here"); } if (firstName.trim() !== "" || lastName.trim() !== "") { - let isRecipeInitialised = false; - try { - UserMetadataRecipe.getInstanceOrThrowError(); - isRecipeInitialised = true; - } catch (_) { - // no op - } + let usermetadataRecipe = stInstance.getRecipeInstance("usermetadata"); - if (isRecipeInitialised) { + if (usermetadataRecipe) { let metaDataUpdate: any = {}; if (firstName.trim() !== "") { @@ -366,12 +357,17 @@ export const userPut = async ( metaDataUpdate["last_name"] = lastName.trim(); } - await UserMetadata.updateUserMetadata(userResponse.user.id, metaDataUpdate, userContext); + await usermetadataRecipe.recipeInterfaceImpl.updateUserMetadata({ + userId: userResponse.user.id, + metadataUpdate: metaDataUpdate, + userContext, + }); } } if (email.trim() !== "") { const emailUpdateResponse = await updateEmailForRecipeId( + stInstance, userResponse.recipe, new RecipeUserId(recipeUserId), email.trim(), @@ -393,6 +389,7 @@ export const userPut = async ( if (phone.trim() !== "") { const phoneUpdateResponse = await updatePhoneForRecipeId( + stInstance, new RecipeUserId(recipeUserId), phone.trim(), tenantId, diff --git a/lib/ts/recipe/dashboard/api/userdetails/userSessionsGet.ts b/lib/ts/recipe/dashboard/api/userdetails/userSessionsGet.ts index f043ad944..e4f9f0d52 100644 --- a/lib/ts/recipe/dashboard/api/userdetails/userSessionsGet.ts +++ b/lib/ts/recipe/dashboard/api/userdetails/userSessionsGet.ts @@ -1,7 +1,6 @@ -import { APIFunction, APIInterface, APIOptions } from "../../types"; +import { APIFunction } from "../../types"; import STError from "../../../../error"; -import Session from "../../../session"; -import { UserContext } from "../../../../types"; +import { DEFAULT_TENANT_ID } from "../../../multitenancy/constants"; type SessionType = { sessionDataInDatabase: any; @@ -17,12 +16,11 @@ type Response = { sessions: SessionType[]; }; -export const userSessionsGet: APIFunction = async ( - _: APIInterface, - ___: string, - options: APIOptions, - userContext: UserContext -): Promise => { +export const userSessionsGet: APIFunction = async ({ + stInstance, + options, + userContext, +}: Parameters[0]): Promise => { const userId = options.req.getKeyValueFromQuery("userId"); if (userId === undefined || userId === "") { @@ -32,7 +30,14 @@ export const userSessionsGet: APIFunction = async ( }); } - const response = await Session.getAllSessionHandlesForUser(userId, undefined, undefined, userContext); + const sessionRecipe = stInstance.getRecipeInstanceOrThrow("session"); + const response = await sessionRecipe.recipeInterfaceImpl.getAllSessionHandlesForUser({ + userId, + fetchSessionsForAllLinkedAccounts: true, + tenantId: DEFAULT_TENANT_ID, + fetchAcrossAllTenants: true, + userContext, + }); let sessions: SessionType[] = []; let sessionInfoPromises: Promise[] = []; @@ -41,7 +46,10 @@ export const userSessionsGet: APIFunction = async ( sessionInfoPromises.push( new Promise(async (res, rej) => { try { - const sessionResponse = await Session.getSessionInformation(response[i], userContext); + const sessionResponse = await sessionRecipe.recipeInterfaceImpl.getSessionInformation({ + sessionHandle: response[i], + userContext, + }); if (sessionResponse !== undefined) { const accessTokenPayload = sessionResponse.customClaimsInAccessTokenPayload; diff --git a/lib/ts/recipe/dashboard/api/userdetails/userSessionsPost.ts b/lib/ts/recipe/dashboard/api/userdetails/userSessionsPost.ts index 116b3d214..14c7f0d53 100644 --- a/lib/ts/recipe/dashboard/api/userdetails/userSessionsPost.ts +++ b/lib/ts/recipe/dashboard/api/userdetails/userSessionsPost.ts @@ -1,18 +1,15 @@ -import { APIInterface, APIOptions } from "../../types"; +import { APIFunction } from "../../types"; import STError from "../../../../error"; -import Session from "../../../session"; -import { UserContext } from "../../../../types"; type Response = { status: "OK"; }; -export const userSessionsPost = async ( - _: APIInterface, - ___: string, - options: APIOptions, - userContext: UserContext -): Promise => { +export const userSessionsPost = async ({ + stInstance, + options, + userContext, +}: Parameters[0]): Promise => { const requestBody = await options.req.getJSONBody(); const sessionHandles = requestBody.sessionHandles; @@ -23,7 +20,8 @@ export const userSessionsPost = async ( }); } - await Session.revokeMultipleSessions(sessionHandles, userContext); + const sessionRecipe = stInstance.getRecipeInstanceOrThrow("session"); + await sessionRecipe.recipeInterfaceImpl.revokeMultipleSessions({ sessionHandles, userContext }); return { status: "OK", }; diff --git a/lib/ts/recipe/dashboard/api/userdetails/userUnlinkGet.ts b/lib/ts/recipe/dashboard/api/userdetails/userUnlinkGet.ts index 4da025412..78cb8477e 100644 --- a/lib/ts/recipe/dashboard/api/userdetails/userUnlinkGet.ts +++ b/lib/ts/recipe/dashboard/api/userdetails/userUnlinkGet.ts @@ -1,19 +1,16 @@ -import { APIInterface, APIOptions } from "../../types"; +import { APIFunction } from "../../types"; import STError from "../../../../error"; -import AccountLinking from "../../../accountlinking"; import RecipeUserId from "../../../../recipeUserId"; -import { UserContext } from "../../../../types"; type Response = { status: "OK"; }; -export const userUnlink = async ( - _: APIInterface, - ___: string, - options: APIOptions, - userContext: UserContext -): Promise => { +export const userUnlink = async ({ + stInstance, + options, + userContext, +}: Parameters[0]): Promise => { const recipeUserId = options.req.getKeyValueFromQuery("recipeUserId"); if (recipeUserId === undefined) { @@ -23,7 +20,9 @@ export const userUnlink = async ( }); } - await AccountLinking.unlinkAccount(new RecipeUserId(recipeUserId), userContext); + await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.unlinkAccount({ recipeUserId: new RecipeUserId(recipeUserId), userContext }); return { status: "OK", diff --git a/lib/ts/recipe/dashboard/api/userroles/addRoleToUser.ts b/lib/ts/recipe/dashboard/api/userroles/addRoleToUser.ts index 5c732e95f..60b8c6b03 100644 --- a/lib/ts/recipe/dashboard/api/userroles/addRoleToUser.ts +++ b/lib/ts/recipe/dashboard/api/userroles/addRoleToUser.ts @@ -1,15 +1,13 @@ -import { APIInterface, APIOptions } from "../../types"; -import UserRolesRecipe from "../../../userroles/recipe"; -import UserRoles from "../../../userroles"; +import { APIFunction } from "../../types"; import STError from "../../../../error"; -const addRoleToUser = async ( - _: APIInterface, - tenantId: string, - options: APIOptions, - __: any -): Promise< +const addRoleToUser = async ({ + stInstance, + tenantId, + options, + userContext, +}: Parameters[0]): Promise< | { status: "OK"; didUserAlreadyHaveRole: boolean; @@ -18,8 +16,9 @@ const addRoleToUser = async ( status: "UNKNOWN_ROLE_ERROR" | "FEATURE_NOT_ENABLED_ERROR"; } > => { + let userrolesRecipe = undefined; try { - UserRolesRecipe.getInstanceOrThrowError(); + userrolesRecipe = stInstance.getRecipeInstanceOrThrow("userroles"); } catch (_) { return { status: "FEATURE_NOT_ENABLED_ERROR", @@ -45,7 +44,7 @@ const addRoleToUser = async ( }); } - const response = await UserRoles.addRoleToUser(tenantId, userId, role); + const response = await userrolesRecipe.recipeInterfaceImpl.addRoleToUser({ userId, role, tenantId, userContext }); return response; }; diff --git a/lib/ts/recipe/dashboard/api/userroles/getRolesForUser.ts b/lib/ts/recipe/dashboard/api/userroles/getRolesForUser.ts index 1627f7b84..eb33880a0 100644 --- a/lib/ts/recipe/dashboard/api/userroles/getRolesForUser.ts +++ b/lib/ts/recipe/dashboard/api/userroles/getRolesForUser.ts @@ -1,15 +1,13 @@ -import { APIInterface, APIOptions } from "../../types"; -import UserRoles from "../../../userroles"; -import UserRolesRecipe from "../../../userroles/recipe"; +import { APIFunction } from "../../types"; import STError from "../../../../error"; -const getRolesForUser = async ( - _: APIInterface, - tenantId: string, - options: APIOptions, - __: any -): Promise< +const getRolesForUser = async ({ + stInstance, + tenantId, + options, + userContext, +}: Parameters[0]): Promise< | { status: "OK"; roles: string[]; @@ -20,8 +18,9 @@ const getRolesForUser = async ( > => { const userId = options.req.getKeyValueFromQuery("userId"); + let userrolesRecipe = undefined; try { - UserRolesRecipe.getInstanceOrThrowError(); + userrolesRecipe = stInstance.getRecipeInstanceOrThrow("userroles"); } catch (_) { return { status: "FEATURE_NOT_ENABLED_ERROR", @@ -35,7 +34,7 @@ const getRolesForUser = async ( }); } - const response = await UserRoles.getRolesForUser(tenantId, userId); + const response = await userrolesRecipe.recipeInterfaceImpl.getRolesForUser({ userId, tenantId, userContext }); return response; }; diff --git a/lib/ts/recipe/dashboard/api/userroles/permissions/getPermissionsForRole.ts b/lib/ts/recipe/dashboard/api/userroles/permissions/getPermissionsForRole.ts index a5a2b0d6a..4a127a946 100644 --- a/lib/ts/recipe/dashboard/api/userroles/permissions/getPermissionsForRole.ts +++ b/lib/ts/recipe/dashboard/api/userroles/permissions/getPermissionsForRole.ts @@ -1,23 +1,21 @@ -import UserRolesRecipe from "../../../../userroles/recipe"; -import UserRoles from "../../../../userroles"; -import { APIInterface, APIOptions } from "../../../types"; +import { APIFunction } from "../../../types"; import STError from "../../../../../error"; -const getPermissionsForRole = async ( - _: APIInterface, - ___: string, - options: APIOptions, - __: any -): Promise< +const getPermissionsForRole = async ({ + stInstance, + options, + userContext, +}: Parameters[0]): Promise< | { status: "OK"; permissions: string[]; } | { status: "FEATURE_NOT_ENABLED_ERROR" | "UNKNOWN_ROLE_ERROR" } > => { + let userrolesRecipe = undefined; try { - UserRolesRecipe.getInstanceOrThrowError(); + userrolesRecipe = stInstance.getRecipeInstanceOrThrow("userroles"); } catch (_) { return { status: "FEATURE_NOT_ENABLED_ERROR", @@ -33,7 +31,7 @@ const getPermissionsForRole = async ( }); } - const response = await UserRoles.getPermissionsForRole(role); + const response = await userrolesRecipe.recipeInterfaceImpl.getPermissionsForRole({ role, userContext }); return response; }; diff --git a/lib/ts/recipe/dashboard/api/userroles/permissions/removePermissions.ts b/lib/ts/recipe/dashboard/api/userroles/permissions/removePermissions.ts index c847d789d..a416ae640 100644 --- a/lib/ts/recipe/dashboard/api/userroles/permissions/removePermissions.ts +++ b/lib/ts/recipe/dashboard/api/userroles/permissions/removePermissions.ts @@ -1,19 +1,17 @@ -import UserRolesRecipe from "../../../../userroles/recipe"; -import UserRoles from "../../../../userroles"; -import { APIInterface, APIOptions } from "../../../types"; +import { APIFunction } from "../../../types"; import STError from "../../../../../error"; -const removePermissionsFromRole = async ( - _: APIInterface, - ___: string, - options: APIOptions, - __: any -): Promise<{ +const removePermissionsFromRole = async ({ + stInstance, + options, + userContext, +}: Parameters[0]): Promise<{ status: "OK" | "UNKNOWN_ROLE_ERROR" | "FEATURE_NOT_ENABLED_ERROR"; }> => { + let userrolesRecipe = undefined; try { - UserRolesRecipe.getInstanceOrThrowError(); + userrolesRecipe = stInstance.getRecipeInstanceOrThrow("userroles"); } catch (_) { return { status: "FEATURE_NOT_ENABLED_ERROR", @@ -40,7 +38,11 @@ const removePermissionsFromRole = async ( }); } - const response = await UserRoles.removePermissionsFromRole(role, permissions); + const response = await userrolesRecipe.recipeInterfaceImpl.removePermissionsFromRole({ + role, + permissions, + userContext, + }); return response; }; diff --git a/lib/ts/recipe/dashboard/api/userroles/removeUserRole.ts b/lib/ts/recipe/dashboard/api/userroles/removeUserRole.ts index 5015b7acf..4b4103ece 100644 --- a/lib/ts/recipe/dashboard/api/userroles/removeUserRole.ts +++ b/lib/ts/recipe/dashboard/api/userroles/removeUserRole.ts @@ -1,15 +1,13 @@ -import { APIInterface, APIOptions } from "../../types"; -import UserRolesRecipe from "../../../userroles/recipe"; -import UserRoles from "../../../userroles"; +import { APIFunction } from "../../types"; import STError from "../../../../error"; -const removeUserRole = async ( - _: APIInterface, - tenantId: string, - options: APIOptions, - __: any -): Promise< +const removeUserRole = async ({ + stInstance, + tenantId, + options, + userContext, +}: Parameters[0]): Promise< | { status: "OK"; didUserHaveRole: boolean; @@ -18,8 +16,9 @@ const removeUserRole = async ( status: "UNKNOWN_ROLE_ERROR" | "FEATURE_NOT_ENABLED_ERROR"; } > => { + let userrolesRecipe = undefined; try { - UserRolesRecipe.getInstanceOrThrowError(); + userrolesRecipe = stInstance.getRecipeInstanceOrThrow("userroles"); } catch (_) { return { status: "FEATURE_NOT_ENABLED_ERROR", @@ -43,7 +42,7 @@ const removeUserRole = async ( }); } - const response = await UserRoles.removeUserRole(tenantId, userId, role); + const response = await userrolesRecipe.recipeInterfaceImpl.removeUserRole({ userId, role, tenantId, userContext }); return response; }; diff --git a/lib/ts/recipe/dashboard/api/userroles/roles/createRoleOrAddPermissions.ts b/lib/ts/recipe/dashboard/api/userroles/roles/createRoleOrAddPermissions.ts index 7e7f8cdce..90077dc59 100644 --- a/lib/ts/recipe/dashboard/api/userroles/roles/createRoleOrAddPermissions.ts +++ b/lib/ts/recipe/dashboard/api/userroles/roles/createRoleOrAddPermissions.ts @@ -1,17 +1,17 @@ -import { APIInterface, APIOptions } from "../../../types"; -import UserRolesRecipe from "../../../../userroles/recipe"; -import UserRoles from "../../../../userroles"; +import { APIFunction } from "../../../types"; import STError from "../../../../../error"; -const createRoleOrAddPermissions = async ( - _: APIInterface, - __: string, - options: APIOptions, - ___: any -): Promise<{ status: "OK"; createdNewRole: boolean } | { status: "FEATURE_NOT_ENABLED_ERROR" }> => { +const createRoleOrAddPermissions = async ({ + stInstance, + options, + userContext, +}: Parameters[0]): Promise< + { status: "OK"; createdNewRole: boolean } | { status: "FEATURE_NOT_ENABLED_ERROR" } +> => { + let userrolesRecipe = undefined; try { - UserRolesRecipe.getInstanceOrThrowError(); + userrolesRecipe = stInstance.getRecipeInstanceOrThrow("userroles"); } catch (_) { return { status: "FEATURE_NOT_ENABLED_ERROR", @@ -36,7 +36,11 @@ const createRoleOrAddPermissions = async ( }); } - const response = await UserRoles.createNewRoleOrAddPermissions(role, permissions); + const response = await userrolesRecipe.recipeInterfaceImpl.createNewRoleOrAddPermissions({ + role, + permissions, + userContext, + }); return response; }; diff --git a/lib/ts/recipe/dashboard/api/userroles/roles/deleteRole.ts b/lib/ts/recipe/dashboard/api/userroles/roles/deleteRole.ts index 28c06d073..e0da9bc2f 100644 --- a/lib/ts/recipe/dashboard/api/userroles/roles/deleteRole.ts +++ b/lib/ts/recipe/dashboard/api/userroles/roles/deleteRole.ts @@ -1,15 +1,12 @@ -import UserRolesRecipe from "../../../../userroles/recipe"; -import UserRoles from "../../../../userroles"; -import { APIInterface, APIOptions } from "../../../types"; +import { APIFunction } from "../../../types"; import STError from "../../../../../error"; -const deleteRole = async ( - _: APIInterface, - ___: string, - options: APIOptions, - __: any -): Promise< +const deleteRole = async ({ + stInstance, + options, + userContext, +}: Parameters[0]): Promise< | { status: "OK"; didRoleExist: boolean; @@ -18,8 +15,9 @@ const deleteRole = async ( status: "FEATURE_NOT_ENABLED_ERROR"; } > => { + let userrolesRecipe = undefined; try { - UserRolesRecipe.getInstanceOrThrowError(); + userrolesRecipe = stInstance.getRecipeInstanceOrThrow("userroles"); } catch (_) { return { status: "FEATURE_NOT_ENABLED_ERROR", @@ -35,7 +33,7 @@ const deleteRole = async ( }); } - const response = await UserRoles.deleteRole(role); + const response = await userrolesRecipe.recipeInterfaceImpl.deleteRole({ role, userContext }); return response; }; diff --git a/lib/ts/recipe/dashboard/api/userroles/roles/getAllRoles.ts b/lib/ts/recipe/dashboard/api/userroles/roles/getAllRoles.ts index fcafe72a0..eae4325b1 100644 --- a/lib/ts/recipe/dashboard/api/userroles/roles/getAllRoles.ts +++ b/lib/ts/recipe/dashboard/api/userroles/roles/getAllRoles.ts @@ -1,7 +1,4 @@ -import UserRoles from "../../../../userroles"; -import UserRolesRecipe from "../../../../userroles/recipe"; - -import { APIFunction, APIInterface } from "../../../types"; +import { APIFunction } from "../../../types"; type Response = | { @@ -12,16 +9,17 @@ type Response = status: "FEATURE_NOT_ENABLED_ERROR"; }; -const getAllRoles: APIFunction = async (_: APIInterface, __: string, ____: any): Promise => { +const getAllRoles: APIFunction = async ({ stInstance, userContext }: Parameters[0]): Promise => { + let userrolesRecipe = undefined; try { - UserRolesRecipe.getInstanceOrThrowError(); + userrolesRecipe = stInstance.getRecipeInstanceOrThrow("userroles"); } catch (_) { return { status: "FEATURE_NOT_ENABLED_ERROR", }; } - const response = await UserRoles.getAllRoles(); + const response = await userrolesRecipe.recipeInterfaceImpl.getAllRoles({ userContext }); return { status: "OK", roles: response.roles, diff --git a/lib/ts/recipe/dashboard/api/usersCountGet.ts b/lib/ts/recipe/dashboard/api/usersCountGet.ts index ca1473882..a2f8eca56 100644 --- a/lib/ts/recipe/dashboard/api/usersCountGet.ts +++ b/lib/ts/recipe/dashboard/api/usersCountGet.ts @@ -13,22 +13,19 @@ * under the License. */ -import { APIInterface, APIOptions } from "../types"; -import SuperTokens from "../../../supertokens"; -import { UserContext } from "../../../types"; +import { APIFunction } from "../types"; export type Response = { status: "OK"; count: number; }; -export default async function usersCountGet( - _: APIInterface, - tenantId: string, - __: APIOptions, - userContext: UserContext -): Promise { - const count = await SuperTokens.getInstanceOrThrowError().getUserCount(undefined, tenantId, userContext); +export default async function usersCountGet({ + stInstance, + tenantId, + userContext, +}: Parameters[0]): Promise { + const count = await stInstance.getUserCount(undefined, tenantId, userContext); return { status: "OK", diff --git a/lib/ts/recipe/dashboard/api/usersGet.ts b/lib/ts/recipe/dashboard/api/usersGet.ts index 06dbdcbd3..405059fad 100644 --- a/lib/ts/recipe/dashboard/api/usersGet.ts +++ b/lib/ts/recipe/dashboard/api/usersGet.ts @@ -12,11 +12,9 @@ * License for the specific language governing permissions and limitations * under the License. */ -import { APIInterface, APIOptions, UserWithFirstAndLastName } from "../types"; +import { APIFunction, UserWithFirstAndLastName } from "../types"; import STError from "../../../error"; import { getUsersNewestFirst, getUsersOldestFirst } from "../../.."; -import UserMetaDataRecipe from "../../usermetadata/recipe"; -import UserMetaData from "../../usermetadata"; export type Response = { status: "OK"; @@ -24,7 +22,12 @@ export type Response = { users: UserWithFirstAndLastName[]; }; -export default async function usersGet(_: APIInterface, tenantId: string, options: APIOptions): Promise { +export default async function usersGet({ + stInstance, + tenantId, + options, + userContext, +}: Parameters[0]): Promise { const req = options.req; const limit = options.req.getKeyValueFromQuery("limit"); @@ -66,9 +69,10 @@ export default async function usersGet(_: APIInterface, tenantId: string, option paginationToken, }); + let usermetadataRecipe = undefined; // If the UserMetaData recipe has been initialised, fetch first and last name try { - UserMetaDataRecipe.getInstanceOrThrowError(); + usermetadataRecipe = stInstance.getRecipeInstanceOrThrow("usermetadata"); } catch (e) { // Recipe has not been initialised, return without first name and last name return { @@ -87,7 +91,10 @@ export default async function usersGet(_: APIInterface, tenantId: string, option (): Promise => new Promise(async (resolve, reject) => { try { - const userMetaDataResponse = await UserMetaData.getUserMetadata(userObj.id); + const userMetaDataResponse = await usermetadataRecipe.recipeInterfaceImpl.getUserMetadata({ + userId: userObj.id, + userContext, + }); const { first_name, last_name } = userMetaDataResponse.metadata; updatedUsersArray[i] = { diff --git a/lib/ts/recipe/dashboard/recipe.ts b/lib/ts/recipe/dashboard/recipe.ts index 270d9b586..1f79fc0be 100644 --- a/lib/ts/recipe/dashboard/recipe.ts +++ b/lib/ts/recipe/dashboard/recipe.ts @@ -96,6 +96,7 @@ import updateTenantCoreConfig from "./api/multitenancy/updateTenantCoreConfig"; import getThirdPartyConfig from "./api/multitenancy/getThirdPartyConfig"; import { isTestEnv } from "../../utils"; import { applyPlugins } from "../../plugins"; +import type SuperTokens from "../../supertokens"; export default class Recipe extends RecipeModule { private static instance: Recipe | undefined = undefined; @@ -109,18 +110,24 @@ export default class Recipe extends RecipeModule { isInServerlessEnv: boolean; - constructor(recipeId: string, appInfo: NormalisedAppinfo, isInServerlessEnv: boolean, config?: TypeInput) { - super(recipeId, appInfo); + constructor( + stInstance: SuperTokens, + recipeId: string, + appInfo: NormalisedAppinfo, + isInServerlessEnv: boolean, + config?: TypeInput + ) { + super(stInstance, recipeId, appInfo); this.config = validateAndNormaliseUserInput(config); this.isInServerlessEnv = isInServerlessEnv; { - let builder = new OverrideableBuilder(RecipeImplementation()); + let builder = new OverrideableBuilder(RecipeImplementation(this.querier)); this.recipeInterfaceImpl = builder.override(this.config.override.functions).build(); } { - let builder = new OverrideableBuilder(APIImplementation()); + let builder = new OverrideableBuilder(APIImplementation(this.stInstance)); this.apiImpl = builder.override(this.config.override.apis).build(); } } @@ -133,9 +140,10 @@ export default class Recipe extends RecipeModule { } static init(config?: TypeInput): RecipeListFunction { - return (appInfo, isInServerlessEnv, plugins) => { + return (stInstance, appInfo, isInServerlessEnv, plugins) => { if (Recipe.instance === undefined) { Recipe.instance = new Recipe( + stInstance, Recipe.RECIPE_ID, appInfo, isInServerlessEnv, @@ -463,11 +471,25 @@ export default class Recipe extends RecipeModule { // For these APIs we dont need API key validation if (id === DASHBOARD_API) { - return await dashboard(this.apiImpl, options, userContext); + return await dashboard({ + apiImplementation: this.apiImpl, + recipeInstance: this, + stInstance: this.stInstance, + tenantId, + options, + userContext, + }); } if (id === SIGN_IN_API) { - return await signIn(this.apiImpl, options, userContext); + return await signIn({ + apiImplementation: this.apiImpl, + recipeInstance: this, + stInstance: this.stInstance, + tenantId, + options, + userContext, + }); } if (id === VALIDATE_KEY_API) { @@ -599,7 +621,14 @@ export default class Recipe extends RecipeModule { return false; } - return await apiKeyProtector(this.apiImpl, tenantId, options, apiFunction, userContext); + return await apiKeyProtector(apiFunction, { + apiImplementation: this.apiImpl, + recipeInstance: this, + stInstance: this.stInstance, + tenantId, + options, + userContext, + }); }; handleError = async (err: error, _: BaseRequest, __: BaseResponse): Promise => { diff --git a/lib/ts/recipe/dashboard/recipeImplementation.ts b/lib/ts/recipe/dashboard/recipeImplementation.ts index a000f5d60..e99486d3b 100644 --- a/lib/ts/recipe/dashboard/recipeImplementation.ts +++ b/lib/ts/recipe/dashboard/recipeImplementation.ts @@ -22,7 +22,7 @@ import { DASHBOARD_ANALYTICS_API, SIGN_OUT_API } from "./constants"; import { RecipeInterface } from "./types"; import { validateApiKey } from "./utils"; -export default function getRecipeImplementation(): RecipeInterface { +export default function getRecipeImplementation(querier: Querier): RecipeInterface { return { getDashboardBundleLocation: async function () { return `https://cdn.jsdelivr.net/gh/supertokens/dashboard@v${dashboardVersion}/build/`; @@ -31,7 +31,6 @@ export default function getRecipeImplementation(): RecipeInterface { // For cases where we're not using the API key, the JWT is being used; we allow their access by default if (!input.config.apiKey) { // make the check for the API endpoint here with querier - let querier = Querier.getNewInstanceOrThrowError(undefined); const authHeaderValue = input.req.getHeaderValue("authorization")?.split(" ")[1]; const sessionVerificationResponse = await querier.sendPostRequest( "/recipe/dashboard/session/verify", diff --git a/lib/ts/recipe/dashboard/types.ts b/lib/ts/recipe/dashboard/types.ts index f5e40d596..c034c897d 100644 --- a/lib/ts/recipe/dashboard/types.ts +++ b/lib/ts/recipe/dashboard/types.ts @@ -15,7 +15,9 @@ import OverrideableBuilder from "supertokens-js-override"; import type { BaseRequest, BaseResponse } from "../../framework"; -import { NormalisedAppinfo, User, UserContext } from "../../types"; +import type { NormalisedAppinfo, User, UserContext } from "../../types"; +import type DashboardRecipe from "./recipe"; +import type SuperTokens from "../../supertokens"; export type TypeInput = { apiKey?: string; @@ -65,12 +67,14 @@ export type APIInterface = { dashboardGET: undefined | ((input: { options: APIOptions; userContext: UserContext }) => Promise); }; -export type APIFunction = ( - apiImplementation: APIInterface, - tenantId: string, - options: APIOptions, - userContext: UserContext -) => Promise; +export type APIFunction = (input: { + apiImplementation: APIInterface; + recipeInstance: DashboardRecipe; + stInstance: SuperTokens; + tenantId: string; + options: APIOptions; + userContext: UserContext; +}) => Promise; export type RecipeIdForUser = "emailpassword" | "thirdparty" | "passwordless" | "webauthn"; diff --git a/lib/ts/recipe/dashboard/utils.ts b/lib/ts/recipe/dashboard/utils.ts index 1c1608e35..b9544b4f7 100644 --- a/lib/ts/recipe/dashboard/utils.ts +++ b/lib/ts/recipe/dashboard/utils.ts @@ -24,14 +24,10 @@ import { TypeNormalisedInput, UserWithFirstAndLastName, } from "./types"; -import AccountLinking from "../accountlinking/recipe"; -import EmailPasswordRecipe from "../emailpassword/recipe"; -import ThirdPartyRecipe from "../thirdparty/recipe"; -import PasswordlessRecipe from "../passwordless/recipe"; -import WebAuthnRecipe from "../webauthn/recipe"; import RecipeUserId from "../../recipeUserId"; import { User, UserContext } from "../../types"; import { logDebugMessage } from "../../logger"; +import type SuperTokens from "../../supertokens"; export function validateAndNormaliseUserInput(config?: TypeInput): TypeNormalisedInput { let override = { @@ -72,6 +68,7 @@ export function isValidRecipeId(recipeId: string): recipeId is RecipeIdForUser { } export async function getUserForRecipeId( + stInstance: SuperTokens, recipeUserId: RecipeUserId, recipeId: string, userContext: UserContext @@ -79,7 +76,7 @@ export async function getUserForRecipeId( user: UserWithFirstAndLastName | undefined; recipe: "emailpassword" | "thirdparty" | "passwordless" | "webauthn" | undefined; }> { - let userResponse = await _getUserForRecipeId(recipeUserId, recipeId, userContext); + let userResponse = await _getUserForRecipeId(stInstance, recipeUserId, recipeId, userContext); let user: UserWithFirstAndLastName | undefined = undefined; if (userResponse.user !== undefined) { user = { @@ -95,6 +92,7 @@ export async function getUserForRecipeId( } async function _getUserForRecipeId( + stInstance: SuperTokens, recipeUserId: RecipeUserId, recipeId: string, userContext: UserContext @@ -104,7 +102,7 @@ async function _getUserForRecipeId( }> { let recipe: "emailpassword" | "thirdparty" | "passwordless" | "webauthn" | undefined; - const user = await AccountLinking.getInstanceOrThrowError().recipeInterfaceImpl.getUser({ + const user = await stInstance.getRecipeInstanceOrThrow("accountlinking").recipeInterfaceImpl.getUser({ userId: recipeUserId.getAsString(), userContext, }); @@ -127,34 +125,25 @@ async function _getUserForRecipeId( }; } - if (recipeId === EmailPasswordRecipe.RECIPE_ID) { - try { - // we detect if this recipe has been init or not.. - EmailPasswordRecipe.getInstanceOrThrowError(); + if (recipeId === "emailpassword") { + let emailpasswordRecipe = stInstance.getRecipeInstance("emailpassword"); + if (emailpasswordRecipe !== undefined) { recipe = "emailpassword"; - } catch (e) { - // No - op } - } else if (recipeId === ThirdPartyRecipe.RECIPE_ID) { - try { - ThirdPartyRecipe.getInstanceOrThrowError(); + } else if (recipeId === "thirdparty") { + let thirdpartyRecipe = stInstance.getRecipeInstance("thirdparty"); + if (thirdpartyRecipe !== undefined) { recipe = "thirdparty"; - } catch (e) { - // No - op } - } else if (recipeId === PasswordlessRecipe.RECIPE_ID) { - try { - PasswordlessRecipe.getInstanceOrThrowError(); + } else if (recipeId === "passwordless") { + let passwordlessRecipe = stInstance.getRecipeInstance("passwordless"); + if (passwordlessRecipe !== undefined) { recipe = "passwordless"; - } catch (e) { - // No - op } - } else if (recipeId === WebAuthnRecipe.RECIPE_ID) { - try { - WebAuthnRecipe.getInstanceOrThrowError(); + } else if (recipeId === "webauthn") { + let webauthnRecipe = stInstance.getRecipeInstance("webauthn"); + if (webauthnRecipe !== undefined) { recipe = "webauthn"; - } catch (e) { - // No - op } } return { diff --git a/lib/ts/recipe/emailpassword/api/emailExists.ts b/lib/ts/recipe/emailpassword/api/emailExists.ts index 3ed5ecab6..2d20c4485 100644 --- a/lib/ts/recipe/emailpassword/api/emailExists.ts +++ b/lib/ts/recipe/emailpassword/api/emailExists.ts @@ -15,7 +15,7 @@ import { send200Response } from "../../../utils"; import STError from "../error"; -import { APIInterface, APIOptions } from "../"; +import type { APIInterface, APIOptions } from "../types"; import { UserContext } from "../../../types"; export default async function emailExists( diff --git a/lib/ts/recipe/emailpassword/api/implementation.ts b/lib/ts/recipe/emailpassword/api/implementation.ts index 55777032b..213bc6296 100644 --- a/lib/ts/recipe/emailpassword/api/implementation.ts +++ b/lib/ts/recipe/emailpassword/api/implementation.ts @@ -1,17 +1,15 @@ import { APIInterface, APIOptions } from "../"; import { logDebugMessage } from "../../../logger"; import { GeneralErrorResponse, User, UserContext } from "../../../types"; -import { getUser } from "../../../"; -import AccountLinking from "../../accountlinking/recipe"; -import EmailVerification from "../../emailverification/recipe"; import { RecipeLevelUser } from "../../accountlinking/types"; import RecipeUserId from "../../../recipeUserId"; import { getPasswordResetLink } from "../utils"; import { AuthUtils } from "../../../authUtils"; import { isFakeEmail } from "../../thirdparty/utils"; import { SessionContainerInterface } from "../../session/types"; +import type SuperTokens from "../../../supertokens"; -export default function getAPIImplementation(): APIInterface { +export default function getAPIImplementation(stInstance: SuperTokens): APIInterface { return { emailExistsGET: async function ({ email, @@ -32,14 +30,16 @@ export default function getAPIImplementation(): APIInterface { // even if the above returns true, we still need to check if there // exists an email password user with the same email cause the function // above does not check for that. - let users = await AccountLinking.getInstanceOrThrowError().recipeInterfaceImpl.listUsersByAccountInfo({ - tenantId, - accountInfo: { - email, - }, - doUnionOfAccountInfo: false, - userContext, - }); + let users = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.listUsersByAccountInfo({ + tenantId, + accountInfo: { + email, + }, + doUnionOfAccountInfo: false, + userContext, + }); let emailPasswordUserExists = users.find((u) => { return ( @@ -128,14 +128,16 @@ export default function getAPIImplementation(): APIInterface { /** * check if primaryUserId is linked with this email */ - let users = await AccountLinking.getInstanceOrThrowError().recipeInterfaceImpl.listUsersByAccountInfo({ - tenantId, - accountInfo: { - email, - }, - doUnionOfAccountInfo: false, - userContext, - }); + let users = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.listUsersByAccountInfo({ + tenantId, + accountInfo: { + email, + }, + doUnionOfAccountInfo: false, + userContext, + }); // we find the recipe user ID of the email password account from the user's list // for later use. @@ -179,12 +181,9 @@ export default function getAPIImplementation(): APIInterface { } email)` ); // Otherwise, we check if the user can become primary. - const shouldBecomePrimaryUser = await AccountLinking.getInstanceOrThrowError().shouldBecomePrimaryUser( - oldestUser, - tenantId, - undefined, - userContext - ); + const shouldBecomePrimaryUser = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .shouldBecomePrimaryUser(oldestUser, tenantId, undefined, userContext); logDebugMessage( `generatePasswordResetTokenPOST: recipe level-linking candidate ${ @@ -282,8 +281,9 @@ export default function getAPIImplementation(): APIInterface { // is verified, and if not, we need to make sure that there is no other email / phone number // associated with the primary user account. If there is, then we do not proceed. - let shouldDoAccountLinkingResponse = - await AccountLinking.getInstanceOrThrowError().config.shouldDoAutomaticAccountLinking( + let shouldDoAccountLinkingResponse = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .config.shouldDoAutomaticAccountLinking( emailPasswordAccount !== undefined ? emailPasswordAccount : { @@ -318,7 +318,7 @@ export default function getAPIImplementation(): APIInterface { }; } - let isSignUpAllowed = await AccountLinking.getInstanceOrThrowError().isSignUpAllowed({ + let isSignUpAllowed = await stInstance.getRecipeInstanceOrThrow("accountlinking").isSignUpAllowed({ newUser: { recipeId: "emailpassword", email, @@ -384,7 +384,13 @@ export default function getAPIImplementation(): APIInterface { | GeneralErrorResponse > { async function markEmailAsVerified(recipeUserId: RecipeUserId, email: string) { - const emailVerificationInstance = EmailVerification.getInstance(); + let emailVerificationInstance = undefined; + try { + emailVerificationInstance = stInstance.getRecipeInstanceOrThrow("emailverification"); + } catch (_) { + logDebugMessage("email verification recipe not initialised, not marking email as verified"); + } + if (emailVerificationInstance) { const tokenResponse = await emailVerificationInstance.recipeInterfaceImpl.createEmailVerificationToken({ @@ -455,7 +461,9 @@ export default function getAPIImplementation(): APIInterface { // If we verified (and linked) the existing user with the original password, User M would get access to the current user and any linked users. await markEmailAsVerified(recipeUserId, emailForWhomTokenWasGenerated); // We refresh the user information here, because the verification status may be updated, which is used during linking. - const updatedUserAfterEmailVerification = await getUser(recipeUserId.getAsString(), userContext); + const updatedUserAfterEmailVerification = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: recipeUserId.getAsString(), userContext }); if (updatedUserAfterEmailVerification === undefined) { throw new Error("Should never happen - user deleted after during password reset"); } @@ -475,8 +483,9 @@ export default function getAPIImplementation(): APIInterface { // The function below will try and also create a primary user of the new account, this can happen if: // 1. the user was unverified and linking requires verification // We do not take try linking by session here, since this is supposed to be called without a session - const linkRes = - await AccountLinking.getInstanceOrThrowError().tryLinkingByAccountInfoOrCreatePrimaryUser({ + const linkRes = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .tryLinkingByAccountInfoOrCreatePrimaryUser({ tenantId, inputUser: updatedUserAfterEmailVerification, session: undefined, @@ -516,7 +525,9 @@ export default function getAPIImplementation(): APIInterface { let userIdForWhomTokenWasGenerated = tokenConsumptionResponse.userId; let emailForWhomTokenWasGenerated = tokenConsumptionResponse.email; - let existingUser = await getUser(userIdForWhomTokenWasGenerated, userContext); + let existingUser = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: userIdForWhomTokenWasGenerated, userContext }); if (existingUser === undefined) { // This should happen only cause of a race condition where the user @@ -629,7 +640,9 @@ export default function getAPIImplementation(): APIInterface { createUserResponse.user.loginMethods[0].recipeUserId, tokenConsumptionResponse.email ); - const updatedUser = await getUser(createUserResponse.user.id, userContext); + const updatedUser = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: createUserResponse.user.id, userContext }); if (updatedUser === undefined) { throw new Error("Should never happen - user deleted after during password reset"); } @@ -640,8 +653,9 @@ export default function getAPIImplementation(): APIInterface { // email is shared. // We do not take try linking by session here, since this is supposed to be called without a session // Still, the session object is passed around because it is a required input for shouldDoAutomaticAccountLinking - const linkRes = - await AccountLinking.getInstanceOrThrowError().tryLinkingByAccountInfoOrCreatePrimaryUser({ + const linkRes = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .tryLinkingByAccountInfoOrCreatePrimaryUser({ tenantId, inputUser: createUserResponse.user, session: undefined, @@ -744,6 +758,7 @@ export default function getAPIImplementation(): APIInterface { } const authenticatingUser = await AuthUtils.getAuthenticatingUserAndAddToCurrentTenantIfRequired({ + stInstance, accountInfo: { email }, userContext, recipeId, @@ -763,6 +778,7 @@ export default function getAPIImplementation(): APIInterface { }; } const preAuthChecks = await AuthUtils.preAuthChecks({ + stInstance, authenticatingAccountInfo: { recipeId, email, @@ -809,6 +825,7 @@ export default function getAPIImplementation(): APIInterface { } const postAuthChecks = await AuthUtils.postAuthChecks({ + stInstance, authenticatedUser: signInResponse.user, recipeUserId: signInResponse.recipeUserId, isSignUp: false, @@ -897,6 +914,7 @@ export default function getAPIImplementation(): APIInterface { let password: string = passwordAsUnknown; const preAuthCheckRes = await AuthUtils.preAuthChecks({ + stInstance, authenticatingAccountInfo: { recipeId: "emailpassword", email, @@ -914,8 +932,9 @@ export default function getAPIImplementation(): APIInterface { }); if (preAuthCheckRes.status === "SIGN_UP_NOT_ALLOWED") { - const conflictingUsers = - await AccountLinking.getInstanceOrThrowError().recipeInterfaceImpl.listUsersByAccountInfo({ + const conflictingUsers = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.listUsersByAccountInfo({ tenantId, accountInfo: { email, @@ -961,6 +980,7 @@ export default function getAPIImplementation(): APIInterface { } const postAuthChecks = await AuthUtils.postAuthChecks({ + stInstance, authenticatedUser: signUpResponse.user, recipeUserId: signUpResponse.recipeUserId, isSignUp: true, diff --git a/lib/ts/recipe/emailpassword/api/signin.ts b/lib/ts/recipe/emailpassword/api/signin.ts index 899d06bc0..7d05ce88f 100644 --- a/lib/ts/recipe/emailpassword/api/signin.ts +++ b/lib/ts/recipe/emailpassword/api/signin.ts @@ -22,8 +22,10 @@ import { validateFormFieldsOrThrowError } from "./utils"; import { APIInterface, APIOptions } from "../"; import { UserContext } from "../../../types"; import { AuthUtils } from "../../../authUtils"; +import type SuperTokens from "../../../supertokens"; export default async function signInAPI( + stInstance: SuperTokens, apiImplementation: APIInterface, tenantId: string, options: APIOptions, @@ -49,6 +51,7 @@ export default async function signInAPI( const shouldTryLinkingWithSessionUser = getNormalisedShouldTryLinkingWithSessionUserFlag(options.req, body); const session = await AuthUtils.loadSessionInAuthAPIIfNeeded( + stInstance, options.req, options.res, shouldTryLinkingWithSessionUser, diff --git a/lib/ts/recipe/emailpassword/api/signup.ts b/lib/ts/recipe/emailpassword/api/signup.ts index bb4c1efa2..d1c8338fa 100644 --- a/lib/ts/recipe/emailpassword/api/signup.ts +++ b/lib/ts/recipe/emailpassword/api/signup.ts @@ -23,8 +23,10 @@ import { APIInterface, APIOptions } from "../"; import STError from "../error"; import { UserContext } from "../../../types"; import { AuthUtils } from "../../../authUtils"; +import type SuperTokens from "../../../supertokens"; export default async function signUpAPI( + stInstance: SuperTokens, apiImplementation: APIInterface, tenantId: string, options: APIOptions, @@ -52,6 +54,7 @@ export default async function signUpAPI( const shouldTryLinkingWithSessionUser = getNormalisedShouldTryLinkingWithSessionUserFlag(options.req, requestBody); const session = await AuthUtils.loadSessionInAuthAPIIfNeeded( + stInstance, options.req, options.res, shouldTryLinkingWithSessionUser, diff --git a/lib/ts/recipe/emailpassword/passwordResetFunctions.ts b/lib/ts/recipe/emailpassword/passwordResetFunctions.ts index ca23af864..7b76837e1 100644 --- a/lib/ts/recipe/emailpassword/passwordResetFunctions.ts +++ b/lib/ts/recipe/emailpassword/passwordResetFunctions.ts @@ -14,7 +14,8 @@ */ import { NormalisedAppinfo } from "../../types"; -import { isTestEnv, postWithFetch } from "../../utils"; +import { isTestEnv } from "../../utils"; +import { postWithFetch } from "../../querier"; export async function createAndSendEmailUsingSupertokensService( appInfo: NormalisedAppinfo, diff --git a/lib/ts/recipe/emailpassword/recipe.ts b/lib/ts/recipe/emailpassword/recipe.ts index 2d6ace0c8..9a3f21574 100644 --- a/lib/ts/recipe/emailpassword/recipe.ts +++ b/lib/ts/recipe/emailpassword/recipe.ts @@ -36,17 +36,15 @@ import { applyPlugins } from "../../plugins"; import emailExistsAPI from "./api/emailExists"; import RecipeImplementation from "./recipeImplementation"; import APIImplementation from "./api/implementation"; -import { Querier } from "../../querier"; import type { BaseRequest, BaseResponse } from "../../framework"; import OverrideableBuilder from "supertokens-js-override"; import EmailDeliveryIngredient from "../../ingredients/emaildelivery"; import { TypeEmailPasswordEmailDeliveryInput } from "./types"; import { PostSuperTokensInitCallbacks } from "../../postSuperTokensInitCallbacks"; -import MultiFactorAuthRecipe from "../multifactorauth/recipe"; -import MultitenancyRecipe from "../multitenancy/recipe"; import { User } from "../../user"; import { isFakeEmail } from "../thirdparty/utils"; import { FactorIds } from "../multifactorauth"; +import type SuperTokens from "../../supertokens"; export default class Recipe extends RecipeModule { private static instance: Recipe | undefined = undefined; @@ -63,6 +61,7 @@ export default class Recipe extends RecipeModule { emailDelivery: EmailDeliveryIngredient; constructor( + stInstance: SuperTokens, recipeId: string, appInfo: NormalisedAppinfo, isInServerlessEnv: boolean, @@ -71,18 +70,18 @@ export default class Recipe extends RecipeModule { emailDelivery: EmailDeliveryIngredient | undefined; } ) { - super(recipeId, appInfo); + super(stInstance, recipeId, appInfo); this.isInServerlessEnv = isInServerlessEnv; this.config = validateAndNormaliseUserInput(this, appInfo, config); { const getEmailPasswordConfig = () => this.config; let builder = new OverrideableBuilder( - RecipeImplementation(Querier.getNewInstanceOrThrowError(recipeId), getEmailPasswordConfig) + RecipeImplementation(this.stInstance, this.querier, getEmailPasswordConfig) ); this.recipeInterfaceImpl = builder.override(this.config.override.functions).build(); } { - let builder = new OverrideableBuilder(APIImplementation()); + let builder = new OverrideableBuilder(APIImplementation(this.stInstance)); this.apiImpl = builder.override(this.config.override.apis).build(); } @@ -96,7 +95,7 @@ export default class Recipe extends RecipeModule { : ingredients.emailDelivery; PostSuperTokensInitCallbacks.addPostInitCallback(() => { - const mfaInstance = MultiFactorAuthRecipe.getInstance(); + const mfaInstance = stInstance.getRecipeInstance("multifactorauth"); if (mfaInstance !== undefined) { mfaInstance.addFuncToGetAllAvailableSecondaryFactorIdsFromOtherRecipes(() => { return ["emailpassword"]; @@ -215,7 +214,7 @@ export default class Recipe extends RecipeModule { }); } - const mtRecipe = MultitenancyRecipe.getInstance(); + const mtRecipe = stInstance.getRecipeInstance("multitenancy"); if (mtRecipe !== undefined) { mtRecipe.allAvailableFirstFactors.push(FactorIds.EMAILPASSWORD); } @@ -230,9 +229,10 @@ export default class Recipe extends RecipeModule { } static init(config?: TypeInput): RecipeListFunction { - return (appInfo, isInServerlessEnv, plugins) => { + return (stInstance, appInfo, isInServerlessEnv, plugins) => { if (Recipe.instance === undefined) { Recipe.instance = new Recipe( + stInstance, Recipe.RECIPE_ID, appInfo, isInServerlessEnv, @@ -319,9 +319,9 @@ export default class Recipe extends RecipeModule { appInfo: this.getAppInfo(), }; if (id === SIGN_UP_API) { - return await signUpAPI(this.apiImpl, tenantId, options, userContext); + return await signUpAPI(this.stInstance, this.apiImpl, tenantId, options, userContext); } else if (id === SIGN_IN_API) { - return await signInAPI(this.apiImpl, tenantId, options, userContext); + return await signInAPI(this.stInstance, this.apiImpl, tenantId, options, userContext); } else if (id === GENERATE_PASSWORD_RESET_TOKEN_API) { return await generatePasswordResetTokenAPI(this.apiImpl, tenantId, options, userContext); } else if (id === PASSWORD_RESET_API) { diff --git a/lib/ts/recipe/emailpassword/recipeImplementation.ts b/lib/ts/recipe/emailpassword/recipeImplementation.ts index 98b8529d2..ec1cf3117 100644 --- a/lib/ts/recipe/emailpassword/recipeImplementation.ts +++ b/lib/ts/recipe/emailpassword/recipeImplementation.ts @@ -1,16 +1,15 @@ import { RecipeInterface, TypeNormalisedInput } from "./types"; -import AccountLinking from "../accountlinking/recipe"; -import EmailVerification from "../emailverification/recipe"; import { Querier } from "../../querier"; -import { getUser } from "../.."; import { FORM_FIELD_PASSWORD_ID } from "./constants"; import RecipeUserId from "../../recipeUserId"; import { DEFAULT_TENANT_ID } from "../multitenancy/constants"; import { UserContext, User as UserType } from "../../types"; import { LoginMethod, User } from "../../user"; import { AuthUtils } from "../../authUtils"; +import type SuperTokens from "../../supertokens"; export default function getRecipeInterface( + stInstance: SuperTokens, querier: Querier, getEmailPasswordConfig: () => TypeNormalisedInput ): RecipeInterface { @@ -47,8 +46,9 @@ export default function getRecipeInterface( let updatedUser = response.user; const linkResult = await AuthUtils.linkToSessionIfRequiredElseCreatePrimaryUserIdOrLinkByAccountInfo({ + stInstance, tenantId, - inputUser: response.user, + inputUser: updatedUser, recipeUserId: response.recipeUserId, session, shouldTryLinkingWithSessionUser, @@ -118,11 +118,13 @@ export default function getRecipeInterface( )!; if (!loginMethod.verified) { - await AccountLinking.getInstanceOrThrowError().verifyEmailForRecipeUserIfLinkedAccountsAreVerified({ - user: response.user, - recipeUserId: response.recipeUserId, - userContext, - }); + await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .verifyEmailForRecipeUserIfLinkedAccountsAreVerified({ + user: response.user, + recipeUserId: response.recipeUserId, + userContext, + }); // Unlike in the sign up recipe function, we do not do account linking here // cause we do not want sign in to change the potentially user ID of a user @@ -136,10 +138,13 @@ export default function getRecipeInterface( // We do this so that we get the updated user (in case the above // function updated the verification status) and can return that - response.user = (await getUser(response.recipeUserId!.getAsString(), userContext))!; + response.user = (await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: response.recipeUserId!.getAsString(), userContext }))!; } const linkResult = await AuthUtils.linkToSessionIfRequiredElseCreatePrimaryUserIdOrLinkByAccountInfo({ + stInstance, tenantId, inputUser: response.user, recipeUserId: response.recipeUserId, @@ -265,15 +270,18 @@ export default function getRecipeInterface( } | { status: "PASSWORD_POLICY_VIOLATED_ERROR"; failureReason: string } > { - const accountLinking = AccountLinking.getInstanceOrThrowError(); + const accountLinking = stInstance.getRecipeInstanceOrThrow("accountlinking"); if (input.email) { - const user = await getUser(input.recipeUserId.getAsString(), input.userContext); + const user = await stInstance.getRecipeInstanceOrThrow("accountlinking").recipeInterfaceImpl.getUser({ + userId: input.recipeUserId.getAsString(), + userContext: input.userContext, + }); if (user === undefined) { return { status: "UNKNOWN_USER_ID_ERROR" }; } - const evInstance = EmailVerification.getInstance(); + const evInstance = stInstance.getRecipeInstance("emailverification"); let isEmailVerified = false; if (evInstance) { @@ -337,18 +345,23 @@ export default function getRecipeInterface( ); if (response.status === "OK") { - const user = await getUser(input.recipeUserId.getAsString(), input.userContext); + const user = await stInstance.getRecipeInstanceOrThrow("accountlinking").recipeInterfaceImpl.getUser({ + userId: input.recipeUserId.getAsString(), + userContext: input.userContext, + }); if (user === undefined) { // This means that the user was deleted between the put and get requests return { status: "UNKNOWN_USER_ID_ERROR", }; } - await AccountLinking.getInstanceOrThrowError().verifyEmailForRecipeUserIfLinkedAccountsAreVerified({ - user, - recipeUserId: input.recipeUserId, - userContext: input.userContext, - }); + await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .verifyEmailForRecipeUserIfLinkedAccountsAreVerified({ + user, + recipeUserId: input.recipeUserId, + userContext: input.userContext, + }); } return response; diff --git a/lib/ts/recipe/emailpassword/types.ts b/lib/ts/recipe/emailpassword/types.ts index 34660d952..fab18786f 100644 --- a/lib/ts/recipe/emailpassword/types.ts +++ b/lib/ts/recipe/emailpassword/types.ts @@ -330,3 +330,10 @@ export type TypeEmailPasswordPasswordResetEmailDeliveryInput = { }; export type TypeEmailPasswordEmailDeliveryInput = TypeEmailPasswordPasswordResetEmailDeliveryInput; + +export type APIFunction = (input: { + apiImplementation: APIInterface; + tenantId: string; + options: APIOptions; + userContext: UserContext; +}) => Promise; diff --git a/lib/ts/recipe/emailpassword/utils.ts b/lib/ts/recipe/emailpassword/utils.ts index f6ce4316d..f4934dbc0 100644 --- a/lib/ts/recipe/emailpassword/utils.ts +++ b/lib/ts/recipe/emailpassword/utils.ts @@ -28,7 +28,7 @@ import { NormalisedAppinfo, UserContext } from "../../types"; import { FORM_FIELD_EMAIL_ID, FORM_FIELD_PASSWORD_ID } from "./constants"; import { RecipeInterface, APIInterface } from "./types"; import BackwardCompatibilityService from "./emaildelivery/services/backwardCompatibility"; -import { BaseRequest } from "../../framework"; +import type { BaseRequest } from "../../framework"; export function validateAndNormaliseUserInput( recipeInstance: Recipe, diff --git a/lib/ts/recipe/emailverification/api/emailVerify.ts b/lib/ts/recipe/emailverification/api/emailVerify.ts index 2924dd5b5..70526c4c8 100644 --- a/lib/ts/recipe/emailverification/api/emailVerify.ts +++ b/lib/ts/recipe/emailverification/api/emailVerify.ts @@ -16,10 +16,11 @@ import { send200Response, normaliseHttpMethod } from "../../../utils"; import STError from "../error"; import { APIInterface, APIOptions } from "../"; -import Session from "../../session"; import { UserContext } from "../../../types"; +import SuperTokens from "../../../supertokens"; export default async function emailVerify( + stInstance: SuperTokens, apiImplementation: APIInterface, tenantId: string, options: APIOptions, @@ -50,12 +51,12 @@ export default async function emailVerify( }); } - const session = await Session.getSession( - options.req, - options.res, - { overrideGlobalClaimValidators: () => [], sessionRequired: false }, - userContext - ); + const session = await stInstance.getRecipeInstanceOrThrow("session").getSession({ + req: options.req, + res: options.res, + options: { overrideGlobalClaimValidators: () => [], sessionRequired: false }, + userContext, + }); let response = await apiImplementation.verifyEmailPOST({ token, @@ -77,15 +78,16 @@ export default async function emailVerify( return false; } - const session = await Session.getSession( - options.req, - options.res, - { overrideGlobalClaimValidators: () => [] }, - userContext - ); + const session = await stInstance.getRecipeInstanceOrThrow("session").getSession({ + req: options.req, + res: options.res, + options: { overrideGlobalClaimValidators: () => [] }, + userContext, + }); + result = await apiImplementation.isEmailVerifiedGET({ options, - session, + session: session!, userContext, }); } diff --git a/lib/ts/recipe/emailverification/api/generateEmailVerifyToken.ts b/lib/ts/recipe/emailverification/api/generateEmailVerifyToken.ts index 2c1021059..adc69e962 100644 --- a/lib/ts/recipe/emailverification/api/generateEmailVerifyToken.ts +++ b/lib/ts/recipe/emailverification/api/generateEmailVerifyToken.ts @@ -15,10 +15,11 @@ import { send200Response } from "../../../utils"; import { APIInterface, APIOptions } from "../"; -import Session from "../../session"; import { UserContext } from "../../../types"; +import type SuperTokens from "../../../supertokens"; export default async function generateEmailVerifyToken( + stInstance: SuperTokens, apiImplementation: APIInterface, options: APIOptions, userContext: UserContext @@ -28,16 +29,16 @@ export default async function generateEmailVerifyToken( if (apiImplementation.generateEmailVerifyTokenPOST === undefined) { return false; } - const session = await Session.getSession( - options.req, - options.res, - { overrideGlobalClaimValidators: () => [] }, - userContext - ); + const session = await stInstance.getRecipeInstanceOrThrow("session").getSession({ + req: options.req, + res: options.res, + options: { overrideGlobalClaimValidators: () => [] }, + userContext, + }); const result = await apiImplementation.generateEmailVerifyTokenPOST({ options, - session: session, + session: session!, userContext, }); diff --git a/lib/ts/recipe/emailverification/api/implementation.ts b/lib/ts/recipe/emailverification/api/implementation.ts index 89e81c9ab..f5d450529 100644 --- a/lib/ts/recipe/emailverification/api/implementation.ts +++ b/lib/ts/recipe/emailverification/api/implementation.ts @@ -1,13 +1,13 @@ import { APIInterface, UserEmailInfo } from "../"; import { logDebugMessage } from "../../../logger"; -import EmailVerificationRecipe from "../recipe"; import { GeneralErrorResponse } from "../../../types"; import { EmailVerificationClaim } from "../emailVerificationClaim"; import SessionError from "../../session/error"; import { getEmailVerifyLink } from "../utils"; import { SessionContainerInterface } from "../../session/types"; +import type SuperTokens from "../../../supertokens"; -export default function getAPIInterface(): APIInterface { +export default function getAPIInterface(stInstance: SuperTokens): APIInterface { return { verifyEmailPOST: async function ( this: APIInterface, @@ -29,15 +29,15 @@ export default function getAPIInterface(): APIInterface { } // status: "OK" - let newSession = await EmailVerificationRecipe.getInstanceOrThrowError().updateSessionIfRequiredPostEmailVerification( - { + let newSession = await stInstance + .getRecipeInstanceOrThrow("emailverification") + .updateSessionIfRequiredPostEmailVerification({ req: options.req, res: options.res, session, recipeUserIdWhoseEmailGotVerified: verifyTokenResponse.user.recipeUserId, userContext, - } - ); + }); return { status: "OK", @@ -59,11 +59,9 @@ export default function getAPIInterface(): APIInterface { > { // In this API, we will check if the session's recipe user id's email is verified or not. - const emailInfo = await EmailVerificationRecipe.getInstanceOrThrowError().getEmailForRecipeUserId( - undefined, - session.getRecipeUserId(userContext), - userContext - ); + const emailInfo = await stInstance + .getRecipeInstanceOrThrow("emailverification") + .getEmailForRecipeUserId(undefined, session.getRecipeUserId(userContext), userContext); if (emailInfo.status === "OK") { const isVerified = await options.recipeImplementation.isEmailVerified({ @@ -78,15 +76,15 @@ export default function getAPIInterface(): APIInterface { // whilst the first browser is polling this API - in this case, // we want to have the same effect to the session as if the // email was opened on the original browser itself. - let newSession = await EmailVerificationRecipe.getInstanceOrThrowError().updateSessionIfRequiredPostEmailVerification( - { + let newSession = await stInstance + .getRecipeInstanceOrThrow("emailverification") + .updateSessionIfRequiredPostEmailVerification({ req: options.req, res: options.res, session, recipeUserIdWhoseEmailGotVerified: session.getRecipeUserId(userContext), userContext, - } - ); + }); return { status: "OK", isVerified: true, @@ -129,11 +127,9 @@ export default function getAPIInterface(): APIInterface { // In this API, we generate the email verification token for session's recipe user ID. const tenantId = session.getTenantId(); - const emailInfo = await EmailVerificationRecipe.getInstanceOrThrowError().getEmailForRecipeUserId( - undefined, - session.getRecipeUserId(userContext), - userContext - ); + const emailInfo = await stInstance + .getRecipeInstanceOrThrow("emailverification") + .getEmailForRecipeUserId(undefined, session.getRecipeUserId(userContext), userContext); if (emailInfo.status === "EMAIL_DOES_NOT_EXIST_ERROR") { logDebugMessage( @@ -143,15 +139,15 @@ export default function getAPIInterface(): APIInterface { ); // this can happen if the user ID was found, but it has no email. In this // case, we treat it as a success case. - let newSession = await EmailVerificationRecipe.getInstanceOrThrowError().updateSessionIfRequiredPostEmailVerification( - { + let newSession = await stInstance + .getRecipeInstanceOrThrow("emailverification") + .updateSessionIfRequiredPostEmailVerification({ req: options.req, res: options.res, session, recipeUserIdWhoseEmailGotVerified: session.getRecipeUserId(userContext), userContext, - } - ); + }); return { status: "EMAIL_ALREADY_VERIFIED_ERROR", newSession, @@ -172,15 +168,15 @@ export default function getAPIInterface(): APIInterface { .getRecipeUserId(userContext) .getAsString()} because it is already verified.` ); - let newSession = await EmailVerificationRecipe.getInstanceOrThrowError().updateSessionIfRequiredPostEmailVerification( - { + let newSession = await stInstance + .getRecipeInstanceOrThrow("emailverification") + .updateSessionIfRequiredPostEmailVerification({ req: options.req, res: options.res, session, recipeUserIdWhoseEmailGotVerified: session.getRecipeUserId(userContext), userContext, - } - ); + }); return { status: "EMAIL_ALREADY_VERIFIED_ERROR", newSession, diff --git a/lib/ts/recipe/emailverification/emailVerificationFunctions.ts b/lib/ts/recipe/emailverification/emailVerificationFunctions.ts index e0ab293a7..bc146418c 100644 --- a/lib/ts/recipe/emailverification/emailVerificationFunctions.ts +++ b/lib/ts/recipe/emailverification/emailVerificationFunctions.ts @@ -15,7 +15,8 @@ import { UserEmailInfo } from "./types"; import { NormalisedAppinfo } from "../../types"; -import { isTestEnv, postWithFetch } from "../../utils"; +import { isTestEnv } from "../../utils"; +import { postWithFetch } from "../../querier"; export async function createAndSendEmailUsingSupertokensService( appInfo: NormalisedAppinfo, diff --git a/lib/ts/recipe/emailverification/recipe.ts b/lib/ts/recipe/emailverification/recipe.ts index b53ad0452..c5fb545cd 100644 --- a/lib/ts/recipe/emailverification/recipe.ts +++ b/lib/ts/recipe/emailverification/recipe.ts @@ -24,22 +24,20 @@ import generateEmailVerifyTokenAPI from "./api/generateEmailVerifyToken"; import emailVerifyAPI from "./api/emailVerify"; import RecipeImplementation from "./recipeImplementation"; import APIImplementation from "./api/implementation"; -import { Querier } from "../../querier"; import type { BaseRequest, BaseResponse } from "../../framework"; import OverrideableBuilder from "supertokens-js-override"; import EmailDeliveryIngredient from "../../ingredients/emaildelivery"; import { TypeEmailVerificationEmailDeliveryInput } from "./types"; import { PostSuperTokensInitCallbacks } from "../../postSuperTokensInitCallbacks"; -import SessionRecipe from "../session/recipe"; import { EmailVerificationClaim } from "./emailVerificationClaim"; import { SessionContainerInterface } from "../session/types"; import SessionError from "../session/error"; import Session from "../session"; -import { getUser } from "../.."; import RecipeUserId from "../../recipeUserId"; import { logDebugMessage } from "../../logger"; import { isTestEnv } from "../../utils"; import { applyPlugins } from "../../plugins"; +import type SuperTokens from "../../supertokens"; export default class Recipe extends RecipeModule { private static instance: Recipe | undefined = undefined; @@ -56,6 +54,7 @@ export default class Recipe extends RecipeModule { emailDelivery: EmailDeliveryIngredient; constructor( + stInstance: SuperTokens, recipeId: string, appInfo: NormalisedAppinfo, isInServerlessEnv: boolean, @@ -64,18 +63,18 @@ export default class Recipe extends RecipeModule { emailDelivery: EmailDeliveryIngredient | undefined; } ) { - super(recipeId, appInfo); + super(stInstance, recipeId, appInfo); this.config = validateAndNormaliseUserInput(this, appInfo, config); this.isInServerlessEnv = isInServerlessEnv; { let builder = new OverrideableBuilder( - RecipeImplementation(Querier.getNewInstanceOrThrowError(recipeId), this.getEmailForRecipeUserId) + RecipeImplementation(this.stInstance, this.querier, this.getEmailForRecipeUserId) ); this.recipeInterfaceImpl = builder.override(this.config.override.functions).build(); } { - let builder = new OverrideableBuilder(APIImplementation()); + let builder = new OverrideableBuilder(APIImplementation(this.stInstance)); this.apiImpl = builder.override(this.config.override.apis).build(); } @@ -101,9 +100,10 @@ export default class Recipe extends RecipeModule { } static init(config: TypeInput): RecipeListFunction { - return (appInfo, isInServerlessEnv, plugins) => { + return (stInstance, appInfo, isInServerlessEnv, plugins) => { if (Recipe.instance === undefined) { Recipe.instance = new Recipe( + stInstance, Recipe.RECIPE_ID, appInfo, isInServerlessEnv, @@ -114,12 +114,12 @@ export default class Recipe extends RecipeModule { ); PostSuperTokensInitCallbacks.addPostInitCallback(() => { - SessionRecipe.getInstanceOrThrowError().addClaimFromOtherRecipe(EmailVerificationClaim); + stInstance.getRecipeInstanceOrThrow("session").addClaimFromOtherRecipe(EmailVerificationClaim); if (config.mode === "REQUIRED") { - SessionRecipe.getInstanceOrThrowError().addClaimValidatorFromOtherRecipe( - EmailVerificationClaim.validators.isVerified() - ); + stInstance + .getRecipeInstanceOrThrow("session") + .addClaimValidatorFromOtherRecipe(EmailVerificationClaim.validators.isVerified()); } }); @@ -184,9 +184,9 @@ export default class Recipe extends RecipeModule { appInfo: this.getAppInfo(), }; if (id === GENERATE_EMAIL_VERIFY_TOKEN_API) { - return await generateEmailVerifyTokenAPI(this.apiImpl, options, userContext); + return await generateEmailVerifyTokenAPI(this.stInstance, this.apiImpl, options, userContext); } else { - return await emailVerifyAPI(this.apiImpl, tenantId, options, userContext); + return await emailVerifyAPI(this.stInstance, this.apiImpl, tenantId, options, userContext); } }; @@ -211,7 +211,9 @@ export default class Recipe extends RecipeModule { } if (user === undefined) { - user = await getUser(recipeUserId.getAsString(), userContext); + user = await this.stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: recipeUserId.getAsString(), userContext }); if (user === undefined) { return { @@ -253,7 +255,9 @@ export default class Recipe extends RecipeModule { // so that the consumer of the getUser function does not read the email // from the primaryUser. Hence, this function only returns the string ID // and nothing else from the primaryUser. - let primaryUser = await getUser(recipeUserId.getAsString(), userContext); + let primaryUser = await this.stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: recipeUserId.getAsString(), userContext }); if (primaryUser === undefined) { // This can come here if the user is using session + email verification // recipe with a user ID that is not known to supertokens. In this case, diff --git a/lib/ts/recipe/emailverification/recipeImplementation.ts b/lib/ts/recipe/emailverification/recipeImplementation.ts index 9d84ec973..2fa943d1b 100644 --- a/lib/ts/recipe/emailverification/recipeImplementation.ts +++ b/lib/ts/recipe/emailverification/recipeImplementation.ts @@ -2,11 +2,11 @@ import { RecipeInterface } from "./"; import { Querier } from "../../querier"; import RecipeUserId from "../../recipeUserId"; import { GetEmailForRecipeUserIdFunc, UserEmailInfo } from "./types"; -import { getUser } from "../.."; import { UserContext } from "../../types"; -import type AccountLinkingRecipe from "../accountlinking/recipe"; +import SuperTokens from "../../supertokens"; export default function getRecipeInterface( + stInstance: SuperTokens, querier: Querier, getEmailForRecipeUserId: GetEmailForRecipeUserIdFunc ): RecipeInterface { @@ -76,7 +76,9 @@ export default function getRecipeInterface( const recipeUserId = new RecipeUserId(response.userId); if (attemptAccountLinking) { // TODO: this should ideally come from the api response - const updatedUser = await getUser(recipeUserId.getAsString()); + const updatedUser = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: recipeUserId.getAsString(), userContext }); if (updatedUser) { // before attempting this, we must check that the email that got verified @@ -85,16 +87,14 @@ export default function getRecipeInterface( // and not necessarily the email that is currently associated with the ID) let emailInfo = await getEmailForRecipeUserId(updatedUser, recipeUserId, userContext); if (emailInfo.status === "OK" && emailInfo.email === response.email) { - // we do this here to prevent cyclic dependencies. - // TODO: Fix this. - let AccountLinking = - require("../accountlinking/recipe").default.getInstanceOrThrowError() as AccountLinkingRecipe; - await AccountLinking.tryLinkingByAccountInfoOrCreatePrimaryUser({ - tenantId, - inputUser: updatedUser, - session: undefined, - userContext, - }); + await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .tryLinkingByAccountInfoOrCreatePrimaryUser({ + tenantId, + inputUser: updatedUser, + session: undefined, + userContext, + }); } } } diff --git a/lib/ts/recipe/emailverification/utils.ts b/lib/ts/recipe/emailverification/utils.ts index 29dddef97..a51d521c1 100644 --- a/lib/ts/recipe/emailverification/utils.ts +++ b/lib/ts/recipe/emailverification/utils.ts @@ -17,7 +17,7 @@ import Recipe from "./recipe"; import { TypeInput, TypeNormalisedInput, RecipeInterface, APIInterface } from "./types"; import { NormalisedAppinfo, UserContext } from "../../types"; import BackwardCompatibilityService from "./emaildelivery/services/backwardCompatibility"; -import { BaseRequest } from "../../framework"; +import type { BaseRequest } from "../../framework"; export function validateAndNormaliseUserInput( _: Recipe, diff --git a/lib/ts/recipe/jwt/recipe.ts b/lib/ts/recipe/jwt/recipe.ts index 8dc043261..aa1b6c967 100644 --- a/lib/ts/recipe/jwt/recipe.ts +++ b/lib/ts/recipe/jwt/recipe.ts @@ -18,7 +18,6 @@ import error from "../../error"; import type { BaseRequest, BaseResponse } from "../../framework"; import NormalisedURLPath from "../../normalisedURLPath"; import normalisedURLPath from "../../normalisedURLPath"; -import { Querier } from "../../querier"; import RecipeModule from "../../recipeModule"; import { APIHandled, HTTPMethod, NormalisedAppinfo, RecipeListFunction, UserContext } from "../../types"; import { isTestEnv } from "../../utils"; @@ -30,6 +29,7 @@ import RecipeImplementation from "./recipeImplementation"; import { APIInterface, RecipeInterface, TypeInput, TypeNormalisedInput } from "./types"; import { validateAndNormaliseUserInput } from "./utils"; import OverrideableBuilder from "supertokens-js-override"; +import type SuperTokens from "../../supertokens"; export default class Recipe extends RecipeModule { static RECIPE_ID = "jwt" as const; @@ -40,15 +40,19 @@ export default class Recipe extends RecipeModule { apiImpl: APIInterface; isInServerlessEnv: boolean; - constructor(recipeId: string, appInfo: NormalisedAppinfo, isInServerlessEnv: boolean, config?: TypeInput) { - super(recipeId, appInfo); + constructor( + stInstance: SuperTokens, + recipeId: string, + appInfo: NormalisedAppinfo, + isInServerlessEnv: boolean, + config?: TypeInput + ) { + super(stInstance, recipeId, appInfo); this.config = validateAndNormaliseUserInput(this, appInfo, config); this.isInServerlessEnv = isInServerlessEnv; { - let builder = new OverrideableBuilder( - RecipeImplementation(Querier.getNewInstanceOrThrowError(recipeId), this.config, appInfo) - ); + let builder = new OverrideableBuilder(RecipeImplementation(this.querier, this.config, appInfo)); this.recipeInterfaceImpl = builder.override(this.config.override.functions).build(); } { @@ -67,9 +71,10 @@ export default class Recipe extends RecipeModule { } static init(config?: TypeInput): RecipeListFunction { - return (appInfo, isInServerlessEnv, plugins) => { + return (stInstance, appInfo, isInServerlessEnv, plugins) => { if (Recipe.instance === undefined) { Recipe.instance = new Recipe( + stInstance, Recipe.RECIPE_ID, appInfo, isInServerlessEnv, diff --git a/lib/ts/recipe/multifactorauth/api/implementation.ts b/lib/ts/recipe/multifactorauth/api/implementation.ts index c0c8ced7e..246c8bd6e 100644 --- a/lib/ts/recipe/multifactorauth/api/implementation.ts +++ b/lib/ts/recipe/multifactorauth/api/implementation.ts @@ -14,16 +14,20 @@ */ import { APIInterface } from "../"; -import { MultiFactorAuthClaim } from "../multiFactorAuthClaim"; import SessionError from "../../session/error"; import { updateAndGetMFARelatedInfoInSession } from "../utils"; -import Multitenancy from "../../multitenancy"; -import { getUser } from "../../.."; +import type SuperTokens from "../../../supertokens"; +import { MultiFactorAuthClaimClass } from "../multiFactorAuthClaim"; -export default function getAPIInterface(): APIInterface { +export default function getAPIInterface( + stInstance: SuperTokens, + multiFactorAuthClaim: MultiFactorAuthClaimClass +): APIInterface { return { resyncSessionAndFetchMFAInfoPUT: async ({ options, session, userContext }) => { - const sessionUser = await getUser(session.getUserId(), userContext); + const sessionUser = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: session.getUserId(), userContext }); if (sessionUser === undefined) { throw new SessionError({ @@ -34,13 +38,16 @@ export default function getAPIInterface(): APIInterface { const mfaInfo = await updateAndGetMFARelatedInfoInSession({ session, + stInstance, userContext, }); const factorsSetUpForUser = await options.recipeImplementation.getFactorsSetupForUser({ user: sessionUser, userContext, }); - const tenantInfo = await Multitenancy.getTenant(session.getTenantId(userContext), userContext); + const tenantInfo = await stInstance + .getRecipeInstanceOrThrow("multitenancy") + .recipeInterfaceImpl.getTenant({ tenantId: session.getTenantId(userContext), userContext }); if (tenantInfo === undefined) { throw new SessionError({ type: SessionError.UNAUTHORISED, @@ -73,7 +80,7 @@ export default function getAPIInterface(): APIInterface { } } - const nextSetOfUnsatisfiedFactors = MultiFactorAuthClaim.getNextSetOfUnsatisfiedFactors( + const nextSetOfUnsatisfiedFactors = multiFactorAuthClaim.getNextSetOfUnsatisfiedFactors( mfaInfo.completedFactors, mfaInfo.mfaRequirementsForAuth ); diff --git a/lib/ts/recipe/multifactorauth/api/resyncSessionAndFetchMFAInfo.ts b/lib/ts/recipe/multifactorauth/api/resyncSessionAndFetchMFAInfo.ts index c02594d50..fe015d5d6 100644 --- a/lib/ts/recipe/multifactorauth/api/resyncSessionAndFetchMFAInfo.ts +++ b/lib/ts/recipe/multifactorauth/api/resyncSessionAndFetchMFAInfo.ts @@ -15,10 +15,11 @@ import { send200Response } from "../../../utils"; import { APIInterface, APIOptions } from ".."; -import Session from "../../session"; import { UserContext } from "../../../types"; +import SuperTokens from "../../../supertokens"; export default async function resyncSessionAndFetchMFAInfo( + stInstance: SuperTokens, apiImplementation: APIInterface, options: APIOptions, userContext: UserContext @@ -27,16 +28,16 @@ export default async function resyncSessionAndFetchMFAInfo( return false; } - const session = await Session.getSession( - options.req, - options.res, - { overrideGlobalClaimValidators: () => [], sessionRequired: true }, - userContext - ); + const session = await stInstance.getRecipeInstanceOrThrow("session").getSession({ + req: options.req, + res: options.res, + options: { overrideGlobalClaimValidators: () => [], sessionRequired: true }, + userContext, + }); let response = await apiImplementation.resyncSessionAndFetchMFAInfoPUT({ options, - session, + session: session!, userContext, }); diff --git a/lib/ts/recipe/multifactorauth/index.ts b/lib/ts/recipe/multifactorauth/index.ts index 6b1bcf3f6..16a1ea574 100644 --- a/lib/ts/recipe/multifactorauth/index.ts +++ b/lib/ts/recipe/multifactorauth/index.ts @@ -15,17 +15,17 @@ import Recipe from "./recipe"; import { RecipeInterface, APIOptions, APIInterface } from "./types"; -import { MultiFactorAuthClaim } from "./multiFactorAuthClaim"; import { SessionContainerInterface } from "../session/types"; import { getUser } from "../.."; import { getUserContext } from "../../utils"; import { updateAndGetMFARelatedInfoInSession } from "./utils"; import { FactorIds } from "./types"; - +import SuperTokens from "../../supertokens"; +import { MultiFactorAuthClaimClass } from "./multiFactorAuthClaim"; export default class Wrapper { static init = Recipe.init; - static MultiFactorAuthClaim = MultiFactorAuthClaim; + static MultiFactorAuthClaim = new MultiFactorAuthClaimClass(() => SuperTokens.getInstanceOrThrowError()); static FactorIds = FactorIds; static async assertAllowedToSetupFactorElseThrowInvalidClaimError( @@ -35,23 +35,10 @@ export default class Wrapper { ) { let ctx = getUserContext(userContext); - const mfaInfo = await updateAndGetMFARelatedInfoInSession({ + await Recipe.getInstanceOrThrowError().assertAllowedToSetupFactorElseThrowInvalidClaimError( session, - userContext: ctx, - }); - const factorsSetUpForUser = await Wrapper.getFactorsSetupForUser(session.getUserId(), ctx); - await Recipe.getInstanceOrThrowError().recipeInterfaceImpl.assertAllowedToSetupFactorElseThrowInvalidClaimError( - { - session, - factorId, - get factorsSetUpForUser() { - return Promise.resolve(factorsSetUpForUser); - }, - get mfaRequirementsForAuth() { - return Promise.resolve(mfaInfo.mfaRequirementsForAuth); - }, - userContext: ctx, - } + factorId, + ctx ); } @@ -59,6 +46,7 @@ export default class Wrapper { let ctx = getUserContext(userContext); const mfaInfo = await updateAndGetMFARelatedInfoInSession({ + stInstance: SuperTokens.getInstanceOrThrowError(), session, userContext: ctx, }); @@ -134,6 +122,6 @@ export let getMFARequirementsForAuth = Wrapper.getMFARequirementsForAuth; export const addToRequiredSecondaryFactorsForUser = Wrapper.addToRequiredSecondaryFactorsForUser; export const removeFromRequiredSecondaryFactorsForUser = Wrapper.removeFromRequiredSecondaryFactorsForUser; -export { MultiFactorAuthClaim }; +export const MultiFactorAuthClaim = Wrapper.MultiFactorAuthClaim; export { FactorIds }; export type { RecipeInterface, APIOptions, APIInterface }; diff --git a/lib/ts/recipe/multifactorauth/multiFactorAuthClaim.ts b/lib/ts/recipe/multifactorauth/multiFactorAuthClaim.ts index 70dd5ed50..825f9370e 100644 --- a/lib/ts/recipe/multifactorauth/multiFactorAuthClaim.ts +++ b/lib/ts/recipe/multifactorauth/multiFactorAuthClaim.ts @@ -20,12 +20,13 @@ import { JSONObject } from "../usermetadata"; import { MFAClaimValue, MFARequirementList } from "./types"; import { UserContext } from "../../types"; import { updateAndGetMFARelatedInfoInSession } from "./utils"; +import type SuperTokens from "../../supertokens"; /** * We include "Class" in the class name, because it makes it easier to import the right thing (the instance) instead of this. * */ export class MultiFactorAuthClaimClass extends SessionClaim { - constructor(key?: string) { + constructor(private readonly stInstanceGetter: () => SuperTokens, key?: string) { super(key ?? "st-mfa"); this.validators = { @@ -196,6 +197,7 @@ export class MultiFactorAuthClaimClass extends SessionClaim { userContext: UserContext ) => { const mfaInfo = await updateAndGetMFARelatedInfoInSession({ + stInstance: this.stInstanceGetter(), sessionRecipeUserId: recipeUserId, tenantId, accessTokenPayload: currentPayload, @@ -243,5 +245,3 @@ export class MultiFactorAuthClaimClass extends SessionClaim { return payload[this.key] as MFAClaimValue; }; } - -export const MultiFactorAuthClaim = new MultiFactorAuthClaimClass(); diff --git a/lib/ts/recipe/multifactorauth/recipe.ts b/lib/ts/recipe/multifactorauth/recipe.ts index 01a9f9659..c9172fa69 100644 --- a/lib/ts/recipe/multifactorauth/recipe.ts +++ b/lib/ts/recipe/multifactorauth/recipe.ts @@ -14,7 +14,7 @@ */ import OverrideableBuilder from "supertokens-js-override"; -import { BaseRequest, BaseResponse } from "../../framework"; +import type { BaseRequest, BaseResponse } from "../../framework"; import NormalisedURLPath from "../../normalisedURLPath"; import RecipeModule from "../../recipeModule"; import STError from "../../error"; @@ -22,7 +22,7 @@ import { APIHandled, HTTPMethod, NormalisedAppinfo, RecipeListFunction, UserCont import RecipeImplementation from "./recipeImplementation"; import APIImplementation from "./api/implementation"; import { RESYNC_SESSION_AND_FETCH_MFA_INFO } from "./constants"; -import { MultiFactorAuthClaim } from "./multiFactorAuthClaim"; +import { MultiFactorAuthClaimClass } from "./multiFactorAuthClaim"; import { APIInterface, GetAllAvailableSecondaryFactorIdsFromOtherRecipesFunc, @@ -33,20 +33,20 @@ import { TypeInput, TypeNormalisedInput, } from "./types"; -import { validateAndNormaliseUserInput } from "./utils"; +import { updateAndGetMFARelatedInfoInSession, validateAndNormaliseUserInput } from "./utils"; import resyncSessionAndFetchMFAInfoAPI from "./api/resyncSessionAndFetchMFAInfo"; -import SessionRecipe from "../session/recipe"; import { PostSuperTokensInitCallbacks } from "../../postSuperTokensInitCallbacks"; import { User } from "../../user"; import RecipeUserId from "../../recipeUserId"; -import MultitenancyRecipe from "../multitenancy/recipe"; -import { Querier } from "../../querier"; import { TenantConfig } from "../multitenancy/types"; import { isTestEnv } from "../../utils"; import { applyPlugins } from "../../plugins"; +import type SuperTokens from "../../supertokens"; +import { SessionContainerInterface } from "../session/types"; export default class Recipe extends RecipeModule { private static instance: Recipe | undefined = undefined; + public multiFactorAuthClaim: MultiFactorAuthClaimClass; static RECIPE_ID = "multifactorauth" as const; getFactorsSetupForUserFromOtherRecipesFuncs: GetFactorsSetupForUserFromOtherRecipesFunc[] = []; @@ -66,15 +66,19 @@ export default class Recipe extends RecipeModule { isInServerlessEnv: boolean; - querier: Querier; - - constructor(recipeId: string, appInfo: NormalisedAppinfo, isInServerlessEnv: boolean, config?: TypeInput) { - super(recipeId, appInfo); + constructor( + stInstance: SuperTokens, + recipeId: string, + appInfo: NormalisedAppinfo, + isInServerlessEnv: boolean, + config?: TypeInput + ) { + super(stInstance, recipeId, appInfo); this.config = validateAndNormaliseUserInput(config); this.isInServerlessEnv = isInServerlessEnv; - + this.multiFactorAuthClaim = new MultiFactorAuthClaimClass(() => stInstance); { - let originalImpl = RecipeImplementation(this); + let originalImpl = RecipeImplementation(stInstance, this); let builder = new OverrideableBuilder(originalImpl); this.recipeInterfaceImpl = builder.override(this.config.override.functions).build(); @@ -84,12 +88,12 @@ export default class Recipe extends RecipeModule { } { - let builder = new OverrideableBuilder(APIImplementation()); + let builder = new OverrideableBuilder(APIImplementation(this.stInstance, this.multiFactorAuthClaim)); this.apiImpl = builder.override(this.config.override.apis).build(); } PostSuperTokensInitCallbacks.addPostInitCallback(() => { - const mtRecipe = MultitenancyRecipe.getInstance(); + const mtRecipe = stInstance.getRecipeInstance("multitenancy"); if (mtRecipe !== undefined) { mtRecipe.staticFirstFactors = this.config.firstFactors; } @@ -98,12 +102,12 @@ export default class Recipe extends RecipeModule { // on factor setup / completion any way (in the sign in / up APIs). // SessionRecipe.getInstanceOrThrowError().addClaimFromOtherRecipe(MultiFactorAuthClaim); - SessionRecipe.getInstanceOrThrowError().addClaimValidatorFromOtherRecipe( - MultiFactorAuthClaim.validators.hasCompletedMFARequirementsForAuth() - ); + stInstance + .getRecipeInstanceOrThrow("session") + .addClaimValidatorFromOtherRecipe( + this.multiFactorAuthClaim.validators.hasCompletedMFARequirementsForAuth() + ); }); - - this.querier = Querier.getNewInstanceOrThrowError(recipeId); } static getInstanceOrThrowError(): Recipe { @@ -118,9 +122,10 @@ export default class Recipe extends RecipeModule { } static init(config?: TypeInput): RecipeListFunction { - return (appInfo, isInServerlessEnv, plugins) => { + return (stInstance, appInfo, isInServerlessEnv, plugins) => { if (Recipe.instance === undefined) { Recipe.instance = new Recipe( + stInstance, Recipe.RECIPE_ID, appInfo, isInServerlessEnv, @@ -174,7 +179,7 @@ export default class Recipe extends RecipeModule { res, }; if (id === RESYNC_SESSION_AND_FETCH_MFA_INFO) { - return await resyncSessionAndFetchMFAInfoAPI(this.apiImpl, options, userContext); + return await resyncSessionAndFetchMFAInfoAPI(this.stInstance, this.apiImpl, options, userContext); } throw new Error("should never come here"); }; @@ -273,4 +278,39 @@ export default class Recipe extends RecipeModule { } return result; }; + + async assertAllowedToSetupFactorElseThrowInvalidClaimError( + session: SessionContainerInterface, + factorId: string, + userContext: UserContext + ) { + const user = await this.stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: session.getUserId(), userContext }); + if (!user) { + throw new Error("Unknown user id"); + } + const mfaInfo = await updateAndGetMFARelatedInfoInSession({ + stInstance: this.stInstance, + session, + userContext, + }); + + const factorsSetUpForUser = await this.recipeInterfaceImpl.getFactorsSetupForUser({ + user, + userContext, + }); + + await this.recipeInterfaceImpl.assertAllowedToSetupFactorElseThrowInvalidClaimError({ + session, + factorId, + get factorsSetUpForUser() { + return Promise.resolve(factorsSetUpForUser); + }, + get mfaRequirementsForAuth() { + return Promise.resolve(mfaInfo.mfaRequirementsForAuth); + }, + userContext, + }); + } } diff --git a/lib/ts/recipe/multifactorauth/recipeImplementation.ts b/lib/ts/recipe/multifactorauth/recipeImplementation.ts index 4d385c7b6..1c22425b2 100644 --- a/lib/ts/recipe/multifactorauth/recipeImplementation.ts +++ b/lib/ts/recipe/multifactorauth/recipeImplementation.ts @@ -15,13 +15,16 @@ import { RecipeInterface } from "./"; import UserMetadata from "../usermetadata"; -import { MultiFactorAuthClaim } from "./multiFactorAuthClaim"; import type MultiFactorAuthRecipe from "./recipe"; import { logDebugMessage } from "../../logger"; import { SessionClaimValidator } from "../session"; import { updateAndGetMFARelatedInfoInSession } from "./utils"; +import type SuperTokens from "../../supertokens"; -export default function getRecipeInterface(recipeInstance: MultiFactorAuthRecipe): RecipeInterface { +export default function getRecipeInterface( + stInstance: SuperTokens, + recipeInstance: MultiFactorAuthRecipe +): RecipeInterface { return { getFactorsSetupForUser: async function ({ user, userContext }) { // factors setup for user are provided by each of the initialized recipes @@ -77,14 +80,14 @@ export default function getRecipeInterface(recipeInstance: MultiFactorAuthRecipe // because the user will not be able to complete the MFA requirements for auth otherwise. const validator: SessionClaimValidator = { - id: MultiFactorAuthClaim.key, - claim: MultiFactorAuthClaim, + id: recipeInstance.multiFactorAuthClaim.key, + claim: recipeInstance.multiFactorAuthClaim, shouldRefetch: (payload) => { - const value = MultiFactorAuthClaim.getValueFromPayload(payload); + const value = recipeInstance.multiFactorAuthClaim.getValueFromPayload(payload); return value === undefined; }, validate: async (payload) => { - const claimVal = MultiFactorAuthClaim.getValueFromPayload(payload); + const claimVal = recipeInstance.multiFactorAuthClaim.getValueFromPayload(payload); if (!claimVal) { throw new Error("should never happen"); } @@ -96,7 +99,7 @@ export default function getRecipeInterface(recipeInstance: MultiFactorAuthRecipe return { isValid: true }; } - const setOfUnsatisfiedFactors = MultiFactorAuthClaim.getNextSetOfUnsatisfiedFactors( + const setOfUnsatisfiedFactors = recipeInstance.multiFactorAuthClaim.getNextSetOfUnsatisfiedFactors( claimVal.c, await input.mfaRequirementsForAuth ); @@ -155,6 +158,7 @@ export default function getRecipeInterface(recipeInstance: MultiFactorAuthRecipe markFactorAsCompleteInSession: async function (this: RecipeInterface, { session, factorId, userContext }) { await updateAndGetMFARelatedInfoInSession({ + stInstance: stInstance, session, updatedFactorId: factorId, userContext, diff --git a/lib/ts/recipe/multifactorauth/types.ts b/lib/ts/recipe/multifactorauth/types.ts index 5f1ee3ec9..af47e5baa 100644 --- a/lib/ts/recipe/multifactorauth/types.ts +++ b/lib/ts/recipe/multifactorauth/types.ts @@ -13,7 +13,7 @@ * under the License. */ -import { BaseRequest, BaseResponse } from "../../framework"; +import type { BaseRequest, BaseResponse } from "../../framework"; import OverrideableBuilder from "supertokens-js-override"; import { GeneralErrorResponse, JSONObject, UserContext } from "../../types"; import { User } from "../../user"; diff --git a/lib/ts/recipe/multifactorauth/utils.ts b/lib/ts/recipe/multifactorauth/utils.ts index c68c18843..aa6b8cd7f 100644 --- a/lib/ts/recipe/multifactorauth/utils.ts +++ b/lib/ts/recipe/multifactorauth/utils.ts @@ -21,13 +21,10 @@ import { MFAClaimValue, MFARequirementList, } from "./types"; -import Multitenancy from "../multitenancy"; import { User, UserContext } from "../../types"; import { SessionContainerInterface } from "../session/types"; -import { RecipeUserId, getUser } from "../.."; -import Recipe from "./recipe"; -import { MultiFactorAuthClaim } from "./multiFactorAuthClaim"; -import Session from "../session"; +import { RecipeUserId } from "../.."; +import type SuperTokens from "../../supertokens"; import SessionError from "../session/error"; import { FactorIds } from "./types"; import { isValidFirstFactor } from "../multitenancy/utils"; @@ -62,6 +59,7 @@ export const updateAndGetMFARelatedInfoInSession = async function ( } ) & { updatedFactorId?: string; + stInstance: SuperTokens; userContext: UserContext; } ): Promise<{ @@ -87,7 +85,9 @@ export const updateAndGetMFARelatedInfoInSession = async function ( } let updatedClaimVal = false; - let mfaClaimValue = MultiFactorAuthClaim.getValueFromPayload(accessTokenPayload); + let mfaClaimValue = input.stInstance + .getRecipeInstanceOrThrow("multifactorauth") + .multiFactorAuthClaim.getValueFromPayload(accessTokenPayload); if (input.updatedFactorId) { if (mfaClaimValue === undefined) { @@ -106,7 +106,9 @@ export const updateAndGetMFARelatedInfoInSession = async function ( if (mfaClaimValue === undefined) { // it should be fine to get the user multiple times since the caching will de-duplicate these requests - const sessionUser = await getUser(sessionRecipeUserId.getAsString(), input.userContext); + const sessionUser = await input.stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: sessionRecipeUserId.getAsString(), userContext: input.userContext }); if (sessionUser === undefined) { throw new SessionError({ type: SessionError.UNAUTHORISED, @@ -116,7 +118,9 @@ export const updateAndGetMFARelatedInfoInSession = async function ( // This can happen with older session, because we did not add MFA claims previously. // We try to determine best possible factorId based on the session's recipe user id. - const sessionInfo = await Session.getSessionInformation(sessionHandle, input.userContext); + const sessionInfo = await input.stInstance + .getRecipeInstanceOrThrow("session") + .recipeInterfaceImpl.getSessionInformation({ sessionHandle, userContext: input.userContext }); if (sessionInfo === undefined) { throw new SessionError({ @@ -130,7 +134,12 @@ export const updateAndGetMFARelatedInfoInSession = async function ( for (const lM of sessionUser.loginMethods) { if (lM.recipeUserId.getAsString() === sessionRecipeUserId.getAsString()) { if (lM.recipeId === "emailpassword") { - let validRes = await isValidFirstFactor(tenantId, FactorIds.EMAILPASSWORD, input.userContext); + let validRes = await isValidFirstFactor( + input.stInstance, + tenantId, + FactorIds.EMAILPASSWORD, + input.userContext + ); if (validRes.status === "TENANT_NOT_FOUND_ERROR") { throw new SessionError({ type: SessionError.UNAUTHORISED, @@ -141,7 +150,12 @@ export const updateAndGetMFARelatedInfoInSession = async function ( break; } } else if (lM.recipeId === "thirdparty") { - let validRes = await isValidFirstFactor(tenantId, FactorIds.THIRDPARTY, input.userContext); + let validRes = await isValidFirstFactor( + input.stInstance, + tenantId, + FactorIds.THIRDPARTY, + input.userContext + ); if (validRes.status === "TENANT_NOT_FOUND_ERROR") { throw new SessionError({ type: SessionError.UNAUTHORISED, @@ -163,7 +177,12 @@ export const updateAndGetMFARelatedInfoInSession = async function ( } for (const factorId of factorsToCheck) { - let validRes = await isValidFirstFactor(tenantId, factorId, input.userContext); + let validRes = await isValidFirstFactor( + input.stInstance, + tenantId, + factorId, + input.userContext + ); if (validRes.status === "TENANT_NOT_FOUND_ERROR") { throw new SessionError({ type: SessionError.UNAUTHORISED, @@ -205,20 +224,24 @@ export const updateAndGetMFARelatedInfoInSession = async function ( if (userProm) { return userProm; } - userProm = getUser(sessionRecipeUserId.getAsString(), input.userContext).then((sessionUser) => { - if (sessionUser === undefined) { - throw new SessionError({ - type: SessionError.UNAUTHORISED, - message: "Session user not found", - }); - } - return sessionUser; - }); + userProm = input.stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: sessionRecipeUserId.getAsString(), userContext: input.userContext }) + .then((sessionUser) => { + if (sessionUser === undefined) { + throw new SessionError({ + type: SessionError.UNAUTHORISED, + message: "Session user not found", + }); + } + return sessionUser; + }); return userProm; } - const mfaRequirementsForAuth = await Recipe.getInstanceOrThrowError().recipeInterfaceImpl.getMFARequirementsForAuth( - { + const mfaRequirementsForAuth = await input.stInstance + .getRecipeInstanceOrThrow("multifactorauth") + .recipeInterfaceImpl.getMFARequirementsForAuth({ accessTokenPayload, tenantId, get user() { @@ -226,10 +249,12 @@ export const updateAndGetMFARelatedInfoInSession = async function ( }, get factorsSetUpForUser() { return userGetter().then((user) => - Recipe.getInstanceOrThrowError().recipeInterfaceImpl.getFactorsSetupForUser({ - user, - userContext: input.userContext, - }) + input.stInstance + .getRecipeInstanceOrThrow("multifactorauth") + .recipeInterfaceImpl.getFactorsSetupForUser({ + user, + userContext: input.userContext, + }) ); }, get requiredSecondaryFactorsForUser() { @@ -241,31 +266,37 @@ export const updateAndGetMFARelatedInfoInSession = async function ( }); } - return Recipe.getInstanceOrThrowError().recipeInterfaceImpl.getRequiredSecondaryFactorsForUser({ - userId: sessionUser.id, - userContext: input.userContext, - }); + return input.stInstance + .getRecipeInstanceOrThrow("multifactorauth") + .recipeInterfaceImpl.getRequiredSecondaryFactorsForUser({ + userId: sessionUser.id, + userContext: input.userContext, + }); }); }, get requiredSecondaryFactorsForTenant() { - return Multitenancy.getTenant(tenantId, input.userContext).then((tenantInfo) => { - if (tenantInfo === undefined) { - throw new SessionError({ - type: SessionError.UNAUTHORISED, - message: "Tenant not found", - }); - } + return input.stInstance + .getRecipeInstanceOrThrow("multitenancy") + .recipeInterfaceImpl.getTenant({ tenantId, userContext: input.userContext }) + .then((tenantInfo) => { + if (tenantInfo === undefined) { + throw new SessionError({ + type: SessionError.UNAUTHORISED, + message: "Tenant not found", + }); + } - return tenantInfo.requiredSecondaryFactors ?? []; - }); + return tenantInfo.requiredSecondaryFactors ?? []; + }); }, completedFactors, userContext: input.userContext, - } - ); + }); const areAuthReqsComplete = - MultiFactorAuthClaim.getNextSetOfUnsatisfiedFactors(completedFactors, mfaRequirementsForAuth).factorIds + input.stInstance + .getRecipeInstanceOrThrow("multifactorauth") + .multiFactorAuthClaim.getNextSetOfUnsatisfiedFactors(completedFactors, mfaRequirementsForAuth).factorIds .length === 0; if (mfaClaimValue.v !== areAuthReqsComplete) { updatedClaimVal = true; @@ -273,7 +304,11 @@ export const updateAndGetMFARelatedInfoInSession = async function ( } if ("session" in input && updatedClaimVal) { - await input.session.setClaimValue(MultiFactorAuthClaim, mfaClaimValue, input.userContext); + await input.session.setClaimValue( + input.stInstance.getRecipeInstanceOrThrow("multifactorauth").multiFactorAuthClaim, + mfaClaimValue, + input.userContext + ); } return { diff --git a/lib/ts/recipe/multitenancy/allowedDomainsClaim.ts b/lib/ts/recipe/multitenancy/allowedDomainsClaim.ts index ba3422333..e71d32c67 100644 --- a/lib/ts/recipe/multitenancy/allowedDomainsClaim.ts +++ b/lib/ts/recipe/multitenancy/allowedDomainsClaim.ts @@ -1,23 +1,20 @@ import { PrimitiveArrayClaim } from "../session/claims"; -import Recipe from "./recipe"; +import type Recipe from "./recipe"; /** * We include "Class" in the class name, because it makes it easier to import the right thing (the instance) instead of this. * */ export class AllowedDomainsClaimClass extends PrimitiveArrayClaim { - constructor() { + constructor(getRecipe: () => Recipe) { super({ key: "st-t-dmns", async fetchValue(_userId, _recipeUserId, tenantId, _currentPayload, userContext) { - const recipe = Recipe.getInstanceOrThrowError(); - - if (recipe.getAllowedDomainsForTenantId === undefined) { + let getAllowedDomainsForTenantId = getRecipe().getAllowedDomainsForTenantId; + if (getAllowedDomainsForTenantId === undefined) { return undefined; // User did not provide a function to get allowed domains, but is using a validator. So we don't allow any domains by default } - return await recipe.getAllowedDomainsForTenantId(tenantId, userContext); + return await getAllowedDomainsForTenantId(tenantId, userContext); }, }); } } - -export const AllowedDomainsClaim = new AllowedDomainsClaimClass(); diff --git a/lib/ts/recipe/multitenancy/api/implementation.ts b/lib/ts/recipe/multitenancy/api/implementation.ts index 8e3b95544..690699a47 100644 --- a/lib/ts/recipe/multitenancy/api/implementation.ts +++ b/lib/ts/recipe/multitenancy/api/implementation.ts @@ -2,8 +2,9 @@ import { APIInterface } from "../"; import { isValidFirstFactor } from "../../multitenancy/utils"; import { findAndCreateProviderInstance, mergeProvidersFromCoreAndStatic } from "../../thirdparty/providers/configUtils"; import { DEFAULT_TENANT_ID } from "../constants"; +import type SuperTokens from "../../../supertokens"; -export default function getAPIInterface(): APIInterface { +export default function getAPIInterface(stInstance: SuperTokens): APIInterface { return { loginMethodsGET: async function ({ tenantId, clientType, options, userContext }) { const tenantConfigRes = await options.recipeImplementation.getTenant({ @@ -72,7 +73,7 @@ export default function getAPIInterface(): APIInterface { // enabled recipes in all cases irrespective of whether they are using MFA or not let validFirstFactors: string[] = []; for (const factorId of firstFactors) { - let validRes = await isValidFirstFactor(tenantId, factorId, userContext); + let validRes = await isValidFirstFactor(stInstance, tenantId, factorId, userContext); if (validRes.status === "OK") { validFirstFactors.push(factorId); } diff --git a/lib/ts/recipe/multitenancy/index.ts b/lib/ts/recipe/multitenancy/index.ts index 55ce848e1..2a6c28b31 100644 --- a/lib/ts/recipe/multitenancy/index.ts +++ b/lib/ts/recipe/multitenancy/index.ts @@ -16,13 +16,15 @@ import Recipe from "./recipe"; import { RecipeInterface, APIOptions, APIInterface, TenantConfig } from "./types"; import { ProviderConfig } from "../thirdparty/types"; -import { AllowedDomainsClaim } from "./allowedDomainsClaim"; +import { AllowedDomainsClaimClass } from "./allowedDomainsClaim"; import RecipeUserId from "../../recipeUserId"; import { getUserContext } from "../../utils"; export default class Wrapper { static init = Recipe.init; + static AllowedDomainsClaim = new AllowedDomainsClaimClass(() => Recipe.getInstanceOrThrowError()); + static async createOrUpdateTenant( tenantId: string, config?: { @@ -73,9 +75,7 @@ export default class Wrapper { }); } - static async listAllTenants( - userContext?: Record - ): Promise<{ + static async listAllTenants(userContext?: Record): Promise<{ status: "OK"; tenants: ({ tenantId: string; @@ -180,5 +180,5 @@ export let deleteThirdPartyConfig = Wrapper.deleteThirdPartyConfig; export let associateUserToTenant = Wrapper.associateUserToTenant; export let disassociateUserFromTenant = Wrapper.disassociateUserFromTenant; -export { AllowedDomainsClaim }; +export const AllowedDomainsClaim = Wrapper.AllowedDomainsClaim; export type { RecipeInterface, APIOptions, APIInterface }; diff --git a/lib/ts/recipe/multitenancy/recipe.ts b/lib/ts/recipe/multitenancy/recipe.ts index a48220020..6cdaccf5c 100644 --- a/lib/ts/recipe/multitenancy/recipe.ts +++ b/lib/ts/recipe/multitenancy/recipe.ts @@ -14,27 +14,27 @@ */ import OverrideableBuilder from "supertokens-js-override"; -import { BaseRequest, BaseResponse } from "../../framework"; +import type { BaseRequest, BaseResponse } from "../../framework"; import NormalisedURLPath from "../../normalisedURLPath"; import { PostSuperTokensInitCallbacks } from "../../postSuperTokensInitCallbacks"; -import { Querier } from "../../querier"; import RecipeModule from "../../recipeModule"; import STError from "../../error"; import { APIHandled, HTTPMethod, NormalisedAppinfo, RecipeListFunction, UserContext } from "../../types"; import RecipeImplementation from "./recipeImplementation"; import APIImplementation from "./api/implementation"; -import SessionRecipe from "../session/recipe"; import { ProviderInput } from "../thirdparty/types"; import { LOGIN_METHODS_API } from "./constants"; -import { AllowedDomainsClaim } from "./allowedDomainsClaim"; import { APIInterface, RecipeInterface, TypeInput, TypeNormalisedInput } from "./types"; import { validateAndNormaliseUserInput } from "./utils"; import loginMethodsAPI from "./api/loginMethods"; import { isTestEnv } from "../../utils"; import { applyPlugins } from "../../plugins"; +import type SuperTokens from "../../supertokens"; +import { AllowedDomainsClaimClass } from "./allowedDomainsClaim"; export default class Recipe extends RecipeModule { private static instance: Recipe | undefined = undefined; + public allowedDomainsClaim: AllowedDomainsClaimClass; static RECIPE_ID = "multitenancy" as const; config: TypeNormalisedInput; @@ -52,18 +52,25 @@ export default class Recipe extends RecipeModule { getAllowedDomainsForTenantId?: (tenantId: string, userContext: UserContext) => Promise; - constructor(recipeId: string, appInfo: NormalisedAppinfo, isInServerlessEnv: boolean, config?: TypeInput) { - super(recipeId, appInfo); + constructor( + stInstance: SuperTokens, + recipeId: string, + appInfo: NormalisedAppinfo, + isInServerlessEnv: boolean, + config?: TypeInput + ) { + super(stInstance, recipeId, appInfo); this.config = validateAndNormaliseUserInput(config); this.isInServerlessEnv = isInServerlessEnv; + this.allowedDomainsClaim = new AllowedDomainsClaimClass(() => this); { - let builder = new OverrideableBuilder(RecipeImplementation(Querier.getNewInstanceOrThrowError(recipeId))); + let builder = new OverrideableBuilder(RecipeImplementation(this.querier)); this.recipeInterfaceImpl = builder.override(this.config.override.functions).build(); } { - let builder = new OverrideableBuilder(APIImplementation()); + let builder = new OverrideableBuilder(APIImplementation(this.stInstance)); this.apiImpl = builder.override(this.config.override.apis).build(); } @@ -82,9 +89,10 @@ export default class Recipe extends RecipeModule { } static init(config?: TypeInput): RecipeListFunction { - return (appInfo, isInServerlessEnv, plugins) => { + return (stInstance, appInfo, isInServerlessEnv, plugins) => { if (Recipe.instance === undefined) { Recipe.instance = new Recipe( + stInstance, Recipe.RECIPE_ID, appInfo, isInServerlessEnv, @@ -94,7 +102,9 @@ export default class Recipe extends RecipeModule { if (Recipe.instance.getAllowedDomainsForTenantId !== undefined) { PostSuperTokensInitCallbacks.addPostInitCallback(() => { try { - SessionRecipe.getInstanceOrThrowError().addClaimFromOtherRecipe(AllowedDomainsClaim); + stInstance + .getRecipeInstanceOrThrow("session") + .addClaimFromOtherRecipe(Recipe.instance!.allowedDomainsClaim); } catch { // Skip adding claims if session recipe is not initialised } diff --git a/lib/ts/recipe/multitenancy/types.ts b/lib/ts/recipe/multitenancy/types.ts index b8caf8b0e..11da7328e 100644 --- a/lib/ts/recipe/multitenancy/types.ts +++ b/lib/ts/recipe/multitenancy/types.ts @@ -13,7 +13,7 @@ * under the License. */ -import { BaseRequest, BaseResponse } from "../../framework"; +import type { BaseRequest, BaseResponse } from "../../framework"; import OverrideableBuilder from "supertokens-js-override"; import { ProviderConfig, ProviderInput } from "../thirdparty/types"; import { GeneralErrorResponse, UserContext } from "../../types"; diff --git a/lib/ts/recipe/multitenancy/utils.ts b/lib/ts/recipe/multitenancy/utils.ts index 49642b4f3..d1eb9ec0e 100644 --- a/lib/ts/recipe/multitenancy/utils.ts +++ b/lib/ts/recipe/multitenancy/utils.ts @@ -14,10 +14,10 @@ */ import { TypeInput, TypeNormalisedInput, RecipeInterface, APIInterface, TenantConfig } from "./types"; -import MultitenancyRecipe from "./recipe"; import { logDebugMessage } from "../../logger"; import { UserContext } from "../../types"; import { FactorIds } from "../multifactorauth/types"; +import type SuperTokens from "../../supertokens"; export function validateAndNormaliseUserInput(config?: TypeInput): TypeNormalisedInput { let override = { @@ -33,6 +33,7 @@ export function validateAndNormaliseUserInput(config?: TypeInput): TypeNormalise } export const isValidFirstFactor = async function ( + stInstance: SuperTokens, tenantId: string, factorId: string, userContext: UserContext @@ -47,7 +48,7 @@ export const isValidFirstFactor = async function ( status: "TENANT_NOT_FOUND_ERROR"; } > { - const mtRecipe = MultitenancyRecipe.getInstance(); + const mtRecipe = stInstance.getRecipeInstanceOrThrow("multitenancy"); if (mtRecipe === undefined) { throw new Error("Should never happen"); } diff --git a/lib/ts/recipe/oauth2provider/api/auth.ts b/lib/ts/recipe/oauth2provider/api/auth.ts index 349e4e187..64bfc3cd8 100644 --- a/lib/ts/recipe/oauth2provider/api/auth.ts +++ b/lib/ts/recipe/oauth2provider/api/auth.ts @@ -17,10 +17,11 @@ import { send200Response, sendNon200Response } from "../../../utils"; import { APIInterface, APIOptions } from ".."; import { UserContext } from "../../../types"; import setCookieParser from "set-cookie-parser"; -import Session from "../../session"; import SessionError from "../../../recipe/session/error"; +import type SuperTokens from "../../../supertokens"; export default async function authGET( + stInstance: SuperTokens, apiImplementation: APIInterface, options: APIOptions, userContext: UserContext @@ -33,7 +34,12 @@ export default async function authGET( const params = new URLSearchParams(splitURL[1]); let session, shouldTryRefresh; try { - session = await Session.getSession(options.req, options.res, { sessionRequired: false }, userContext); + session = await stInstance.getRecipeInstanceOrThrow("session").getSession({ + req: options.req, + res: options.res, + options: { sessionRequired: false }, + userContext, + }); shouldTryRefresh = false; } catch (error) { session = undefined; @@ -50,7 +56,7 @@ export default async function authGET( options, params: Object.fromEntries(params.entries()), cookie: options.req.getHeaderValue("cookie"), - session, + session: session, shouldTryRefresh, userContext, }); diff --git a/lib/ts/recipe/oauth2provider/api/endSession.ts b/lib/ts/recipe/oauth2provider/api/endSession.ts index e298b8271..d06034c18 100644 --- a/lib/ts/recipe/oauth2provider/api/endSession.ts +++ b/lib/ts/recipe/oauth2provider/api/endSession.ts @@ -16,11 +16,12 @@ import { send200Response, sendNon200Response } from "../../../utils"; import { APIInterface, APIOptions } from ".."; import { UserContext } from "../../../types"; -import Session from "../../session"; import SuperTokensError from "../../../error"; import SessionError from "../../../recipe/session/error"; +import type SuperTokens from "../../../supertokens"; export async function endSessionGET( + stInstance: SuperTokens, apiImplementation: APIInterface, options: APIOptions, userContext: UserContext @@ -33,6 +34,7 @@ export async function endSessionGET( const params = new URLSearchParams(splitURL[1]); return endSessionCommon( + stInstance, Object.fromEntries(params.entries()), apiImplementation.endSessionGET, options, @@ -41,6 +43,7 @@ export async function endSessionGET( } export async function endSessionPOST( + stInstance: SuperTokens, apiImplementation: APIInterface, options: APIOptions, userContext: UserContext @@ -50,10 +53,11 @@ export async function endSessionPOST( } const params = await options.req.getBodyAsJSONOrFormData(); - return endSessionCommon(params, apiImplementation.endSessionPOST, options, userContext); + return endSessionCommon(stInstance, params, apiImplementation.endSessionPOST, options, userContext); } async function endSessionCommon( + stInstance: SuperTokens, params: Record, apiImplementation: APIInterface["endSessionGET"] | APIInterface["endSessionPOST"], options: APIOptions, @@ -65,7 +69,12 @@ async function endSessionCommon( let session, shouldTryRefresh; try { - session = await Session.getSession(options.req, options.res, { sessionRequired: false }, userContext); + session = await stInstance.getRecipeInstanceOrThrow("session").getSession({ + req: options.req, + res: options.res, + options: { sessionRequired: false }, + userContext, + }); shouldTryRefresh = false; } catch (error) { // We can handle this as if the session is not present, because then we redirect to the frontend, diff --git a/lib/ts/recipe/oauth2provider/api/implementation.ts b/lib/ts/recipe/oauth2provider/api/implementation.ts index 28dd37a0c..d7ebee379 100644 --- a/lib/ts/recipe/oauth2provider/api/implementation.ts +++ b/lib/ts/recipe/oauth2provider/api/implementation.ts @@ -13,13 +13,15 @@ * under the License. */ +import type SuperTokens from "../../../supertokens"; import { APIInterface } from "../types"; import { handleLoginInternalRedirects, handleLogoutInternalRedirects, loginGET } from "./utils"; -export default function getAPIImplementation(): APIInterface { +export default function getAPIImplementation(stInstance: SuperTokens): APIInterface { return { loginGET: async ({ loginChallenge, options, session, shouldTryRefresh, userContext }) => { const response = await loginGET({ + stInstance, recipeImplementation: options.recipeImplementation, loginChallenge, session, @@ -33,6 +35,7 @@ export default function getAPIImplementation(): APIInterface { } const respAfterInternalRedirects = await handleLoginInternalRedirects({ + stInstance, response, cookie: options.req.getHeaderValue("cookie"), recipeImplementation: options.recipeImplementation, @@ -64,6 +67,7 @@ export default function getAPIImplementation(): APIInterface { } return handleLoginInternalRedirects({ + stInstance, response, recipeImplementation: options.recipeImplementation, cookie, @@ -150,6 +154,7 @@ export default function getAPIImplementation(): APIInterface { } return handleLogoutInternalRedirects({ + stInstance, response, session, recipeImplementation: options.recipeImplementation, @@ -169,6 +174,7 @@ export default function getAPIImplementation(): APIInterface { } return handleLogoutInternalRedirects({ + stInstance, response, session, recipeImplementation: options.recipeImplementation, @@ -190,6 +196,7 @@ export default function getAPIImplementation(): APIInterface { } const res = await handleLogoutInternalRedirects({ + stInstance, response, recipeImplementation: options.recipeImplementation, userContext, diff --git a/lib/ts/recipe/oauth2provider/api/login.ts b/lib/ts/recipe/oauth2provider/api/login.ts index d20728cf2..96852a3ad 100644 --- a/lib/ts/recipe/oauth2provider/api/login.ts +++ b/lib/ts/recipe/oauth2provider/api/login.ts @@ -16,12 +16,13 @@ import setCookieParser from "set-cookie-parser"; import { send200Response, sendNon200Response } from "../../../utils"; import { APIInterface, APIOptions } from ".."; -import Session from "../../session"; import { UserContext } from "../../../types"; import SuperTokensError from "../../../error"; import SessionError from "../../../recipe/session/error"; +import type SuperTokens from "../../../supertokens"; export default async function login( + stInstance: SuperTokens, apiImplementation: APIInterface, options: APIOptions, userContext: UserContext @@ -32,7 +33,12 @@ export default async function login( let session, shouldTryRefresh; try { - session = await Session.getSession(options.req, options.res, { sessionRequired: false }, userContext); + session = await stInstance.getRecipeInstanceOrThrow("session").getSession({ + req: options.req, + res: options.res, + options: { sessionRequired: false }, + userContext, + }); shouldTryRefresh = false; } catch (error) { // We can handle this as if the session is not present, because then we redirect to the frontend, diff --git a/lib/ts/recipe/oauth2provider/api/logout.ts b/lib/ts/recipe/oauth2provider/api/logout.ts index 68ea83441..1fdf39d22 100644 --- a/lib/ts/recipe/oauth2provider/api/logout.ts +++ b/lib/ts/recipe/oauth2provider/api/logout.ts @@ -15,11 +15,12 @@ import { send200Response, sendNon200Response } from "../../../utils"; import { APIInterface, APIOptions } from ".."; -import Session from "../../session"; import { UserContext } from "../../../types"; import SuperTokensError from "../../../error"; +import type SuperTokens from "../../../supertokens"; export async function logoutPOST( + stInstance: SuperTokens, apiImplementation: APIInterface, options: APIOptions, userContext: UserContext @@ -30,7 +31,12 @@ export async function logoutPOST( let session; try { - session = await Session.getSession(options.req, options.res, { sessionRequired: false }, userContext); + session = await stInstance.getRecipeInstanceOrThrow("session").getSession({ + req: options.req, + res: options.res, + options: { sessionRequired: false }, + userContext, + }); } catch { session = undefined; } diff --git a/lib/ts/recipe/oauth2provider/api/userInfo.ts b/lib/ts/recipe/oauth2provider/api/userInfo.ts index f1ae402ad..9e2c1dc77 100644 --- a/lib/ts/recipe/oauth2provider/api/userInfo.ts +++ b/lib/ts/recipe/oauth2provider/api/userInfo.ts @@ -13,13 +13,13 @@ * under the License. */ -import OAuth2ProviderRecipe from "../recipe"; import { send200Response, sendNon200ResponseWithMessage } from "../../../utils"; import { APIInterface, APIOptions } from ".."; import { JSONObject, UserContext } from "../../../types"; -import { getUser } from "../../.."; +import SuperTokens from "../../../supertokens"; export default async function userInfoGET( + stInstance: SuperTokens, apiImplementation: APIInterface, tenantId: string, options: APIOptions, @@ -41,11 +41,10 @@ export default async function userInfoGET( let accessTokenPayload: JSONObject; try { - const validateTokenResponse = - await OAuth2ProviderRecipe.getInstanceOrThrowError().recipeInterfaceImpl.validateOAuth2AccessToken({ - token: accessToken, - userContext, - }); + const validateTokenResponse = await options.recipeImplementation.validateOAuth2AccessToken({ + token: accessToken, + userContext, + }); accessTokenPayload = validateTokenResponse.payload; } catch (error) { @@ -69,7 +68,9 @@ export default async function userInfoGET( const userId = accessTokenPayload.sub; - const user = await getUser(userId, userContext); + const user = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId, userContext }); if (user === undefined) { options.res.setHeader("WWW-Authenticate", 'Bearer error="invalid_token"', false); diff --git a/lib/ts/recipe/oauth2provider/api/utils.ts b/lib/ts/recipe/oauth2provider/api/utils.ts index c0aebacf4..8fa7853b0 100644 --- a/lib/ts/recipe/oauth2provider/api/utils.ts +++ b/lib/ts/recipe/oauth2provider/api/utils.ts @@ -1,7 +1,6 @@ -import SuperTokens from "../../../supertokens"; +import type SuperTokens from "../../../supertokens"; import { UserContext } from "../../../types"; import { DEFAULT_TENANT_ID } from "../../multitenancy/constants"; -import { getSessionInformation } from "../../session"; import { SessionContainerInterface } from "../../session/types"; import { AUTH_PATH, LOGIN_PATH, END_SESSION_PATH } from "../constants"; import { ErrorOAuth2, RecipeInterface } from "../types"; @@ -10,6 +9,7 @@ import setCookieParser from "set-cookie-parser"; // API implementation for the loginGET function. // Extracted for use in both apiImplementation and handleInternalRedirects. export async function loginGET({ + stInstance, recipeImplementation, loginChallenge, shouldTryRefresh, @@ -18,6 +18,7 @@ export async function loginGET({ isDirectCall, userContext, }: { + stInstance: SuperTokens; recipeImplementation: RecipeInterface; loginChallenge: string; session?: SessionContainerInterface; @@ -35,7 +36,12 @@ export async function loginGET({ return loginRequest; } - const sessionInfo = session !== undefined ? await getSessionInformation(session?.getHandle()) : undefined; + const sessionInfo = + session !== undefined + ? await stInstance + .getRecipeInstanceOrThrow("session") + .recipeInterfaceImpl.getSessionInformation({ sessionHandle: session?.getHandle(), userContext }) + : undefined; if (!sessionInfo) { session = undefined; } @@ -207,15 +213,15 @@ function mergeSetCookieHeaders(setCookie1?: string[], setCookie2?: string[]): st return [...setCookie1, ...setCookie2]; } -function isLoginInternalRedirect(redirectTo: string): boolean { - const { apiDomain, apiBasePath } = SuperTokens.getInstanceOrThrowError().appInfo; +function isLoginInternalRedirect(stInstance: SuperTokens, redirectTo: string): boolean { + const { apiDomain, apiBasePath } = stInstance.appInfo; const basePath = `${apiDomain.getAsStringDangerous()}${apiBasePath.getAsStringDangerous()}`; return [LOGIN_PATH, AUTH_PATH].some((path) => redirectTo.startsWith(`${basePath}${path}`)); } -function isLogoutInternalRedirect(redirectTo: string): boolean { - const { apiDomain, apiBasePath } = SuperTokens.getInstanceOrThrowError().appInfo; +function isLogoutInternalRedirect(stInstance: SuperTokens, redirectTo: string): boolean { + const { apiDomain, apiBasePath } = stInstance.appInfo; const basePath = `${apiDomain.getAsStringDangerous()}${apiBasePath.getAsStringDangerous()}`; return redirectTo.startsWith(`${basePath}${END_SESSION_PATH}`); } @@ -224,6 +230,7 @@ function isLogoutInternalRedirect(redirectTo: string): boolean { // If an internal redirect is identified, it's handled directly by this function. // Currently, we only need to handle redirects to /oauth/login and /oauth/auth endpoints in the login flow. export async function handleLoginInternalRedirects({ + stInstance, response, recipeImplementation, session, @@ -231,6 +238,7 @@ export async function handleLoginInternalRedirects({ cookie = "", userContext, }: { + stInstance: SuperTokens; response: { redirectTo: string; cookies?: string[] }; recipeImplementation: RecipeInterface; session?: SessionContainerInterface; @@ -238,7 +246,7 @@ export async function handleLoginInternalRedirects({ cookie?: string; userContext: UserContext; }): Promise<{ redirectTo: string; cookies?: string[] } | ErrorOAuth2> { - if (!isLoginInternalRedirect(response.redirectTo)) { + if (!isLoginInternalRedirect(stInstance, response.redirectTo)) { return response; } @@ -247,7 +255,7 @@ export async function handleLoginInternalRedirects({ const maxRedirects = 10; let redirectCount = 0; - while (redirectCount < maxRedirects && isLoginInternalRedirect(response.redirectTo)) { + while (redirectCount < maxRedirects && isLoginInternalRedirect(stInstance, response.redirectTo)) { cookie = getMergedCookies({ origCookies: cookie, newCookies: response.cookies }); const queryString = response.redirectTo.split("?")[1]; @@ -260,6 +268,7 @@ export async function handleLoginInternalRedirects({ } const loginRes = await loginGET({ + stInstance, recipeImplementation, loginChallenge, session, @@ -306,17 +315,19 @@ export async function handleLoginInternalRedirects({ // If an internal redirect is identified, it's handled directly by this function. // Currently, we only need to handle redirects to /oauth/end_session endpoint in the logout flow. export async function handleLogoutInternalRedirects({ + stInstance, response, recipeImplementation, session, userContext, }: { + stInstance: SuperTokens; response: { redirectTo: string }; recipeImplementation: RecipeInterface; session?: SessionContainerInterface; userContext: UserContext; }): Promise<{ redirectTo: string } | ErrorOAuth2> { - if (!isLogoutInternalRedirect(response.redirectTo)) { + if (!isLogoutInternalRedirect(stInstance, response.redirectTo)) { return response; } @@ -325,7 +336,7 @@ export async function handleLogoutInternalRedirects({ const maxRedirects = 10; let redirectCount = 0; - while (redirectCount < maxRedirects && isLogoutInternalRedirect(response.redirectTo)) { + while (redirectCount < maxRedirects && isLogoutInternalRedirect(stInstance, response.redirectTo)) { const queryString = response.redirectTo.split("?")[1]; const params = new URLSearchParams(queryString); diff --git a/lib/ts/recipe/oauth2provider/recipe.ts b/lib/ts/recipe/oauth2provider/recipe.ts index f8d38747a..e9c07c0b5 100644 --- a/lib/ts/recipe/oauth2provider/recipe.ts +++ b/lib/ts/recipe/oauth2provider/recipe.ts @@ -17,7 +17,6 @@ import SuperTokensError from "../../error"; import error from "../../error"; import type { BaseRequest, BaseResponse } from "../../framework"; import NormalisedURLPath from "../../normalisedURLPath"; -import { Querier } from "../../querier"; import RecipeModule from "../../recipeModule"; import { APIHandled, HTTPMethod, JSONObject, NormalisedAppinfo, RecipeListFunction, UserContext } from "../../types"; import authGET from "./api/auth"; @@ -56,6 +55,7 @@ import introspectTokenPOST from "./api/introspectToken"; import { endSessionGET, endSessionPOST } from "./api/endSession"; import { logoutPOST } from "./api/logout"; import { applyPlugins } from "../../plugins"; +import type SuperTokens from "../../supertokens"; export default class Recipe extends RecipeModule { static RECIPE_ID = "oauth2provider" as const; @@ -69,15 +69,22 @@ export default class Recipe extends RecipeModule { apiImpl: APIInterface; isInServerlessEnv: boolean; - constructor(recipeId: string, appInfo: NormalisedAppinfo, isInServerlessEnv: boolean, config?: TypeInput) { - super(recipeId, appInfo); + constructor( + stInstance: SuperTokens, + recipeId: string, + appInfo: NormalisedAppinfo, + isInServerlessEnv: boolean, + config?: TypeInput + ) { + super(stInstance, recipeId, appInfo); this.config = validateAndNormaliseUserInput(this, appInfo, config); this.isInServerlessEnv = isInServerlessEnv; { let builder = new OverrideableBuilder( RecipeImplementation( - Querier.getNewInstanceOrThrowError(recipeId), + this.stInstance, + this.querier, this.config, appInfo, this.getDefaultAccessTokenPayload.bind(this), @@ -88,7 +95,7 @@ export default class Recipe extends RecipeModule { this.recipeInterfaceImpl = builder.override(this.config.override.functions).build(); } { - let builder = new OverrideableBuilder(APIImplementation()); + let builder = new OverrideableBuilder(APIImplementation(this.stInstance)); this.apiImpl = builder.override(this.config.override.apis).build(); } } @@ -106,9 +113,10 @@ export default class Recipe extends RecipeModule { } static init(config?: TypeInput): RecipeListFunction { - return (appInfo, isInServerlessEnv, plugins) => { + return (stInstance, appInfo, isInServerlessEnv, plugins) => { if (Recipe.instance === undefined) { Recipe.instance = new Recipe( + stInstance, Recipe.RECIPE_ID, appInfo, isInServerlessEnv, @@ -226,19 +234,19 @@ export default class Recipe extends RecipeModule { }; if (id === LOGIN_PATH) { - return loginAPI(this.apiImpl, options, userContext); + return loginAPI(this.stInstance, this.apiImpl, options, userContext); } if (id === TOKEN_PATH) { return tokenPOST(this.apiImpl, options, userContext); } if (id === AUTH_PATH) { - return authGET(this.apiImpl, options, userContext); + return authGET(this.stInstance, this.apiImpl, options, userContext); } if (id === LOGIN_INFO_PATH) { return loginInfoGET(this.apiImpl, options, userContext); } if (id === USER_INFO_PATH) { - return userInfoGET(this.apiImpl, tenantId, options, userContext); + return userInfoGET(this.stInstance, this.apiImpl, tenantId, options, userContext); } if (id === REVOKE_TOKEN_PATH) { return revokeTokenPOST(this.apiImpl, options, userContext); @@ -247,13 +255,13 @@ export default class Recipe extends RecipeModule { return introspectTokenPOST(this.apiImpl, options, userContext); } if (id === END_SESSION_PATH && method === "get") { - return endSessionGET(this.apiImpl, options, userContext); + return endSessionGET(this.stInstance, this.apiImpl, options, userContext); } if (id === END_SESSION_PATH && method === "post") { - return endSessionPOST(this.apiImpl, options, userContext); + return endSessionPOST(this.stInstance, this.apiImpl, options, userContext); } if (id === LOGOUT_PATH && method === "post") { - return logoutPOST(this.apiImpl, options, userContext); + return logoutPOST(this.stInstance, this.apiImpl, options, userContext); } throw new Error("Should never come here: handleAPIRequest called with unknown id"); }; diff --git a/lib/ts/recipe/oauth2provider/recipeImplementation.ts b/lib/ts/recipe/oauth2provider/recipeImplementation.ts index 31395d149..306c24547 100644 --- a/lib/ts/recipe/oauth2provider/recipeImplementation.ts +++ b/lib/ts/recipe/oauth2provider/recipeImplementation.ts @@ -25,12 +25,10 @@ import { ErrorOAuth2, } from "./types"; import { OAuth2Client } from "./OAuth2Client"; -import { getUser } from "../.."; import { getCombinedJWKS } from "../../combinedRemoteJWKSet"; -import SessionRecipe from "../session/recipe"; -import OpenIdRecipe from "../openid/recipe"; import { DEFAULT_TENANT_ID } from "../multitenancy/constants"; import { decodeBase64 } from "../../utils"; +import type SuperTokens from "../../supertokens"; function getUpdatedRedirectTo(appInfo: NormalisedAppinfo, redirectTo: string) { return redirectTo.replace( @@ -51,6 +49,7 @@ function copyAndCleanRequestBodyInput(input: any): any { } export default function getRecipeInterface( + stInstance: SuperTokens, querier: Querier, _config: TypeNormalisedInput, appInfo: NormalisedAppinfo, @@ -187,7 +186,7 @@ export default function getRecipeInterface( grantAccessTokenAudience: input.grantAccessTokenAudience, grantScope: input.grantScope, handledAt: input.handledAt, - iss: await OpenIdRecipe.getIssuer(input.userContext), + iss: await stInstance.getRecipeInstanceOrThrow("openid").getIssuer(input.userContext), tId: input.tenantId, rsub: input.rsub, sessionHandle: input.sessionHandle, @@ -286,7 +285,9 @@ export default function getRecipeInterface( } const client = clientInfo.client; - const user = await getUser(input.session.getUserId()); + const user = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: input.session.getUserId(), userContext: input.userContext }); if (!user) { return { status: "ERROR", @@ -331,7 +332,7 @@ export default function getRecipeInterface( ...input.params, scope: scopes.join(" "), }, - iss: await OpenIdRecipe.getIssuer(input.userContext), + iss: await stInstance.getRecipeInstanceOrThrow("openid").getIssuer(input.userContext), cookies: input.cookies, session: payloads, }, @@ -402,7 +403,7 @@ export default function getRecipeInterface( authorizationHeader: input.authorizationHeader, }; - body.iss = await OpenIdRecipe.getIssuer(input.userContext); + body.iss = await stInstance.getRecipeInstanceOrThrow("openid").getIssuer(input.userContext); if (input.body.grant_type === "password") { return { @@ -497,7 +498,12 @@ export default function getRecipeInterface( }; } const client = clientInfo.client; - const user = await getUser(tokenInfo.sub as string); + const user = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ + userId: tokenInfo.sub as string, + userContext: input.userContext, + }); if (!user) { return { status: "ERROR", @@ -711,7 +717,10 @@ export default function getRecipeInterface( }, validateOAuth2AccessToken: async function (input) { const payload = ( - await jose.jwtVerify(input.token, getCombinedJWKS(SessionRecipe.getInstanceOrThrowError().config)) + await jose.jwtVerify( + input.token, + getCombinedJWKS(querier, stInstance.getRecipeInstanceOrThrow("session").config) + ) ).payload; if (payload.stt !== 1) { diff --git a/lib/ts/recipe/openid/recipe.ts b/lib/ts/recipe/openid/recipe.ts index f40b6d491..99d1590cb 100644 --- a/lib/ts/recipe/openid/recipe.ts +++ b/lib/ts/recipe/openid/recipe.ts @@ -27,6 +27,7 @@ import { GET_DISCOVERY_CONFIG_URL } from "./constants"; import getOpenIdDiscoveryConfiguration from "./api/getOpenIdDiscoveryConfiguration"; import { isTestEnv } from "../../utils"; import { applyPlugins } from "../../plugins"; +import type SuperTokens from "../../supertokens"; export default class OpenIdRecipe extends RecipeModule { static RECIPE_ID = "openid" as const; @@ -35,12 +36,12 @@ export default class OpenIdRecipe extends RecipeModule { recipeImplementation: RecipeInterface; apiImpl: APIInterface; - constructor(recipeId: string, appInfo: NormalisedAppinfo, config?: TypeInput) { - super(recipeId, appInfo); + constructor(stInstance: SuperTokens, recipeId: string, appInfo: NormalisedAppinfo, config?: TypeInput) { + super(stInstance, recipeId, appInfo); this.config = validateAndNormaliseUserInput(config); - let builder = new OverrideableBuilder(RecipeImplementation(appInfo)); + let builder = new OverrideableBuilder(RecipeImplementation(stInstance, appInfo)); this.recipeImplementation = builder.override(this.config.override.functions).build(); @@ -57,9 +58,10 @@ export default class OpenIdRecipe extends RecipeModule { } static init(config?: TypeInput): RecipeListFunction { - return (appInfo, _isInServerlessEnv, plugins) => { + return (stInstance, appInfo, _isInServerlessEnv, plugins) => { if (OpenIdRecipe.instance === undefined) { OpenIdRecipe.instance = new OpenIdRecipe( + stInstance, OpenIdRecipe.RECIPE_ID, appInfo, applyPlugins(OpenIdRecipe.RECIPE_ID, config, plugins ?? []) @@ -78,10 +80,8 @@ export default class OpenIdRecipe extends RecipeModule { OpenIdRecipe.instance = undefined; } - static async getIssuer(userContext: UserContext) { - return ( - await this.getInstanceOrThrowError().recipeImplementation.getOpenIdDiscoveryConfiguration({ userContext }) - ).issuer; + async getIssuer(userContext: UserContext) { + return (await this.recipeImplementation.getOpenIdDiscoveryConfiguration({ userContext })).issuer; } getAPIsHandled = (): APIHandled[] => { diff --git a/lib/ts/recipe/openid/recipeImplementation.ts b/lib/ts/recipe/openid/recipeImplementation.ts index 5fa6751a3..d388dc0b0 100644 --- a/lib/ts/recipe/openid/recipeImplementation.ts +++ b/lib/ts/recipe/openid/recipeImplementation.ts @@ -13,7 +13,6 @@ * under the License. */ import { RecipeInterface } from "./types"; -import JWTRecipe from "../jwt/recipe"; import NormalisedURLPath from "../../normalisedURLPath"; import { GET_JWKS_API } from "../jwt/constants"; import { NormalisedAppinfo, UserContext } from "../../types"; @@ -25,8 +24,9 @@ import { TOKEN_PATH, USER_INFO_PATH, } from "../oauth2provider/constants"; +import type SuperTokens from "../../supertokens"; -export default function getRecipeInterface(appInfo: NormalisedAppinfo): RecipeInterface { +export default function getRecipeInterface(stInstance: SuperTokens, appInfo: NormalisedAppinfo): RecipeInterface { return { getOpenIdDiscoveryConfiguration: async function () { let issuer = appInfo.apiDomain.getAsStringDangerous() + appInfo.apiBasePath.getAsStringDangerous(); @@ -75,7 +75,7 @@ export default function getRecipeInterface(appInfo: NormalisedAppinfo): RecipeIn payload = payload === undefined || payload === null ? {} : payload; let issuer = (await this.getOpenIdDiscoveryConfiguration({ userContext })).issuer; - return await JWTRecipe.getInstanceOrThrowError().recipeInterfaceImpl.createJWT({ + return await stInstance.getRecipeInstanceOrThrow("jwt").recipeInterfaceImpl.createJWT({ payload: { iss: issuer, ...payload, diff --git a/lib/ts/recipe/passwordless/api/consumeCode.ts b/lib/ts/recipe/passwordless/api/consumeCode.ts index 39229cca7..47e734b24 100644 --- a/lib/ts/recipe/passwordless/api/consumeCode.ts +++ b/lib/ts/recipe/passwordless/api/consumeCode.ts @@ -22,8 +22,10 @@ import STError from "../error"; import { APIInterface, APIOptions } from ".."; import { UserContext } from "../../../types"; import { AuthUtils } from "../../../authUtils"; +import type SuperTokens from "../../../supertokens"; export default async function consumeCode( + stInstance: SuperTokens, apiImplementation: APIInterface, tenantId: string, options: APIOptions, @@ -69,6 +71,7 @@ export default async function consumeCode( const shouldTryLinkingWithSessionUser = getNormalisedShouldTryLinkingWithSessionUserFlag(options.req, body); const session = await AuthUtils.loadSessionInAuthAPIIfNeeded( + stInstance, options.req, options.res, shouldTryLinkingWithSessionUser, diff --git a/lib/ts/recipe/passwordless/api/createCode.ts b/lib/ts/recipe/passwordless/api/createCode.ts index 246742c8c..b354e2a41 100644 --- a/lib/ts/recipe/passwordless/api/createCode.ts +++ b/lib/ts/recipe/passwordless/api/createCode.ts @@ -19,8 +19,10 @@ import { APIInterface, APIOptions } from ".."; import parsePhoneNumber from "libphonenumber-js/max"; import { UserContext } from "../../../types"; import { AuthUtils } from "../../../authUtils"; +import type SuperTokens from "../../../supertokens"; export default async function createCode( + stInstance: SuperTokens, apiImplementation: APIInterface, tenantId: string, options: APIOptions, @@ -96,6 +98,7 @@ export default async function createCode( const shouldTryLinkingWithSessionUser = getNormalisedShouldTryLinkingWithSessionUserFlag(options.req, body); const session = await AuthUtils.loadSessionInAuthAPIIfNeeded( + stInstance, options.req, options.res, shouldTryLinkingWithSessionUser, diff --git a/lib/ts/recipe/passwordless/api/implementation.ts b/lib/ts/recipe/passwordless/api/implementation.ts index 559e57bf3..44f5d10d3 100644 --- a/lib/ts/recipe/passwordless/api/implementation.ts +++ b/lib/ts/recipe/passwordless/api/implementation.ts @@ -2,16 +2,14 @@ import { APIInterface, RecipeInterface } from "../"; import { logDebugMessage } from "../../../logger"; import { AuthUtils } from "../../../authUtils"; import { FactorIds } from "../../multifactorauth"; -import AccountLinking from "../../accountlinking/recipe"; -import EmailVerification from "../../emailverification/recipe"; import { getEnabledPwlessFactors } from "../utils"; -import { getUser, listUsersByAccountInfo } from "../../.."; import { SessionContainerInterface } from "../../session/types"; import { UserContext } from "../../../types"; import { LoginMethod, User } from "../../../user"; import SessionError from "../../session/error"; +import type SuperTokens from "../../../supertokens"; -export default function getAPIImplementation(): APIInterface { +export default function getAPIImplementation(stInstance: SuperTokens): APIInterface { return { consumeCodePOST: async function (input) { const errorCodeMap = { @@ -79,6 +77,7 @@ export default function getAPIImplementation(): APIInterface { }; const authenticatingUser = await AuthUtils.getAuthenticatingUserAndAddToCurrentTenantIfRequired({ + stInstance, accountInfo, recipeId, userContext: input.userContext, @@ -87,7 +86,7 @@ export default function getAPIImplementation(): APIInterface { checkCredentialsOnTenant: checkCredentials, }); - const emailVerificationInstance = EmailVerification.getInstance(); + const emailVerificationInstance = stInstance.getRecipeInstance("emailverification"); // If we have a session and emailverification was initialized plus this code was sent to an email // then we check if we can/should verify this email address for the session user. // This helps in usecases like phone-password and emailverification-with-otp where we only want to allow linking @@ -102,7 +101,9 @@ export default function getAPIImplementation(): APIInterface { ) { // We first load the session user, so we can check if verification is required // We do this first, it is better for caching if we group the post calls together (verifyIng the code and the email address) - const sessionUser = await getUser(input.session.getUserId(), input.userContext); + const sessionUser = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: input.session.getUserId(), userContext: input.userContext }); if (sessionUser === undefined) { throw new SessionError({ type: SessionError.UNAUTHORISED, @@ -164,6 +165,7 @@ export default function getAPIImplementation(): APIInterface { const isSignUp = authenticatingUser === undefined; const preAuthChecks = await AuthUtils.preAuthChecks({ + stInstance, authenticatingAccountInfo: { recipeId: "passwordless", email: deviceInfo.email, @@ -239,6 +241,7 @@ export default function getAPIImplementation(): APIInterface { // of the user), it's OK to do this check here cause the preAuthChecks already checks // conditions related to account linking const postAuthChecks = await AuthUtils.postAuthChecks({ + stInstance, factorId, isSignUp, authenticatedUser: response.user ?? authenticatingUser!.user, @@ -285,7 +288,11 @@ export default function getAPIImplementation(): APIInterface { // Here we use do not use the helper from AuthUtil to check if this is going to be a sign in or up, because: // 1. At this point we have no way to check credentials // 2. We do not want to associate the relevant recipe user with the current tenant (yet) - const userWithMatchingLoginMethod = await getPasswordlessUserByAccountInfo({ ...input, accountInfo }); + const userWithMatchingLoginMethod = await getPasswordlessUserByAccountInfo({ + ...input, + accountInfo, + stInstance, + }); let factorIds; if (input.session !== undefined) { @@ -308,6 +315,7 @@ export default function getAPIImplementation(): APIInterface { } const preAuthChecks = await AuthUtils.preAuthChecks({ + stInstance, authenticatingAccountInfo: { ...accountInfo, recipeId: "passwordless", @@ -445,14 +453,16 @@ export default function getAPIImplementation(): APIInterface { }; }, emailExistsGET: async function (input) { - const users = await AccountLinking.getInstanceOrThrowError().recipeInterfaceImpl.listUsersByAccountInfo({ - tenantId: input.tenantId, - accountInfo: { - email: input.email, - }, - doUnionOfAccountInfo: false, - userContext: input.userContext, - }); + const users = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.listUsersByAccountInfo({ + tenantId: input.tenantId, + accountInfo: { + email: input.email, + }, + doUnionOfAccountInfo: false, + userContext: input.userContext, + }); const userExists = users.some((u) => u.loginMethods.some((lm) => lm.recipeId === "passwordless" && lm.hasSameEmailAs(input.email)) ); @@ -463,15 +473,16 @@ export default function getAPIImplementation(): APIInterface { }; }, phoneNumberExistsGET: async function (input) { - let users = await listUsersByAccountInfo( - input.tenantId, - { - phoneNumber: input.phoneNumber, - // tenantId: input.tenantId, - }, - false, - input.userContext - ); + let users = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.listUsersByAccountInfo({ + tenantId: input.tenantId, + accountInfo: { + phoneNumber: input.phoneNumber, + }, + doUnionOfAccountInfo: false, + userContext: input.userContext, + }); return { exists: users.length > 0, @@ -502,8 +513,10 @@ export default function getAPIImplementation(): APIInterface { const userWithMatchingLoginMethod = await getPasswordlessUserByAccountInfo({ ...input, accountInfo: deviceInfo, + stInstance: stInstance, }); const authTypeInfo = await AuthUtils.checkAuthTypeAndLinkingStatus( + stInstance, input.session, input.shouldTryLinkingWithSessionUser, { @@ -571,6 +584,7 @@ export default function getAPIImplementation(): APIInterface { } else { factorIds = getEnabledPwlessFactors(input.options.config); factorIds = await AuthUtils.filterOutInvalidFirstFactorsOrThrowIfAllAreInvalid( + stInstance, factorIds, input.tenantId, false, @@ -658,13 +672,16 @@ async function getPasswordlessUserByAccountInfo(input: { session?: SessionContainerInterface; userContext: UserContext; accountInfo: { phoneNumber?: string | undefined; email?: string | undefined }; + stInstance: SuperTokens; }): Promise<{ user: User; loginMethod: LoginMethod } | undefined> { - const existingUsers = await AccountLinking.getInstanceOrThrowError().recipeInterfaceImpl.listUsersByAccountInfo({ - tenantId: input.tenantId, - accountInfo: input.accountInfo, - doUnionOfAccountInfo: false, - userContext: input.userContext, - }); + const existingUsers = await input.stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.listUsersByAccountInfo({ + tenantId: input.tenantId, + accountInfo: input.accountInfo, + doUnionOfAccountInfo: false, + userContext: input.userContext, + }); logDebugMessage( `getPasswordlessUserByAccountInfo got ${existingUsers.length} from core resp ${JSON.stringify( input.accountInfo diff --git a/lib/ts/recipe/passwordless/api/resendCode.ts b/lib/ts/recipe/passwordless/api/resendCode.ts index 1f1abe48d..fbd7d6c57 100644 --- a/lib/ts/recipe/passwordless/api/resendCode.ts +++ b/lib/ts/recipe/passwordless/api/resendCode.ts @@ -18,8 +18,10 @@ import STError from "../error"; import { APIInterface, APIOptions } from ".."; import { UserContext } from "../../../types"; import { AuthUtils } from "../../../authUtils"; +import type SuperTokens from "../../../supertokens"; export default async function resendCode( + stInstance: SuperTokens, apiImplementation: APIInterface, tenantId: string, options: APIOptions, @@ -50,6 +52,7 @@ export default async function resendCode( const shouldTryLinkingWithSessionUser = getNormalisedShouldTryLinkingWithSessionUserFlag(options.req, body); const session = await AuthUtils.loadSessionInAuthAPIIfNeeded( + stInstance, options.req, options.res, shouldTryLinkingWithSessionUser, diff --git a/lib/ts/recipe/passwordless/emaildelivery/services/backwardCompatibility/index.ts b/lib/ts/recipe/passwordless/emaildelivery/services/backwardCompatibility/index.ts index 3ee2fc5ac..91ab0a2b0 100644 --- a/lib/ts/recipe/passwordless/emaildelivery/services/backwardCompatibility/index.ts +++ b/lib/ts/recipe/passwordless/emaildelivery/services/backwardCompatibility/index.ts @@ -15,7 +15,8 @@ import { TypePasswordlessEmailDeliveryInput } from "../../../types"; import { EmailDeliveryInterface } from "../../../../../ingredients/emaildelivery/types"; import { NormalisedAppinfo, UserContext } from "../../../../../types"; -import { isTestEnv, postWithFetch } from "../../../../../utils"; +import { isTestEnv } from "../../../../../utils"; +import { postWithFetch } from "../../../../../querier"; async function createAndSendEmailUsingSupertokensService(input: { appInfo: NormalisedAppinfo; @@ -67,7 +68,8 @@ async function createAndSendEmailUsingSupertokensService(input: { } export default class BackwardCompatibilityService - implements EmailDeliveryInterface { + implements EmailDeliveryInterface +{ private appInfo: NormalisedAppinfo; constructor(appInfo: NormalisedAppinfo) { diff --git a/lib/ts/recipe/passwordless/recipe.ts b/lib/ts/recipe/passwordless/recipe.ts index 03df04e5d..451520cb4 100644 --- a/lib/ts/recipe/passwordless/recipe.ts +++ b/lib/ts/recipe/passwordless/recipe.ts @@ -21,7 +21,6 @@ import { getEnabledPwlessFactors, validateAndNormaliseUserInput } from "./utils" import NormalisedURLPath from "../../normalisedURLPath"; import RecipeImplementation from "./recipeImplementation"; import APIImplementation from "./api/implementation"; -import { Querier } from "../../querier"; import type { BaseRequest, BaseResponse } from "../../framework"; import OverrideableBuilder from "supertokens-js-override"; import consumeCodeAPI from "./api/consumeCode"; @@ -42,14 +41,13 @@ import EmailDeliveryIngredient from "../../ingredients/emaildelivery"; import { TypePasswordlessEmailDeliveryInput, TypePasswordlessSmsDeliveryInput } from "./types"; import SmsDeliveryIngredient from "../../ingredients/smsdelivery"; import { PostSuperTokensInitCallbacks } from "../../postSuperTokensInitCallbacks"; -import MultiFactorAuthRecipe from "../multifactorauth/recipe"; -import MultitenancyRecipe from "../multitenancy/recipe"; import { User } from "../../user"; import { isFakeEmail } from "../thirdparty/utils"; import { FactorIds } from "../multifactorauth"; import { SessionContainerInterface } from "../session/types"; import { isTestEnv } from "../../utils"; import { applyPlugins } from "../../plugins"; +import type SuperTokens from "../../supertokens"; export default class Recipe extends RecipeModule { private static instance: Recipe | undefined = undefined; @@ -68,6 +66,7 @@ export default class Recipe extends RecipeModule { smsDelivery: SmsDeliveryIngredient; constructor( + stInstance: SuperTokens, recipeId: string, appInfo: NormalisedAppinfo, isInServerlessEnv: boolean, @@ -77,16 +76,16 @@ export default class Recipe extends RecipeModule { smsDelivery: SmsDeliveryIngredient | undefined; } ) { - super(recipeId, appInfo); + super(stInstance, recipeId, appInfo); this.isInServerlessEnv = isInServerlessEnv; this.config = validateAndNormaliseUserInput(this, appInfo, config); { - let builder = new OverrideableBuilder(RecipeImplementation(Querier.getNewInstanceOrThrowError(recipeId))); + let builder = new OverrideableBuilder(RecipeImplementation(this.stInstance, this.querier)); this.recipeInterfaceImpl = builder.override(this.config.override.functions).build(); } { - let builder = new OverrideableBuilder(APIImplementation()); + let builder = new OverrideableBuilder(APIImplementation(this.stInstance)); this.apiImpl = builder.override(this.config.override.apis).build(); } @@ -107,7 +106,7 @@ export default class Recipe extends RecipeModule { let allFactors = getEnabledPwlessFactors(this.config); PostSuperTokensInitCallbacks.addPostInitCallback(() => { - const mfaInstance = MultiFactorAuthRecipe.getInstance(); + const mfaInstance = stInstance.getRecipeInstance("multifactorauth"); if (mfaInstance !== undefined) { mfaInstance.addFuncToGetAllAvailableSecondaryFactorIdsFromOtherRecipes(() => { @@ -413,7 +412,7 @@ export default class Recipe extends RecipeModule { }); } - const mtRecipe = MultitenancyRecipe.getInstance(); + const mtRecipe = stInstance.getRecipeInstance("multitenancy"); if (mtRecipe !== undefined) { for (const factorId of allFactors) { mtRecipe.allAvailableFirstFactors.push(factorId); @@ -430,9 +429,10 @@ export default class Recipe extends RecipeModule { } static init(config: TypeInput): RecipeListFunction { - return (appInfo, isInServerlessEnv, plugins) => { + return (stInstance, appInfo, isInServerlessEnv, plugins) => { if (Recipe.instance === undefined) { Recipe.instance = new Recipe( + stInstance, Recipe.RECIPE_ID, appInfo, isInServerlessEnv, @@ -527,15 +527,15 @@ export default class Recipe extends RecipeModule { appInfo: this.getAppInfo(), }; if (id === CONSUME_CODE_API) { - return await consumeCodeAPI(this.apiImpl, tenantId, options, userContext); + return await consumeCodeAPI(this.stInstance, this.apiImpl, tenantId, options, userContext); } else if (id === CREATE_CODE_API) { - return await createCodeAPI(this.apiImpl, tenantId, options, userContext); + return await createCodeAPI(this.stInstance, this.apiImpl, tenantId, options, userContext); } else if (id === DOES_EMAIL_EXIST_API || id === DOES_EMAIL_EXIST_API_OLD) { return await emailExistsAPI(this.apiImpl, tenantId, options, userContext); } else if (id === DOES_PHONE_NUMBER_EXIST_API || id === DOES_PHONE_NUMBER_EXIST_API_OLD) { return await phoneNumberExistsAPI(this.apiImpl, tenantId, options, userContext); } else { - return await resendCodeAPI(this.apiImpl, tenantId, options, userContext); + return await resendCodeAPI(this.stInstance, this.apiImpl, tenantId, options, userContext); } }; diff --git a/lib/ts/recipe/passwordless/recipeImplementation.ts b/lib/ts/recipe/passwordless/recipeImplementation.ts index bdcf631e0..5566c99ea 100644 --- a/lib/ts/recipe/passwordless/recipeImplementation.ts +++ b/lib/ts/recipe/passwordless/recipeImplementation.ts @@ -1,14 +1,12 @@ import { RecipeInterface } from "./types"; import { Querier } from "../../querier"; -import AccountLinking from "../accountlinking/recipe"; -import EmailVerification from "../emailverification/recipe"; import { logDebugMessage } from "../../logger"; import { User } from "../../user"; -import { getUser } from "../.."; import RecipeUserId from "../../recipeUserId"; import { AuthUtils } from "../../authUtils"; +import type SuperTokens from "../../supertokens"; -export default function getRecipeInterface(querier: Querier): RecipeInterface { +export default function getRecipeInterface(stInstance: SuperTokens, querier: Querier): RecipeInterface { function copyAndRemoveUserContextAndTenantId(input: any): any { let result = { ...input, @@ -48,6 +46,7 @@ export default function getRecipeInterface(querier: Querier): RecipeInterface { let updatedUser = userAsObj; const linkResult = await AuthUtils.linkToSessionIfRequiredElseCreatePrimaryUserIdOrLinkByAccountInfo({ + stInstance, tenantId: input.tenantId, inputUser: userAsObj, recipeUserId: recipeUserIdAsObj, @@ -198,15 +197,18 @@ export default function getRecipeInterface(querier: Querier): RecipeInterface { return { status: "OK" }; }, updateUser: async function (input) { - const accountLinking = AccountLinking.getInstanceOrThrowError(); + const accountLinking = stInstance.getRecipeInstanceOrThrow("accountlinking"); if (input.email) { - const user = await getUser(input.recipeUserId.getAsString(), input.userContext); + const user = await stInstance.getRecipeInstanceOrThrow("accountlinking").recipeInterfaceImpl.getUser({ + userId: input.recipeUserId.getAsString(), + userContext: input.userContext, + }); if (user === undefined) { return { status: "UNKNOWN_USER_ID_ERROR" }; } - const evInstance = EmailVerification.getInstance(); + const evInstance = stInstance.getRecipeInstance("emailverification"); let isEmailVerified = false; if (evInstance) { @@ -242,18 +244,23 @@ export default function getRecipeInterface(querier: Querier): RecipeInterface { if (response.status !== "OK") { return response; } - const user = await getUser(input.recipeUserId.getAsString(), input.userContext); + const user = await stInstance.getRecipeInstanceOrThrow("accountlinking").recipeInterfaceImpl.getUser({ + userId: input.recipeUserId.getAsString(), + userContext: input.userContext, + }); if (user === undefined) { // This means that the user was deleted between the put and get requests return { status: "UNKNOWN_USER_ID_ERROR", }; } - await AccountLinking.getInstanceOrThrowError().verifyEmailForRecipeUserIfLinkedAccountsAreVerified({ - user, - recipeUserId: input.recipeUserId, - userContext: input.userContext, - }); + await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .verifyEmailForRecipeUserIfLinkedAccountsAreVerified({ + user, + recipeUserId: input.recipeUserId, + userContext: input.userContext, + }); return response; }, }; diff --git a/lib/ts/recipe/passwordless/smsdelivery/services/backwardCompatibility/index.ts b/lib/ts/recipe/passwordless/smsdelivery/services/backwardCompatibility/index.ts index d603a1e3f..a07aff777 100644 --- a/lib/ts/recipe/passwordless/smsdelivery/services/backwardCompatibility/index.ts +++ b/lib/ts/recipe/passwordless/smsdelivery/services/backwardCompatibility/index.ts @@ -16,7 +16,7 @@ import { TypePasswordlessSmsDeliveryInput } from "../../../types"; import { SmsDeliveryInterface } from "../../../../../ingredients/smsdelivery/types"; import { SUPERTOKENS_SMS_SERVICE_URL } from "../../../../../ingredients/smsdelivery/services/supertokens"; import Supertokens from "../../../../../supertokens"; -import { postWithFetch } from "../../../../../utils"; +import { postWithFetch } from "../../../../../querier"; import { UserContext } from "../../../../../types"; async function createAndSendSmsUsingSupertokensService(input: { diff --git a/lib/ts/recipe/passwordless/smsdelivery/services/supertokens/index.ts b/lib/ts/recipe/passwordless/smsdelivery/services/supertokens/index.ts index 2045187fa..de517d9fd 100644 --- a/lib/ts/recipe/passwordless/smsdelivery/services/supertokens/index.ts +++ b/lib/ts/recipe/passwordless/smsdelivery/services/supertokens/index.ts @@ -16,7 +16,7 @@ import { SUPERTOKENS_SMS_SERVICE_URL } from "../../../../../ingredients/smsdeliv import { SmsDeliveryInterface } from "../../../../../ingredients/smsdelivery/types"; import { TypePasswordlessSmsDeliveryInput } from "../../../types"; import Supertokens from "../../../../../supertokens"; -import { postWithFetch } from "../../../../../utils"; +import { postWithFetch } from "../../../../../querier"; export default class SupertokensService implements SmsDeliveryInterface { private apiKey: string; diff --git a/lib/ts/recipe/session/api/implementation.ts b/lib/ts/recipe/session/api/implementation.ts index e6b799e9d..b9a0cb81b 100644 --- a/lib/ts/recipe/session/api/implementation.ts +++ b/lib/ts/recipe/session/api/implementation.ts @@ -4,8 +4,10 @@ import NormalisedURLPath from "../../../normalisedURLPath"; import { SessionContainerInterface } from "../types"; import { GeneralErrorResponse, UserContext } from "../../../types"; import { getSessionFromRequest, refreshSessionInRequest } from "../sessionRequestFunctions"; +import type SessionRecipe from "../recipe"; +import type SuperTokens from "../../../supertokens"; -export default function getAPIInterface(): APIInterface { +export default function getAPIInterface(stInstance: SuperTokens, recipeInstance: SessionRecipe): APIInterface { return { refreshPOST: async function ({ options, @@ -20,6 +22,7 @@ export default function getAPIInterface(): APIInterface { userContext, config: options.config, recipeInterfaceImpl: options.recipeImplementation, + stInstance, }); }, @@ -48,6 +51,7 @@ export default function getAPIInterface(): APIInterface { userContext, config: options.config, recipeInterfaceImpl: options.recipeImplementation, + stInstance, }); } else { return getSessionFromRequest({ @@ -56,6 +60,8 @@ export default function getAPIInterface(): APIInterface { options: verifySessionOptions, config: options.config, recipeInterfaceImpl: options.recipeImplementation, + recipeInstance, + stInstance, userContext, }); } diff --git a/lib/ts/recipe/session/api/signout.ts b/lib/ts/recipe/session/api/signout.ts index 633d84341..4ce316301 100644 --- a/lib/ts/recipe/session/api/signout.ts +++ b/lib/ts/recipe/session/api/signout.ts @@ -17,8 +17,10 @@ import { send200Response } from "../../../utils"; import { APIInterface, APIOptions } from "../"; import { getSessionFromRequest } from "../sessionRequestFunctions"; import { UserContext } from "../../../types"; +import type SuperTokens from "../../../supertokens"; export default async function signOutAPI( + stInstance: SuperTokens, apiImplementation: APIInterface, options: APIOptions, userContext: UserContext @@ -32,8 +34,10 @@ export default async function signOutAPI( const session = await getSessionFromRequest({ req: options.req, res: options.res, + stInstance, config: options.config, recipeInterfaceImpl: options.recipeImplementation, + recipeInstance: stInstance.getRecipeInstanceOrThrow("session"), options: { sessionRequired: true, overrideGlobalClaimValidators: () => [], diff --git a/lib/ts/recipe/session/framework/custom.ts b/lib/ts/recipe/session/framework/custom.ts index 65db71ffd..4606e3984 100644 --- a/lib/ts/recipe/session/framework/custom.ts +++ b/lib/ts/recipe/session/framework/custom.ts @@ -16,8 +16,8 @@ import Session from "../recipe"; import type { VerifySessionOptions } from ".."; import SuperTokens from "../../../supertokens"; import { makeDefaultUserContextFromAPI } from "../../../utils"; -import { BaseRequest, BaseResponse } from "../../../framework"; -import { NextFunction } from "../../../framework/custom/framework"; +import type { BaseRequest, BaseResponse } from "../../../framework"; +import type { NextFunction } from "../../../framework/custom/framework"; import { SessionContainerInterface } from "../types"; export function verifySession( diff --git a/lib/ts/recipe/session/index.ts b/lib/ts/recipe/session/index.ts index 76e060612..cd234bba3 100644 --- a/lib/ts/recipe/session/index.ts +++ b/lib/ts/recipe/session/index.ts @@ -29,13 +29,13 @@ import Recipe from "./recipe"; import OpenIdRecipe from "../openid/recipe"; import JWTRecipe from "../jwt/recipe"; import { JSONObject, UserContext } from "../../types"; -import { getRequiredClaimValidators } from "./utils"; -import { createNewSessionInRequest, getSessionFromRequest, refreshSessionInRequest } from "./sessionRequestFunctions"; +import { refreshSessionInRequest } from "./sessionRequestFunctions"; import RecipeUserId from "../../recipeUserId"; import { getUser } from "../.."; import { DEFAULT_TENANT_ID } from "../multitenancy/constants"; import { protectedProps } from "./constants"; import { getUserContext } from "../../utils"; +import SuperTokens from "../../supertokens"; export default class SessionWrapper { static init = Recipe.init; @@ -52,25 +52,13 @@ export default class SessionWrapper { userContext?: Record ) { const recipeInstance = Recipe.getInstanceOrThrowError(); - const config = recipeInstance.config; - const appInfo = recipeInstance.getAppInfo(); - let user = await getUser(recipeUserId.getAsString(), userContext); - let userId = recipeUserId.getAsString(); - if (user !== undefined) { - userId = user.id; - } - - return await createNewSessionInRequest({ + return await recipeInstance.createNewSession({ req, res, userContext: getUserContext(userContext), - recipeInstance, accessTokenPayload, - userId, recipeUserId, - config, - appInfo, sessionDataInDatabase, tenantId, }); @@ -87,7 +75,7 @@ export default class SessionWrapper { const ctx = getUserContext(userContext); const recipeInstance = Recipe.getInstanceOrThrowError(); const claimsAddedByOtherRecipes = recipeInstance.getClaimsAddedByOtherRecipes(); - const issuer = await OpenIdRecipe.getIssuer(ctx); + const issuer = await OpenIdRecipe.getInstanceOrThrowError().getIssuer(ctx); let finalAccessTokenPayload = { ...accessTokenPayload, @@ -215,16 +203,11 @@ export default class SessionWrapper { ): Promise; static async getSession(req: any, res: any, options?: VerifySessionOptions, userContext?: Record) { const recipeInstance = Recipe.getInstanceOrThrowError(); - const config = recipeInstance.config; - const recipeInterfaceImpl = recipeInstance.recipeInterfaceImpl; - - return getSessionFromRequest({ + return await recipeInstance.getSession({ req, res, - recipeInterfaceImpl, - config, options, - userContext: getUserContext(userContext), // userContext is normalized inside the function + userContext: getUserContext(userContext), }); } @@ -286,7 +269,7 @@ export default class SessionWrapper { }); if (session !== undefined) { - const claimValidators = await getRequiredClaimValidators( + const claimValidators = await Recipe.getInstanceOrThrowError().getRequiredClaimValidators( session, options?.overrideGlobalClaimValidators, ctx @@ -312,6 +295,7 @@ export default class SessionWrapper { return refreshSessionInRequest({ res, req, + stInstance: SuperTokens.getInstanceOrThrowError(), userContext: getUserContext(userContext), config, recipeInterfaceImpl, diff --git a/lib/ts/recipe/session/recipe.ts b/lib/ts/recipe/session/recipe.ts index 1204b332c..31bdbb50b 100644 --- a/lib/ts/recipe/session/recipe.ts +++ b/lib/ts/recipe/session/recipe.ts @@ -22,6 +22,7 @@ import { VerifySessionOptions, SessionClaimValidator, SessionClaim, + SessionContainerInterface, } from "./types"; import STError from "./error"; import { validateAndNormaliseUserInput } from "./utils"; @@ -35,7 +36,6 @@ import { getCORSAllowedHeaders as getCORSAllowedHeadersFromCookiesAndHeaders, } from "./cookieAndHeaders"; import RecipeImplementation from "./recipeImplementation"; -import { Querier } from "../../querier"; import APIImplementation from "./api/implementation"; import type { BaseRequest, BaseResponse } from "../../framework"; import OverrideableBuilder from "supertokens-js-override"; @@ -44,6 +44,9 @@ import { logDebugMessage } from "../../logger"; import { resetCombinedJWKS } from "../../combinedRemoteJWKSet"; import { isTestEnv } from "../../utils"; import { applyPlugins } from "../../plugins"; +import type SuperTokens from "../../supertokens"; +import { RecipeUserId } from "../.."; +import { createNewSessionInRequest, getSessionFromRequest } from "./sessionRequestFunctions"; // For Express export default class SessionRecipe extends RecipeModule { @@ -61,8 +64,14 @@ export default class SessionRecipe extends RecipeModule { isInServerlessEnv: boolean; - constructor(recipeId: string, appInfo: NormalisedAppinfo, isInServerlessEnv: boolean, config?: TypeInput) { - super(recipeId, appInfo); + constructor( + stInstance: SuperTokens, + recipeId: string, + appInfo: NormalisedAppinfo, + isInServerlessEnv: boolean, + config?: TypeInput + ) { + super(stInstance, recipeId, appInfo); this.config = validateAndNormaliseUserInput(this, appInfo, config); const antiCsrfToLog: string = @@ -82,17 +91,12 @@ export default class SessionRecipe extends RecipeModule { this.isInServerlessEnv = isInServerlessEnv; let builder = new OverrideableBuilder( - RecipeImplementation( - Querier.getNewInstanceOrThrowError(recipeId), - this.config, - this.getAppInfo(), - () => this.recipeInterfaceImpl - ) + RecipeImplementation(this.querier, this.config, this.getAppInfo(), () => this.recipeInterfaceImpl) ); this.recipeInterfaceImpl = builder.override(this.config.override.functions).build(); { - let builder = new OverrideableBuilder(APIImplementation()); + let builder = new OverrideableBuilder(APIImplementation(this.stInstance, this)); this.apiImpl = builder.override(this.config.override.apis).build(); } } @@ -107,9 +111,10 @@ export default class SessionRecipe extends RecipeModule { } static init(config?: TypeInput): RecipeListFunction { - return (appInfo, isInServerlessEnv, plugins) => { + return (stInstance, appInfo, isInServerlessEnv, plugins) => { if (SessionRecipe.instance === undefined) { SessionRecipe.instance = new SessionRecipe( + stInstance, SessionRecipe.RECIPE_ID, appInfo, isInServerlessEnv, @@ -193,7 +198,7 @@ export default class SessionRecipe extends RecipeModule { if (id === REFRESH_API_PATH) { return await handleRefreshAPI(this.apiImpl, options, userContext); } else if (id === SIGNOUT_API_PATH) { - return await signOutAPI(this.apiImpl, options, userContext); + return await signOutAPI(this.stInstance, this.apiImpl, options, userContext); } else { return false; } @@ -278,4 +283,67 @@ export default class SessionRecipe extends RecipeModule { userContext, }); }; + getRequiredClaimValidators = async ( + session: SessionContainerInterface, + overrideGlobalClaimValidators: VerifySessionOptions["overrideGlobalClaimValidators"], + userContext: UserContext + ) => { + const claimValidatorsAddedByOtherRecipes = this.getClaimValidatorsAddedByOtherRecipes(); + const globalClaimValidators: SessionClaimValidator[] = await this.recipeInterfaceImpl.getGlobalClaimValidators({ + userId: session.getUserId(userContext), + recipeUserId: session.getRecipeUserId(userContext), + tenantId: session.getTenantId(userContext), + claimValidatorsAddedByOtherRecipes, + userContext, + }); + + return overrideGlobalClaimValidators !== undefined + ? await overrideGlobalClaimValidators(globalClaimValidators, session, userContext) + : globalClaimValidators; + }; + + createNewSession = async (input: { + req: any; + res: any; + tenantId: string; + recipeUserId: RecipeUserId; + accessTokenPayload: any; + sessionDataInDatabase: any; + userContext: UserContext; + }) => { + let user = await this.stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: input.recipeUserId.getAsString(), userContext: input.userContext }); + let userId = input.recipeUserId.getAsString(); + if (user !== undefined) { + userId = user.id; + } + return await createNewSessionInRequest({ + req: input.req, + res: input.res, + userContext: input.userContext, + recipeInstance: this, + stInstance: this.stInstance, + accessTokenPayload: input.accessTokenPayload, + userId, + recipeUserId: input.recipeUserId, + config: this.config, + appInfo: this.stInstance.appInfo, + sessionDataInDatabase: input.sessionDataInDatabase, + tenantId: input.tenantId, + }); + }; + + getSession = async (input: { req: any; res: any; options?: VerifySessionOptions; userContext: UserContext }) => { + return getSessionFromRequest({ + req: input.req, + res: input.res, + recipeInterfaceImpl: this.recipeInterfaceImpl, + recipeInstance: this, + stInstance: this.stInstance, + config: this.config, + options: input.options, + userContext: input.userContext, // userContext is normalized inside the function + }); + }; } diff --git a/lib/ts/recipe/session/sessionFunctions.ts b/lib/ts/recipe/session/sessionFunctions.ts index c4bd5f42b..2eeb9e28b 100644 --- a/lib/ts/recipe/session/sessionFunctions.ts +++ b/lib/ts/recipe/session/sessionFunctions.ts @@ -116,7 +116,7 @@ export async function getSession( */ accessTokenInfo = await getInfoFromAccessToken( parsedAccessToken, - getCombinedJWKS(config), + getCombinedJWKS(helpers.querier, config), helpers.config.antiCsrfFunctionOrString === "VIA_TOKEN" && doAntiCsrfCheck ); } catch (err) { diff --git a/lib/ts/recipe/session/sessionRequestFunctions.ts b/lib/ts/recipe/session/sessionRequestFunctions.ts index 1c5ba176b..fc005308d 100644 --- a/lib/ts/recipe/session/sessionRequestFunctions.ts +++ b/lib/ts/recipe/session/sessionRequestFunctions.ts @@ -1,4 +1,3 @@ -import Recipe from "./recipe"; import { VerifySessionOptions, RecipeInterface, @@ -7,10 +6,8 @@ import { SessionContainerInterface, } from "./types"; import frameworks from "../../framework"; -import SuperTokens from "../../supertokens"; -import OpenIdRecipe from "../openid/recipe"; -import { getRequiredClaimValidators } from "./utils"; -import { getRidFromHeader, isAnIpAddress, normaliseHttpMethod, setRequestInUserContextIfNotDefined } from "../../utils"; +import type SuperTokens from "../../supertokens"; +import { getRidFromHeader, normaliseHttpMethod, setRequestInUserContextIfNotDefined } from "../../utils"; import { logDebugMessage } from "../../logger"; import { availableTokenTransferMethods, protectedProps } from "./constants"; import { @@ -27,6 +24,8 @@ import { validateAccessTokenStructure } from "./accessToken"; import { NormalisedAppinfo, UserContext } from "../../types"; import SessionError from "./error"; import RecipeUserId from "../../recipeUserId"; +import { isAnIpAddress } from "../../normalisedURLDomain"; +import type SessionRecipe from "./recipe"; // We are defining this here (and not exporting it) to reduce the scope of legacy code const LEGACY_ID_REFRESH_TOKEN_COOKIE_NAME = "sIdRefreshToken"; @@ -36,6 +35,8 @@ export async function getSessionFromRequest({ res, config, recipeInterfaceImpl, + recipeInstance, + stInstance, options, userContext, }: { @@ -43,12 +44,14 @@ export async function getSessionFromRequest({ res: any; config: TypeNormalisedInput; recipeInterfaceImpl: RecipeInterface; + recipeInstance: SessionRecipe; + stInstance: SuperTokens; options?: VerifySessionOptions; userContext: UserContext; }): Promise { logDebugMessage("getSession: Started"); - const configuredFramework = SuperTokens.getInstanceOrThrowError().framework; + const configuredFramework = stInstance.framework; if (configuredFramework !== "custom") { if (!req.wrapperUsed) { req = frameworks[configuredFramework].wrapRequest(req); @@ -137,7 +140,7 @@ export async function getSessionFromRequest({ }); if (session !== undefined) { - const claimValidators = await getRequiredClaimValidators( + const claimValidators = await recipeInstance.getRequiredClaimValidators( session, options?.overrideGlobalClaimValidators, userContext @@ -239,15 +242,17 @@ export async function refreshSessionInRequest({ userContext, config, recipeInterfaceImpl, + stInstance, }: { res: any; req: any; userContext: UserContext; config: TypeNormalisedInput; recipeInterfaceImpl: RecipeInterface; + stInstance: SuperTokens; }) { logDebugMessage("refreshSession: Started"); - const configuredFramework = SuperTokens.getInstanceOrThrowError().framework; + const configuredFramework = stInstance.framework; if (configuredFramework !== "custom") { if (!req.wrapperUsed) { req = frameworks[configuredFramework].wrapRequest(req); @@ -419,6 +424,7 @@ export async function createNewSessionInRequest({ res, userContext, recipeInstance, + stInstance, accessTokenPayload, userId, recipeUserId, @@ -430,7 +436,8 @@ export async function createNewSessionInRequest({ req: any; res: any; userContext: UserContext; - recipeInstance: Recipe; + recipeInstance: SessionRecipe; + stInstance: SuperTokens; accessTokenPayload: any; userId: string; recipeUserId: RecipeUserId; @@ -440,7 +447,7 @@ export async function createNewSessionInRequest({ tenantId: string; }) { logDebugMessage("createNewSession: Started"); - const configuredFramework = SuperTokens.getInstanceOrThrowError().framework; + const configuredFramework = stInstance.framework; if (configuredFramework !== "custom") { if (!req.wrapperUsed) { req = frameworks[configuredFramework].wrapRequest(req); @@ -455,7 +462,7 @@ export async function createNewSessionInRequest({ userContext = setRequestInUserContextIfNotDefined(userContext, req); const claimsAddedByOtherRecipes = recipeInstance.getClaimsAddedByOtherRecipes(); - const issuer = await OpenIdRecipe.getIssuer(userContext); + const issuer = await stInstance.getRecipeInstanceOrThrow("openid").getIssuer(userContext); let finalAccessTokenPayload = { ...accessTokenPayload, diff --git a/lib/ts/recipe/session/utils.ts b/lib/ts/recipe/session/utils.ts index 3a7b3439f..c0ef7e569 100644 --- a/lib/ts/recipe/session/utils.ts +++ b/lib/ts/recipe/session/utils.ts @@ -19,13 +19,11 @@ import { NormalisedErrorHandlers, ClaimValidationError, SessionClaimValidator, - SessionContainerInterface, - VerifySessionOptions, TokenTransferMethod, TokenType, } from "./types"; import { setFrontTokenInHeaders, setToken, getAuthModeFromHeader } from "./cookieAndHeaders"; -import SessionRecipe from "./recipe"; +import type SessionRecipe from "./recipe"; import { REFRESH_API_PATH, accessTokenCookieKey, @@ -36,12 +34,13 @@ import { } from "./constants"; import NormalisedURLPath from "../../normalisedURLPath"; import { NormalisedAppinfo, UserContext } from "../../types"; -import { isAnIpAddress, send200Response } from "../../utils"; +import { send200Response } from "../../utils"; import { RecipeInterface, APIInterface } from "./types"; import type { BaseRequest, BaseResponse } from "../../framework"; import { sendNon200ResponseWithMessage, sendNon200Response } from "../../utils"; import { logDebugMessage } from "../../logger"; import RecipeUserId from "../../recipeUserId"; +import { isAnIpAddress } from "../../normalisedURLDomain"; export async function sendTryRefreshTokenResponse( recipeInstance: SessionRecipe, @@ -370,27 +369,6 @@ export function setAccessTokenInResponse( } } -export async function getRequiredClaimValidators( - session: SessionContainerInterface, - overrideGlobalClaimValidators: VerifySessionOptions["overrideGlobalClaimValidators"], - userContext: UserContext -) { - const claimValidatorsAddedByOtherRecipes = - SessionRecipe.getInstanceOrThrowError().getClaimValidatorsAddedByOtherRecipes(); - const globalClaimValidators: SessionClaimValidator[] = - await SessionRecipe.getInstanceOrThrowError().recipeInterfaceImpl.getGlobalClaimValidators({ - userId: session.getUserId(userContext), - recipeUserId: session.getRecipeUserId(userContext), - tenantId: session.getTenantId(userContext), - claimValidatorsAddedByOtherRecipes, - userContext, - }); - - return overrideGlobalClaimValidators !== undefined - ? await overrideGlobalClaimValidators(globalClaimValidators, session, userContext) - : globalClaimValidators; -} - export async function validateClaimsInPayload( claimValidators: SessionClaimValidator[], newAccessTokenPayload: any, diff --git a/lib/ts/recipe/thirdparty/api/implementation.ts b/lib/ts/recipe/thirdparty/api/implementation.ts index 1b633a3e6..789cad0bb 100644 --- a/lib/ts/recipe/thirdparty/api/implementation.ts +++ b/lib/ts/recipe/thirdparty/api/implementation.ts @@ -1,11 +1,10 @@ import { APIInterface } from "../"; -import EmailVerification from "../../emailverification"; -import EmailVerificationRecipe from "../../emailverification/recipe"; import { AuthUtils } from "../../../authUtils"; import { logDebugMessage } from "../../../logger"; import { decodeBase64 } from "../../../utils"; +import type SuperTokens from "../../../supertokens"; -export default function getAPIInterface(): APIInterface { +export default function getAPIInterface(stInstance: SuperTokens): APIInterface { return { authorisationUrlGET: async function ({ provider, redirectURIOnProviderDashboard, userContext }) { const authUrl = await provider.getAuthorisationRedirectURL({ @@ -78,6 +77,7 @@ export default function getAPIInterface(): APIInterface { }; const authenticatingUser = await AuthUtils.getAuthenticatingUserAndAddToCurrentTenantIfRequired({ + stInstance, accountInfo: { thirdParty: { userId: userInfo.thirdPartyUserId, @@ -107,16 +107,18 @@ export default function getAPIInterface(): APIInterface { const recipeUserId = authenticatingUser.loginMethod.recipeUserId; - if (!emailInfo.isVerified && EmailVerificationRecipe.getInstance() !== undefined) { - emailInfo.isVerified = await EmailVerification.isEmailVerified( - recipeUserId!, - emailInfo.id, - userContext - ); + const emailVerificationRecipe = stInstance.getRecipeInstance("emailverification"); + if (!emailInfo.isVerified && emailVerificationRecipe !== undefined) { + emailInfo.isVerified = await emailVerificationRecipe.recipeInterfaceImpl.isEmailVerified({ + recipeUserId: recipeUserId!, + email: emailInfo.id, + userContext, + }); } } const preAuthChecks = await AuthUtils.preAuthChecks({ + stInstance, authenticatingAccountInfo: { recipeId, email: emailInfo.id, @@ -183,6 +185,7 @@ export default function getAPIInterface(): APIInterface { // of the user), it's OK to do this check here cause the preAuthChecks checks // conditions related to account linking const postAuthChecks = await AuthUtils.postAuthChecks({ + stInstance, factorId: "thirdparty", isSignUp, authenticatedUser: response.user, diff --git a/lib/ts/recipe/thirdparty/api/signinup.ts b/lib/ts/recipe/thirdparty/api/signinup.ts index cc57dff1d..cbe5aa7b1 100644 --- a/lib/ts/recipe/thirdparty/api/signinup.ts +++ b/lib/ts/recipe/thirdparty/api/signinup.ts @@ -22,8 +22,10 @@ import { import { APIInterface, APIOptions } from "../"; import { UserContext } from "../../../types"; import { AuthUtils } from "../../../authUtils"; +import type SuperTokens from "../../../supertokens"; export default async function signInUpAPI( + stInstance: SuperTokens, apiImplementation: APIInterface, tenantId: string, options: APIOptions, @@ -89,6 +91,7 @@ export default async function signInUpAPI( const shouldTryLinkingWithSessionUser = getNormalisedShouldTryLinkingWithSessionUserFlag(options.req, bodyParams); const session = await AuthUtils.loadSessionInAuthAPIIfNeeded( + stInstance, options.req, options.res, shouldTryLinkingWithSessionUser, diff --git a/lib/ts/recipe/thirdparty/providers/configUtils.ts b/lib/ts/recipe/thirdparty/providers/configUtils.ts index 0b6ab49c2..77030ee70 100644 --- a/lib/ts/recipe/thirdparty/providers/configUtils.ts +++ b/lib/ts/recipe/thirdparty/providers/configUtils.ts @@ -14,26 +14,10 @@ import { Twitter, } from "."; import { UserContext } from "../../../types"; -import { - ProviderClientConfig, - ProviderConfig, - ProviderConfigForClientType, - ProviderInput, - TypeProvider, -} from "../types"; +import { ProviderConfig, ProviderInput, TypeProvider } from "../types"; import NewProvider from "./custom"; import { discoverOIDCEndpoints } from "./utils"; -export function getProviderConfigForClient( - providerConfig: ProviderConfig, - clientConfig: ProviderClientConfig -): ProviderConfigForClientType { - return { - ...providerConfig, - ...clientConfig, - }; -} - async function fetchAndSetConfig(provider: TypeProvider, clientType: string | undefined, userContext: UserContext) { let config = await provider.getConfigForClientType({ clientType, userContext }); diff --git a/lib/ts/recipe/thirdparty/providers/custom.ts b/lib/ts/recipe/thirdparty/providers/custom.ts index e082c4e7a..5622b8dc9 100644 --- a/lib/ts/recipe/thirdparty/providers/custom.ts +++ b/lib/ts/recipe/thirdparty/providers/custom.ts @@ -1,8 +1,14 @@ -import { TypeProvider, ProviderInput, UserInfo, ProviderConfigForClientType } from "../types"; +import { + TypeProvider, + ProviderInput, + UserInfo, + ProviderConfigForClientType, + ProviderConfig, + ProviderClientConfig, +} from "../types"; import { doGetRequest, doPostRequest, verifyIdTokenFromJWKSEndpointAndGetPayload } from "../../../thirdpartyUtils"; import { getUserContext } from "../../../utils"; import pkceChallenge from "pkce-challenge"; -import { getProviderConfigForClient } from "./configUtils"; import { JWTVerifyGetKey, createRemoteJWKSet } from "jose"; import { logDebugMessage } from "../../../logger"; @@ -20,6 +26,16 @@ export function isUsingDevelopmentClientId(client_id: string): boolean { return client_id.startsWith(DEV_KEY_IDENTIFIER) || DEV_OAUTH_CLIENT_IDS.includes(client_id); } +function getProviderConfigForClient( + providerConfig: ProviderConfig, + clientConfig: ProviderClientConfig +): ProviderConfigForClientType { + return { + ...providerConfig, + ...clientConfig, + }; +} + export function getActualClientIdFromDevelopmentClientId(client_id: string): string { if (client_id.startsWith(DEV_KEY_IDENTIFIER)) { return client_id.split(DEV_KEY_IDENTIFIER)[1]; diff --git a/lib/ts/recipe/thirdparty/providers/utils.ts b/lib/ts/recipe/thirdparty/providers/utils.ts index 28a57fc6d..c89bfb0b9 100644 --- a/lib/ts/recipe/thirdparty/providers/utils.ts +++ b/lib/ts/recipe/thirdparty/providers/utils.ts @@ -4,7 +4,7 @@ import { getOIDCDiscoveryInfo } from "../../../thirdpartyUtils"; import NormalisedURLDomain from "../../../normalisedURLDomain"; import NormalisedURLPath from "../../../normalisedURLPath"; import { logDebugMessage } from "../../../logger"; -import { doFetch } from "../../../utils"; +import { doFetch } from "../../../querier"; export async function doGetRequest( url: string, diff --git a/lib/ts/recipe/thirdparty/recipe.ts b/lib/ts/recipe/thirdparty/recipe.ts index 776572ee1..7c8f75c9d 100644 --- a/lib/ts/recipe/thirdparty/recipe.ts +++ b/lib/ts/recipe/thirdparty/recipe.ts @@ -17,7 +17,6 @@ import RecipeModule from "../../recipeModule"; import { NormalisedAppinfo, APIHandled, RecipeListFunction, HTTPMethod, UserContext } from "../../types"; import { TypeInput, TypeNormalisedInput, RecipeInterface, APIInterface, ProviderInput } from "./types"; import { validateAndNormaliseUserInput } from "./utils"; -import MultitenancyRecipe from "../multitenancy/recipe"; import STError from "./error"; import { SIGN_IN_UP_API, AUTHORISATION_API, APPLE_REDIRECT_HANDLER } from "./constants"; @@ -26,7 +25,6 @@ import signInUpAPI from "./api/signinup"; import authorisationUrlAPI from "./api/authorisationUrl"; import RecipeImplementation from "./recipeImplementation"; import APIImplementation from "./api/implementation"; -import { Querier } from "../../querier"; import type { BaseRequest, BaseResponse } from "../../framework"; import appleRedirectHandler from "./api/appleRedirect"; import OverrideableBuilder from "supertokens-js-override"; @@ -34,6 +32,7 @@ import { PostSuperTokensInitCallbacks } from "../../postSuperTokensInitCallbacks import { FactorIds } from "../multifactorauth"; import { isTestEnv } from "../../utils"; import { applyPlugins } from "../../plugins"; +import type SuperTokens from "../../supertokens"; export default class Recipe extends RecipeModule { private static instance: Recipe | undefined = undefined; @@ -50,6 +49,7 @@ export default class Recipe extends RecipeModule { isInServerlessEnv: boolean; constructor( + stInstance: SuperTokens, recipeId: string, appInfo: NormalisedAppinfo, isInServerlessEnv: boolean, @@ -57,25 +57,23 @@ export default class Recipe extends RecipeModule { _recipes: {}, _ingredients: {} ) { - super(recipeId, appInfo); + super(stInstance, recipeId, appInfo); this.config = validateAndNormaliseUserInput(appInfo, config); this.isInServerlessEnv = isInServerlessEnv; this.providers = this.config.signInAndUpFeature.providers; { - let builder = new OverrideableBuilder( - RecipeImplementation(Querier.getNewInstanceOrThrowError(recipeId), this.providers) - ); + let builder = new OverrideableBuilder(RecipeImplementation(this.stInstance, this.querier, this.providers)); this.recipeInterfaceImpl = builder.override(this.config.override.functions).build(); } { - let builder = new OverrideableBuilder(APIImplementation()); + let builder = new OverrideableBuilder(APIImplementation(stInstance)); this.apiImpl = builder.override(this.config.override.apis).build(); } PostSuperTokensInitCallbacks.addPostInitCallback(() => { - const mtRecipe = MultitenancyRecipe.getInstance(); + const mtRecipe = stInstance.getRecipeInstance("multitenancy"); if (mtRecipe !== undefined) { mtRecipe.staticThirdPartyProviders = this.config.signInAndUpFeature.providers; mtRecipe.allAvailableFirstFactors.push(FactorIds.THIRDPARTY); @@ -84,9 +82,10 @@ export default class Recipe extends RecipeModule { } static init(config?: TypeInput): RecipeListFunction { - return (appInfo, isInServerlessEnv, plugins) => { + return (stInstance, appInfo, isInServerlessEnv, plugins) => { if (Recipe.instance === undefined) { Recipe.instance = new Recipe( + stInstance, Recipe.RECIPE_ID, appInfo, isInServerlessEnv, @@ -161,7 +160,7 @@ export default class Recipe extends RecipeModule { appInfo: this.getAppInfo(), }; if (id === SIGN_IN_UP_API) { - return await signInUpAPI(this.apiImpl, tenantId, options, userContext); + return await signInUpAPI(this.stInstance, this.apiImpl, tenantId, options, userContext); } else if (id === AUTHORISATION_API) { return await authorisationUrlAPI(this.apiImpl, tenantId, options, userContext); } else if (id === APPLE_REDIRECT_HANDLER) { diff --git a/lib/ts/recipe/thirdparty/recipeImplementation.ts b/lib/ts/recipe/thirdparty/recipeImplementation.ts index 154b0f5d6..0c53cda55 100644 --- a/lib/ts/recipe/thirdparty/recipeImplementation.ts +++ b/lib/ts/recipe/thirdparty/recipeImplementation.ts @@ -1,16 +1,18 @@ import { RecipeInterface, ProviderInput } from "./types"; import { Querier } from "../../querier"; import { findAndCreateProviderInstance, mergeProvidersFromCoreAndStatic } from "./providers/configUtils"; -import AccountLinking from "../accountlinking/recipe"; -import MultitenancyRecipe from "../multitenancy/recipe"; import RecipeUserId from "../../recipeUserId"; -import { getUser, listUsersByAccountInfo } from "../.."; import { User as UserType } from "../../types"; import { User } from "../../user"; import { AuthUtils } from "../../authUtils"; import { DEFAULT_TENANT_ID } from "../multitenancy/constants"; +import type SuperTokens from "../../supertokens"; -export default function getRecipeImplementation(querier: Querier, providers: ProviderInput[]): RecipeInterface { +export default function getRecipeImplementation( + stInstance: SuperTokens, + querier: Querier, + providers: ProviderInput[] +): RecipeInterface { return { manuallyCreateOrUpdateUser: async function ( this: RecipeInterface, @@ -25,13 +27,13 @@ export default function getRecipeImplementation(querier: Querier, providers: Pro userContext, } ) { - const accountLinking = AccountLinking.getInstanceOrThrowError(); - const users = await listUsersByAccountInfo( + const accountLinking = stInstance.getRecipeInstanceOrThrow("accountlinking"); + const users = await accountLinking.recipeInterfaceImpl.listUsersByAccountInfo({ tenantId, - { thirdParty: { id: thirdPartyId, userId: thirdPartyUserId } }, - false, - userContext - ); + accountInfo: { thirdParty: { id: thirdPartyId, userId: thirdPartyUserId } }, + doUnionOfAccountInfo: false, + userContext, + }); const user = users[0]; if (user !== undefined) { @@ -74,7 +76,7 @@ export default function getRecipeImplementation(querier: Querier, providers: Pro let userAsObj = User.fromApi(response.user); const recipeUserIdAsObj = new RecipeUserId(response.recipeUserId); - await AccountLinking.getInstanceOrThrowError().verifyEmailForRecipeUserIfLinkedAccountsAreVerified({ + await accountLinking.verifyEmailForRecipeUserIfLinkedAccountsAreVerified({ user: userAsObj, recipeUserId: recipeUserIdAsObj, userContext, @@ -82,9 +84,13 @@ export default function getRecipeImplementation(querier: Querier, providers: Pro // we do this so that we get the updated user (in case the above // function updated the verification status) and can return that - userAsObj = (await getUser(recipeUserIdAsObj.getAsString(), userContext))!; + userAsObj = (await accountLinking.recipeInterfaceImpl.getUser({ + userId: recipeUserIdAsObj.getAsString(), + userContext, + }))!; const linkResult = await AuthUtils.linkToSessionIfRequiredElseCreatePrimaryUserIdOrLinkByAccountInfo({ + stInstance, tenantId, shouldTryLinkingWithSessionUser, inputUser: userAsObj, @@ -177,7 +183,7 @@ export default function getRecipeImplementation(querier: Querier, providers: Pro }, getProvider: async function ({ thirdPartyId, tenantId, clientType, userContext }) { - const mtRecipe = MultitenancyRecipe.getInstanceOrThrowError(); + const mtRecipe = stInstance.getRecipeInstanceOrThrow("multitenancy"); const tenantConfig = await mtRecipe.recipeInterfaceImpl.getTenant({ tenantId, userContext }); if (tenantConfig === undefined) { diff --git a/lib/ts/recipe/totp/api/createDevice.ts b/lib/ts/recipe/totp/api/createDevice.ts index cab3c318a..a38d209cd 100644 --- a/lib/ts/recipe/totp/api/createDevice.ts +++ b/lib/ts/recipe/totp/api/createDevice.ts @@ -15,10 +15,11 @@ import { send200Response } from "../../../utils"; import { APIInterface, APIOptions } from ".."; -import Session from "../../session"; import { UserContext } from "../../../types"; +import type SuperTokens from "../../../supertokens"; export default async function createDeviceAPI( + stInstance: SuperTokens, apiImplementation: APIInterface, options: APIOptions, userContext: UserContext @@ -27,12 +28,12 @@ export default async function createDeviceAPI( return false; } - const session = await Session.getSession( - options.req, - options.res, - { overrideGlobalClaimValidators: () => [], sessionRequired: true }, - userContext - ); + const session = await stInstance.getRecipeInstanceOrThrow("session").getSession({ + req: options.req, + res: options.res, + options: { overrideGlobalClaimValidators: () => [], sessionRequired: true }, + userContext, + }); const bodyParams = await options.req.getJSONBody(); const deviceName = bodyParams.deviceName; @@ -44,7 +45,7 @@ export default async function createDeviceAPI( let response = await apiImplementation.createDevicePOST({ deviceName, options, - session, + session: session!, userContext, }); send200Response(options.res, response); diff --git a/lib/ts/recipe/totp/api/implementation.ts b/lib/ts/recipe/totp/api/implementation.ts index 3e1359a3a..96e136bd6 100644 --- a/lib/ts/recipe/totp/api/implementation.ts +++ b/lib/ts/recipe/totp/api/implementation.ts @@ -14,22 +14,21 @@ */ import { APIInterface } from "../"; -import MultiFactorAuth, { MultiFactorAuthClaim } from "../../multifactorauth"; -import MultiFactorAuthRecipe from "../../multifactorauth/recipe"; import SessionError from "../../session/error"; +import type SuperTokens from "../../../supertokens"; -export default function getAPIInterface(): APIInterface { +export default function getAPIInterface(stInstance: SuperTokens): APIInterface { return { createDevicePOST: async function ({ deviceName, options, session, userContext }) { const userId = session.getUserId(); - let mfaInstance = MultiFactorAuthRecipe.getInstance(); + let mfaInstance = stInstance.getRecipeInstance("multifactorauth"); if (mfaInstance === undefined) { throw new Error("should never come here"); // If TOTP initialised, MFA is auto initialised. This should never happen. } - await MultiFactorAuth.assertAllowedToSetupFactorElseThrowInvalidClaimError(session, "totp", userContext); + await mfaInstance.assertAllowedToSetupFactorElseThrowInvalidClaimError(session, "totp", userContext); const createDeviceRes = await options.recipeImplementation.createDevice({ userId, @@ -65,7 +64,11 @@ export default function getAPIInterface(): APIInterface { }); if (deviceList.devices.some((device) => device.name === deviceName && device.verified)) { - await session.assertClaims([MultiFactorAuthClaim.validators.hasCompletedMFARequirementsForAuth()]); + await session.assertClaims([ + stInstance + .getRecipeInstanceOrThrow("multifactorauth") + .multiFactorAuthClaim.validators.hasCompletedMFARequirementsForAuth(), + ]); } return await options.recipeImplementation.removeDevice({ @@ -79,13 +82,13 @@ export default function getAPIInterface(): APIInterface { const userId = session.getUserId(); const tenantId = session.getTenantId(); - const mfaInstance = MultiFactorAuthRecipe.getInstance(); + const mfaInstance = stInstance.getRecipeInstance("multifactorauth"); if (mfaInstance === undefined) { throw new Error("should never come here"); // If TOTP initialised, MFA is auto initialised. This should never happen. } - await MultiFactorAuth.assertAllowedToSetupFactorElseThrowInvalidClaimError(session, "totp", userContext); + await mfaInstance.assertAllowedToSetupFactorElseThrowInvalidClaimError(session, "totp", userContext); const res = await options.recipeImplementation.verifyDevice({ tenantId, @@ -110,7 +113,7 @@ export default function getAPIInterface(): APIInterface { const userId = session.getUserId(); const tenantId = session.getTenantId(); - const mfaInstance = MultiFactorAuthRecipe.getInstance(); + const mfaInstance = stInstance.getRecipeInstance("multifactorauth"); if (mfaInstance === undefined) { throw new Error("should never come here"); // If TOTP initialised, MFA is auto initialised. This should never happen. } diff --git a/lib/ts/recipe/totp/api/listDevices.ts b/lib/ts/recipe/totp/api/listDevices.ts index 735893438..538f053d4 100644 --- a/lib/ts/recipe/totp/api/listDevices.ts +++ b/lib/ts/recipe/totp/api/listDevices.ts @@ -15,10 +15,11 @@ import { send200Response } from "../../../utils"; import { APIInterface, APIOptions } from ".."; -import Session from "../../session"; import { UserContext } from "../../../types"; +import type SuperTokens from "../../../supertokens"; export default async function listDevicesAPI( + stInstance: SuperTokens, apiImplementation: APIInterface, options: APIOptions, userContext: UserContext @@ -27,16 +28,16 @@ export default async function listDevicesAPI( return false; } - const session = await Session.getSession( - options.req, - options.res, - { overrideGlobalClaimValidators: () => [], sessionRequired: true }, - userContext - ); + const session = await stInstance.getRecipeInstanceOrThrow("session").getSession({ + req: options.req, + res: options.res, + options: { overrideGlobalClaimValidators: () => [], sessionRequired: true }, + userContext, + }); let response = await apiImplementation.listDevicesGET({ options, - session, + session: session!, userContext, }); send200Response(options.res, response); diff --git a/lib/ts/recipe/totp/api/removeDevice.ts b/lib/ts/recipe/totp/api/removeDevice.ts index 9e87abe96..e12382e63 100644 --- a/lib/ts/recipe/totp/api/removeDevice.ts +++ b/lib/ts/recipe/totp/api/removeDevice.ts @@ -15,10 +15,11 @@ import { send200Response } from "../../../utils"; import { APIInterface, APIOptions } from ".."; -import Session from "../../session"; import { UserContext } from "../../../types"; +import SuperTokens from "../../../supertokens"; export default async function removeDeviceAPI( + stInstance: SuperTokens, apiImplementation: APIInterface, options: APIOptions, userContext: UserContext @@ -27,15 +28,12 @@ export default async function removeDeviceAPI( return false; } - const session = await Session.getSession( - options.req, - options.res, - { - overrideGlobalClaimValidators: () => [], - sessionRequired: true, - }, - userContext - ); + const session = await stInstance.getRecipeInstanceOrThrow("session").getSession({ + req: options.req, + res: options.res, + options: { overrideGlobalClaimValidators: () => [], sessionRequired: true }, + userContext, + }); const bodyParams = await options.req.getJSONBody(); const deviceName = bodyParams.deviceName; @@ -47,7 +45,7 @@ export default async function removeDeviceAPI( let response = await apiImplementation.removeDevicePOST({ deviceName, options, - session, + session: session!, userContext, }); send200Response(options.res, response); diff --git a/lib/ts/recipe/totp/api/verifyDevice.ts b/lib/ts/recipe/totp/api/verifyDevice.ts index 90343ee07..fc6dfcf76 100644 --- a/lib/ts/recipe/totp/api/verifyDevice.ts +++ b/lib/ts/recipe/totp/api/verifyDevice.ts @@ -15,10 +15,11 @@ import { send200Response } from "../../../utils"; import { APIInterface, APIOptions } from ".."; -import Session from "../../session"; import { UserContext } from "../../../types"; +import SuperTokens from "../../../supertokens"; export default async function verifyDeviceAPI( + stInstance: SuperTokens, apiImplementation: APIInterface, options: APIOptions, userContext: UserContext @@ -27,12 +28,12 @@ export default async function verifyDeviceAPI( return false; } - const session = await Session.getSession( - options.req, - options.res, - { overrideGlobalClaimValidators: () => [], sessionRequired: true }, - userContext - ); + const session = await stInstance.getRecipeInstanceOrThrow("session").getSession({ + req: options.req, + res: options.res, + options: { overrideGlobalClaimValidators: () => [], sessionRequired: true }, + userContext, + }); const bodyParams = await options.req.getJSONBody(); const deviceName = bodyParams.deviceName; @@ -50,7 +51,7 @@ export default async function verifyDeviceAPI( deviceName, totp, options, - session, + session: session!, userContext, }); send200Response(options.res, response); diff --git a/lib/ts/recipe/totp/api/verifyTOTP.ts b/lib/ts/recipe/totp/api/verifyTOTP.ts index 8123fcfb2..f7c8fc532 100644 --- a/lib/ts/recipe/totp/api/verifyTOTP.ts +++ b/lib/ts/recipe/totp/api/verifyTOTP.ts @@ -15,10 +15,11 @@ import { send200Response } from "../../../utils"; import { APIInterface, APIOptions } from ".."; -import Session from "../../session"; import { UserContext } from "../../../types"; +import type SuperTokens from "../../../supertokens"; export default async function verifyTOTPAPI( + stInstance: SuperTokens, apiImplementation: APIInterface, options: APIOptions, userContext: UserContext @@ -27,12 +28,12 @@ export default async function verifyTOTPAPI( return false; } - const session = await Session.getSession( - options.req, - options.res, - { overrideGlobalClaimValidators: () => [], sessionRequired: true }, - userContext - ); + const session = await stInstance.getRecipeInstanceOrThrow("session").getSession({ + req: options.req, + res: options.res, + options: { overrideGlobalClaimValidators: () => [], sessionRequired: true }, + userContext, + }); const bodyParams = await options.req.getJSONBody(); const totp = bodyParams.totp; @@ -44,7 +45,7 @@ export default async function verifyTOTPAPI( let response = await apiImplementation.verifyTOTPPOST({ totp, options, - session, + session: session!, userContext, }); send200Response(options.res, response); diff --git a/lib/ts/recipe/totp/recipe.ts b/lib/ts/recipe/totp/recipe.ts index c0c60e910..e0f51b7f6 100644 --- a/lib/ts/recipe/totp/recipe.ts +++ b/lib/ts/recipe/totp/recipe.ts @@ -14,9 +14,8 @@ */ import OverrideableBuilder from "supertokens-js-override"; -import { BaseRequest, BaseResponse } from "../../framework"; +import type { BaseRequest, BaseResponse } from "../../framework"; import NormalisedURLPath from "../../normalisedURLPath"; -import { Querier } from "../../querier"; import RecipeModule from "../../recipeModule"; import STError from "../../error"; import { APIHandled, HTTPMethod, NormalisedAppinfo, RecipeListFunction, UserContext } from "../../types"; @@ -39,9 +38,9 @@ import listDevicesAPI from "./api/listDevices"; import removeDeviceAPI from "./api/removeDevice"; import { User } from "../.."; import { PostSuperTokensInitCallbacks } from "../../postSuperTokensInitCallbacks"; -import MultiFactorAuthRecipe from "../multifactorauth/recipe"; import { isTestEnv } from "../../utils"; import { applyPlugins } from "../../plugins"; +import type SuperTokens from "../../supertokens"; export default class Recipe extends RecipeModule { private static instance: Recipe | undefined = undefined; @@ -55,32 +54,38 @@ export default class Recipe extends RecipeModule { isInServerlessEnv: boolean; - constructor(recipeId: string, appInfo: NormalisedAppinfo, isInServerlessEnv: boolean, config?: TypeInput) { - super(recipeId, appInfo); + constructor( + stInstance: SuperTokens, + recipeId: string, + appInfo: NormalisedAppinfo, + isInServerlessEnv: boolean, + config?: TypeInput + ) { + super(stInstance, recipeId, appInfo); this.config = validateAndNormaliseUserInput(appInfo, config); this.isInServerlessEnv = isInServerlessEnv; { - let builder = new OverrideableBuilder( - RecipeImplementation(Querier.getNewInstanceOrThrowError(recipeId), this.config) - ); + let builder = new OverrideableBuilder(RecipeImplementation(this.stInstance, this.querier, this.config)); this.recipeInterfaceImpl = builder.override(this.config.override.functions).build(); } { - let builder = new OverrideableBuilder(APIImplementation()); + let builder = new OverrideableBuilder(APIImplementation(this.stInstance)); this.apiImpl = builder.override(this.config.override.apis).build(); } + const instance = this; + PostSuperTokensInitCallbacks.addPostInitCallback(() => { - const mfaInstance = MultiFactorAuthRecipe.getInstance(); + const mfaInstance = this.stInstance.getRecipeInstance("multifactorauth"); if (mfaInstance !== undefined) { mfaInstance.addFuncToGetAllAvailableSecondaryFactorIdsFromOtherRecipes(() => { return ["totp"]; }); mfaInstance.addFuncToGetFactorsSetupForUserFromOtherRecipes( async (user: User, userContext: UserContext) => { - const deviceRes = await Recipe.getInstanceOrThrowError().recipeInterfaceImpl.listDevices({ + const deviceRes = await instance.recipeInterfaceImpl.listDevices({ userId: user.id, userContext, }); @@ -108,9 +113,10 @@ export default class Recipe extends RecipeModule { } static init(config?: TypeInput): RecipeListFunction { - return (appInfo, isInServerlessEnv, plugins) => { + return (stInstance, appInfo, isInServerlessEnv, plugins) => { if (Recipe.instance === undefined) { Recipe.instance = new Recipe( + stInstance, Recipe.RECIPE_ID, appInfo, isInServerlessEnv, @@ -186,15 +192,15 @@ export default class Recipe extends RecipeModule { res, }; if (id === CREATE_TOTP_DEVICE) { - return await createDeviceAPI(this.apiImpl, options, userContext); + return await createDeviceAPI(this.stInstance, this.apiImpl, options, userContext); } else if (id === LIST_TOTP_DEVICES) { - return await listDevicesAPI(this.apiImpl, options, userContext); + return await listDevicesAPI(this.stInstance, this.apiImpl, options, userContext); } else if (id === REMOVE_TOTP_DEVICE) { - return await removeDeviceAPI(this.apiImpl, options, userContext); + return await removeDeviceAPI(this.stInstance, this.apiImpl, options, userContext); } else if (id === VERIFY_TOTP_DEVICE) { - return await verifyDeviceAPI(this.apiImpl, options, userContext); + return await verifyDeviceAPI(this.stInstance, this.apiImpl, options, userContext); } else if (id === VERIFY_TOTP) { - return await verifyTOTPAPI(this.apiImpl, options, userContext); + return await verifyTOTPAPI(this.stInstance, this.apiImpl, options, userContext); } throw new Error("should never come here"); }; diff --git a/lib/ts/recipe/totp/recipeImplementation.ts b/lib/ts/recipe/totp/recipeImplementation.ts index cf2b744d0..6f0577c5d 100644 --- a/lib/ts/recipe/totp/recipeImplementation.ts +++ b/lib/ts/recipe/totp/recipeImplementation.ts @@ -17,12 +17,18 @@ import { RecipeInterface } from "./"; import { Querier } from "../../querier"; import { TypeNormalisedInput } from "./types"; import { UserContext } from "../../types"; -import { getUser } from "../.."; +import SuperTokens from "../../supertokens"; -export default function getRecipeInterface(querier: Querier, config: TypeNormalisedInput): RecipeInterface { +export default function getRecipeInterface( + stInstance: SuperTokens, + querier: Querier, + config: TypeNormalisedInput +): RecipeInterface { return { getUserIdentifierInfoForUserId: async function (this: RecipeInterface, { userId, userContext }) { - let user = await getUser(userId, userContext); + let user = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId, userContext }); if (user === undefined) { return { diff --git a/lib/ts/recipe/totp/types.ts b/lib/ts/recipe/totp/types.ts index 6fac2e06c..b57c5c312 100644 --- a/lib/ts/recipe/totp/types.ts +++ b/lib/ts/recipe/totp/types.ts @@ -13,7 +13,7 @@ * under the License. */ -import { BaseRequest, BaseResponse } from "../../framework"; +import type { BaseRequest, BaseResponse } from "../../framework"; import OverrideableBuilder from "supertokens-js-override"; import { GeneralErrorResponse, UserContext } from "../../types"; import { SessionContainerInterface } from "../session/types"; diff --git a/lib/ts/recipe/usermetadata/recipe.ts b/lib/ts/recipe/usermetadata/recipe.ts index 82b3e9839..6513c0792 100644 --- a/lib/ts/recipe/usermetadata/recipe.ts +++ b/lib/ts/recipe/usermetadata/recipe.ts @@ -17,7 +17,6 @@ import SuperTokensError from "../../error"; import error from "../../error"; import type { BaseRequest, BaseResponse } from "../../framework"; import normalisedURLPath from "../../normalisedURLPath"; -import { Querier } from "../../querier"; import RecipeModule from "../../recipeModule"; import { APIHandled, HTTPMethod, NormalisedAppinfo, RecipeListFunction } from "../../types"; import { isTestEnv } from "../../utils"; @@ -27,6 +26,7 @@ import RecipeImplementation from "./recipeImplementation"; import { RecipeInterface, TypeInput, TypeNormalisedInput } from "./types"; import { validateAndNormaliseUserInput } from "./utils"; import OverrideableBuilder from "supertokens-js-override"; +import type SuperTokens from "../../supertokens"; export default class Recipe extends RecipeModule { static RECIPE_ID = "usermetadata" as const; @@ -36,13 +36,19 @@ export default class Recipe extends RecipeModule { recipeInterfaceImpl: RecipeInterface; isInServerlessEnv: boolean; - constructor(recipeId: string, appInfo: NormalisedAppinfo, isInServerlessEnv: boolean, config?: TypeInput) { - super(recipeId, appInfo); + constructor( + stInstance: SuperTokens, + recipeId: string, + appInfo: NormalisedAppinfo, + isInServerlessEnv: boolean, + config?: TypeInput + ) { + super(stInstance, recipeId, appInfo); this.config = validateAndNormaliseUserInput(this, appInfo, config); this.isInServerlessEnv = isInServerlessEnv; { - let builder = new OverrideableBuilder(RecipeImplementation(Querier.getNewInstanceOrThrowError(recipeId))); + let builder = new OverrideableBuilder(RecipeImplementation(this.querier)); this.recipeInterfaceImpl = builder.override(this.config.override.functions).build(); } } @@ -59,9 +65,10 @@ export default class Recipe extends RecipeModule { } static init(config?: TypeInput): RecipeListFunction { - return (appInfo, isInServerlessEnv, plugins) => { + return (stInstance, appInfo, isInServerlessEnv, plugins) => { if (Recipe.instance === undefined) { Recipe.instance = new Recipe( + stInstance, Recipe.RECIPE_ID, appInfo, isInServerlessEnv, diff --git a/lib/ts/recipe/userroles/recipe.ts b/lib/ts/recipe/userroles/recipe.ts index 6642b7d6a..6c258b694 100644 --- a/lib/ts/recipe/userroles/recipe.ts +++ b/lib/ts/recipe/userroles/recipe.ts @@ -17,7 +17,6 @@ import SuperTokensError from "../../error"; import error from "../../error"; import type { BaseRequest, BaseResponse } from "../../framework"; import normalisedURLPath from "../../normalisedURLPath"; -import { Querier } from "../../querier"; import RecipeModule from "../../recipeModule"; import { APIHandled, HTTPMethod, NormalisedAppinfo, RecipeListFunction, UserContext } from "../../types"; @@ -26,14 +25,13 @@ import { RecipeInterface, TypeInput, TypeNormalisedInput } from "./types"; import { validateAndNormaliseUserInput } from "./utils"; import OverrideableBuilder from "supertokens-js-override"; import { PostSuperTokensInitCallbacks } from "../../postSuperTokensInitCallbacks"; -import SessionRecipe from "../session/recipe"; -import OAuth2Recipe from "../oauth2provider/recipe"; import { UserRoleClaim } from "./userRoleClaim"; import { PermissionClaim } from "./permissionClaim"; import { User } from "../../user"; import { getSessionInformation } from "../session"; import { isTestEnv } from "../../utils"; import { applyPlugins } from "../../plugins"; +import type SuperTokens from "../../supertokens"; export default class Recipe extends RecipeModule { static RECIPE_ID = "userroles" as const; @@ -43,22 +41,28 @@ export default class Recipe extends RecipeModule { recipeInterfaceImpl: RecipeInterface; isInServerlessEnv: boolean; - constructor(recipeId: string, appInfo: NormalisedAppinfo, isInServerlessEnv: boolean, config?: TypeInput) { - super(recipeId, appInfo); + constructor( + stInstance: SuperTokens, + recipeId: string, + appInfo: NormalisedAppinfo, + isInServerlessEnv: boolean, + config?: TypeInput + ) { + super(stInstance, recipeId, appInfo); this.config = validateAndNormaliseUserInput(this, appInfo, config); this.isInServerlessEnv = isInServerlessEnv; { - let builder = new OverrideableBuilder(RecipeImplementation(Querier.getNewInstanceOrThrowError(recipeId))); + let builder = new OverrideableBuilder(RecipeImplementation(this.querier)); this.recipeInterfaceImpl = builder.override(this.config.override.functions).build(); } PostSuperTokensInitCallbacks.addPostInitCallback(() => { if (!this.config.skipAddingRolesToAccessToken) { - SessionRecipe.getInstanceOrThrowError().addClaimFromOtherRecipe(UserRoleClaim); + stInstance.getRecipeInstanceOrThrow("session").addClaimFromOtherRecipe(UserRoleClaim); } if (!this.config.skipAddingPermissionsToAccessToken) { - SessionRecipe.getInstanceOrThrowError().addClaimFromOtherRecipe(PermissionClaim); + stInstance.getRecipeInstanceOrThrow("session").addClaimFromOtherRecipe(PermissionClaim); } const tokenPayloadBuilder = async ( @@ -116,11 +120,14 @@ export default class Recipe extends RecipeModule { return payload; }; - OAuth2Recipe.getInstanceOrThrowError().addAccessTokenBuilderFromOtherRecipe(tokenPayloadBuilder); - OAuth2Recipe.getInstanceOrThrowError().addIdTokenBuilderFromOtherRecipe(tokenPayloadBuilder); + stInstance + .getRecipeInstanceOrThrow("oauth2provider") + .addAccessTokenBuilderFromOtherRecipe(tokenPayloadBuilder); + stInstance.getRecipeInstanceOrThrow("oauth2provider").addIdTokenBuilderFromOtherRecipe(tokenPayloadBuilder); - OAuth2Recipe.getInstanceOrThrowError().addUserInfoBuilderFromOtherRecipe( - async (user, _accessTokenPayload, scopes, tenantId, userContext) => { + stInstance + .getRecipeInstanceOrThrow("oauth2provider") + .addUserInfoBuilderFromOtherRecipe(async (user, _accessTokenPayload, scopes, tenantId, userContext) => { let userInfo: { roles?: string[]; permissions?: string[]; @@ -166,8 +173,7 @@ export default class Recipe extends RecipeModule { } return userInfo; - } - ); + }); }); } @@ -183,9 +189,10 @@ export default class Recipe extends RecipeModule { } static init(config?: TypeInput): RecipeListFunction { - return (appInfo, isInServerlessEnv, plugins) => { + return (stInstance, appInfo, isInServerlessEnv, plugins) => { if (Recipe.instance === undefined) { Recipe.instance = new Recipe( + stInstance, Recipe.RECIPE_ID, appInfo, isInServerlessEnv, diff --git a/lib/ts/recipe/webauthn/api/implementation.ts b/lib/ts/recipe/webauthn/api/implementation.ts index 5d2405050..363d52be8 100644 --- a/lib/ts/recipe/webauthn/api/implementation.ts +++ b/lib/ts/recipe/webauthn/api/implementation.ts @@ -1,7 +1,5 @@ import { APIInterface } from ".."; import { GeneralErrorResponse, User } from "../../../types"; -import AccountLinking from "../../accountlinking/recipe"; -import EmailVerification from "../../emailverification/recipe"; import { AuthUtils } from "../../../authUtils"; import { isFakeEmail } from "../../thirdparty/utils"; import { @@ -19,11 +17,10 @@ import RecipeUserId from "../../../recipeUserId"; import { getRecoverAccountLink } from "../utils"; import { logDebugMessage } from "../../../logger"; import { RecipeLevelUser } from "../../accountlinking/types"; -import { getUser } from "../../.."; -import MultiFactorAuth from "../../multifactorauth"; -import MultiFactorAuthRecipe from "../../multifactorauth/recipe"; +import { FactorIds } from "../../multifactorauth/types"; +import type SuperTokens from "../../../supertokens"; -export default function getAPIImplementation(): APIInterface { +export default function getAPIImplementation(stInstance: SuperTokens): APIInterface { return { registerOptionsPOST: async function ({ tenantId, options, userContext, ...props }) { const relyingPartyId = await options.config.getRelyingPartyId({ @@ -181,11 +178,12 @@ export default function getAPIImplementation(): APIInterface { } const preAuthCheckRes = await AuthUtils.preAuthChecks({ + stInstance, authenticatingAccountInfo: { recipeId: "webauthn", email, }, - factorIds: [MultiFactorAuth.FactorIds.WEBAUTHN], + factorIds: [FactorIds.WEBAUTHN], isSignUp: true, isVerified: isFakeEmail(email), signInVerifiesLoginMethod: false, @@ -198,8 +196,9 @@ export default function getAPIImplementation(): APIInterface { }); if (preAuthCheckRes.status === "SIGN_UP_NOT_ALLOWED") { - const conflictingUsers = - await AccountLinking.getInstanceOrThrowError().recipeInterfaceImpl.listUsersByAccountInfo({ + const conflictingUsers = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.listUsersByAccountInfo({ tenantId, accountInfo: { email, @@ -257,6 +256,7 @@ export default function getAPIImplementation(): APIInterface { } const postAuthChecks = await AuthUtils.postAuthChecks({ + stInstance, authenticatedUser: signUpResponse.user, recipeUserId: signUpResponse.recipeUserId, isSignUp: true, @@ -336,6 +336,7 @@ export default function getAPIImplementation(): APIInterface { const accountInfo = { webauthn: { credentialId: credential.id } }; const authenticatingUser = await AuthUtils.getAuthenticatingUserAndAddToCurrentTenantIfRequired({ + stInstance, accountInfo, userContext, recipeId, @@ -364,11 +365,12 @@ export default function getAPIImplementation(): APIInterface { } const preAuthChecks = await AuthUtils.preAuthChecks({ + stInstance, authenticatingAccountInfo: { recipeId, email, }, - factorIds: [MultiFactorAuth.FactorIds.WEBAUTHN], + factorIds: [FactorIds.WEBAUTHN], isSignUp: false, authenticatingUser: authenticatingUser?.user, isVerified, @@ -420,6 +422,7 @@ export default function getAPIImplementation(): APIInterface { } const postAuthChecks = await AuthUtils.postAuthChecks({ + stInstance, authenticatedUser: signInResponse.user, recipeUserId: signInResponse.recipeUserId, isSignUp: false, @@ -446,14 +449,16 @@ export default function getAPIImplementation(): APIInterface { // even if the above returns true, we still need to check if there // exists an webauthn user with the same email cause the function // above does not check for that. - const users = await AccountLinking.getInstanceOrThrowError().recipeInterfaceImpl.listUsersByAccountInfo({ - tenantId, - accountInfo: { - email, - }, - doUnionOfAccountInfo: false, - userContext, - }); + const users = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.listUsersByAccountInfo({ + tenantId, + accountInfo: { + email, + }, + doUnionOfAccountInfo: false, + userContext, + }); const webauthnUserExists = users.find((u) => { return ( @@ -531,14 +536,16 @@ export default function getAPIImplementation(): APIInterface { } //check if primaryUserId is linked with this email - const users = await AccountLinking.getInstanceOrThrowError().recipeInterfaceImpl.listUsersByAccountInfo({ - tenantId, - accountInfo: { - email, - }, - doUnionOfAccountInfo: false, - userContext, - }); + const users = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.listUsersByAccountInfo({ + tenantId, + accountInfo: { + email, + }, + doUnionOfAccountInfo: false, + userContext, + }); // we find the recipe user ID of the webauthn account from the user's list // for later use. @@ -598,8 +605,9 @@ export default function getAPIImplementation(): APIInterface { }; } - const shouldDoAccountLinkingResponse = - await AccountLinking.getInstanceOrThrowError().config.shouldDoAutomaticAccountLinking( + const shouldDoAccountLinkingResponse = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .config.shouldDoAutomaticAccountLinking( webauthnAccount !== undefined ? webauthnAccount : { @@ -634,7 +642,7 @@ export default function getAPIImplementation(): APIInterface { }; } - const isSignUpAllowed = await AccountLinking.getInstanceOrThrowError().isSignUpAllowed({ + const isSignUpAllowed = await stInstance.getRecipeInstanceOrThrow("accountlinking").isSignUpAllowed({ newUser: { recipeId: "webauthn", email, @@ -729,7 +737,7 @@ export default function getAPIImplementation(): APIInterface { userContext, }) { async function markEmailAsVerified(recipeUserId: RecipeUserId, email: string) { - const emailVerificationInstance = EmailVerification.getInstance(); + const emailVerificationInstance = stInstance.getRecipeInstance("emailverification"); if (emailVerificationInstance) { const tokenResponse = await emailVerificationInstance.recipeInterfaceImpl.createEmailVerificationToken({ @@ -802,7 +810,9 @@ export default function getAPIImplementation(): APIInterface { // If we verified (and linked) the existing user with the original credential, User M would get access to the current user and any linked users. await markEmailAsVerified(recipeUserId, emailForWhomTokenWasGenerated); // We refresh the user information here, because the verification status may be updated, which is used during linking. - const updatedUserAfterEmailVerification = await getUser(recipeUserId.getAsString(), userContext); + const updatedUserAfterEmailVerification = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: recipeUserId.getAsString(), userContext }); if (updatedUserAfterEmailVerification === undefined) { throw new Error("Should never happen - user deleted after during recover account"); } @@ -823,8 +833,9 @@ export default function getAPIImplementation(): APIInterface { // 1. the user was unverified and linking requires verification // We do not take try linking by session here, since this is supposed to be called without a session // Still, the session object is passed around because it is a required input for shouldDoAutomaticAccountLinking - const linkRes = - await AccountLinking.getInstanceOrThrowError().tryLinkingByAccountInfoOrCreatePrimaryUser({ + const linkRes = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .tryLinkingByAccountInfoOrCreatePrimaryUser({ tenantId, inputUser: updatedUserAfterEmailVerification, session: undefined, @@ -854,7 +865,9 @@ export default function getAPIImplementation(): APIInterface { const userIdForWhomTokenWasGenerated = tokenConsumptionResponse.userId; const emailForWhomTokenWasGenerated = tokenConsumptionResponse.email; - const existingUser = await getUser(tokenConsumptionResponse.userId, userContext); + const existingUser = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: tokenConsumptionResponse.userId, userContext }); if (existingUser === undefined) { // This should happen only cause of a race condition where the user @@ -941,7 +954,9 @@ export default function getAPIImplementation(): APIInterface { createUserResponse.user.loginMethods[0].recipeUserId, tokenConsumptionResponse.email ); - const updatedUser = await getUser(createUserResponse.user.id, userContext); + const updatedUser = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: createUserResponse.user.id, userContext }); if (updatedUser === undefined) { throw new Error("Should never happen - user deleted after during recover account"); } @@ -952,8 +967,9 @@ export default function getAPIImplementation(): APIInterface { // email is shared. // We do not take try linking by session here, since this is supposed to be called without a session // Still, the session object is passed around because it is a required input for shouldDoAutomaticAccountLinking - const linkRes = - await AccountLinking.getInstanceOrThrowError().tryLinkingByAccountInfoOrCreatePrimaryUser({ + const linkRes = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .tryLinkingByAccountInfoOrCreatePrimaryUser({ tenantId, inputUser: createUserResponse.user, session: undefined, @@ -986,7 +1002,9 @@ export default function getAPIImplementation(): APIInterface { }, listCredentialsGET: async function ({ options, userContext, session }) { - const existingUser = await getUser(session.getUserId(), userContext); + const existingUser = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: session.getUserId(), userContext }); if (!existingUser) { return { status: "GENERAL_ERROR", @@ -1042,16 +1060,18 @@ export default function getAPIImplementation(): APIInterface { "The credentials are incorrect. Please make sure you are using the correct credentials. (ERR_CODE_025)", }; - const mfaInstance = MultiFactorAuthRecipe.getInstance(); + const mfaInstance = stInstance.getRecipeInstance("multifactorauth"); if (mfaInstance) { - await MultiFactorAuth.assertAllowedToSetupFactorElseThrowInvalidClaimError( + await mfaInstance.assertAllowedToSetupFactorElseThrowInvalidClaimError( session, - MultiFactorAuth.FactorIds.WEBAUTHN, + FactorIds.WEBAUTHN, userContext ); } - const user = await getUser(session.getUserId(), userContext); + const user = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: session.getUserId(), userContext }); if (!user) { return { status: "GENERAL_ERROR", @@ -1115,14 +1135,16 @@ export default function getAPIImplementation(): APIInterface { }; }, removeCredentialPOST: async function ({ webauthnCredentialId, options, userContext, session }) { - const mfaInstance = MultiFactorAuthRecipe.getInstance(); + const mfaInstance = stInstance.getRecipeInstance("multifactorauth"); if (mfaInstance) { await session.assertClaims([ - MultiFactorAuth.MultiFactorAuthClaim.validators.hasCompletedMFARequirementsForAuth(), + mfaInstance.multiFactorAuthClaim.validators.hasCompletedMFARequirementsForAuth(), ]); } - const user = await getUser(session.getUserId(), userContext); + const user = await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: session.getUserId(), userContext }); if (!user) { return { status: "GENERAL_ERROR", diff --git a/lib/ts/recipe/webauthn/api/listCredentials.ts b/lib/ts/recipe/webauthn/api/listCredentials.ts index 68b7c0f64..7e6fa98a2 100644 --- a/lib/ts/recipe/webauthn/api/listCredentials.ts +++ b/lib/ts/recipe/webauthn/api/listCredentials.ts @@ -16,9 +16,10 @@ import { send200Response } from "../../../utils"; import { APIInterface, APIOptions } from ".."; import { UserContext } from "../../../types"; -import Session from "../../session"; +import type SuperTokens from "../../../supertokens"; export default async function listCredentialsAPI( + stInstance: SuperTokens, apiImplementation: APIInterface, _: string, options: APIOptions, @@ -28,17 +29,17 @@ export default async function listCredentialsAPI( return false; } - const session = await Session.getSession( - options.req, - options.res, - { overrideGlobalClaimValidators: () => [], sessionRequired: true }, - userContext - ); + const session = await stInstance.getRecipeInstanceOrThrow("session").getSession({ + req: options.req, + res: options.res, + options: { overrideGlobalClaimValidators: () => [], sessionRequired: true }, + userContext, + }); const result = await apiImplementation.listCredentialsGET({ options, userContext: userContext, - session, + session: session!, }); send200Response(options.res, result); diff --git a/lib/ts/recipe/webauthn/api/registerCredential.ts b/lib/ts/recipe/webauthn/api/registerCredential.ts index e9fd5e2a8..5bab70241 100644 --- a/lib/ts/recipe/webauthn/api/registerCredential.ts +++ b/lib/ts/recipe/webauthn/api/registerCredential.ts @@ -17,10 +17,11 @@ import { send200Response } from "../../../utils"; import { validateWebauthnGeneratedOptionsIdOrThrowError, validateCredentialOrThrowError } from "./utils"; import { APIInterface, APIOptions } from ".."; import { UserContext } from "../../../types"; -import Session from "../../session"; import STError from "../../../error"; +import type SuperTokens from "../../../supertokens"; export default async function registerCredentialAPI( + stInstance: SuperTokens, apiImplementation: APIInterface, tenantId: string, options: APIOptions, @@ -30,12 +31,12 @@ export default async function registerCredentialAPI( return false; } - const session = await Session.getSession( - options.req, - options.res, - { overrideGlobalClaimValidators: () => [], sessionRequired: true }, - userContext - ); + const session = await stInstance.getRecipeInstanceOrThrow("session").getSession({ + req: options.req, + res: options.res, + options: { overrideGlobalClaimValidators: () => [], sessionRequired: true }, + userContext, + }); const requestBody = await options.req.getJSONBody(); const webauthnGeneratedOptionsId = validateWebauthnGeneratedOptionsIdOrThrowError( @@ -58,7 +59,7 @@ export default async function registerCredentialAPI( tenantId, options, userContext: userContext, - session, + session: session!, }); if (result.status === "OK") { diff --git a/lib/ts/recipe/webauthn/api/removeCredential.ts b/lib/ts/recipe/webauthn/api/removeCredential.ts index adabae573..99be169e1 100644 --- a/lib/ts/recipe/webauthn/api/removeCredential.ts +++ b/lib/ts/recipe/webauthn/api/removeCredential.ts @@ -17,9 +17,10 @@ import { send200Response } from "../../../utils"; import { APIInterface, APIOptions } from ".."; import STError from "../error"; import { UserContext } from "../../../types"; -import Session from "../../session"; +import type SuperTokens from "../../../supertokens"; export default async function removeCredentialAPI( + stInstance: SuperTokens, apiImplementation: APIInterface, _: string, options: APIOptions, @@ -29,12 +30,12 @@ export default async function removeCredentialAPI( return false; } - const session = await Session.getSession( - options.req, - options.res, - { overrideGlobalClaimValidators: () => [], sessionRequired: true }, - userContext - ); + const session = await stInstance.getRecipeInstanceOrThrow("session").getSession({ + req: options.req, + res: options.res, + options: { overrideGlobalClaimValidators: () => [], sessionRequired: true }, + userContext, + }); const requestBody = await options.req.getJSONBody(); const webauthnCredentialId = requestBody.webauthnCredentialId; @@ -49,7 +50,7 @@ export default async function removeCredentialAPI( webauthnCredentialId, options, userContext: userContext, - session, + session: session!, }); send200Response(options.res, result); diff --git a/lib/ts/recipe/webauthn/api/signin.ts b/lib/ts/recipe/webauthn/api/signin.ts index fe6976992..cf03b73cc 100644 --- a/lib/ts/recipe/webauthn/api/signin.ts +++ b/lib/ts/recipe/webauthn/api/signin.ts @@ -22,8 +22,10 @@ import { validateWebauthnGeneratedOptionsIdOrThrowError, validateCredentialOrThr import { APIInterface, APIOptions } from ".."; import { UserContext } from "../../../types"; import { AuthUtils } from "../../../authUtils"; +import type SuperTokens from "../../../supertokens"; export default async function signInAPI( + stInstance: SuperTokens, apiImplementation: APIInterface, tenantId: string, options: APIOptions, @@ -42,6 +44,7 @@ export default async function signInAPI( const shouldTryLinkingWithSessionUser = getNormalisedShouldTryLinkingWithSessionUserFlag(options.req, requestBody); const session = await AuthUtils.loadSessionInAuthAPIIfNeeded( + stInstance, options.req, options.res, shouldTryLinkingWithSessionUser, diff --git a/lib/ts/recipe/webauthn/api/signup.ts b/lib/ts/recipe/webauthn/api/signup.ts index f4e22c9dc..3f072bfed 100644 --- a/lib/ts/recipe/webauthn/api/signup.ts +++ b/lib/ts/recipe/webauthn/api/signup.ts @@ -22,8 +22,10 @@ import { validateWebauthnGeneratedOptionsIdOrThrowError, validateCredentialOrThr import { APIInterface, APIOptions } from ".."; import { UserContext } from "../../../types"; import { AuthUtils } from "../../../authUtils"; +import type SuperTokens from "../../../supertokens"; export default async function signUpAPI( + stInstance: SuperTokens, apiImplementation: APIInterface, tenantId: string, options: APIOptions, @@ -42,6 +44,7 @@ export default async function signUpAPI( const shouldTryLinkingWithSessionUser = getNormalisedShouldTryLinkingWithSessionUserFlag(options.req, requestBody); const session = await AuthUtils.loadSessionInAuthAPIIfNeeded( + stInstance, options.req, options.res, shouldTryLinkingWithSessionUser, diff --git a/lib/ts/recipe/webauthn/emaildelivery/services/backwardCompatibility/index.ts b/lib/ts/recipe/webauthn/emaildelivery/services/backwardCompatibility/index.ts index f1e68e2c8..c08f2b68d 100644 --- a/lib/ts/recipe/webauthn/emaildelivery/services/backwardCompatibility/index.ts +++ b/lib/ts/recipe/webauthn/emaildelivery/services/backwardCompatibility/index.ts @@ -15,7 +15,8 @@ import { TypeWebauthnEmailDeliveryInput } from "../../../types"; import { NormalisedAppinfo, UserContext } from "../../../../../types"; import { EmailDeliveryInterface } from "../../../../../ingredients/emaildelivery/types"; -import { isTestEnv, postWithFetch } from "../../../../../utils"; +import { isTestEnv } from "../../../../../utils"; +import { postWithFetch } from "../../../../../querier"; async function createAndSendEmailUsingSupertokensService(input: { appInfo: NormalisedAppinfo; diff --git a/lib/ts/recipe/webauthn/recipe.ts b/lib/ts/recipe/webauthn/recipe.ts index 1886ae09f..226dc1aa4 100644 --- a/lib/ts/recipe/webauthn/recipe.ts +++ b/lib/ts/recipe/webauthn/recipe.ts @@ -47,15 +47,13 @@ import OverrideableBuilder from "supertokens-js-override"; import EmailDeliveryIngredient from "../../ingredients/emaildelivery"; import { TypeWebauthnEmailDeliveryInput } from "./types"; import { PostSuperTokensInitCallbacks } from "../../postSuperTokensInitCallbacks"; -import MultiFactorAuthRecipe from "../multifactorauth/recipe"; -import MultitenancyRecipe from "../multitenancy/recipe"; import { User } from "../../user"; import { isFakeEmail } from "../thirdparty/utils"; -import { FactorIds } from "../multifactorauth"; -import { Querier } from "../../querier"; +import { FactorIds } from "../multifactorauth/types"; import { applyPlugins } from "../../plugins"; import listCredentialsAPI from "./api/listCredentials"; import removeCredentialAPI from "./api/removeCredential"; +import type SuperTokens from "../../supertokens"; export default class Recipe extends RecipeModule { private static instance: Recipe | undefined = undefined; @@ -72,6 +70,7 @@ export default class Recipe extends RecipeModule { emailDelivery: EmailDeliveryIngredient; constructor( + stInstance: SuperTokens, recipeId: string, appInfo: NormalisedAppinfo, isInServerlessEnv: boolean, @@ -80,17 +79,16 @@ export default class Recipe extends RecipeModule { emailDelivery: EmailDeliveryIngredient | undefined; } ) { - super(recipeId, appInfo); + super(stInstance, recipeId, appInfo); this.isInServerlessEnv = isInServerlessEnv; this.config = validateAndNormaliseUserInput(this, appInfo, config); { const getWebauthnConfig = () => this.config; - const querier = Querier.getNewInstanceOrThrowError(recipeId); - let builder = new OverrideableBuilder(RecipeImplementation(querier, getWebauthnConfig)); + let builder = new OverrideableBuilder(RecipeImplementation(stInstance, this.querier, getWebauthnConfig)); this.recipeInterfaceImpl = builder.override(this.config.override.functions).build(); } { - let builder = new OverrideableBuilder(APIImplementation()); + let builder = new OverrideableBuilder(APIImplementation(stInstance)); this.apiImpl = builder.override(this.config.override.apis).build(); } @@ -104,7 +102,7 @@ export default class Recipe extends RecipeModule { : ingredients.emailDelivery; PostSuperTokensInitCallbacks.addPostInitCallback(() => { - const mfaInstance = MultiFactorAuthRecipe.getInstance(); + const mfaInstance = stInstance.getRecipeInstance("multifactorauth"); if (mfaInstance !== undefined) { mfaInstance.addFuncToGetAllAvailableSecondaryFactorIdsFromOtherRecipes(() => { return ["webauthn"]; @@ -215,7 +213,7 @@ export default class Recipe extends RecipeModule { }); } - const mtRecipe = MultitenancyRecipe.getInstance(); + const mtRecipe = stInstance.getRecipeInstance("multitenancy"); if (mtRecipe !== undefined) { mtRecipe.allAvailableFirstFactors.push(FactorIds.WEBAUTHN); } @@ -230,9 +228,10 @@ export default class Recipe extends RecipeModule { } static init(config?: TypeInput): RecipeListFunction { - return (appInfo, isInServerlessEnv, plugins) => { + return (stInstance, appInfo, isInServerlessEnv, plugins) => { if (Recipe.instance === undefined) { Recipe.instance = new Recipe( + stInstance, Recipe.RECIPE_ID, appInfo, isInServerlessEnv, @@ -347,9 +346,9 @@ export default class Recipe extends RecipeModule { } else if (id === SIGNIN_OPTIONS_API) { return await signInOptionsAPI(this.apiImpl, tenantId, options, userContext); } else if (id === SIGN_UP_API) { - return await signUpAPI(this.apiImpl, tenantId, options, userContext); + return await signUpAPI(this.stInstance, this.apiImpl, tenantId, options, userContext); } else if (id === SIGN_IN_API) { - return await signInAPI(this.apiImpl, tenantId, options, userContext); + return await signInAPI(this.stInstance, this.apiImpl, tenantId, options, userContext); } else if (id === GENERATE_RECOVER_ACCOUNT_TOKEN_API) { return await generateRecoverAccountTokenAPI(this.apiImpl, tenantId, options, userContext); } else if (id === RECOVER_ACCOUNT_API) { @@ -357,11 +356,11 @@ export default class Recipe extends RecipeModule { } else if (id === SIGNUP_EMAIL_EXISTS_API) { return await emailExistsAPI(this.apiImpl, tenantId, options, userContext); } else if (id === REGISTER_CREDENTIAL_API) { - return await registerCredentialAPI(this.apiImpl, tenantId, options, userContext); + return await registerCredentialAPI(this.stInstance, this.apiImpl, tenantId, options, userContext); } else if (id === LIST_CREDENTIALS_API) { - return await listCredentialsAPI(this.apiImpl, tenantId, options, userContext); + return await listCredentialsAPI(this.stInstance, this.apiImpl, tenantId, options, userContext); } else if (id === REMOVE_CREDENTIAL_API) { - return await removeCredentialAPI(this.apiImpl, tenantId, options, userContext); + return await removeCredentialAPI(this.stInstance, this.apiImpl, tenantId, options, userContext); } else return false; }; diff --git a/lib/ts/recipe/webauthn/recipeImplementation.ts b/lib/ts/recipe/webauthn/recipeImplementation.ts index 01779783d..94e74ca77 100644 --- a/lib/ts/recipe/webauthn/recipeImplementation.ts +++ b/lib/ts/recipe/webauthn/recipeImplementation.ts @@ -14,14 +14,14 @@ */ import { RecipeInterface, TypeNormalisedInput } from "./types"; -import AccountLinking from "../accountlinking/recipe"; import { Querier } from "../../querier"; -import { getUser } from "../.."; import RecipeUserId from "../../recipeUserId"; import { LoginMethod, User } from "../../user"; import { AuthUtils } from "../../authUtils"; +import type SuperTokens from "../../supertokens"; export default function getRecipeInterface( + stInstance: SuperTokens, querier: Querier, getWebauthnConfig: () => TypeNormalisedInput ): RecipeInterface { @@ -153,6 +153,7 @@ export default function getRecipeInterface( } const linkResult = await AuthUtils.linkToSessionIfRequiredElseCreatePrimaryUserIdOrLinkByAccountInfo({ + stInstance, tenantId, inputUser: response.user, recipeUserId: response.recipeUserId, @@ -190,18 +191,23 @@ export default function getRecipeInterface( )!; if (!loginMethod.verified) { - await AccountLinking.getInstanceOrThrowError().verifyEmailForRecipeUserIfLinkedAccountsAreVerified({ - user: response.user, - recipeUserId: response.recipeUserId, - userContext, - }); + await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .verifyEmailForRecipeUserIfLinkedAccountsAreVerified({ + user: response.user, + recipeUserId: response.recipeUserId, + userContext, + }); // We do this so that we get the updated user (in case the above // function updated the verification status) and can return that - response.user = (await getUser(response.recipeUserId!.getAsString(), userContext))!; + response.user = (await stInstance + .getRecipeInstanceOrThrow("accountlinking") + .recipeInterfaceImpl.getUser({ userId: response.recipeUserId!.getAsString(), userContext }))!; } const linkResult = await AuthUtils.linkToSessionIfRequiredElseCreatePrimaryUserIdOrLinkByAccountInfo({ + stInstance, tenantId, inputUser: response.user, recipeUserId: response.recipeUserId, diff --git a/lib/ts/recipe/webauthn/utils.ts b/lib/ts/recipe/webauthn/utils.ts index 6a562d617..6399f17eb 100644 --- a/lib/ts/recipe/webauthn/utils.ts +++ b/lib/ts/recipe/webauthn/utils.ts @@ -28,7 +28,7 @@ import { } from "./types"; import { NormalisedAppinfo, UserContext } from "../../types"; import { RecipeInterface, APIInterface } from "./types"; -import { BaseRequest } from "../../framework"; +import type { BaseRequest } from "../../framework"; import BackwardCompatibilityService from "./emaildelivery/services/backwardCompatibility"; export function validateAndNormaliseUserInput( diff --git a/lib/ts/recipeIdToRecipeType.ts b/lib/ts/recipeIdToRecipeType.ts new file mode 100644 index 000000000..e39cdb94b --- /dev/null +++ b/lib/ts/recipeIdToRecipeType.ts @@ -0,0 +1,35 @@ +import SessionRecipe from "./recipe/session/recipe"; +import JwtRecipe from "./recipe/jwt/recipe"; +import MultifactorAuthRecipe from "./recipe/multifactorauth/recipe"; +import MultitenancyRecipe from "./recipe/multitenancy/recipe"; +import OAuth2ProviderRecipe from "./recipe/oauth2provider/recipe"; +import OpenIdRecipe from "./recipe/openid/recipe"; +import PasswordlessRecipe from "./recipe/passwordless/recipe"; +import ThirdPartyRecipe from "./recipe/thirdparty/recipe"; +import TotpRecipe from "./recipe/totp/recipe"; +import UserMetadataRecipe from "./recipe/usermetadata/recipe"; +import UserRolesRecipe from "./recipe/userroles/recipe"; +import WebauthnRecipe from "./recipe/webauthn/recipe"; +import AccountLinkingRecipe from "./recipe/accountlinking/recipe"; +import DashboardRecipe from "./recipe/dashboard/recipe"; +import EmailPasswordRecipe from "./recipe/emailpassword/recipe"; +import EmailVerificationRecipe from "./recipe/emailverification/recipe"; + +export type RecipeIdToRecipeTypeMap = { + [SessionRecipe.RECIPE_ID]: SessionRecipe; + [JwtRecipe.RECIPE_ID]: JwtRecipe; + [MultifactorAuthRecipe.RECIPE_ID]: MultifactorAuthRecipe; + [MultitenancyRecipe.RECIPE_ID]: MultitenancyRecipe; + [OAuth2ProviderRecipe.RECIPE_ID]: OAuth2ProviderRecipe; + [OpenIdRecipe.RECIPE_ID]: OpenIdRecipe; + [PasswordlessRecipe.RECIPE_ID]: PasswordlessRecipe; + [ThirdPartyRecipe.RECIPE_ID]: ThirdPartyRecipe; + [TotpRecipe.RECIPE_ID]: TotpRecipe; + [UserMetadataRecipe.RECIPE_ID]: UserMetadataRecipe; + [UserRolesRecipe.RECIPE_ID]: UserRolesRecipe; + [WebauthnRecipe.RECIPE_ID]: WebauthnRecipe; + [AccountLinkingRecipe.RECIPE_ID]: AccountLinkingRecipe; + [DashboardRecipe.RECIPE_ID]: DashboardRecipe; + [EmailPasswordRecipe.RECIPE_ID]: EmailPasswordRecipe; + [EmailVerificationRecipe.RECIPE_ID]: EmailVerificationRecipe; +}; diff --git a/lib/ts/recipeModule.ts b/lib/ts/recipeModule.ts index 1f3c14b45..bbcfb109d 100644 --- a/lib/ts/recipeModule.ts +++ b/lib/ts/recipeModule.ts @@ -16,15 +16,20 @@ import STError from "./error"; import { NormalisedAppinfo, APIHandled, HTTPMethod, UserContext } from "./types"; import NormalisedURLPath from "./normalisedURLPath"; -import { BaseRequest, BaseResponse } from "./framework"; +import type { BaseRequest, BaseResponse } from "./framework"; import { DEFAULT_TENANT_ID } from "./recipe/multitenancy/constants"; +import { Querier } from "./querier"; +import type SuperTokens from "./supertokens"; export default abstract class RecipeModule { private recipeId: string; - protected appInfo: NormalisedAppinfo; + protected stInstance: SuperTokens; + protected querier: Querier; - constructor(recipeId: string, appInfo: NormalisedAppinfo) { + constructor(stInstance: SuperTokens, recipeId: string, appInfo: NormalisedAppinfo) { + this.stInstance = stInstance; + this.querier = Querier.getNewInstanceOrThrowError(stInstance, recipeId); this.recipeId = recipeId; this.appInfo = appInfo; } @@ -57,11 +62,7 @@ export default abstract class RecipeModule { remainingPath = new NormalisedURLPath(match[2]); } - // Multitenancy recipe is an always initialized recipe and needs to be imported this way - // so that there is no circular dependency. Otherwise there would be cyclic dependency - // between `supertokens.ts` -> `recipeModule.ts` -> `multitenancy/recipe.ts` - let MultitenancyRecipe = require("./recipe/multitenancy/recipe").default; - const mtRecipe = MultitenancyRecipe.getInstanceOrThrowError(); + const mtRecipe = this.stInstance.getRecipeInstanceOrThrow("multitenancy"); for (let i = 0; i < apisHandled.length; i++) { let currAPI = apisHandled[i]; diff --git a/lib/ts/supertokens.ts b/lib/ts/supertokens.ts index ab86c5411..c288a3a15 100644 --- a/lib/ts/supertokens.ts +++ b/lib/ts/supertokens.ts @@ -43,7 +43,7 @@ import { enableDebugLogs, logDebugMessage } from "./logger"; import { PostSuperTokensInitCallbacks } from "./postSuperTokensInitCallbacks"; import { DEFAULT_TENANT_ID } from "./recipe/multitenancy/constants"; import { SessionContainerInterface } from "./recipe/session/types"; -import Session from "./recipe/session/recipe"; +import { RecipeIdToRecipeTypeMap } from "./recipeIdToRecipeType"; export default class SuperTokens { private static instance: SuperTokens | undefined; @@ -153,7 +153,7 @@ export default class SuperTokens { let AccountLinkingRecipe = require("./recipe/accountlinking/recipe").default; this.recipeModules = config.recipeList.map((func) => { - const recipeModule = func(this.appInfo, this.isInServerlessEnv, this.pluginOverrideMaps); + const recipeModule = func(this, this.appInfo, this.isInServerlessEnv, this.pluginOverrideMaps); if (recipeModule.getRecipeId() === MultitenancyRecipe.RECIPE_ID) { multitenancyFound = true; @@ -178,18 +178,22 @@ export default class SuperTokens { if (!accountLinkingFound) { this.recipeModules.push( - AccountLinkingRecipe.init()(this.appInfo, this.isInServerlessEnv, this.pluginOverrideMaps) + AccountLinkingRecipe.init()(this, this.appInfo, this.isInServerlessEnv, this.pluginOverrideMaps) ); } if (!jwtFound) { - this.recipeModules.push(jwtRecipe.init()(this.appInfo, this.isInServerlessEnv, this.pluginOverrideMaps)); + this.recipeModules.push( + jwtRecipe.init()(this, this.appInfo, this.isInServerlessEnv, this.pluginOverrideMaps) + ); } if (!openIdFound) { - this.recipeModules.push(OpenIdRecipe.init()(this.appInfo, this.isInServerlessEnv, this.pluginOverrideMaps)); + this.recipeModules.push( + OpenIdRecipe.init()(this, this.appInfo, this.isInServerlessEnv, this.pluginOverrideMaps) + ); } if (!multitenancyFound) { this.recipeModules.push( - MultitenancyRecipe.init()(this.appInfo, this.isInServerlessEnv, this.pluginOverrideMaps) + MultitenancyRecipe.init()(this, this.appInfo, this.isInServerlessEnv, this.pluginOverrideMaps) ); } if (totpFound && !multiFactorAuthFound) { @@ -199,7 +203,7 @@ export default class SuperTokens { // Initializing the user metadata recipe shouldn't cause any issues/side effects and it doesn't expose any APIs, // so we can just always initialize it this.recipeModules.push( - UserMetadataRecipe.init()(this.appInfo, this.isInServerlessEnv, this.pluginOverrideMaps) + UserMetadataRecipe.init()(this, this.appInfo, this.isInServerlessEnv, this.pluginOverrideMaps) ); } // While for many usecases account linking recipe also has to be initialized for MFA to function well, @@ -210,7 +214,7 @@ export default class SuperTokens { // We've decided to always initialize the OAuth2Provider recipe if (!oauth2Found) { this.recipeModules.push( - OAuth2ProviderRecipe.init()(this.appInfo, this.isInServerlessEnv, this.pluginOverrideMaps) + OAuth2ProviderRecipe.init()(this, this.appInfo, this.isInServerlessEnv, this.pluginOverrideMaps) ); } this.telemetryEnabled = config.telemetry === undefined ? !isTestEnv() : config.telemetry; @@ -279,7 +283,7 @@ export default class SuperTokens { tenantId: string | undefined, userContext: UserContext ): Promise => { - let querier = Querier.getNewInstanceOrThrowError(undefined); + let querier = Querier.getNewInstanceOrThrowError(this); let apiVersion = await querier.getAPIVersion(userContext); if (maxVersion(apiVersion, "2.7") === "2.7") { throw new Error( @@ -323,7 +327,7 @@ export default class SuperTokens { doesExternalUserIdExist: boolean; } > { - let querier = Querier.getNewInstanceOrThrowError(undefined); + let querier = Querier.getNewInstanceOrThrowError(this); let cdiVersion = await querier.getAPIVersion(input.userContext); if (maxVersion("2.15", cdiVersion) === cdiVersion) { // create userId mapping is only available >= CDI 2.15 @@ -357,7 +361,7 @@ export default class SuperTokens { status: "UNKNOWN_MAPPING_ERROR"; } > { - let querier = Querier.getNewInstanceOrThrowError(undefined); + let querier = Querier.getNewInstanceOrThrowError(this); let cdiVersion = await querier.getAPIVersion(input.userContext); if (maxVersion("2.15", cdiVersion) === cdiVersion) { // create userId mapping is only available >= CDI 2.15 @@ -384,7 +388,7 @@ export default class SuperTokens { status: "OK"; didMappingExist: boolean; }> { - let querier = Querier.getNewInstanceOrThrowError(undefined); + let querier = Querier.getNewInstanceOrThrowError(this); let cdiVersion = await querier.getAPIVersion(input.userContext); if (maxVersion("2.15", cdiVersion) === cdiVersion) { return await querier.sendPostRequest( @@ -409,7 +413,7 @@ export default class SuperTokens { }): Promise<{ status: "OK" | "UNKNOWN_MAPPING_ERROR"; }> { - let querier = Querier.getNewInstanceOrThrowError(undefined); + let querier = Querier.getNewInstanceOrThrowError(this); let cdiVersion = await querier.getAPIVersion(input.userContext); if (maxVersion("2.15", cdiVersion) === cdiVersion) { return await querier.sendPutRequest( @@ -438,7 +442,7 @@ export default class SuperTokens { if (handlerFromApis) { let session: SessionContainerInterface | undefined = undefined; if (handlerFromApis.verifySessionOptions !== undefined) { - session = await Session.getInstanceOrThrowError().verifySession( + session = await this.getRecipeInstanceOrThrow("session").verifySession( handlerFromApis.verifySessionOptions, request, response, @@ -677,4 +681,24 @@ export default class SuperTokens { return userContext._default.request; }; + + getRecipeInstanceOrThrow = (recipeId: T): RecipeIdToRecipeTypeMap[T] => { + const recipe = this.recipeModules.find((recipe) => recipe.getRecipeId() === recipeId); + if (recipe === undefined) { + throw new Error( + `Recipe ${recipeId} not initialised. Did you forget to call the add it to the recipe list?` + ); + } + return recipe as RecipeIdToRecipeTypeMap[T]; + }; + + getRecipeInstance = ( + recipeId: T + ): RecipeIdToRecipeTypeMap[T] | undefined => { + const recipe = this.recipeModules.find((recipe) => recipe.getRecipeId() === recipeId); + if (recipe === undefined) { + return undefined; + } + return recipe as RecipeIdToRecipeTypeMap[T]; + }; } diff --git a/lib/ts/thirdpartyUtils.ts b/lib/ts/thirdpartyUtils.ts index 54a268888..811e2061d 100644 --- a/lib/ts/thirdpartyUtils.ts +++ b/lib/ts/thirdpartyUtils.ts @@ -1,6 +1,6 @@ import * as jose from "jose"; import { logDebugMessage } from "./logger"; -import { doFetch } from "./utils"; +import { doFetch } from "./querier"; import NormalisedURLDomain from "./normalisedURLDomain"; import NormalisedURLPath from "./normalisedURLPath"; diff --git a/lib/ts/types.ts b/lib/ts/types.ts index 379b564e4..1bf815b2f 100644 --- a/lib/ts/types.ts +++ b/lib/ts/types.ts @@ -16,9 +16,9 @@ import RecipeModule from "./recipeModule"; import NormalisedURLDomain from "./normalisedURLDomain"; import NormalisedURLPath from "./normalisedURLPath"; -import { TypeFramework } from "./framework/types"; +import type { TypeFramework } from "./framework/types"; import { RecipeLevelUser } from "./recipe/accountlinking/types"; -import { BaseRequest, BaseResponse } from "./framework"; +import type { BaseRequest, BaseResponse } from "./framework"; import type { TypeInput as AccountLinkingTypeInput } from "./recipe/accountlinking/types"; import type { TypeInput as DashboardTypeInput } from "./recipe/dashboard/types"; import type { TypeInput as EmailPasswordTypeInput } from "./recipe/emailpassword/types"; @@ -39,6 +39,7 @@ import type { TypeInput as TotpTypeInput } from "./recipe/totp/types"; import type { TypeInput as UserMetadataTypeInput } from "./recipe/usermetadata/types"; import type { TypeInput as UserRolesTypeInput } from "./recipe/userroles/types"; import type { TypeInput as WebauthnTypeInput } from "./recipe/webauthn/types"; +import type SuperTokens from "./supertokens"; declare const __brand: unique symbol; type Brand = { [__brand]: B }; @@ -203,6 +204,7 @@ export interface HttpRequest { } export type RecipeListFunction = ( + superTokens: SuperTokens, appInfo: NormalisedAppinfo, isInServerlessEnv: boolean, overrideMaps: NonNullable[] diff --git a/lib/ts/utils.ts b/lib/ts/utils.ts index 58ae91d7f..5ba627ea3 100644 --- a/lib/ts/utils.ts +++ b/lib/ts/utils.ts @@ -11,61 +11,13 @@ import type { SuperTokensConfigWithNormalisedAppInfo, } from "./types"; import { nonPublicConfigProperties, NonPublicConfigPropertiesType, Entries } from "./types"; -import NormalisedURLDomain from "./normalisedURLDomain"; +import NormalisedURLDomain, { isAnIpAddress } from "./normalisedURLDomain"; import NormalisedURLPath from "./normalisedURLPath"; import type { BaseRequest, BaseResponse } from "./framework"; import { logDebugMessage } from "./logger"; import { HEADER_FDI, HEADER_RID } from "./constants"; -import crossFetch from "cross-fetch"; import { LoginMethod, User } from "./user"; import { SessionContainer } from "./recipe/session"; -import { ProcessState, PROCESS_STATE } from "./processState"; - -export const doFetch: typeof fetch = async (input: RequestInfo | URL, init?: RequestInit | undefined) => { - // frameworks like nextJS cache fetch GET requests (https://nextjs.org/docs/app/building-your-application/caching#data-cache) - // we don't want that because it may lead to weird behaviour when querying the core. - if (init === undefined) { - ProcessState.getInstance().addState(PROCESS_STATE.ADDING_NO_CACHE_HEADER_IN_FETCH); - init = { - cache: "no-store", - redirect: "manual", - }; - } else { - if (init.cache === undefined) { - ProcessState.getInstance().addState(PROCESS_STATE.ADDING_NO_CACHE_HEADER_IN_FETCH); - init.cache = "no-store"; - init.redirect = "manual"; - } - } - - // Remove the cache field if the runtime is Cloudflare Workers - // - // CF Workers did not support the cache field at all until Nov, 2024 - // when they added support for the `cache` field but it only supports - // `no-store`. - // - // The following check is to ensure that this doesn't error out in - // Cloudflare Workers where compatibility flag is set to an older version. - // - // Since there is no way for us to determine which compatibility flags are - // enabled, we are disabling the cache functionality for CF Workers altogether. - // Ref issue: https://github.com/cloudflare/workerd/issues/698 - if (isRunningInCloudflareWorker()) { - delete init.cache; - } - - const fetchFunction = typeof fetch !== "undefined" ? fetch : crossFetch; - try { - return await fetchFunction(input, init); - } catch (e) { - logDebugMessage("Error fetching: " + e); - throw e; - } -}; - -function isRunningInCloudflareWorker() { - return typeof navigator !== "undefined" && navigator.userAgent === "Cloudflare-Workers"; -} export function getLargestVersionFromIntersection(v1: string[], v2: string[]): string | undefined { let intersection = v1.filter((value) => v2.indexOf(value) !== -1); @@ -207,11 +159,6 @@ function deepTransform(obj: { [key: string]: any }): { [key: string]: any } { return out; } -export function isAnIpAddress(ipaddress: string) { - return /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test( - ipaddress - ); -} export function getNormalisedShouldTryLinkingWithSessionUserFlag(req: BaseRequest, body: any) { if (hasGreaterThanEqualToFDI(req, "3.1")) { return body.shouldTryLinkingWithSessionUser ?? false; @@ -405,54 +352,6 @@ export function getFromObjectCaseInsensitive(key: string, object: Record, - body: any, - { successLog, errorLogHeader }: { successLog: string; errorLogHeader: string } -): Promise<{ resp: { status: number; body: any } } | { error: any }> { - let error; - let resp: { status: number; body: any }; - try { - const fetchResp = await doFetch(url, { - method: "POST", - body: JSON.stringify(body), - headers, - }); - const respText = await fetchResp.text(); - resp = { - status: fetchResp.status, - body: JSON.parse(respText), - }; - if (fetchResp.status < 300) { - logDebugMessage(successLog); - return { resp }; - } - logDebugMessage(errorLogHeader); - logDebugMessage(`Error status: ${fetchResp.status}`); - logDebugMessage(`Error response: ${respText}`); - } catch (caught) { - error = caught; - logDebugMessage(errorLogHeader); - if (error instanceof Error) { - logDebugMessage(`Error: ${error.message}`); - logDebugMessage(`Stack: ${error.stack}`); - } else { - logDebugMessage(`Error: ${JSON.stringify(error)}`); - } - } - logDebugMessage("Logging the input below:"); - logDebugMessage(JSON.stringify(body, null, 2)); - if (error !== undefined) { - return { - error, - }; - } - return { - resp: resp!, - }; -} - export function normaliseEmail(email: string): string { email = email.trim(); email = email.toLowerCase(); diff --git a/package-lock.json b/package-lock.json index 1dbc1ecb2..88c12d0e9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,7 @@ "pako": "^2.1.0", "pkce-challenge": "^3.0.0", "process": "^0.11.10", - "set-cookie-parser": "^2.6.0", + "set-cookie-parser": "^2.7.1", "supertokens-js-override": "^0.0.4", "tldts": "^6.1.48", "twilio": "^4.19.3" @@ -56,9 +56,12 @@ "lambda-tester": "^4.0.1", "loopback-datasource-juggler": "^4.26.0", "mocha": "^10.2.0", + "mocha-json-output-reporter": "^2.1.0", + "mocha-junit-reporter": "^2.2.1", + "mocha-multi-reporters": "^1.5.1", "mocha-split-tests": "github:rishabhpoddar/mocha-split-tests", "next": "^14.0.4", - "next-test-api-route-handler": "^3.1.10", + "next-test-api-route-handler": "^4.0.16", "nock": "11.7.0", "node-fetch": "^3.3.2", "nyc": "^15.1.0", @@ -496,6 +499,20 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@envelop/instrumentation": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@envelop/instrumentation/-/instrumentation-1.0.0.tgz", + "integrity": "sha512-cxgkB66RQB95H3X27jlnxCRNTmPuSTgmBAq6/4n2Dtv4hsk4yz8FadA1ggmd0uZzvKqWD6CR+WFgTjhDqg7eyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@whatwg-node/promise-helpers": "^1.2.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@extra-number/significant-digits": { "version": "1.3.9", "resolved": "https://registry.npmjs.org/@extra-number/significant-digits/-/significant-digits-1.3.9.tgz", @@ -512,6 +529,13 @@ "ajv": "^6.12.6" } }, + "node_modules/@fastify/busboy": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-3.2.0.tgz", + "integrity": "sha512-m9FVDXU3GT2ITSe0UaMA5rU3QkfC/UXtCU8y0gSN/GugTqtVldOBWIB5V6V3sbmenVZUIpU6f+mPEO2+m5iTaA==", + "dev": true, + "license": "MIT" + }, "node_modules/@gerrit0/mini-shiki": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/@gerrit0/mini-shiki/-/mini-shiki-3.7.0.tgz", @@ -1972,6 +1996,80 @@ "node": ">=18.20.0" } }, + "node_modules/@whatwg-node/disposablestack": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@whatwg-node/disposablestack/-/disposablestack-0.0.6.tgz", + "integrity": "sha512-LOtTn+JgJvX8WfBVJtF08TGrdjuFzGJc4mkP8EdDI8ADbvO7kiexYep1o8dwnt0okb0jYclCDXF13xU7Ge4zSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@whatwg-node/promise-helpers": "^1.0.0", + "tslib": "^2.6.3" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@whatwg-node/fetch": { + "version": "0.10.13", + "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.10.13.tgz", + "integrity": "sha512-b4PhJ+zYj4357zwk4TTuF2nEe0vVtOrwdsrNo5hL+u1ojXNhh1FgJ6pg1jzDlwlT4oBdzfSwaBwMCtFCsIWg8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@whatwg-node/node-fetch": "^0.8.3", + "urlpattern-polyfill": "^10.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@whatwg-node/node-fetch": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.8.4.tgz", + "integrity": "sha512-AlKLc57loGoyYlrzDbejB9EeR+pfdJdGzbYnkEuZaGekFboBwzfVYVMsy88PMriqPI1ORpiGYGgSSWpx7a2sDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@fastify/busboy": "^3.1.1", + "@whatwg-node/disposablestack": "^0.0.6", + "@whatwg-node/promise-helpers": "^1.3.2", + "tslib": "^2.6.3" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@whatwg-node/promise-helpers": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@whatwg-node/promise-helpers/-/promise-helpers-1.3.2.tgz", + "integrity": "sha512-Nst5JdK47VIl9UcGwtv2Rcgyn5lWtZ0/mhRQ4G8NN2isxpq2TO30iqHzmwoJycjWuyUfg3GFXqP/gFHXeV57IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.6.3" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@whatwg-node/server": { + "version": "0.10.17", + "resolved": "https://registry.npmjs.org/@whatwg-node/server/-/server-0.10.17.tgz", + "integrity": "sha512-QxI+HQfJeI/UscFNCTcSri6nrHP25mtyAMbhEri7W2ctdb3EsorPuJz7IovSgNjvKVs73dg9Fmayewx1O2xOxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@envelop/instrumentation": "^1.0.0", + "@whatwg-node/disposablestack": "^0.0.6", + "@whatwg-node/fetch": "^0.10.13", + "@whatwg-node/promise-helpers": "^1.3.2", + "tslib": "^2.6.3" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/abstract-logging": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz", @@ -3101,11 +3199,12 @@ } }, "node_modules/core-js": { - "version": "3.36.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.36.1.tgz", - "integrity": "sha512-BTvUrwxVBezj5SZ3f10ImnX2oRByMxql3EimVqMysepbC9EeMUOpLwdy6Eoili2x6E4kf+ZUB5k/+Jv55alPfA==", + "version": "3.47.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.47.0.tgz", + "integrity": "sha512-c3Q2VVkGAUyupsjRnaNX6u8Dq2vAdzm9iuPj5FW0fRxzlxgq9Q39MDq10IvmQSpLgHQNyQzQmOo6bgGHmH3NNg==", "dev": true, "hasInstallScript": true, + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/core-js" @@ -5778,6 +5877,90 @@ "node": ">= 14.0.0" } }, + "node_modules/mocha-json-output-reporter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mocha-json-output-reporter/-/mocha-json-output-reporter-2.1.0.tgz", + "integrity": "sha512-FF2BItlMo8nK9+SgN/WAD01ue7G+qI1Po0U3JCZXQiiyTJ5OV3KcT1mSoZKirjYP73JFZznaaPC6Mp052PF3Vw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "mocha": "^10.0.0", + "moment": "^2.21.0" + } + }, + "node_modules/mocha-junit-reporter": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/mocha-junit-reporter/-/mocha-junit-reporter-2.2.1.tgz", + "integrity": "sha512-iDn2tlKHn8Vh8o4nCzcUVW4q7iXp7cC4EB78N0cDHIobLymyHNwe0XG8HEHHjc3hJlXm0Vy6zcrxaIhnI2fWmw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4", + "md5": "^2.3.0", + "mkdirp": "^3.0.0", + "strip-ansi": "^6.0.1", + "xml": "^1.0.1" + }, + "peerDependencies": { + "mocha": ">=2.2.5" + } + }, + "node_modules/mocha-junit-reporter/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha-junit-reporter/node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha-junit-reporter/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha-multi-reporters": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/mocha-multi-reporters/-/mocha-multi-reporters-1.5.1.tgz", + "integrity": "sha512-Yb4QJOaGLIcmB0VY7Wif5AjvLMUFAdV57D2TWEva1Y0kU/3LjKpeRVmlMIfuO1SVbauve459kgtIizADqxMWPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "lodash": "^4.17.15" + }, + "engines": { + "node": ">=6.0.0" + }, + "peerDependencies": { + "mocha": ">=3.1.2" + } + }, "node_modules/mocha-split-tests": { "version": "1.4.0", "resolved": "git+ssh://git@github.com/rishabhpoddar/mocha-split-tests.git#b0bd99a7d5870493dbe921dbdd5195b47e555035", @@ -5850,6 +6033,17 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "*" + } + }, "node_modules/mri": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", @@ -5980,55 +6174,31 @@ } }, "node_modules/next-test-api-route-handler": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/next-test-api-route-handler/-/next-test-api-route-handler-3.2.0.tgz", - "integrity": "sha512-gEev0YpErOjcfGY6Vj50xKAFBYCymYTdVCQuid1rqY2NIbA99GrTIEs79j6FF7+6j2R6ruQPcbwt+z0f9Z1J9w==", + "version": "4.0.16", + "resolved": "https://registry.npmjs.org/next-test-api-route-handler/-/next-test-api-route-handler-4.0.16.tgz", + "integrity": "sha512-13YKH1X52YzZKDU1fplR3DS6SRZUx+wsw6x6XZXGJnjUWEPL9HmVdyX9/i/8Rv4kC2UXisqLPuTGePTvWRAZGQ==", "dev": true, + "license": "MIT", "dependencies": { - "cookie": "^0.6.0", - "core-js": "^3.35.0", - "node-fetch": "^2.6.7" + "@whatwg-node/server": "^0.10.3", + "cookie": "^1.0.2", + "core-js": "^3.41.0" }, "engines": { - "node": ">=12" + "node": "^18.18.2 || ^20.10.0 || >=21.2.0" }, "peerDependencies": { - "msw": ">=2", "next": ">=9" - }, - "peerDependenciesMeta": { - "msw": { - "optional": true - } } }, "node_modules/next-test-api-route-handler/node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/next-test-api-route-handler/node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", "dev": true, - "dependencies": { - "whatwg-url": "^5.0.0" - }, + "license": "MIT", "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } + "node": ">=18" } }, "node_modules/nise": { @@ -7451,9 +7621,10 @@ "dev": true }, "node_modules/set-cookie-parser": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz", - "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==" + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", + "license": "MIT" }, "node_modules/set-function-length": { "version": "1.2.2", @@ -8119,10 +8290,11 @@ } }, "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" }, "node_modules/tsscmp": { "version": "1.0.6", @@ -8372,6 +8544,13 @@ "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==", "dev": true }, + "node_modules/urlpattern-polyfill": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.1.0.tgz", + "integrity": "sha512-IGjKp/o0NL3Bso1PymYURCJxMPNAf/ILOpendP9f5B6e1rTJgdgiOvgfoT8VxCAdY+Wisb9uhGaJJf3yZ2V9nw==", + "dev": true, + "license": "MIT" + }, "node_modules/util": { "version": "0.12.5", "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", @@ -8574,6 +8753,13 @@ "typedarray-to-buffer": "^3.1.5" } }, + "node_modules/xml": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", + "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==", + "dev": true, + "license": "MIT" + }, "node_modules/xml2js": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", diff --git a/test/config.test.js b/test/config.test.js index e05c0e470..e1d7edbe3 100644 --- a/test/config.test.js +++ b/test/config.test.js @@ -227,7 +227,7 @@ describe(`configTest: ${printPath("[test/config.test.js]")}`, function () { recipeList: [Session.init({ getTokenTransferMethod: () => "cookie" })], }); SessionRecipe.getInstanceOrThrowError(); - assert.strictEqual(SuperTokens.getInstanceOrThrowError().recipeModules.length, 6); // openid,jwt,multitenancy,usermetadata&oauth2provider is initialised by default + assert.strictEqual(SuperTokens.getInstanceOrThrowError().recipeModules.length, 7); // accountlinking,openid,jwt,multitenancy,usermetadata&oauth2provider is initialised by default resetAll(); } @@ -245,7 +245,7 @@ describe(`configTest: ${printPath("[test/config.test.js]")}`, function () { }); SessionRecipe.getInstanceOrThrowError(); EmailPasswordRecipe.getInstanceOrThrowError(); - assert(SuperTokens.getInstanceOrThrowError().recipeModules.length === 7); // openid,jwt,multitenancy,usermetadata&oauth2provider is initialised by default + assert(SuperTokens.getInstanceOrThrowError().recipeModules.length === 8); // accountlinking,openid,jwt,multitenancy,usermetadata&oauth2provider is initialised by default resetAll(); } }); diff --git a/test/emailpassword/deleteUser.test.js b/test/emailpassword/deleteUser.test.js index d9bf9b978..328af4f3c 100644 --- a/test/emailpassword/deleteUser.test.js +++ b/test/emailpassword/deleteUser.test.js @@ -59,22 +59,18 @@ describe(`deleteUser: ${printPath("[test/emailpassword/deleteUser.test.js]")}`, recipeList: [EmailPassword.init(), Session.init({ getTokenTransferMethod: () => "cookie" })], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let cdiVersion = await querier.getAPIVersion(); - if (maxVersion("2.10", cdiVersion) === cdiVersion) { - let user = await EmailPassword.signUp("public", "test@example.com", "1234abcd"); + let user = await EmailPassword.signUp("public", "test@example.com", "1234abcd"); - { - let response = await STExpress.getUsersOldestFirst({ tenantId: "public" }); - assert(response.users.length === 1); - } + { + let response = await STExpress.getUsersOldestFirst({ tenantId: "public" }); + assert(response.users.length === 1); + } - await STExpress.deleteUser(user.user.id); + await STExpress.deleteUser(user.user.id); - { - let response = await STExpress.getUsersOldestFirst({ tenantId: "public" }); - assert(response.users.length === 0); - } + { + let response = await STExpress.getUsersOldestFirst({ tenantId: "public" }); + assert(response.users.length === 0); } }); }); diff --git a/test/emailpassword/emailverify.test.js b/test/emailpassword/emailverify.test.js index 055d66c5e..3b6304fc8 100644 --- a/test/emailpassword/emailverify.test.js +++ b/test/emailpassword/emailverify.test.js @@ -1205,11 +1205,6 @@ describe(`emailverify: ${printPath("[test/emailpassword/emailverify.test.js]")}` ], }); - let apiVersion = await Querier.getNewInstanceOrThrowError(undefined).getAPIVersion(); - if (maxVersion(apiVersion, "2.7") === "2.7") { - return; - } - const app = express(); app.use(middleware()); @@ -1251,11 +1246,6 @@ describe(`emailverify: ${printPath("[test/emailpassword/emailverify.test.js]")}` ], }); - let apiVersion = await Querier.getNewInstanceOrThrowError(undefined).getAPIVersion(); - if (maxVersion(apiVersion, "2.7") === "2.7") { - return; - } - const app = express(); app.use(middleware()); @@ -1319,12 +1309,6 @@ describe(`emailverify: ${printPath("[test/emailpassword/emailverify.test.js]")}` app.use(errorHandler()); - const querier = Querier.getNewInstanceOrThrowError(undefined); - const apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.10") !== apiVersion) { - return this.skip(); - } - let response = await signUPRequest(app, "test@gmail.com", "testPass123"); assert.strictEqual(response.body.status, "OK"); assert.strictEqual(response.status, 200); @@ -1374,12 +1358,6 @@ describe(`emailverify: ${printPath("[test/emailpassword/emailverify.test.js]")}` app.use(errorHandler()); - const querier = Querier.getNewInstanceOrThrowError(undefined); - const apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.10") !== apiVersion) { - return this.skip(); - } - let response = await signUPRequest(app, "test@gmail.com", "testPass123"); assert.strictEqual(response.body.status, "OK"); assert.strictEqual(response.status, 200); diff --git a/test/emailpassword/updateEmailPass.test.js b/test/emailpassword/updateEmailPass.test.js index 96274f179..5c9d99cbe 100644 --- a/test/emailpassword/updateEmailPass.test.js +++ b/test/emailpassword/updateEmailPass.test.js @@ -43,11 +43,6 @@ describe(`updateEmailPassTest: ${printPath("[test/emailpassword/updateEmailPass. recipeList: [EmailPassword.init(), Session.init({ getTokenTransferMethod: () => "cookie" })], }); - let apiVersion = await Querier.getNewInstanceOrThrowError(undefined).getAPIVersion(); - if (maxVersion(apiVersion, "2.7") === "2.7") { - return; - } - const express = require("express"); const app = express(); @@ -103,11 +98,6 @@ describe(`updateEmailPassTest: ${printPath("[test/emailpassword/updateEmailPass. ], }); - let apiVersion = await Querier.getNewInstanceOrThrowError(undefined).getAPIVersion(); - if (maxVersion(apiVersion, "2.7") === "2.7") { - return; - } - const express = require("express"); const app = express(); @@ -161,11 +151,6 @@ describe(`updateEmailPassTest: ${printPath("[test/emailpassword/updateEmailPass. ], }); - let apiVersion = await Querier.getNewInstanceOrThrowError(undefined).getAPIVersion(); - if (maxVersion(apiVersion, "2.7") === "2.7") { - return; - } - const express = require("express"); const app = express(); @@ -200,11 +185,6 @@ describe(`updateEmailPassTest: ${printPath("[test/emailpassword/updateEmailPass. recipeList: [EmailPassword.init(), Session.init({ getTokenTransferMethod: () => "cookie" })], }); - let apiVersion = await Querier.getNewInstanceOrThrowError(undefined).getAPIVersion(); - if (maxVersion(apiVersion, "2.7") === "2.7") { - return; - } - const express = require("express"); const app = express(); diff --git a/test/emailpassword/users.test.js b/test/emailpassword/users.test.js index 15d8e340c..9080d2dd5 100644 --- a/test/emailpassword/users.test.js +++ b/test/emailpassword/users.test.js @@ -121,11 +121,6 @@ describe(`usersTest: ${printPath("[test/emailpassword/users.test.js]")}`, functi app.use(errorHandler()); - const cdiVersion = await Querier.getNewInstanceOrThrowError("emailpassword").getAPIVersion(); - if (maxVersion("2.20", cdiVersion) !== cdiVersion) { - return; - } - const randomValue = Math.random(); const emails = [ Math.random() + "@gmail.com", @@ -243,11 +238,6 @@ describe(`usersTest: ${printPath("[test/emailpassword/users.test.js]")}`, functi app.use(errorHandler()); - const cdiVersion = await Querier.getNewInstanceOrThrowError("emailpassword").getAPIVersion(); - if (maxVersion("2.20", cdiVersion) !== cdiVersion) { - return; - } - const randomValue = Math.random(); const emails = [ Math.random() + "@gmail.com", diff --git a/test/framework/awsLambda.test.js b/test/framework/awsLambda.test.js index 4fceaa15f..6537b1f18 100644 --- a/test/framework/awsLambda.test.js +++ b/test/framework/awsLambda.test.js @@ -691,12 +691,6 @@ describe(`AWS Lambda: ${printPath("[test/framework/awsLambda.test.js]")}`, funct ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - let proxy = "/dev"; let event = mockLambdaProxyEventV2( @@ -749,12 +743,6 @@ describe(`AWS Lambda: ${printPath("[test/framework/awsLambda.test.js]")}`, funct ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - let proxy = "/dev"; await createUsers(EmailPassword); @@ -812,12 +800,6 @@ describe(`AWS Lambda: ${printPath("[test/framework/awsLambda.test.js]")}`, funct ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - let proxy = "/dev"; await createUsers(EmailPassword); @@ -874,12 +856,6 @@ describe(`AWS Lambda: ${printPath("[test/framework/awsLambda.test.js]")}`, funct EmailPassword.init(), ], }); - - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } let proxy = "/dev"; await createUsers(EmailPassword); @@ -939,12 +915,6 @@ describe(`AWS Lambda: ${printPath("[test/framework/awsLambda.test.js]")}`, funct }), ], }); - - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } let proxy = "/dev"; await createUsers(null, Passwordless); @@ -1004,12 +974,6 @@ describe(`AWS Lambda: ${printPath("[test/framework/awsLambda.test.js]")}`, funct }), ], }); - - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } let proxy = "/dev"; await createUsers(null, Passwordless); @@ -1110,12 +1074,6 @@ describe(`AWS Lambda: ${printPath("[test/framework/awsLambda.test.js]")}`, funct }), ], }); - - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } let proxy = "/dev"; await createUsers(null, null, ThirdParty); @@ -1220,12 +1178,6 @@ describe(`AWS Lambda: ${printPath("[test/framework/awsLambda.test.js]")}`, funct }), ], }); - - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } let proxy = "/dev"; await createUsers(null, null, ThirdParty); diff --git a/test/framework/awsLambda.withTenantId.test.js b/test/framework/awsLambda.withTenantId.test.js index a5aa2aab8..fcaeee2fd 100644 --- a/test/framework/awsLambda.withTenantId.test.js +++ b/test/framework/awsLambda.withTenantId.test.js @@ -696,12 +696,6 @@ describe(`AWS Lambda: ${printPath("[test/framework/awsLambda.withTenantId.test.j ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - let proxy = "/dev"; let event = mockLambdaProxyEventV2( @@ -754,12 +748,6 @@ describe(`AWS Lambda: ${printPath("[test/framework/awsLambda.withTenantId.test.j ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - let proxy = "/dev"; await createUsers(EmailPassword); @@ -817,12 +805,6 @@ describe(`AWS Lambda: ${printPath("[test/framework/awsLambda.withTenantId.test.j ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - let proxy = "/dev"; await createUsers(EmailPassword); @@ -880,11 +862,6 @@ describe(`AWS Lambda: ${printPath("[test/framework/awsLambda.withTenantId.test.j ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } let proxy = "/dev"; await createUsers(EmailPassword); @@ -945,11 +922,6 @@ describe(`AWS Lambda: ${printPath("[test/framework/awsLambda.withTenantId.test.j ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } let proxy = "/dev"; await createUsers(null, Passwordless); @@ -1010,11 +982,6 @@ describe(`AWS Lambda: ${printPath("[test/framework/awsLambda.withTenantId.test.j ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } let proxy = "/dev"; await createUsers(null, Passwordless); @@ -1116,11 +1083,6 @@ describe(`AWS Lambda: ${printPath("[test/framework/awsLambda.withTenantId.test.j ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } let proxy = "/dev"; await createUsers(null, null, ThirdParty); @@ -1226,11 +1188,6 @@ describe(`AWS Lambda: ${printPath("[test/framework/awsLambda.withTenantId.test.j ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } let proxy = "/dev"; await createUsers(null, null, ThirdParty); diff --git a/test/framework/fastify.test.js b/test/framework/fastify.test.js index df062e783..16292379e 100644 --- a/test/framework/fastify.test.js +++ b/test/framework/fastify.test.js @@ -1462,12 +1462,6 @@ describe(`Fastify: ${printPath("[test/framework/fastify.test.js]")}`, function ( ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.server.register(FastifyFramework.plugin); let resp = await this.server.inject({ method: "get", @@ -1514,12 +1508,6 @@ describe(`Fastify: ${printPath("[test/framework/fastify.test.js]")}`, function ( ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.server.register(FastifyFramework.plugin); await createUsers(EmailPassword); let resp = await this.server.inject({ @@ -1567,12 +1555,6 @@ describe(`Fastify: ${printPath("[test/framework/fastify.test.js]")}`, function ( ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.server.register(FastifyFramework.plugin); await createUsers(EmailPassword); let resp = await this.server.inject({ @@ -1620,12 +1602,6 @@ describe(`Fastify: ${printPath("[test/framework/fastify.test.js]")}`, function ( ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.server.register(FastifyFramework.plugin); await createUsers(EmailPassword); let resp = await this.server.inject({ @@ -1676,12 +1652,6 @@ describe(`Fastify: ${printPath("[test/framework/fastify.test.js]")}`, function ( ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await createUsers(null, Passwordless); await this.server.register(FastifyFramework.plugin); let resp = await this.server.inject({ @@ -1732,12 +1702,6 @@ describe(`Fastify: ${printPath("[test/framework/fastify.test.js]")}`, function ( ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await createUsers(null, null); await this.server.register(FastifyFramework.plugin); let resp = await this.server.inject({ @@ -1829,12 +1793,6 @@ describe(`Fastify: ${printPath("[test/framework/fastify.test.js]")}`, function ( ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await createUsers(null, null, ThirdParty); await this.server.register(FastifyFramework.plugin); let resp = await this.server.inject({ @@ -1930,12 +1888,6 @@ describe(`Fastify: ${printPath("[test/framework/fastify.test.js]")}`, function ( ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await createUsers(null, Passwordless, ThirdParty); await this.server.register(FastifyFramework.plugin); let resp = await this.server.inject({ diff --git a/test/framework/fastify.withTenantId.test.js b/test/framework/fastify.withTenantId.test.js index 83f1a4a67..cfc251916 100644 --- a/test/framework/fastify.withTenantId.test.js +++ b/test/framework/fastify.withTenantId.test.js @@ -1460,12 +1460,6 @@ describe(`Fastify: ${printPath("[test/framework/fastify.withTenantId.test.js]")} ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.server.register(FastifyFramework.plugin); let resp = await this.server.inject({ method: "get", @@ -1512,12 +1506,6 @@ describe(`Fastify: ${printPath("[test/framework/fastify.withTenantId.test.js]")} ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.server.register(FastifyFramework.plugin); await createUsers(EmailPassword); let resp = await this.server.inject({ @@ -1565,12 +1553,6 @@ describe(`Fastify: ${printPath("[test/framework/fastify.withTenantId.test.js]")} ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.server.register(FastifyFramework.plugin); await createUsers(EmailPassword); let resp = await this.server.inject({ @@ -1618,12 +1600,6 @@ describe(`Fastify: ${printPath("[test/framework/fastify.withTenantId.test.js]")} ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.server.register(FastifyFramework.plugin); await createUsers(EmailPassword); let resp = await this.server.inject({ @@ -1674,12 +1650,6 @@ describe(`Fastify: ${printPath("[test/framework/fastify.withTenantId.test.js]")} ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await createUsers(null, Passwordless); await this.server.register(FastifyFramework.plugin); let resp = await this.server.inject({ @@ -1730,12 +1700,6 @@ describe(`Fastify: ${printPath("[test/framework/fastify.withTenantId.test.js]")} ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await createUsers(null, null); await this.server.register(FastifyFramework.plugin); let resp = await this.server.inject({ @@ -1827,12 +1791,6 @@ describe(`Fastify: ${printPath("[test/framework/fastify.withTenantId.test.js]")} ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await createUsers(null, null, ThirdParty); await this.server.register(FastifyFramework.plugin); let resp = await this.server.inject({ @@ -1928,12 +1886,6 @@ describe(`Fastify: ${printPath("[test/framework/fastify.withTenantId.test.js]")} ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await createUsers(null, Passwordless, ThirdParty); await this.server.register(FastifyFramework.plugin); let resp = await this.server.inject({ diff --git a/test/framework/hapi.test.js b/test/framework/hapi.test.js index 0532df656..8357b6f7b 100644 --- a/test/framework/hapi.test.js +++ b/test/framework/hapi.test.js @@ -1465,12 +1465,6 @@ describe(`Hapi: ${printPath("[test/framework/hapi.test.js]")}`, function () { ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.server.register(HapiFramework.plugin); await this.server.initialize(); @@ -1520,12 +1514,6 @@ describe(`Hapi: ${printPath("[test/framework/hapi.test.js]")}`, function () { ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.server.register(HapiFramework.plugin); await this.server.initialize(); @@ -1575,12 +1563,6 @@ describe(`Hapi: ${printPath("[test/framework/hapi.test.js]")}`, function () { ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.server.register(HapiFramework.plugin); await this.server.initialize(); @@ -1629,12 +1611,6 @@ describe(`Hapi: ${printPath("[test/framework/hapi.test.js]")}`, function () { ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.server.register(HapiFramework.plugin); await this.server.initialize(); @@ -1687,12 +1663,6 @@ describe(`Hapi: ${printPath("[test/framework/hapi.test.js]")}`, function () { ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.server.register(HapiFramework.plugin); await this.server.initialize(); @@ -1745,12 +1715,6 @@ describe(`Hapi: ${printPath("[test/framework/hapi.test.js]")}`, function () { ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.server.register(HapiFramework.plugin); await this.server.initialize(); @@ -1848,12 +1812,6 @@ describe(`Hapi: ${printPath("[test/framework/hapi.test.js]")}`, function () { ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.server.register(HapiFramework.plugin); await this.server.initialize(); @@ -1947,12 +1905,6 @@ describe(`Hapi: ${printPath("[test/framework/hapi.test.js]")}`, function () { ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.server.register(HapiFramework.plugin); await this.server.initialize(); diff --git a/test/framework/hapi.withTenantId.test.js b/test/framework/hapi.withTenantId.test.js index 68fb618ee..ee1cc8f3e 100644 --- a/test/framework/hapi.withTenantId.test.js +++ b/test/framework/hapi.withTenantId.test.js @@ -1463,12 +1463,6 @@ describe(`Hapi: ${printPath("[test/framework/hapi.withTenantId.test.js]")}`, fun ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.server.register(HapiFramework.plugin); await this.server.initialize(); @@ -1518,12 +1512,6 @@ describe(`Hapi: ${printPath("[test/framework/hapi.withTenantId.test.js]")}`, fun ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.server.register(HapiFramework.plugin); await this.server.initialize(); @@ -1573,12 +1561,6 @@ describe(`Hapi: ${printPath("[test/framework/hapi.withTenantId.test.js]")}`, fun ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.server.register(HapiFramework.plugin); await this.server.initialize(); @@ -1627,12 +1609,6 @@ describe(`Hapi: ${printPath("[test/framework/hapi.withTenantId.test.js]")}`, fun ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.server.register(HapiFramework.plugin); await this.server.initialize(); @@ -1685,12 +1661,6 @@ describe(`Hapi: ${printPath("[test/framework/hapi.withTenantId.test.js]")}`, fun ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.server.register(HapiFramework.plugin); await this.server.initialize(); @@ -1743,12 +1713,6 @@ describe(`Hapi: ${printPath("[test/framework/hapi.withTenantId.test.js]")}`, fun ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.server.register(HapiFramework.plugin); await this.server.initialize(); @@ -1846,12 +1810,6 @@ describe(`Hapi: ${printPath("[test/framework/hapi.withTenantId.test.js]")}`, fun ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.server.register(HapiFramework.plugin); await this.server.initialize(); @@ -1945,12 +1903,6 @@ describe(`Hapi: ${printPath("[test/framework/hapi.withTenantId.test.js]")}`, fun ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.server.register(HapiFramework.plugin); await this.server.initialize(); diff --git a/test/framework/koa.test.js b/test/framework/koa.test.js index 5eb6595ec..4be4858bc 100644 --- a/test/framework/koa.test.js +++ b/test/framework/koa.test.js @@ -1594,12 +1594,6 @@ describe(`Koa: ${printPath("[test/framework/koa.test.js]")}`, function () { ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - const app = new Koa(); app.use(KoaFramework.middleware()); this.server = app.listen(9999); @@ -1653,12 +1647,6 @@ describe(`Koa: ${printPath("[test/framework/koa.test.js]")}`, function () { ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - const app = new Koa(); app.use(KoaFramework.middleware()); this.server = app.listen(9999); @@ -1717,12 +1705,6 @@ describe(`Koa: ${printPath("[test/framework/koa.test.js]")}`, function () { ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - const app = new Koa(); app.use(KoaFramework.middleware()); this.server = app.listen(9999); @@ -1781,12 +1763,6 @@ describe(`Koa: ${printPath("[test/framework/koa.test.js]")}`, function () { ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - const app = new Koa(); app.use(KoaFramework.middleware()); this.server = app.listen(9999); @@ -1848,12 +1824,6 @@ describe(`Koa: ${printPath("[test/framework/koa.test.js]")}`, function () { ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - const app = new Koa(); app.use(KoaFramework.middleware()); this.server = app.listen(9999); @@ -1915,12 +1885,6 @@ describe(`Koa: ${printPath("[test/framework/koa.test.js]")}`, function () { ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - const app = new Koa(); app.use(KoaFramework.middleware()); this.server = app.listen(9999); @@ -2023,12 +1987,6 @@ describe(`Koa: ${printPath("[test/framework/koa.test.js]")}`, function () { ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - const app = new Koa(); app.use(KoaFramework.middleware()); this.server = app.listen(9999); @@ -2135,12 +2093,6 @@ describe(`Koa: ${printPath("[test/framework/koa.test.js]")}`, function () { ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - const app = new Koa(); app.use(KoaFramework.middleware()); this.server = app.listen(9999); diff --git a/test/framework/koa.withTenantId.test.js b/test/framework/koa.withTenantId.test.js index 3d12ba25e..4cb14ceb2 100644 --- a/test/framework/koa.withTenantId.test.js +++ b/test/framework/koa.withTenantId.test.js @@ -1592,12 +1592,6 @@ describe(`Koa: ${printPath("[test/framework/koa.withTenantId.test.js]")}`, funct ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - const app = new Koa(); app.use(KoaFramework.middleware()); this.server = app.listen(9999); @@ -1651,12 +1645,6 @@ describe(`Koa: ${printPath("[test/framework/koa.withTenantId.test.js]")}`, funct ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - const app = new Koa(); app.use(KoaFramework.middleware()); this.server = app.listen(9999); @@ -1715,12 +1703,6 @@ describe(`Koa: ${printPath("[test/framework/koa.withTenantId.test.js]")}`, funct ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - const app = new Koa(); app.use(KoaFramework.middleware()); this.server = app.listen(9999); @@ -1779,12 +1761,6 @@ describe(`Koa: ${printPath("[test/framework/koa.withTenantId.test.js]")}`, funct ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - const app = new Koa(); app.use(KoaFramework.middleware()); this.server = app.listen(9999); @@ -1846,12 +1822,6 @@ describe(`Koa: ${printPath("[test/framework/koa.withTenantId.test.js]")}`, funct ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - const app = new Koa(); app.use(KoaFramework.middleware()); this.server = app.listen(9999); @@ -1913,12 +1883,6 @@ describe(`Koa: ${printPath("[test/framework/koa.withTenantId.test.js]")}`, funct ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - const app = new Koa(); app.use(KoaFramework.middleware()); this.server = app.listen(9999); @@ -2021,12 +1985,6 @@ describe(`Koa: ${printPath("[test/framework/koa.withTenantId.test.js]")}`, funct ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - const app = new Koa(); app.use(KoaFramework.middleware()); this.server = app.listen(9999); @@ -2133,12 +2091,6 @@ describe(`Koa: ${printPath("[test/framework/koa.withTenantId.test.js]")}`, funct ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - const app = new Koa(); app.use(KoaFramework.middleware()); this.server = app.listen(9999); diff --git a/test/framework/loopback.test.js b/test/framework/loopback.test.js index 4a81fcd0c..73c70a69c 100644 --- a/test/framework/loopback.test.js +++ b/test/framework/loopback.test.js @@ -310,12 +310,6 @@ describe(`Loopback: ${printPath("[test/framework/loopback.test.js]")}`, function ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.app.start(); let result = await request({ @@ -363,12 +357,6 @@ describe(`Loopback: ${printPath("[test/framework/loopback.test.js]")}`, function ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.app.start(); await createUsers(EmailPassword); @@ -421,12 +409,6 @@ describe(`Loopback: ${printPath("[test/framework/loopback.test.js]")}`, function ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.app.start(); await createUsers(EmailPassword); @@ -480,12 +462,6 @@ describe(`Loopback: ${printPath("[test/framework/loopback.test.js]")}`, function ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.app.start(); await createUsers(EmailPassword); @@ -542,12 +518,6 @@ describe(`Loopback: ${printPath("[test/framework/loopback.test.js]")}`, function ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.app.start(); await createUsers(null, Passwordless); @@ -604,12 +574,6 @@ describe(`Loopback: ${printPath("[test/framework/loopback.test.js]")}`, function ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.app.start(); await createUsers(null, Passwordless); @@ -711,12 +675,6 @@ describe(`Loopback: ${printPath("[test/framework/loopback.test.js]")}`, function ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.app.start(); await createUsers(null, Passwordless, ThirdParty); @@ -815,12 +773,6 @@ describe(`Loopback: ${printPath("[test/framework/loopback.test.js]")}`, function ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.app.start(); await createUsers(null, null, ThirdParty); diff --git a/test/framework/loopback.withTenantId.test.js b/test/framework/loopback.withTenantId.test.js index 9874863ac..b42cc3bca 100644 --- a/test/framework/loopback.withTenantId.test.js +++ b/test/framework/loopback.withTenantId.test.js @@ -308,12 +308,6 @@ describe(`Loopback: ${printPath("[test/framework/loopback.withTenantId.test.js]" ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.app.start(); let result = await request({ @@ -361,12 +355,6 @@ describe(`Loopback: ${printPath("[test/framework/loopback.withTenantId.test.js]" ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.app.start(); await createUsers(EmailPassword); @@ -419,12 +407,6 @@ describe(`Loopback: ${printPath("[test/framework/loopback.withTenantId.test.js]" ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.app.start(); await createUsers(EmailPassword); @@ -478,12 +460,6 @@ describe(`Loopback: ${printPath("[test/framework/loopback.withTenantId.test.js]" ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.app.start(); await createUsers(EmailPassword); @@ -540,12 +516,6 @@ describe(`Loopback: ${printPath("[test/framework/loopback.withTenantId.test.js]" ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.app.start(); await createUsers(null, Passwordless); @@ -602,12 +572,6 @@ describe(`Loopback: ${printPath("[test/framework/loopback.withTenantId.test.js]" ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.app.start(); await createUsers(null, Passwordless); @@ -709,12 +673,6 @@ describe(`Loopback: ${printPath("[test/framework/loopback.withTenantId.test.js]" ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.app.start(); await createUsers(null, Passwordless, ThirdParty); @@ -813,12 +771,6 @@ describe(`Loopback: ${printPath("[test/framework/loopback.withTenantId.test.js]" ], }); - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.19") === "2.19") { - return this.skip(); - } - await this.app.start(); await createUsers(null, null, ThirdParty); diff --git a/test/frontendIntegration/index.js b/test/frontendIntegration/index.js index 69c9184b3..53796014b 100644 --- a/test/frontendIntegration/index.js +++ b/test/frontendIntegration/index.js @@ -34,6 +34,7 @@ let { verifySession } = require("../../recipe/session/framework/express"); let { middleware, errorHandler } = require("../../framework/express"); const { Querier } = require("../../lib/build/querier"); const { default: NormalisedURLPath } = require("../../lib/build/normalisedURLPath"); +const { getQuerierInstance } = require("../utils"); let supertokens_node_version = require("../../lib/build/version").version; let urlencodedParser = bodyParser.urlencoded({ limit: "20mb", extended: true, parameterLimit: 20000 }); @@ -276,7 +277,7 @@ app.post("/login-2.18", async (req, res) => { Querier.apiVersion = "2.18"; const payload = req.body.payload || {}; const userId = req.body.userId; - const legacySessionResp = await Querier.getNewInstanceOrThrowError().sendPostRequest( + const legacySessionResp = await getQuerierInstance("session").sendPostRequest( "/recipe/session", { userId, diff --git a/test/jwt/config.test.js b/test/jwt/config.test.js index b11637a3f..a9715d4bb 100644 --- a/test/jwt/config.test.js +++ b/test/jwt/config.test.js @@ -26,13 +26,6 @@ describe(`configTest: ${printPath("[test/jwt/config.test.js]")}`, function () { recipeList: [JWTRecipe.init()], }); - // Only run for version >= 2.9 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.8") === "2.8") { - return; - } - let jwtRecipe = await JWTRecipe.getInstanceOrThrowError(); assert(jwtRecipe.config.jwtValiditySeconds === 3153600000); }); @@ -55,13 +48,6 @@ describe(`configTest: ${printPath("[test/jwt/config.test.js]")}`, function () { ], }); - // Only run for version >= 2.9 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.8") === "2.8") { - return; - } - let jwtRecipe = await JWTRecipe.getInstanceOrThrowError(); assert(jwtRecipe.config.jwtValiditySeconds === 24 * 60 * 60); }); diff --git a/test/jwt/createJWTFeature.test.js b/test/jwt/createJWTFeature.test.js index 492c8a1a6..88d6d67b2 100644 --- a/test/jwt/createJWTFeature.test.js +++ b/test/jwt/createJWTFeature.test.js @@ -27,13 +27,6 @@ describe(`createJWTFeature: ${printPath("[test/jwt/createJWTFeature.test.js]")}` recipeList: [JWTRecipe.init()], }); - // Only run for version >= 2.9 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.8") === "2.8") { - return; - } - try { await JWTRecipe.createJWT({}, 0); assert.fail(); @@ -56,13 +49,6 @@ describe(`createJWTFeature: ${printPath("[test/jwt/createJWTFeature.test.js]")}` recipeList: [JWTRecipe.init()], }); - // Only run for version >= 2.9 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.8") === "2.8") { - return; - } - let jwt = undefined; try { @@ -88,13 +74,6 @@ describe(`createJWTFeature: ${printPath("[test/jwt/createJWTFeature.test.js]")}` recipeList: [JWTRecipe.init()], }); - // Only run for version >= 2.9 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.8") === "2.8") { - return; - } - let currentTimeInSeconds = Date.now() / 1000; let jwt = (await JWTRecipe.createJWT({})).jwt.split(".")[1]; let decodedJWTPayload = Buffer.from(jwt, "base64").toString("utf-8"); @@ -127,13 +106,6 @@ describe(`createJWTFeature: ${printPath("[test/jwt/createJWTFeature.test.js]")}` ], }); - // Only run for version >= 2.9 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.8") === "2.8") { - return; - } - let currentTimeInSeconds = Date.now() / 1000; let jwt = (await JWTRecipe.createJWT({})).jwt.split(".")[1]; let decodedJWTPayload = Buffer.from(jwt, "base64").toString("utf-8"); @@ -166,13 +138,6 @@ describe(`createJWTFeature: ${printPath("[test/jwt/createJWTFeature.test.js]")}` ], }); - // Only run for version >= 2.9 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.8") === "2.8") { - return; - } - let currentTimeInSeconds = Date.now() / 1000; let targetExpiryDuration = 500; // 100 years in seconds diff --git a/test/jwt/getJWKS.test.js b/test/jwt/getJWKS.test.js index bdf7c513f..c6b6786b5 100644 --- a/test/jwt/getJWKS.test.js +++ b/test/jwt/getJWKS.test.js @@ -40,13 +40,6 @@ describe(`getJWKS: ${printPath("[test/jwt/getJWKS.test.js]")}`, function () { ], }); - // Only run for version >= 2.9 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.8") === "2.8") { - return; - } - const app = express(); app.use(middleware()); @@ -82,13 +75,6 @@ describe(`getJWKS: ${printPath("[test/jwt/getJWKS.test.js]")}`, function () { recipeList: [JWTRecipe.init({})], }); - // Only run for version >= 2.9 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.8") === "2.8") { - return; - } - const app = express(); app.use(middleware()); @@ -148,13 +134,6 @@ describe(`getJWKS: ${printPath("[test/jwt/getJWKS.test.js]")}`, function () { ], }); - // Only run for version >= 2.9 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.8") === "2.8") { - return; - } - const app = express(); app.use(middleware()); @@ -208,13 +187,6 @@ describe(`getJWKS: ${printPath("[test/jwt/getJWKS.test.js]")}`, function () { ], }); - // Only run for version >= 2.9 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.8") === "2.8") { - return; - } - const app = express(); app.use(middleware()); @@ -266,13 +238,6 @@ describe(`getJWKS: ${printPath("[test/jwt/getJWKS.test.js]")}`, function () { ], }); - // Only run for version >= 2.9 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.8") === "2.8") { - return; - } - const app = express(); app.use(middleware()); diff --git a/test/jwt/override.test.js b/test/jwt/override.test.js index cb921dddf..d176a9855 100644 --- a/test/jwt/override.test.js +++ b/test/jwt/override.test.js @@ -59,13 +59,6 @@ describe(`overrideTest: ${printPath("[test/jwt/override.test.js]")}`, function ( ], }); - // Only run for version >= 2.9 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.8") === "2.8") { - return; - } - let app = express(); app.use(middleware()); @@ -144,13 +137,6 @@ describe(`overrideTest: ${printPath("[test/jwt/override.test.js]")}`, function ( ], }); - // Only run for version >= 2.9 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.8") === "2.8") { - return; - } - let app = express(); app.use(middleware()); diff --git a/test/oauth2/config.test.js b/test/oauth2/config.test.js index 7283c26e3..7fdd39798 100644 --- a/test/oauth2/config.test.js +++ b/test/oauth2/config.test.js @@ -26,13 +26,6 @@ describe(`configTest: ${printPath("[test/oauth2/config.test.js]")}`, function () recipeList: [OAuth2ProviderRecipe.init()], }); - // Only run for version >= 2.9 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.8") === "2.8") { - return; - } - OAuth2ProviderRecipe.getInstanceOrThrowError(); }); }); diff --git a/test/openid/api.test.js b/test/openid/api.test.js index 9fde99101..0272b98fb 100644 --- a/test/openid/api.test.js +++ b/test/openid/api.test.js @@ -30,13 +30,6 @@ describe(`apiTest: ${printPath("[test/openid/api.test.js]")}`, function () { recipeList: [OpenIdRecipe.init()], }); - // Only run for version >= 2.9 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.8") === "2.8") { - return; - } - const app = express(); app.use(middleware()); @@ -75,13 +68,6 @@ describe(`apiTest: ${printPath("[test/openid/api.test.js]")}`, function () { recipeList: [OpenIdRecipe.init()], }); - // Only run for version >= 2.9 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.8") === "2.8") { - return; - } - const app = express(); app.use(middleware()); @@ -132,13 +118,6 @@ describe(`apiTest: ${printPath("[test/openid/api.test.js]")}`, function () { ], }); - // Only run for version >= 2.9 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.8") === "2.8") { - return; - } - const app = express(); app.use(middleware()); diff --git a/test/openid/config.test.js b/test/openid/config.test.js index c71eff341..afcdd7081 100644 --- a/test/openid/config.test.js +++ b/test/openid/config.test.js @@ -26,14 +26,7 @@ describe(`configTest: ${printPath("[test/openid/config.test.js]")}`, function () recipeList: [OpenIdRecipe.init()], }); - // Only run for version >= 2.9 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.8") === "2.8") { - return; - } - - assert((await OpenIdRecipe.getIssuer()) === "https://api.supertokens.io/auth"); + assert((await OpenIdRecipe.getInstanceOrThrowError().getIssuer()) === "https://api.supertokens.io/auth"); }); it("Test that the default config sets values correctly for OpenID recipe with apiBasePath", async function () { @@ -51,14 +44,7 @@ describe(`configTest: ${printPath("[test/openid/config.test.js]")}`, function () recipeList: [OpenIdRecipe.init()], }); - // Only run for version >= 2.9 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.8") === "2.8") { - return; - } - - assert((await OpenIdRecipe.getIssuer()) === "https://api.supertokens.io"); + assert((await OpenIdRecipe.getInstanceOrThrowError().getIssuer()) === "https://api.supertokens.io"); }); it("Test that the config sets values correctly for OpenID recipe with issuer", async function () { @@ -91,14 +77,7 @@ describe(`configTest: ${printPath("[test/openid/config.test.js]")}`, function () ], }); - // Only run for version >= 2.9 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.8") === "2.8") { - return; - } - - assert((await OpenIdRecipe.getIssuer()) === "https://customissuer.com"); + assert((await OpenIdRecipe.getInstanceOrThrowError().getIssuer()) === "https://customissuer.com"); }); it("Test that issuer with gateway path works fine", async function () { @@ -116,13 +95,9 @@ describe(`configTest: ${printPath("[test/openid/config.test.js]")}`, function () recipeList: [OpenIdRecipe.init()], }); - // Only run for version >= 2.9 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.8") === "2.8") { - return; - } - - assert.equal(await OpenIdRecipe.getIssuer(), "https://api.supertokens.io/gateway/auth"); + assert.equal( + await OpenIdRecipe.getInstanceOrThrowError().getIssuer(), + "https://api.supertokens.io/gateway/auth" + ); }); }); diff --git a/test/openid/openid.test.js b/test/openid/openid.test.js index 5802b45ac..af1897473 100644 --- a/test/openid/openid.test.js +++ b/test/openid/openid.test.js @@ -27,13 +27,6 @@ describe(`openIdTest: ${printPath("[test/openid/openid.test.js]")}`, function () recipeList: [OpenIdRecipe.init()], }); - // Only run for version >= 2.9 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.8") === "2.8") { - return; - } - let discoveryConfig = await OpenId.getOpenIdDiscoveryConfiguration(); assert.equal(discoveryConfig.issuer, "https://api.supertokens.io/auth"); @@ -55,13 +48,6 @@ describe(`openIdTest: ${printPath("[test/openid/openid.test.js]")}`, function () recipeList: [OpenIdRecipe.init()], }); - // Only run for version >= 2.9 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.8") === "2.8") { - return; - } - let discoveryConfig = await OpenId.getOpenIdDiscoveryConfiguration(); assert.equal(discoveryConfig.issuer, "https://api.supertokens.io"); @@ -98,13 +84,6 @@ describe(`openIdTest: ${printPath("[test/openid/openid.test.js]")}`, function () ], }); - // Only run for version >= 2.9 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.8") === "2.8") { - return; - } - let discoveryConfig = await OpenId.getOpenIdDiscoveryConfiguration(); assert.equal(discoveryConfig.issuer, "https://cusomissuer/auth"); diff --git a/test/openid/override.test.js b/test/openid/override.test.js index a30a9daf3..6cfde98b6 100644 --- a/test/openid/override.test.js +++ b/test/openid/override.test.js @@ -47,13 +47,6 @@ describe(`overrideTest: ${printPath("[test/openid/override.test.js]")}`, functio ], }); - // Only run for version >= 2.9 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.8") === "2.8") { - return; - } - const app = express(); app.use(middleware()); @@ -109,13 +102,6 @@ describe(`overrideTest: ${printPath("[test/openid/override.test.js]")}`, functio ], }); - // Only run for version >= 2.9 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.8") === "2.8") { - return; - } - const app = express(); app.use(middleware()); diff --git a/test/plugins/recipe.ts b/test/plugins/recipe.ts index 6255cabe4..7a8b304c0 100644 --- a/test/plugins/recipe.ts +++ b/test/plugins/recipe.ts @@ -31,8 +31,8 @@ export default class Recipe extends RecipeModule { isInServerlessEnv; - constructor(recipeId, appInfo, isInServerlessEnv, config) { - super(recipeId, appInfo); + constructor(stInstance, recipeId, appInfo, isInServerlessEnv, config) { + super(stInstance, recipeId, appInfo); this.isInServerlessEnv = isInServerlessEnv; this.config = validateAndNormalizeUserInput(appInfo, config); { @@ -56,9 +56,10 @@ export default class Recipe extends RecipeModule { } static init(config) { - return (appInfo, isInServerlessEnv, plugins) => { + return (stInstance, appInfo, isInServerlessEnv, plugins) => { if (Recipe.instance === undefined) { Recipe.instance = new Recipe( + stInstance, Recipe.RECIPE_ID, appInfo, isInServerlessEnv, diff --git a/test/querier.test.js b/test/querier.test.js index 839f71319..d39f1f6fe 100644 --- a/test/querier.test.js +++ b/test/querier.test.js @@ -12,9 +12,8 @@ * License for the specific language governing permissions and limitations * under the License. */ -const { printPath, createCoreApplication } = require("./utils"); +const { printPath, createCoreApplication, getQuerierInstance, getCoreUrl } = require("./utils"); let ST = require("../"); -let { Querier } = require("../lib/build/querier"); let assert = require("assert"); let { ProcessState, PROCESS_STATE } = require("../lib/build/processState"); let Session = require("../recipe/session"); @@ -33,7 +32,7 @@ describe(`Querier: ${printPath("[test/querier.test.js]")}`, function () { // Check that once the API version is there, it doesn't need to query again it("test that if that once API version is there, it doesn't need to query again", async function () { - const connectionURI = await createCoreApplication(); + const connectionURI = await getCoreUrl(); ST.init({ supertokens: { connectionURI, @@ -45,7 +44,7 @@ describe(`Querier: ${printPath("[test/querier.test.js]")}`, function () { }, recipeList: [Session.init({ getTokenTransferMethod: () => "cookie", antiCsrf: "VIA_TOKEN" })], }); - let q = Querier.getNewInstanceOrThrowError(undefined); + let q = getQuerierInstance(); await q.getAPIVersion(); let verifyState = await ProcessState.getInstance().waitForEvent( @@ -66,7 +65,7 @@ describe(`Querier: ${printPath("[test/querier.test.js]")}`, function () { // Check that rid is added to the header iff it's a "/recipe" || "/recipe/*" request. it("test that rid is added to the header if it's a recipe request", async function () { - const connectionURI = await createCoreApplication(); + const connectionURI = await getCoreUrl(); ST.init({ supertokens: { connectionURI, @@ -79,17 +78,19 @@ describe(`Querier: ${printPath("[test/querier.test.js]")}`, function () { recipeList: [Session.init({ getTokenTransferMethod: () => "cookie", antiCsrf: "VIA_TOKEN" })], }); - let querier = Querier.getNewInstanceOrThrowError(SessionRecipe.getInstanceOrThrowError().getRecipeId()); + let querier = getQuerierInstance(SessionRecipe.getInstanceOrThrowError().getRecipeId()); + await querier.getAPIVersion({}); + console.log("connectionURI", "/recipe"); nock(connectionURI, { - allowUnmocked: true, + allowUnmocked: false, }) .get("/recipe") .reply(200, function (uri, requestBody) { return this.req.headers; }); - let response = await querier.sendGetRequest(new NormalisedURLPath("/recipe"), {}, {}); + let response = await querier.sendGetRequest("/recipe", {}, {}); assert.deepStrictEqual(response.rid, ["session"]); nock(connectionURI, { @@ -100,7 +101,7 @@ describe(`Querier: ${printPath("[test/querier.test.js]")}`, function () { return this.req.headers; }); - let response2 = await querier.sendGetRequest(new NormalisedURLPath("/recipe/random"), {}, {}); + let response2 = await querier.sendGetRequest("/recipe/random", {}, {}); assert.deepStrictEqual(response2.rid, ["session"]); nock(connectionURI, { @@ -111,7 +112,7 @@ describe(`Querier: ${printPath("[test/querier.test.js]")}`, function () { return this.req.headers; }); - let response3 = await querier.sendGetRequest(new NormalisedURLPath("/test"), {}, {}); + let response3 = await querier.sendGetRequest("/test", {}, {}); assert.strictEqual(response3.rid, undefined); }); @@ -128,8 +129,8 @@ describe(`Querier: ${printPath("[test/querier.test.js]")}`, function () { recipeList: [Session.init({ getTokenTransferMethod: () => "cookie", antiCsrf: "VIA_TOKEN" })], }); try { - let q = Querier.getNewInstanceOrThrowError(undefined); - await q.sendGetRequest(new NormalisedURLPath("", "/"), {}, {}); + let q = getQuerierInstance(); + await q.sendGetRequest(("", "/"), {}, {}); throw new Error(); } catch (err) { if (err.message !== "No SuperTokens core available to query") { @@ -155,12 +156,12 @@ describe(`Querier: ${printPath("[test/querier.test.js]")}`, function () { }, recipeList: [Session.init({ getTokenTransferMethod: () => "cookie", antiCsrf: "VIA_TOKEN" })], }); - let q = Querier.getNewInstanceOrThrowError(undefined); - assert.equal(await q.sendGetRequest(new NormalisedURLPath("/hello"), {}, {}), "Hello\n"); - assert.equal(await q.sendDeleteRequest(new NormalisedURLPath("/hello"), {}, undefined, {}), "Hello\n"); + let q = getQuerierInstance(); + assert.equal(await q.sendGetRequest("/hello", {}, {}), "Hello\n"); + assert.equal(await q.sendDeleteRequest("/hello", {}, undefined, {}), "Hello\n"); let hostsAlive = q.getHostsAliveForTesting(); assert.equal(hostsAlive.size, 3); - assert.equal(await q.sendGetRequest(new NormalisedURLPath("/hello"), {}, {}), "Hello\n"); // this will be the 4th API call + assert.equal(await q.sendGetRequest("/hello", {}, {}), "Hello\n"); // this will be the 4th API call hostsAlive = q.getHostsAliveForTesting(); assert.equal(hostsAlive.size, 3); assert.equal(hostsAlive.has(connectionURI), true); @@ -183,12 +184,12 @@ describe(`Querier: ${printPath("[test/querier.test.js]")}`, function () { }, recipeList: [Session.init({ getTokenTransferMethod: () => "cookie", antiCsrf: "VIA_TOKEN" })], }); - let q = Querier.getNewInstanceOrThrowError(undefined); - assert.equal(await q.sendGetRequest(new NormalisedURLPath("/hello"), {}, {}), "Hello\n"); - assert.equal(await q.sendPostRequest(new NormalisedURLPath("/hello"), {}, {}), "Hello\n"); + let q = getQuerierInstance(); + assert.equal(await q.sendGetRequest("/hello", {}, {}), "Hello\n"); + assert.equal(await q.sendPostRequest("/hello", {}, {}), "Hello\n"); let hostsAlive = q.getHostsAliveForTesting(); assert.equal(hostsAlive.size, 2); - assert.equal(await q.sendPutRequest(new NormalisedURLPath("/hello"), {}, {}, {}), "Hello\n"); // this will be the 4th API call + assert.equal(await q.sendPutRequest("/hello", {}, {}, {}), "Hello\n"); // this will be the 4th API call hostsAlive = q.getHostsAliveForTesting(); assert.equal(hostsAlive.size, 2); assert.equal(hostsAlive.has(connectionURI), true); @@ -197,7 +198,6 @@ describe(`Querier: ${printPath("[test/querier.test.js]")}`, function () { }); it("test that no connectionURI given, but recipe used throws an error", async function () { - const connectionURI = await createCoreApplication(); ST.init({ appInfo: { apiDomain: "api.supertokens.io", @@ -219,7 +219,6 @@ describe(`Querier: ${printPath("[test/querier.test.js]")}`, function () { }); it("test that no connectionURI given, recipe override and used doesn't thrown an error", async function () { - const connectionURI = await createCoreApplication(); ST.init({ appInfo: { apiDomain: "api.supertokens.io", @@ -371,7 +370,7 @@ describe(`Querier: ${printPath("[test/querier.test.js]")}`, function () { }); it("test that no-cache header is added when querying the core", async function () { - const connectionURI = await createCoreApplication(); + const connectionURI = await getCoreUrl(); ST.init({ supertokens: { connectionURI, @@ -384,7 +383,7 @@ describe(`Querier: ${printPath("[test/querier.test.js]")}`, function () { recipeList: [Session.init({ getTokenTransferMethod: () => "cookie", antiCsrf: "VIA_TOKEN" })], }); - let querier = Querier.getNewInstanceOrThrowError(SessionRecipe.getInstanceOrThrowError().getRecipeId()); + let querier = getQuerierInstance(SessionRecipe.getInstanceOrThrowError().getRecipeId()); nock(connectionURI, { allowUnmocked: true, @@ -394,7 +393,7 @@ describe(`Querier: ${printPath("[test/querier.test.js]")}`, function () { return this.req.headers; }); - let response = await querier.sendGetRequest(new NormalisedURLPath("/recipe"), {}, {}); + let response = await querier.sendGetRequest("/recipe", {}, {}); assert.deepStrictEqual(response.rid, ["session"]); let noCacheHeaderAdded = await ProcessState.getInstance().waitForEvent( PROCESS_STATE.ADDING_NO_CACHE_HEADER_IN_FETCH, diff --git a/test/ratelimiting.test.js b/test/ratelimiting.test.js index 05a7e4c72..f576a6682 100644 --- a/test/ratelimiting.test.js +++ b/test/ratelimiting.test.js @@ -1,5 +1,5 @@ const { ProcessState } = require("../lib/build/processState"); -const { printPath, createCoreApplication } = require("./utils"); +const { printPath, createCoreApplication, getQuerierInstance } = require("./utils"); let STExpress = require("../"); let Dashboard = require("../recipe/dashboard"); let EmailVerification = require("../recipe/emailverification"); @@ -22,11 +22,10 @@ describe(`Querier rate limiting: ${printPath("[test/ratelimiting.test.js]")}`, ( }); it("Test that network call is retried properly", async () => { - const connectionURI = await createCoreApplication(); STExpress.init({ supertokens: { - // Using 8083 because we need querier to call the test express server instead of the core - connectionURI: "http://localhost:8083", + // Using 8089 because we need querier to call the test express server instead of the core + connectionURI: "http://localhost:8089", }, appInfo: { apiDomain: "api.supertokens.io", @@ -76,12 +75,12 @@ describe(`Querier rate limiting: ${printPath("[test/ratelimiting.test.js]")}`, ( app.use(errorHandler()); - const server = app.listen(8083, () => {}); + const server = app.listen(8089, () => {}); - let q = Querier.getNewInstanceOrThrowError(undefined); + let q = getQuerierInstance(undefined); try { - await q.sendGetRequest(new NormalisedURLPath("/testing"), {}, {}); + await q.sendGetRequest("/testing", {}, {}); } catch (e) { if (!e.message.includes("with status code: 429")) { throw e; @@ -91,21 +90,20 @@ describe(`Querier rate limiting: ${printPath("[test/ratelimiting.test.js]")}`, ( // 1 initial request + 5 retries assert.equal(numbersOfTimesRetried, 6); - await q.sendGetRequest(new NormalisedURLPath("/testing2"), {}, {}); + await q.sendGetRequest("/testing2", {}, {}); assert.equal(numberOfTimesSecondCalled, 3); - await q.sendGetRequest(new NormalisedURLPath("/testing3"), {}, {}); + await q.sendGetRequest("/testing3", {}, {}); assert.equal(numberOfTimesThirdCalled, 1); server.close(); }); it("Test that rate limiting errors are thrown back to the user", async () => { - const connectionURI = await createCoreApplication(); STExpress.init({ supertokens: { - // Using 8083 because we need querier to call the test express server instead of the core - connectionURI: "http://localhost:8083", + // Using 8089 because we need querier to call the test express server instead of the core + connectionURI: "http://localhost:8089", }, appInfo: { apiDomain: "api.supertokens.io", @@ -137,12 +135,12 @@ describe(`Querier rate limiting: ${printPath("[test/ratelimiting.test.js]")}`, ( app.use(errorHandler()); - const server = app.listen(8083, () => {}); + const server = app.listen(8089, () => {}); - let q = Querier.getNewInstanceOrThrowError(undefined); + let q = getQuerierInstance(undefined); try { - await q.sendGetRequest(new NormalisedURLPath("/testing"), {}, {}); + await q.sendGetRequest("/testing", {}, {}); } catch (e) { if (!e.message.includes("with status code: 429")) { throw e; @@ -155,11 +153,10 @@ describe(`Querier rate limiting: ${printPath("[test/ratelimiting.test.js]")}`, ( }); it("Test that parallel calls have independent retry counters", async () => { - const connectionURI = await createCoreApplication(); STExpress.init({ supertokens: { - // Using 8083 because we need querier to call the test express server instead of the core - connectionURI: "http://localhost:8083", + // Using 8089 because we need querier to call the test express server instead of the core + connectionURI: "http://localhost:8089", }, appInfo: { apiDomain: "api.supertokens.io", @@ -197,13 +194,13 @@ describe(`Querier rate limiting: ${printPath("[test/ratelimiting.test.js]")}`, ( app.use(errorHandler()); - const server = app.listen(8083, () => {}); + const server = app.listen(8089, () => {}); - let q = Querier.getNewInstanceOrThrowError(undefined); + let q = getQuerierInstance(undefined); const callApi1 = async () => { try { - await q.sendGetRequest(new NormalisedURLPath("/testing"), { id: "1" }, {}); + await q.sendGetRequest("/testing", { id: "1" }, {}); } catch (e) { if (!e.message.includes("with status code: 429")) { throw e; @@ -213,7 +210,7 @@ describe(`Querier rate limiting: ${printPath("[test/ratelimiting.test.js]")}`, ( const callApi2 = async () => { try { - await q.sendGetRequest(new NormalisedURLPath("/testing"), { id: "2" }, {}); + await q.sendGetRequest("/testing", { id: "2" }, {}); } catch (e) { if (!e.message.includes("with status code: 429")) { throw e; diff --git a/test/recipeModuleManager.test.js b/test/recipeModuleManager.test.js index e8b8cb2e7..47cb9d4f3 100644 --- a/test/recipeModuleManager.test.js +++ b/test/recipeModuleManager.test.js @@ -12,7 +12,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -const { printPath, createCoreApplication, resetAll } = require("./utils"); +const { printPath, createCoreApplication, resetAll, getQuerierInstance } = require("./utils"); let { ProcessState } = require("../lib/build/processState"); let ST = require("../"); let Session = require("../recipe/session"); @@ -35,6 +35,7 @@ let { middleware, errorHandler } = require("../framework/express"); * TODO: (later) Make a custom validator throw an error and check that it's transformed into a general error, and then in user's error handler, it's a normal error again * */ +const fakeConnectionURI = "http://localhost:3000"; describe(`recipeModuleManagerTest: ${printPath("[test/recipeModuleManager.test.js]")}`, function () { beforeEach(async function () { @@ -43,11 +44,9 @@ describe(`recipeModuleManagerTest: ${printPath("[test/recipeModuleManager.test.j }); it("calling init multiple times", async function () { - const connectionURI = await createCoreApplication(); - ST.init({ supertokens: { - connectionURI, + connectionURI: fakeConnectionURI, }, appInfo: { apiDomain: "api.supertokens.io", @@ -62,7 +61,7 @@ describe(`recipeModuleManagerTest: ${printPath("[test/recipeModuleManager.test.j ST.init({ supertokens: { - connectionURI, + connectionURI: fakeConnectionURI, }, appInfo: { apiDomain: "api.supertokens.io", @@ -79,20 +78,18 @@ describe(`recipeModuleManagerTest: ${printPath("[test/recipeModuleManager.test.j // Check that querier has been inited when we call supertokens.init // Failure condition: initalizing supertoknes before the the first try catch will fail the test it("test that querier has been initiated when we call supertokens.init", async function () { - const connectionURI = await createCoreApplication(); - try { - await Querier.getNewInstanceOrThrowError(undefined); + await getQuerierInstance(); assert(false); } catch (err) { - if (err.message !== "Please call the supertokens.init function before using SuperTokens") { + if (err.message !== "Initialisation not done. Did you forget to call the SuperTokens.init function?") { throw err; } } ST.init({ supertokens: { - connectionURI, + connectionURI: fakeConnectionURI, }, appInfo: { apiDomain: "api.supertokens.io", @@ -102,14 +99,12 @@ describe(`recipeModuleManagerTest: ${printPath("[test/recipeModuleManager.test.j recipeList: [Session.init({ getTokenTransferMethod: () => "cookie", antiCsrf: "VIA_TOKEN" })], }); - await Querier.getNewInstanceOrThrowError(undefined); + await getQuerierInstance(); }); // Check that modules have been inited when we call supertokens.init // Failure condition: initalizing supertoknes before the the first try catch will fail the test it("test that modules have been initiated when we call supertokens.init", async function () { - const connectionURI = await createCoreApplication(); - try { SessionRecipe.getInstanceOrThrowError(); assert(false); @@ -133,7 +128,7 @@ describe(`recipeModuleManagerTest: ${printPath("[test/recipeModuleManager.test.j ST.init({ supertokens: { - connectionURI, + connectionURI: fakeConnectionURI, }, appInfo: { apiDomain: "api.supertokens.io", @@ -158,10 +153,9 @@ describe(`recipeModuleManagerTest: ${printPath("[test/recipeModuleManager.test.j //Failure condition: Tests will fail is using the incorrect base path it("test various inputs to routing with default base path", async function () { - const connectionURI = await createCoreApplication(); ST.init({ supertokens: { - connectionURI, + connectionURI: fakeConnectionURI, }, appInfo: { apiDomain: "api.supertokens.io", @@ -239,11 +233,10 @@ describe(`recipeModuleManagerTest: ${printPath("[test/recipeModuleManager.test.j //Failure condition: Tests will fail is using the wrong base path it("test various inputs to routing when base path is /", async function () { - const connectionURI = await createCoreApplication(); { ST.init({ supertokens: { - connectionURI, + connectionURI: fakeConnectionURI, }, appInfo: { apiDomain: "api.supertokens.io", @@ -326,11 +319,9 @@ describe(`recipeModuleManagerTest: ${printPath("[test/recipeModuleManager.test.j //Failure condition: Tests will fail if the incorrect rid header value is set when sending a request the path it("test routing with multiple recipes", async function () { - const connectionURI = await createCoreApplication(); - ST.init({ supertokens: { - connectionURI, + connectionURI: fakeConnectionURI, }, appInfo: { apiDomain: "api.supertokens.io", @@ -391,11 +382,9 @@ describe(`recipeModuleManagerTest: ${printPath("[test/recipeModuleManager.test.j // Test various inputs to errorHandler (if it accepts or not) it("test various inputs to errorHandler", async function () { - const connectionURI = await createCoreApplication(); - ST.init({ supertokens: { - connectionURI, + connectionURI: fakeConnectionURI, }, appInfo: { apiDomain: "api.supertokens.io", @@ -429,7 +418,7 @@ describe(`recipeModuleManagerTest: ${printPath("[test/recipeModuleManager.test.j } }) ); - assert(r1 === "General error handled in user error handler"); + assert.strictEqual(r1, "General error handled in user error handler"); r1 = await new Promise((resolve) => request(app) @@ -449,11 +438,9 @@ describe(`recipeModuleManagerTest: ${printPath("[test/recipeModuleManager.test.j // Error thrown from APIs implemented by recipes must not go unhandled it("test that error thrown from APIs implemented by recipes must not go unhandled", async function () { - const connectionURI = await createCoreApplication(); - ST.init({ supertokens: { - connectionURI, + connectionURI: fakeConnectionURI, }, appInfo: { apiDomain: "api.supertokens.io", @@ -543,16 +530,14 @@ describe(`recipeModuleManagerTest: ${printPath("[test/recipeModuleManager.test.j } }) ); - assert(r1 === "user defined api"); + assert.strictEqual(r1, "user defined api"); }); // If an error handler in a recipe throws an error, that error next to go to the user's error handler it("test if the error handler in a recipe throws an error, it goes to the user's error handler", async function () { - const connectionURI = await createCoreApplication(); - ST.init({ supertokens: { - connectionURI, + connectionURI: fakeConnectionURI, }, appInfo: { apiDomain: "api.supertokens.io", @@ -586,16 +571,14 @@ describe(`recipeModuleManagerTest: ${printPath("[test/recipeModuleManager.test.j } }) ); - assert(r1 === "user error handler"); + assert.strictEqual(r1, "user error handler"); }); // Test getAllCORSHeaders it("test the getAllCORSHeaders function", async function () { - const connectionURI = await createCoreApplication(); - ST.init({ supertokens: { - connectionURI, + connectionURI: fakeConnectionURI, }, appInfo: { apiDomain: "api.supertokens.io", @@ -615,14 +598,14 @@ describe(`recipeModuleManagerTest: ${printPath("[test/recipeModuleManager.test.j }); class TestRecipe extends RecipeModule { - constructor(recipeId, appInfo) { - super(recipeId, appInfo); + constructor(stInstance, recipeId, appInfo) { + super(stInstance, recipeId, appInfo); } static init() { - return (appInfo) => { + return (stInstance, appInfo) => { if (TestRecipe.instance === undefined) { - TestRecipe.instance = new TestRecipe("testRecipe", appInfo); + TestRecipe.instance = new TestRecipe(stInstance, "testRecipe", appInfo); return TestRecipe.instance; } else { throw new Error("already initialised"); @@ -743,14 +726,14 @@ class TestRecipeError extends STError { } class TestRecipe1 extends RecipeModule { - constructor(recipeId, appInfo) { - super(recipeId, appInfo); + constructor(stInstance, recipeId, appInfo) { + super(stInstance, recipeId, appInfo); } static init() { - return (appInfo) => { + return (stInstance, appInfo) => { if (TestRecipe1.instance === undefined) { - TestRecipe1.instance = new TestRecipe1("testRecipe1", appInfo); + TestRecipe1.instance = new TestRecipe1(stInstance, "testRecipe1", appInfo); return TestRecipe1.instance; } else { throw new Error("already initialised"); @@ -849,14 +832,14 @@ class TestRecipe1Error extends STError { } class TestRecipe2 extends RecipeModule { - constructor(recipeId, appInfo) { + constructor(stInstance, recipeId, appInfo) { super(recipeId, appInfo); } static init() { - return (appInfo) => { + return (stInstance, appInfo) => { if (TestRecipe2.instance === undefined) { - TestRecipe2.instance = new TestRecipe2("testRecipe2", appInfo); + TestRecipe2.instance = new TestRecipe2(stInstance, "testRecipe2", appInfo); return TestRecipe2.instance; } else { throw new Error("already initialised"); @@ -878,14 +861,14 @@ class TestRecipe2 extends RecipeModule { } class TestRecipe3 extends RecipeModule { - constructor(recipeId, appInfo) { - super(recipeId, appInfo); + constructor(stInstance, recipeId, appInfo) { + super(stInstance, recipeId, appInfo); } static init() { - return (appInfo) => { + return (stInstance, appInfo) => { if (TestRecipe3.instance === undefined) { - TestRecipe3.instance = new TestRecipe3("testRecipe3", appInfo); + TestRecipe3.instance = new TestRecipe3(stInstance, "testRecipe3", appInfo); return TestRecipe3.instance; } else { throw new Error("already initialised"); @@ -907,14 +890,14 @@ class TestRecipe3 extends RecipeModule { } class TestRecipe3Duplicate extends RecipeModule { - constructor(recipeId, appInfo) { - super(recipeId, appInfo); + constructor(stInstance, recipeId, appInfo) { + super(stInstance, recipeId, appInfo); } static init() { - return (appInfo) => { + return (stInstance, appInfo) => { if (TestRecipe3Duplicate.instance === undefined) { - TestRecipe3Duplicate.instance = new TestRecipe3("testRecipe3Duplicate", appInfo); + TestRecipe3Duplicate.instance = new TestRecipe3(stInstance, "testRecipe3Duplicate", appInfo); return TestRecipe3Duplicate.instance; } else { throw new Error("already initialised"); diff --git a/test/session.test.js b/test/session.test.js index 20d85dbb5..788ee6a1e 100644 --- a/test/session.test.js +++ b/test/session.test.js @@ -21,6 +21,7 @@ const { mockResponse, mockRequest, + getQuerierInstance, } = require("./utils"); let assert = require("assert"); let { Querier } = require("../lib/build/querier"); @@ -898,7 +899,7 @@ describe(`session: ${printPath("[test/session.test.js]")}`, function () { }); try { - await Querier.getNewInstanceOrThrowError(undefined).getAPIVersion(); + await getQuerierInstance().getAPIVersion(); throw new Error("should not have come here"); } catch (err) { if ( @@ -1274,14 +1275,6 @@ describe(`session: ${printPath("[test/session.test.js]")}`, function () { recipeList: [Session.init({ getTokenTransferMethod: () => "cookie", antiCsrf: "VIA_TOKEN" })], }); - let q = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await q.getAPIVersion(); - - // Only run test for >= 2.8 - if (maxVersion(apiVersion, "2.7") === "2.7") { - return; - } - let s = SessionRecipe.getInstanceOrThrowError().recipeInterfaceImpl; //adding session data let res = await SessionFunctions.createNewSession(s.helpers, "public", new RecipeUserId(""), false, {}, {}, {}); @@ -1369,14 +1362,6 @@ describe(`session: ${printPath("[test/session.test.js]")}`, function () { recipeList: [Session.init({ getTokenTransferMethod: () => "cookie", antiCsrf: "VIA_TOKEN" })], }); - let q = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await q.getAPIVersion(); - - // Only run test for >= 2.8 - if (maxVersion(apiVersion, "2.7") === "2.7") { - return; - } - let s = SessionRecipe.getInstanceOrThrowError().recipeInterfaceImpl; //adding session data let res = await SessionFunctions.createNewSession( @@ -1463,14 +1448,6 @@ describe(`session: ${printPath("[test/session.test.js]")}`, function () { recipeList: [Session.init({ getTokenTransferMethod: () => "cookie", antiCsrf: "VIA_TOKEN" })], }); - let q = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await q.getAPIVersion(); - - // Only run test for >= 2.8 - if (maxVersion(apiVersion, "2.7") === "2.7") { - return; - } - let s = SessionRecipe.getInstanceOrThrowError().recipeInterfaceImpl; //adding jwt payload let res = await SessionFunctions.createNewSession(s.helpers, "public", new RecipeUserId(""), false, {}, {}, {}); @@ -1559,14 +1536,6 @@ describe(`session: ${printPath("[test/session.test.js]")}`, function () { recipeList: [Session.init({ getTokenTransferMethod: () => "cookie", antiCsrf: "VIA_TOKEN" })], }); - let q = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await q.getAPIVersion(); - - // Only run test for >= 2.8 - if (maxVersion(apiVersion, "2.7") === "2.7") { - return; - } - let s = SessionRecipe.getInstanceOrThrowError().recipeInterfaceImpl; //adding jwt payload let res = await SessionFunctions.createNewSession( @@ -1729,14 +1698,6 @@ describe(`session: ${printPath("[test/session.test.js]")}`, function () { recipeList: [Session.init({ getTokenTransferMethod: () => "cookie", antiCsrf: "VIA_TOKEN" })], }); - let q = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await q.getAPIVersion(); - - // Only run test for >= 2.8 - if (maxVersion(apiVersion, "2.7") === "2.7") { - return; - } - let s = SessionRecipe.getInstanceOrThrowError().recipeInterfaceImpl; //adding session data let res = await SessionFunctions.createNewSession( @@ -1768,14 +1729,6 @@ describe(`session: ${printPath("[test/session.test.js]")}`, function () { recipeList: [Session.init({ getTokenTransferMethod: () => "cookie", antiCsrf: "VIA_TOKEN" })], }); - let q = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await q.getAPIVersion(); - - // Only run test for >= 2.8 - if (maxVersion(apiVersion, "2.7") === "2.7") { - return; - } - let s = SessionRecipe.getInstanceOrThrowError().recipeInterfaceImpl; //adding session data let res = await SessionFunctions.createNewSession( @@ -1811,14 +1764,6 @@ describe(`session: ${printPath("[test/session.test.js]")}`, function () { recipeList: [Session.init({ getTokenTransferMethod: () => "cookie", antiCsrf: "VIA_TOKEN" })], }); - let q = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await q.getAPIVersion(); - - // Only run test for >= 2.8 - if (maxVersion(apiVersion, "2.7") === "2.7") { - return; - } - let s = SessionRecipe.getInstanceOrThrowError().recipeInterfaceImpl; //adding session data let res = await SessionFunctions.createNewSession( diff --git a/test/session/accessTokenVersions.test.js b/test/session/accessTokenVersions.test.js index 1d452d714..59371df00 100644 --- a/test/session/accessTokenVersions.test.js +++ b/test/session/accessTokenVersions.test.js @@ -12,7 +12,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -const { printPath, createCoreApplication, extractInfoFromResponse, resetAll } = require("../utils"); +const { printPath, createCoreApplication, extractInfoFromResponse, resetAll, getQuerierInstance } = require("../utils"); const assert = require("assert"); const { Querier } = require("../../lib/build/querier"); const express = require("express"); @@ -330,7 +330,7 @@ describe(`AccessToken versions: ${printPath("[test/session/accessTokenVersions.t // This CDI version is no longer supported by this SDK, but we want to ensure that sessions keep working after the upgrade // We can hard-code the structure of the request&response, since this is a fixed CDI version and it's not going to change Querier.apiVersion = "2.18"; - const legacySessionResp = await Querier.getNewInstanceOrThrowError().sendPostRequest( + const legacySessionResp = await getQuerierInstance().sendPostRequest( "/recipe/session", { userId: "test-user-id", @@ -431,7 +431,7 @@ describe(`AccessToken versions: ${printPath("[test/session/accessTokenVersions.t // This CDI version is no longer supported by this SDK, but we want to ensure that sessions keep working after the upgrade // We can hard-code the structure of the request&response, since this is a fixed CDI version and it's not going to change Querier.apiVersion = "2.18"; - const legacySessionResp = await Querier.getNewInstanceOrThrowError().sendPostRequest( + const legacySessionResp = await getQuerierInstance().sendPostRequest( "/recipe/session", { userId: "test-user-id", @@ -500,7 +500,7 @@ describe(`AccessToken versions: ${printPath("[test/session/accessTokenVersions.t // This CDI version is no longer supported by this SDK, but we want to ensure that sessions keep working after the upgrade // We can hard-code the structure of the request&response, since this is a fixed CDI version and it's not going to change Querier.apiVersion = "2.18"; - const legacySessionResp = await Querier.getNewInstanceOrThrowError().sendPostRequest( + const legacySessionResp = await getQuerierInstance().sendPostRequest( "/recipe/session", { userId: "test-user-id", @@ -559,7 +559,7 @@ describe(`AccessToken versions: ${printPath("[test/session/accessTokenVersions.t // This CDI version is no longer supported by this SDK, but we want to ensure that sessions keep working after the upgrade // We can hard-code the structure of the request&response, since this is a fixed CDI version and it's not going to change Querier.apiVersion = "2.18"; - const legacySessionResp = await Querier.getNewInstanceOrThrowError().sendPostRequest( + const legacySessionResp = await getQuerierInstance().sendPostRequest( "/recipe/session", { userId: "test-user-id", @@ -648,7 +648,7 @@ describe(`AccessToken versions: ${printPath("[test/session/accessTokenVersions.t // This CDI version is no longer supported by this SDK, but we want to ensure that sessions keep working after the upgrade // We can hard-code the structure of the request&response, since this is a fixed CDI version and it's not going to change Querier.apiVersion = "3.0"; - const legacySessionResp = await Querier.getNewInstanceOrThrowError().sendPostRequest( + const legacySessionResp = await getQuerierInstance().sendPostRequest( "/recipe/session", { userId: "test-user-id", @@ -716,7 +716,7 @@ describe(`AccessToken versions: ${printPath("[test/session/accessTokenVersions.t // This CDI version is no longer supported by this SDK, but we want to ensure that sessions keep working after the upgrade // We can hard-code the structure of the request&response, since this is a fixed CDI version and it's not going to change Querier.apiVersion = "3.0"; - const legacySessionResp = await Querier.getNewInstanceOrThrowError().sendPostRequest( + const legacySessionResp = await getQuerierInstance().sendPostRequest( "/recipe/session", { userId: "test-user-id", @@ -971,7 +971,7 @@ describe(`AccessToken versions: ${printPath("[test/session/accessTokenVersions.t // This CDI version is no longer supported by this SDK, but we want to ensure that sessions keep working after the upgrade // We can hard-code the structure of the request&response, since this is a fixed CDI version and it's not going to change Querier.apiVersion = "2.18"; - const legacySessionResp = await Querier.getNewInstanceOrThrowError().sendPostRequest( + const legacySessionResp = await getQuerierInstance().sendPostRequest( "/recipe/session", { userId: "test-user-id", @@ -1026,7 +1026,7 @@ describe(`AccessToken versions: ${printPath("[test/session/accessTokenVersions.t // This CDI version is no longer supported by this SDK, but we want to ensure that sessions keep working after the upgrade // We can hard-code the structure of the request&response, since this is a fixed CDI version and it's not going to change Querier.apiVersion = "2.18"; - const legacySessionResp = await Querier.getNewInstanceOrThrowError().sendPostRequest( + const legacySessionResp = await getQuerierInstance().sendPostRequest( "/recipe/session", { userId: "test-user-id", diff --git a/test/session/sessionHandlingFuncsWithoutReq.test.js b/test/session/sessionHandlingFuncsWithoutReq.test.js index d0dc2d6d5..1bcaea64f 100644 --- a/test/session/sessionHandlingFuncsWithoutReq.test.js +++ b/test/session/sessionHandlingFuncsWithoutReq.test.js @@ -230,14 +230,6 @@ describe(`Session handling functions without modifying response: ${printPath( recipeList: [Session.init(), JWT.init()], }); - let q = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await q.getAPIVersion(); - - // Only run test for >= 3.0 CDI (3.0 is after 2.21) - if (maxVersion(apiVersion, "2.21") === "2.21") { - return; - } - const session = await Session.createNewSessionWithoutRequestResponse( "public", SuperTokens.convertToRecipeUserId("testId") diff --git a/test/sessionAccessTokenSigningKeyUpdate.test.js b/test/sessionAccessTokenSigningKeyUpdate.test.js index 9b5cc5c3f..86086c69c 100644 --- a/test/sessionAccessTokenSigningKeyUpdate.test.js +++ b/test/sessionAccessTokenSigningKeyUpdate.test.js @@ -12,7 +12,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -const { printPath, createCoreApplication } = require("./utils"); +const { printPath, createCoreApplication, getQuerierInstance } = require("./utils"); let assert = require("assert"); let { Querier } = require("../lib/build/querier"); let { ProcessState, PROCESS_STATE } = require("../lib/build/processState"); @@ -395,8 +395,6 @@ describe(`sessionAccessTokenSigningKeyUpdate: ${printPath( recipeList: [Session.init({ getTokenTransferMethod: () => "cookie", antiCsrf: "VIA_TOKEN" })], }); - const currCDIVersion = await Querier.getNewInstanceOrThrowError(undefined).getAPIVersion(); - let response2 = await SessionFunctions.createNewSession( SessionRecipe.getInstanceOrThrowError().recipeInterfaceImpl.helpers, "public", @@ -651,7 +649,7 @@ describe(`sessionAccessTokenSigningKeyUpdate: ${printPath( recipeList: [Session.init({ getTokenTransferMethod: () => "cookie", antiCsrf: "VIA_TOKEN" })], }); - let q = Querier.getNewInstanceOrThrowError(undefined); + let q = getQuerierInstance(); let apiVersion = await q.getAPIVersion(); // Only run test for >= 2.8 since the fix for this test is in core with CDI >= 2.8 diff --git a/test/thirdparty/signinupFeature.test.js b/test/thirdparty/signinupFeature.test.js index ead1c8e7a..42592f0c4 100644 --- a/test/thirdparty/signinupFeature.test.js +++ b/test/thirdparty/signinupFeature.test.js @@ -1219,13 +1219,6 @@ describe(`signinupTest: ${printPath("[test/thirdparty/signinupFeature.test.js]") ], }); - let currCDIVersion = await Querier.getNewInstanceOrThrowError(undefined).getAPIVersion(); - if (maxVersion(currCDIVersion, "2.7") === "2.7") { - // we don't run the tests below for older versions of the core since it - // was introduced in >= 2.8 CDI - return; - } - const app = express(); app.use(middleware()); diff --git a/test/useridmapping/createUserIdMapping.test.js b/test/useridmapping/createUserIdMapping.test.js index 160d23751..9040f83d7 100644 --- a/test/useridmapping/createUserIdMapping.test.js +++ b/test/useridmapping/createUserIdMapping.test.js @@ -30,13 +30,6 @@ describe(`createUserIdMappingTest: ${printPath("[test/useridmapping/createUserId recipeList: [EmailPasswordRecipe.init(), SessionRecipe.init()], }); - // Only run for version >= 2.15 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.14") === "2.14") { - return this.skip(); - } - // create a user let signUpResponse = await EmailPasswordRecipe.signUp("public", "test@example.com", "testPass123"); assert.strictEqual(signUpResponse.status, "OK"); @@ -81,13 +74,6 @@ describe(`createUserIdMappingTest: ${printPath("[test/useridmapping/createUserId recipeList: [EmailPasswordRecipe.init(), SessionRecipe.init()], }); - // Only run for version >= 2.15 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.14") === "2.14") { - return this.skip(); - } - // create the userId mapping let createUserIdMappingResponse = await STExpress.createUserIdMapping({ superTokensUserId: "unknownuUserId", @@ -113,13 +99,6 @@ describe(`createUserIdMappingTest: ${printPath("[test/useridmapping/createUserId recipeList: [EmailPasswordRecipe.init(), SessionRecipe.init()], }); - // Only run for version >= 2.15 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.14") === "2.14") { - return this.skip(); - } - // create a UserId mapping const signInResponse = await EmailPasswordRecipe.signUp("public", "test@example.com", "testPass123"); @@ -195,13 +174,6 @@ describe(`createUserIdMappingTest: ${printPath("[test/useridmapping/createUserId recipeList: [EmailPasswordRecipe.init(), UserMetadataRecipe.init(), SessionRecipe.init()], }); - // Only run for version >= 2.15 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.14") === "2.14") { - return this.skip(); - } - // create a user const signInResponse = await EmailPasswordRecipe.signUp("public", "test@example.com", "testPass123"); diff --git a/test/useridmapping/deleteUserIdMapping.test.js b/test/useridmapping/deleteUserIdMapping.test.js index 0e1ae84d8..a3b70fb13 100644 --- a/test/useridmapping/deleteUserIdMapping.test.js +++ b/test/useridmapping/deleteUserIdMapping.test.js @@ -30,13 +30,6 @@ describe(`deleteUserIdMappingTest: ${printPath("[test/useridmapping/deleteUserId recipeList: [EmailPasswordRecipe.init(), SessionRecipe.init()], }); - // Only run for version >= 2.15 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.14") === "2.14") { - return this.skip(); - } - { let response = await STExpress.deleteUserIdMapping({ userId: "unknown", userIdType: "SUPERTOKENS" }); assert.strictEqual(Object.keys(response).length, 2); @@ -74,13 +67,6 @@ describe(`deleteUserIdMappingTest: ${printPath("[test/useridmapping/deleteUserId recipeList: [EmailPasswordRecipe.init(), SessionRecipe.init()], }); - // Only run for version >= 2.15 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.14") === "2.14") { - return this.skip(); - } - // create a user let signUpResponse = await EmailPasswordRecipe.signUp("public", "test@example.com", "testPass123"); assert.strictEqual(signUpResponse.status, "OK"); @@ -128,13 +114,6 @@ describe(`deleteUserIdMappingTest: ${printPath("[test/useridmapping/deleteUserId recipeList: [EmailPasswordRecipe.init(), SessionRecipe.init()], }); - // Only run for version >= 2.15 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.14") === "2.14") { - return this.skip(); - } - // create a user let signUpResponse = await EmailPasswordRecipe.signUp("public", "test@example.com", "testPass123"); assert.strictEqual(signUpResponse.status, "OK"); @@ -182,13 +161,6 @@ describe(`deleteUserIdMappingTest: ${printPath("[test/useridmapping/deleteUserId recipeList: [EmailPasswordRecipe.init(), SessionRecipe.init()], }); - // Only run for version >= 2.15 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.14") === "2.14") { - return this.skip(); - } - // create a user let signUpResponse = await EmailPasswordRecipe.signUp("public", "test@example.com", "testPass123"); assert.strictEqual(signUpResponse.status, "OK"); @@ -263,13 +235,6 @@ describe(`deleteUserIdMappingTest: ${printPath("[test/useridmapping/deleteUserId recipeList: [EmailPasswordRecipe.init(), UserMetadataRecipe.init(), SessionRecipe.init()], }); - // Only run for version >= 2.15 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.14") === "2.14") { - return this.skip(); - } - // create a user and map their userId let signUpResponse = await EmailPasswordRecipe.signUp("public", "test@example.com", "testPass123"); assert.strictEqual(signUpResponse.status, "OK"); diff --git a/test/useridmapping/getUserIdMapping.test.js b/test/useridmapping/getUserIdMapping.test.js index c036f74ab..fc7653438 100644 --- a/test/useridmapping/getUserIdMapping.test.js +++ b/test/useridmapping/getUserIdMapping.test.js @@ -29,13 +29,6 @@ describe(`getUserIdMappingTest: ${printPath("[test/useridmapping/getUserIdMappin recipeList: [EmailPasswordRecipe.init(), SessionRecipe.init()], }); - // Only run for version >= 2.15 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.14") === "2.14") { - return this.skip(); - } - // create a user let signUpResponse = await EmailPasswordRecipe.signUp("public", "test@example.com", "testPass123"); assert.strictEqual(signUpResponse.status, "OK"); @@ -122,13 +115,6 @@ describe(`getUserIdMappingTest: ${printPath("[test/useridmapping/getUserIdMappin recipeList: [EmailPasswordRecipe.init(), SessionRecipe.init()], }); - // Only run for version >= 2.15 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.14") === "2.14") { - return this.skip(); - } - { let getUserIdMappingResponse = await STExpress.getUserIdMapping({ userId: "unknownId", @@ -172,13 +158,6 @@ describe(`getUserIdMappingTest: ${printPath("[test/useridmapping/getUserIdMappin recipeList: [EmailPasswordRecipe.init(), SessionRecipe.init()], }); - // Only run for version >= 2.15 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.14") === "2.14") { - return this.skip(); - } - // create a user let signUpResponse = await EmailPasswordRecipe.signUp("public", "test@example.com", "testPass123"); assert.strictEqual(signUpResponse.status, "OK"); diff --git a/test/useridmapping/recipeTests/emailpassword.test.js b/test/useridmapping/recipeTests/emailpassword.test.js index 87c4f75ba..70f9e2d9e 100644 --- a/test/useridmapping/recipeTests/emailpassword.test.js +++ b/test/useridmapping/recipeTests/emailpassword.test.js @@ -29,13 +29,6 @@ describe(`userIdMapping with emailpassword: ${printPath( recipeList: [EmailPasswordRecipe.init(), SessionRecipe.init()], }); - // Only run for version >= 2.15 - const querier = Querier.getNewInstanceOrThrowError(undefined); - const apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.14") === "2.14") { - return this.skip(); - } - // create a new EmailPassword User const email = "test@example.com"; const password = "testPass123"; @@ -92,13 +85,6 @@ describe(`userIdMapping with emailpassword: ${printPath( recipeList: [EmailPasswordRecipe.init(), SessionRecipe.init()], }); - // Only run for version >= 2.15 - const querier = Querier.getNewInstanceOrThrowError(undefined); - const apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.14") === "2.14") { - return this.skip(); - } - // create a new EmailPassword User const email = "test@example.com"; const password = "testPass123"; @@ -147,13 +133,6 @@ describe(`userIdMapping with emailpassword: ${printPath( recipeList: [EmailPasswordRecipe.init(), SessionRecipe.init()], }); - // Only run for version >= 2.15 - const querier = Querier.getNewInstanceOrThrowError(undefined); - const apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.14") === "2.14") { - return this.skip(); - } - // create a new EmailPassword User const email = "test@example.com"; const password = "testPass123"; @@ -199,13 +178,6 @@ describe(`userIdMapping with emailpassword: ${printPath( recipeList: [EmailPasswordRecipe.init(), SessionRecipe.init()], }); - // Only run for version >= 2.15 - const querier = Querier.getNewInstanceOrThrowError(undefined); - const apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.14") === "2.14") { - return this.skip(); - } - // create a new EmailPassword User const email = "test@example.com"; const password = "testPass123"; @@ -272,13 +244,6 @@ describe(`userIdMapping with emailpassword: ${printPath( recipeList: [EmailPasswordRecipe.init(), SessionRecipe.init()], }); - // Only run for version >= 2.15 - const querier = Querier.getNewInstanceOrThrowError(undefined); - const apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.14") === "2.14") { - return this.skip(); - } - // create a new EmailPassword User const email = "test@example.com"; const password = "testPass123"; diff --git a/test/useridmapping/recipeTests/passwordless.test.js b/test/useridmapping/recipeTests/passwordless.test.js index 4ac74439b..c015d0a31 100644 --- a/test/useridmapping/recipeTests/passwordless.test.js +++ b/test/useridmapping/recipeTests/passwordless.test.js @@ -45,13 +45,6 @@ describe(`userIdMapping with passwordless: ${printPath( ], }); - // Only run for version >= 2.15 - const querier = Querier.getNewInstanceOrThrowError(undefined); - const apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.14") === "2.14") { - return this.skip(); - } - // create a Passwordless user const email = "test@example.com"; const codeInfo = await PasswordlessRecipe.createCode({ @@ -130,13 +123,6 @@ describe(`userIdMapping with passwordless: ${printPath( ], }); - // Only run for version >= 2.15 - const querier = Querier.getNewInstanceOrThrowError(undefined); - const apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.14") === "2.14") { - return this.skip(); - } - // create a Passwordless user const email = "test@example.com"; const codeInfo = await PasswordlessRecipe.createCode({ @@ -201,13 +187,6 @@ describe(`userIdMapping with passwordless: ${printPath( ], }); - // Only run for version >= 2.15 - const querier = Querier.getNewInstanceOrThrowError(undefined); - const apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.14") === "2.14") { - return this.skip(); - } - // create a Passwordless user const email = "test@example.com"; const codeInfo = await PasswordlessRecipe.createCode({ @@ -274,13 +253,6 @@ describe(`userIdMapping with passwordless: ${printPath( ], }); - // Only run for version >= 2.15 - const querier = Querier.getNewInstanceOrThrowError(undefined); - const apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.14") === "2.14") { - return this.skip(); - } - // create a Passwordless user const phoneNumber = "+911234566789"; const codeInfo = await PasswordlessRecipe.createCode({ @@ -347,13 +319,6 @@ describe(`userIdMapping with passwordless: ${printPath( ], }); - // Only run for version >= 2.15 - const querier = Querier.getNewInstanceOrThrowError(undefined); - const apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.14") === "2.14") { - return this.skip(); - } - // create a Passwordless user const phoneNumber = "+911234566789"; const codeInfo = await PasswordlessRecipe.createCode({ diff --git a/test/useridmapping/recipeTests/supertokens.test.js b/test/useridmapping/recipeTests/supertokens.test.js index 60253d2d8..08190b800 100644 --- a/test/useridmapping/recipeTests/supertokens.test.js +++ b/test/useridmapping/recipeTests/supertokens.test.js @@ -30,13 +30,6 @@ describe(`userIdMapping with supertokens recipe: ${printPath( recipeList: [EmailPasswordRecipe.init(), UserMetadataRecipe.init(), SessionRecipe.init()], }); - // Only run for version >= 2.15 - const querier = Querier.getNewInstanceOrThrowError(undefined); - const apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.14") === "2.14") { - return this.skip(); - } - // create a new EmailPassword User const email = "test@example.com"; const password = "testPass123"; @@ -114,13 +107,6 @@ describe(`userIdMapping with supertokens recipe: ${printPath( recipeList: [EmailPasswordRecipe.init(), SessionRecipe.init()], }); - // Only run for version >= 2.15 - const querier = Querier.getNewInstanceOrThrowError(undefined); - const apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.14") === "2.14") { - return this.skip(); - } - // create multiple users const email = ["test@example.com", "test1@example.com", "test2@example.com", "test3@example.com"]; const password = "testPass123"; diff --git a/test/useridmapping/recipeTests/thirdparty.test.js b/test/useridmapping/recipeTests/thirdparty.test.js index dd764a82e..a0bd2cc42 100644 --- a/test/useridmapping/recipeTests/thirdparty.test.js +++ b/test/useridmapping/recipeTests/thirdparty.test.js @@ -48,13 +48,6 @@ describe(`userIdMapping with thirdparty: ${printPath( ], }); - // Only run for version >= 2.15 - const querier = Querier.getNewInstanceOrThrowError(undefined); - const apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.14") === "2.14") { - return this.skip(); - } - // create a thirdParty user let signInUpResponse = await ThirdPartyRecipe.manuallyCreateOrUpdateUser( "public", @@ -122,13 +115,6 @@ describe(`userIdMapping with thirdparty: ${printPath( ], }); - // Only run for version >= 2.15 - const querier = Querier.getNewInstanceOrThrowError(undefined); - const apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.14") === "2.14") { - return this.skip(); - } - // create a thirdParty user let signInUpResponse = await ThirdPartyRecipe.manuallyCreateOrUpdateUser( "public", @@ -189,13 +175,6 @@ describe(`userIdMapping with thirdparty: ${printPath( ], }); - // Only run for version >= 2.15 - const querier = Querier.getNewInstanceOrThrowError(undefined); - const apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.14") === "2.14") { - return this.skip(); - } - // create a thirdParty user let signInUpResponse = await ThirdPartyRecipe.manuallyCreateOrUpdateUser( "public", @@ -256,13 +235,6 @@ describe(`userIdMapping with thirdparty: ${printPath( ], }); - // Only run for version >= 2.15 - const querier = Querier.getNewInstanceOrThrowError(undefined); - const apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.14") === "2.14") { - return this.skip(); - } - // create a thirdParty user const thirdPartyId = "google"; const thirdPartyUserId = "tpId"; diff --git a/test/useridmapping/updateOrDeleteUserIdMappingInfo.test.js b/test/useridmapping/updateOrDeleteUserIdMappingInfo.test.js index 9bd7a5a94..aab2c95c9 100644 --- a/test/useridmapping/updateOrDeleteUserIdMappingInfo.test.js +++ b/test/useridmapping/updateOrDeleteUserIdMappingInfo.test.js @@ -31,13 +31,6 @@ describe(`updateOrDeleteUserIdMappingInfoTest: ${printPath( recipeList: [EmailPasswordRecipe.init(), SessionRecipe.init()], }); - // Only run for version >= 2.15 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.14") === "2.14") { - return this.skip(); - } - { const response = await STExpress.updateOrDeleteUserIdMappingInfo({ userId: "unknown", @@ -86,13 +79,6 @@ describe(`updateOrDeleteUserIdMappingInfoTest: ${printPath( recipeList: [EmailPasswordRecipe.init(), SessionRecipe.init()], }); - // Only run for version >= 2.15 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.14") === "2.14") { - return this.skip(); - } - // create a user let signUpResponse = await EmailPasswordRecipe.signUp("public", "test@example.com", "testPass123"); assert.strictEqual(signUpResponse.status, "OK"); @@ -189,13 +175,6 @@ describe(`updateOrDeleteUserIdMappingInfoTest: ${printPath( recipeList: [EmailPasswordRecipe.init(), SessionRecipe.init()], }); - // Only run for version >= 2.15 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.14") === "2.14") { - return this.skip(); - } - // create a user let signUpResponse = await EmailPasswordRecipe.signUp("public", "test@example.com", "testPass123"); assert.strictEqual(signUpResponse.status, "OK"); diff --git a/test/usermetadata/clearUserMetadata.test.js b/test/usermetadata/clearUserMetadata.test.js index f20b5ee48..eb1d5f7d7 100644 --- a/test/usermetadata/clearUserMetadata.test.js +++ b/test/usermetadata/clearUserMetadata.test.js @@ -30,13 +30,6 @@ describe(`clearUserMetadataTest: ${printPath("[test/usermetadata/clearUserMetada recipeList: [UserMetadataRecipe.init()], }); - // Only run for version >= 2.13 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.12") === "2.12") { - return this.skip(); - } - const result = await UserMetadataRecipe.clearUserMetadata(testUserId); assert.strictEqual(result.status, "OK"); @@ -62,12 +55,6 @@ describe(`clearUserMetadataTest: ${printPath("[test/usermetadata/clearUserMetada recipeList: [UserMetadataRecipe.init()], }); - // Only run for version >= 2.13 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.12") === "2.12") { - return this.skip(); - } await UserMetadataRecipe.updateUserMetadata(testUserId, testMetadata); const result = await UserMetadataRecipe.clearUserMetadata(testUserId); diff --git a/test/usermetadata/config.test.js b/test/usermetadata/config.test.js index ceb873b34..9c65a4a5b 100644 --- a/test/usermetadata/config.test.js +++ b/test/usermetadata/config.test.js @@ -25,13 +25,6 @@ describe(`configTest: ${printPath("[test/usermetadata/config.test.js]")}`, funct recipeList: [UserMetadataRecipe.init()], }); - // Only run for version >= 2.13 - const querier = Querier.getNewInstanceOrThrowError(undefined); - const apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.12") === "2.12") { - return this.skip(); - } - await UserMetadataRecipe.getInstanceOrThrowError(); }); }); diff --git a/test/usermetadata/getUserMetadata.test.js b/test/usermetadata/getUserMetadata.test.js index 8c6258c22..54d8257c8 100644 --- a/test/usermetadata/getUserMetadata.test.js +++ b/test/usermetadata/getUserMetadata.test.js @@ -30,13 +30,6 @@ describe(`getUserMetadataTest: ${printPath("[test/usermetadata/getUserMetadata.t recipeList: [UserMetadataRecipe.init()], }); - // Only run for version >= 2.13 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.12") === "2.12") { - return this.skip(); - } - const result = await UserMetadataRecipe.getUserMetadata(testUserId); assert.strictEqual(result.status, "OK"); @@ -62,13 +55,6 @@ describe(`getUserMetadataTest: ${printPath("[test/usermetadata/getUserMetadata.t }, recipeList: [UserMetadataRecipe.init()], }); - - // Only run for version >= 2.13 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.12") === "2.12") { - return this.skip(); - } await UserMetadataRecipe.updateUserMetadata(testUserId, testMetadata); const result = await UserMetadataRecipe.getUserMetadata(testUserId); diff --git a/test/usermetadata/override.test.js b/test/usermetadata/override.test.js index 9ecbe7040..26829d9be 100644 --- a/test/usermetadata/override.test.js +++ b/test/usermetadata/override.test.js @@ -34,13 +34,6 @@ describe(`overrideTest: ${printPath("[test/usermetadata/override.test.js]")}`, f recipeList: [UserMetadataRecipe.init()], }); - // Only run for version >= 2.13 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.12") === "2.12") { - return this.skip(); - } - const updateResult = await UserMetadataRecipe.updateUserMetadata(testUserId, testMetadata, testUserContext); const getResult = await UserMetadataRecipe.getUserMetadata(testUserId, testUserContext); const clearResult = await UserMetadataRecipe.clearUserMetadata(testUserId, testUserContext); @@ -110,13 +103,6 @@ describe(`overrideTest: ${printPath("[test/usermetadata/override.test.js]")}`, f ], }); - // Only run for version >= 2.13 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.12") === "2.12") { - return this.skip(); - } - const updateResult = await UserMetadataRecipe.updateUserMetadata(testUserId, testMetadata, testUserContext); const getResult = await UserMetadataRecipe.getUserMetadata(testUserId, testUserContext); const clearResult = await UserMetadataRecipe.clearUserMetadata(testUserId, testUserContext); diff --git a/test/usermetadata/updateUserMetadata.test.js b/test/usermetadata/updateUserMetadata.test.js index e724d3ee9..7229f477d 100644 --- a/test/usermetadata/updateUserMetadata.test.js +++ b/test/usermetadata/updateUserMetadata.test.js @@ -33,13 +33,6 @@ describe(`updateUserMetadataTest: ${printPath("[test/usermetadata/updateUserMeta recipeList: [UserMetadataRecipe.init()], }); - // Only run for version >= 2.13 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.12") === "2.12") { - return this.skip(); - } - const updateResult = await UserMetadataRecipe.updateUserMetadata(testUserId, testMetadata); const getResult = await UserMetadataRecipe.getUserMetadata(testUserId); @@ -70,13 +63,6 @@ describe(`updateUserMetadataTest: ${printPath("[test/usermetadata/updateUserMeta recipeList: [UserMetadataRecipe.init()], }); - // Only run for version >= 2.13 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.12") === "2.12") { - return this.skip(); - } - const updateResult = await UserMetadataRecipe.updateUserMetadata(testUserId, testMetadata); const getResult = await UserMetadataRecipe.getUserMetadata(testUserId); @@ -107,13 +93,6 @@ describe(`updateUserMetadataTest: ${printPath("[test/usermetadata/updateUserMeta recipeList: [UserMetadataRecipe.init()], }); - // Only run for version >= 2.13 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.12") === "2.12") { - return this.skip(); - } - await UserMetadataRecipe.updateUserMetadata(testUserId, { test: "asdf" }); await UserMetadataRecipe.clearUserMetadata(testUserId); const updateResult = await UserMetadataRecipe.updateUserMetadata(testUserId, testMetadata); @@ -169,13 +148,6 @@ describe(`updateUserMetadataTest: ${printPath("[test/usermetadata/updateUserMeta recipeList: [UserMetadataRecipe.init()], }); - // Only run for version >= 2.13 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.12") === "2.12") { - return this.skip(); - } - await UserMetadataRecipe.updateUserMetadata(testUserId, testMetadata); const updateResult = await UserMetadataRecipe.updateUserMetadata(testUserId, testMetadataUpdate); diff --git a/test/userroles/addRoleToUser.test.js b/test/userroles/addRoleToUser.test.js index 6e83c3ac3..db500a889 100644 --- a/test/userroles/addRoleToUser.test.js +++ b/test/userroles/addRoleToUser.test.js @@ -29,13 +29,6 @@ describe(`addRoleToUserTest: ${printPath("[test/userroles/addRoleToUser.test.js] recipeList: [SessionRecipe.init(), UserRolesRecipe.init()], }); - // Only run for version >= 2.14 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.13") === "2.13") { - return this.skip(); - } - const userId = "userId"; const role = "role"; @@ -77,13 +70,6 @@ describe(`addRoleToUserTest: ${printPath("[test/userroles/addRoleToUser.test.js] recipeList: [SessionRecipe.init(), UserRolesRecipe.init()], }); - // Only run for version >= 2.14 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.13") === "2.13") { - return this.skip(); - } - const userId = "userId"; const role = "role"; @@ -132,13 +118,6 @@ describe(`addRoleToUserTest: ${printPath("[test/userroles/addRoleToUser.test.js] recipeList: [SessionRecipe.init(), UserRolesRecipe.init()], }); - // Only run for version >= 2.14 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.13") === "2.13") { - return this.skip(); - } - const userId = "userId"; const role = "unknownRole"; diff --git a/test/userroles/claims.test.js b/test/userroles/claims.test.js index 45d1bb15b..8a0433bd6 100644 --- a/test/userroles/claims.test.js +++ b/test/userroles/claims.test.js @@ -34,13 +34,6 @@ describe(`claimsTest: ${printPath("[test/userroles/claims.test.js]")}`, function recipeList: [UserRoles.init(), Session.init({ getTokenTransferMethod: () => "cookie" })], }); - // Only run for version >= 2.14 - const querier = Querier.getNewInstanceOrThrowError(undefined); - const apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.13") === "2.13") { - return this.skip(); - } - const session = await Session.createNewSession( mockRequest(), mockResponse(), @@ -71,13 +64,6 @@ describe(`claimsTest: ${printPath("[test/userroles/claims.test.js]")}`, function ], }); - // Only run for version >= 2.14 - const querier = Querier.getNewInstanceOrThrowError(undefined); - const apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.13") === "2.13") { - return this.skip(); - } - const session = await Session.createNewSession( mockRequest(), mockResponse(), @@ -102,13 +88,6 @@ describe(`claimsTest: ${printPath("[test/userroles/claims.test.js]")}`, function recipeList: [UserRoles.init(), Session.init({ getTokenTransferMethod: () => "cookie" })], }); - // Only run for version >= 2.14 - const querier = Querier.getNewInstanceOrThrowError(undefined); - const apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.13") === "2.13") { - return this.skip(); - } - await UserRoles.createNewRoleOrAddPermissions("test", ["a", "b"]); await UserRoles.addRoleToUser("public", "userId", "test"); const session = await Session.createNewSession( @@ -137,13 +116,6 @@ describe(`claimsTest: ${printPath("[test/userroles/claims.test.js]")}`, function recipeList: [UserRoles.init(), Session.init({ getTokenTransferMethod: () => "cookie" })], }); - // Only run for version >= 2.14 - const querier = Querier.getNewInstanceOrThrowError(undefined); - const apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.13") === "2.13") { - return this.skip(); - } - await UserRoles.createNewRoleOrAddPermissions("test", ["a", "b"]); await UserRoles.addRoleToUser("public", "userId", "test"); const session = await Session.createNewSession( @@ -190,13 +162,6 @@ describe(`claimsTest: ${printPath("[test/userroles/claims.test.js]")}`, function ], }); - // Only run for version >= 2.14 - const querier = Querier.getNewInstanceOrThrowError(undefined); - const apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.13") === "2.13") { - return this.skip(); - } - const session = await Session.createNewSession( mockRequest(), mockResponse(), @@ -222,13 +187,6 @@ describe(`claimsTest: ${printPath("[test/userroles/claims.test.js]")}`, function recipeList: [UserRoles.init(), Session.init({ getTokenTransferMethod: () => "cookie" })], }); - // Only run for version >= 2.14 - const querier = Querier.getNewInstanceOrThrowError(undefined); - const apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.13") === "2.13") { - return this.skip(); - } - await UserRoles.createNewRoleOrAddPermissions("test", ["a", "b"]); await UserRoles.addRoleToUser("public", "userId", "test"); const session = await Session.createNewSession( @@ -275,13 +233,6 @@ describe(`claimsTest: ${printPath("[test/userroles/claims.test.js]")}`, function ], }); - // Only run for version >= 2.14 - const querier = Querier.getNewInstanceOrThrowError(undefined); - const apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.13") === "2.13") { - return this.skip(); - } - const session = await Session.createNewSession( mockRequest(), mockResponse(), diff --git a/test/userroles/config.test.js b/test/userroles/config.test.js index a6701ca97..3603e3e7e 100644 --- a/test/userroles/config.test.js +++ b/test/userroles/config.test.js @@ -26,13 +26,6 @@ describe(`configTest: ${printPath("[test/userroles/config.test.js]")}`, function recipeList: [UserRolesRecipe.init(), SessionRecipe.init()], }); - // Only run for version >= 2.14 - const querier = Querier.getNewInstanceOrThrowError(undefined); - const apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.13") === "2.13") { - return this.skip(); - } - await UserRolesRecipe.getInstanceOrThrowError(); }); }); diff --git a/test/userroles/createNewRoleOrAddPermissions.test.js b/test/userroles/createNewRoleOrAddPermissions.test.js index 43a4a59b7..2a86dc618 100644 --- a/test/userroles/createNewRoleOrAddPermissions.test.js +++ b/test/userroles/createNewRoleOrAddPermissions.test.js @@ -31,13 +31,6 @@ describe(`createNewRoleOrAddPermissionsTest: ${printPath( recipeList: [SessionRecipe.init(), UserRolesRecipe.init()], }); - // Only run for version >= 2.14 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.13") === "2.13") { - return this.skip(); - } - const result = await UserRolesRecipe.createNewRoleOrAddPermissions("newRole", []); assert.strictEqual(result.status, "OK"); assert(result.createdNewRole); @@ -60,13 +53,6 @@ describe(`createNewRoleOrAddPermissionsTest: ${printPath( recipeList: [SessionRecipe.init(), UserRolesRecipe.init()], }); - // Only run for version >= 2.14 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.13") === "2.13") { - return this.skip(); - } - { const result = await UserRolesRecipe.createNewRoleOrAddPermissions(role, []); assert.strictEqual(result.status, "OK"); @@ -98,13 +84,6 @@ describe(`createNewRoleOrAddPermissionsTest: ${printPath( recipeList: [SessionRecipe.init(), UserRolesRecipe.init()], }); - // Only run for version >= 2.14 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.13") === "2.13") { - return this.skip(); - } - { const result = await UserRolesRecipe.createNewRoleOrAddPermissions(role, permissions); assert.strictEqual(result.status, "OK"); @@ -137,13 +116,6 @@ describe(`createNewRoleOrAddPermissionsTest: ${printPath( recipeList: [SessionRecipe.init(), UserRolesRecipe.init()], }); - // Only run for version >= 2.14 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.13") === "2.13") { - return this.skip(); - } - { const result = await UserRolesRecipe.createNewRoleOrAddPermissions(role, permissions); assert.strictEqual(result.status, "OK"); @@ -189,13 +161,6 @@ describe(`createNewRoleOrAddPermissionsTest: ${printPath( recipeList: [SessionRecipe.init(), UserRolesRecipe.init()], }); - // Only run for version >= 2.14 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.13") === "2.13") { - return this.skip(); - } - { const result = await UserRolesRecipe.createNewRoleOrAddPermissions(role, permissions); assert.strictEqual(result.status, "OK"); diff --git a/test/userroles/deleteRole.test.js b/test/userroles/deleteRole.test.js index dc500eee6..e9049688d 100644 --- a/test/userroles/deleteRole.test.js +++ b/test/userroles/deleteRole.test.js @@ -29,13 +29,6 @@ describe(`deleteRole: ${printPath("[test/userroles/deleteRole.test.js]")}`, func recipeList: [SessionRecipe.init(), UserRolesRecipe.init()], }); - // Only run for version >= 2.14 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.13") === "2.13") { - return this.skip(); - } - const roles = ["role1", "role2", "role3"]; const userId = "user"; @@ -85,13 +78,6 @@ describe(`deleteRole: ${printPath("[test/userroles/deleteRole.test.js]")}`, func recipeList: [SessionRecipe.init(), UserRolesRecipe.init()], }); - // Only run for version >= 2.14 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.13") === "2.13") { - return this.skip(); - } - const result = await UserRolesRecipe.deleteRole("unknownRole"); assert.strictEqual(result.status, "OK"); assert(!result.didRoleExist); diff --git a/test/userroles/getPermissionsForRole.test.js b/test/userroles/getPermissionsForRole.test.js index 2b959176f..bcf26f0f9 100644 --- a/test/userroles/getPermissionsForRole.test.js +++ b/test/userroles/getPermissionsForRole.test.js @@ -29,13 +29,6 @@ describe(`getPermissionsForRole: ${printPath("[test/userroles/getPermissionsForR recipeList: [SessionRecipe.init(), UserRolesRecipe.init()], }); - // Only run for version >= 2.14 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.13") === "2.13") { - return this.skip(); - } - const role = "role"; const permissions = ["permission1", "permission2", "permission3"]; @@ -68,13 +61,6 @@ describe(`getPermissionsForRole: ${printPath("[test/userroles/getPermissionsForR recipeList: [SessionRecipe.init(), UserRolesRecipe.init()], }); - // Only run for version >= 2.14 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.13") === "2.13") { - return this.skip(); - } - // retrieve the users for role that does not exist const result = await UserRolesRecipe.getPermissionsForRole("unknownRole"); assert.strictEqual(result.status, "UNKNOWN_ROLE_ERROR"); diff --git a/test/userroles/getRolesForUser.test.js b/test/userroles/getRolesForUser.test.js index 1c455780f..e992063d9 100644 --- a/test/userroles/getRolesForUser.test.js +++ b/test/userroles/getRolesForUser.test.js @@ -29,13 +29,6 @@ describe(`getRolesForUser: ${printPath("[test/userroles/getRolesForUser.test.js] recipeList: [SessionRecipe.init(), UserRolesRecipe.init()], }); - // Only run for version >= 2.14 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.13") === "2.13") { - return this.skip(); - } - const userId = "userId"; const roles = ["role1", "role2", "role3"]; diff --git a/test/userroles/getRolesThatHavePermissions.test.js b/test/userroles/getRolesThatHavePermissions.test.js index 89d5cc6ef..bb40a7f01 100644 --- a/test/userroles/getRolesThatHavePermissions.test.js +++ b/test/userroles/getRolesThatHavePermissions.test.js @@ -31,13 +31,6 @@ describe(`getRolesThatHavePermissions: ${printPath( recipeList: [SessionRecipe.init(), UserRolesRecipe.init()], }); - // Only run for version >= 2.14 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.13") === "2.13") { - return this.skip(); - } - const roles = ["role1", "role2", "role3"]; const permission = "permission"; @@ -73,13 +66,6 @@ describe(`getRolesThatHavePermissions: ${printPath( recipeList: [SessionRecipe.init(), UserRolesRecipe.init()], }); - // Only run for version >= 2.14 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.13") === "2.13") { - return this.skip(); - } - // retrieve roles for unknown permission const result = await UserRolesRecipe.getRolesThatHavePermission("unknownPermission"); assert.strictEqual(result.status, "OK"); diff --git a/test/userroles/getUsersThatHaveRole.test.js b/test/userroles/getUsersThatHaveRole.test.js index e6f5aeb35..14711cd06 100644 --- a/test/userroles/getUsersThatHaveRole.test.js +++ b/test/userroles/getUsersThatHaveRole.test.js @@ -29,13 +29,6 @@ describe(`getUsersThatHaveRole: ${printPath("[test/userroles/getUsersThatHaveRol recipeList: [SessionRecipe.init(), UserRolesRecipe.init()], }); - // Only run for version >= 2.14 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.13") === "2.13") { - return this.skip(); - } - const users = ["user1", "user2", "user3"]; const role = "role"; @@ -74,13 +67,6 @@ describe(`getUsersThatHaveRole: ${printPath("[test/userroles/getUsersThatHaveRol recipeList: [SessionRecipe.init(), UserRolesRecipe.init()], }); - // Only run for version >= 2.14 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.13") === "2.13") { - return this.skip(); - } - // retrieve the users for role which that not exist const result = await UserRolesRecipe.getUsersThatHaveRole("public", "unknownRole"); assert.strictEqual(result.status, "UNKNOWN_ROLE_ERROR"); diff --git a/test/userroles/removePermissionsFromRole.test.js b/test/userroles/removePermissionsFromRole.test.js index 4a815ac37..8b6d438e4 100644 --- a/test/userroles/removePermissionsFromRole.test.js +++ b/test/userroles/removePermissionsFromRole.test.js @@ -29,13 +29,6 @@ describe(`getPermissionsForRole: ${printPath("[test/userroles/getPermissionsForR recipeList: [SessionRecipe.init(), UserRolesRecipe.init()], }); - // Only run for version >= 2.14 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.13") === "2.13") { - return this.skip(); - } - const role = "role"; const permissions = ["permission1", "permission2", "permission3"]; @@ -76,13 +69,6 @@ describe(`getPermissionsForRole: ${printPath("[test/userroles/getPermissionsForR recipeList: [SessionRecipe.init(), UserRolesRecipe.init()], }); - // Only run for version >= 2.14 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.13") === "2.13") { - return this.skip(); - } - // remove permission from an unknown role const result = await UserRolesRecipe.removePermissionsFromRole("unknownRole"); assert.strictEqual(result.status, "UNKNOWN_ROLE_ERROR"); diff --git a/test/userroles/removeUserRole.test.js b/test/userroles/removeUserRole.test.js index 3da97ee30..7ffa5d8f8 100644 --- a/test/userroles/removeUserRole.test.js +++ b/test/userroles/removeUserRole.test.js @@ -29,13 +29,6 @@ describe(`removeUserRoleTest: ${printPath("[test/userroles/removeUserRole.test.j recipeList: [SessionRecipe.init(), UserRolesRecipe.init()], }); - // Only run for version >= 2.14 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.13") === "2.13") { - return this.skip(); - } - const userId = "userId"; const role = "role"; @@ -91,13 +84,6 @@ describe(`removeUserRoleTest: ${printPath("[test/userroles/removeUserRole.test.j recipeList: [SessionRecipe.init(), UserRolesRecipe.init()], }); - // Only run for version >= 2.14 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.13") === "2.13") { - return this.skip(); - } - const userId = "userId"; const role = "role"; @@ -131,13 +117,6 @@ describe(`removeUserRoleTest: ${printPath("[test/userroles/removeUserRole.test.j recipeList: [SessionRecipe.init(), UserRolesRecipe.init()], }); - // Only run for version >= 2.14 - let querier = Querier.getNewInstanceOrThrowError(undefined); - let apiVersion = await querier.getAPIVersion(); - if (maxVersion(apiVersion, "2.13") === "2.13") { - return this.skip(); - } - const userId = "userId"; const role = "unknownRole"; diff --git a/test/utils.js b/test/utils.js index c9f18e0e3..da5c45e0d 100644 --- a/test/utils.js +++ b/test/utils.js @@ -376,7 +376,7 @@ const consoleOptions = { }; module.exports.signUPRequest = async function (app, email, password) { - return new Promise(function (resolve) { + return new Promise(function (resolve, reject) { request(app) .post("/auth/signup") .set("st-auth-mode", "cookie") @@ -394,7 +394,7 @@ module.exports.signUPRequest = async function (app, email, password) { }) .end((err, res) => { if (err) { - resolve(undefined); + reject(undefined); } else { resolve(res); } @@ -512,7 +512,8 @@ module.exports.mockLambdaProxyEventV2 = function (path, httpMethod, headers, bod }; module.exports.isCDIVersionCompatible = async function (compatibleCDIVersion) { - let currCDIVersion = await Querier.getNewInstanceOrThrowError(undefined).getAPIVersion(); + const querier = module.exports.getQuerierInstance(); + let currCDIVersion = await querier.getAPIVersion(); if ( maxVersion(currCDIVersion, compatibleCDIVersion) === compatibleCDIVersion && @@ -523,6 +524,10 @@ module.exports.isCDIVersionCompatible = async function (compatibleCDIVersion) { return true; }; +module.exports.getQuerierInstance = function (rid) { + return Querier.getNewInstanceOrThrowError(SuperTokens.getInstanceOrThrowError(), rid); +}; + module.exports.generateRandomCode = function (size) { let characters = "ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz"; let randomString = ""; From fb54d1b96aeae3d3d50e16c208430674b18b80d8 Mon Sep 17 00:00:00 2001 From: Mihaly Lengyel Date: Thu, 27 Nov 2025 18:28:25 +0100 Subject: [PATCH 12/12] test: update test server to match new object structure --- test/test-server/src/emailverification.ts | 9 ++-- test/test-server/src/session.ts | 52 +++++++++++++---------- test/test-server/src/utils.ts | 16 +++++++ 3 files changed, 51 insertions(+), 26 deletions(-) diff --git a/test/test-server/src/emailverification.ts b/test/test-server/src/emailverification.ts index 9cd080e96..99364e5f3 100644 --- a/test/test-server/src/emailverification.ts +++ b/test/test-server/src/emailverification.ts @@ -71,19 +71,20 @@ const router = Router() ); const session: Session.SessionContainer | undefined = req.body.session && (await convertRequestSessionToSessionObject(req.body.session)); - const response = await EmailVerificationRecipe.getInstanceOrThrowError().updateSessionIfRequiredPostEmailVerification( - { + const response = + await EmailVerificationRecipe.getInstanceOrThrowError().updateSessionIfRequiredPostEmailVerification({ ...req.body, session, recipeUserIdWhoseEmailGotVerified, - } - ); + userContext: req.body.userContext ?? {}, + }); logDebugMessage( "EmailVerificationRecipe:updateSessionIfRequiredPostEmailVerification response %j", response ); res.json(response); } catch (e) { + console.error(e); // we do not call next(e) here so that the proper error response is sent back to the client // otherwise the supertokens error handler will send a different type of response. res.status(500).json({ ...e, message: e.message }); diff --git a/test/test-server/src/session.ts b/test/test-server/src/session.ts index 49c2eab59..08417fc12 100644 --- a/test/test-server/src/session.ts +++ b/test/test-server/src/session.ts @@ -4,7 +4,13 @@ import * as supertokens from "../../../lib/build"; import SessionRecipe from "../../../lib/build/recipe/session/recipe"; import { logger } from "./logger"; import { getFunc } from "./testFunctionMapper"; -import { convertRequestSessionToSessionObject, deserializeClaim, deserializeValidator, maxVersion } from "./utils"; +import { + convertRequestSessionToSessionObject, + deserializeClaim, + deserializeValidator, + maxVersion, + serializeResponseSession, +} from "./utils"; import { logOverrideEvent } from "./overrideLogging"; const namespace = "com.supertokens:node-test-server:session"; @@ -34,7 +40,8 @@ const router = Router() req.body.disableAntiCsrf, req.body.userContext ); - res.json(response); + + res.json(serializeResponseSession(response)); } catch (e) { next(e); } @@ -48,7 +55,7 @@ const router = Router() req.body.options, req.body.userContext ); - res.json(response); + res.json(serializeResponseSession(response)); } catch (e) { next(e); } @@ -85,8 +92,9 @@ const router = Router() req.body.antiCsrfToken, req.body.userContext ); - res.json(response); + res.json(serializeResponseSession(response)); } catch (e) { + console.error(e); // we do not call next(e) here so that the proper error response is sent back to the client // otherwise the supertokens error handler will send a different type of response. res.status(500).json({ ...e, message: e.message }); @@ -166,7 +174,7 @@ const router = Router() throw new Error("This should never happen: failed to deserialize session"); } const retVal = await session.revokeSession(req.body.userContext); // : Promise; - res.json({ retVal, updatedSession: { ...session } }); + res.json({ retVal, updatedSession: serializeResponseSession(session) }); logOverrideEvent("sessionobject.revokesession", "RES", retVal); } catch (e) { @@ -183,7 +191,7 @@ const router = Router() throw new Error("This should never happen: failed to deserialize session"); } const retVal = await session.getSessionDataFromDatabase(req.body.userContext); // : Promise; - res.json({ retVal, updatedSession: { ...session } }); + res.json({ retVal, updatedSession: serializeResponseSession(session) }); logOverrideEvent("sessionobject.getsessiondatafromdatabase", "RES", retVal); } catch (e) { @@ -200,7 +208,7 @@ const router = Router() throw new Error("This should never happen: failed to deserialize session"); } const retVal = await session.updateSessionDataInDatabase(req.body.newSessionData, req.body.userContext); // : Promise; - res.json({ retVal, updatedSession: { ...session } }); + res.json({ retVal, updatedSession: serializeResponseSession(session) }); logOverrideEvent("sessionobject.updatesessiondataindatabase", "RES", retVal); } catch (e) { @@ -217,7 +225,7 @@ const router = Router() throw new Error("This should never happen: failed to deserialize session"); } const retVal = await session.getUserId(req.body.userContext); // : string; - res.json({ retVal, updatedSession: { ...session } }); + res.json({ retVal, updatedSession: serializeResponseSession(session) }); logOverrideEvent("sessionobject.getuserid", "RES", retVal); } catch (e) { @@ -234,7 +242,7 @@ const router = Router() throw new Error("This should never happen: failed to deserialize session"); } const retVal = await session.getRecipeUserId(req.body.userContext); // : RecipeUserId; - res.json({ retVal, updatedSession: { ...session } }); + res.json({ retVal, updatedSession: serializeResponseSession(session) }); logOverrideEvent("sessionobject.getrecipeuserid", "RES", retVal); } catch (e) { @@ -251,7 +259,7 @@ const router = Router() throw new Error("This should never happen: failed to deserialize session"); } const retVal = await session.getTenantId(req.body.userContext); // : string; - res.json({ retVal, updatedSession: { ...session } }); + res.json({ retVal, updatedSession: serializeResponseSession(session) }); logOverrideEvent("sessionobject.gettenantid", "RES", retVal); } catch (e) { @@ -268,7 +276,7 @@ const router = Router() throw new Error("This should never happen: failed to deserialize session"); } const retVal = await session.getAccessTokenPayload(req.body.userContext); // : any; - res.json({ retVal, updatedSession: { ...session } }); + res.json({ retVal, updatedSession: serializeResponseSession(session) }); logOverrideEvent("sessionobject.getaccesstokenpayload", "RES", retVal); } catch (e) { @@ -285,7 +293,7 @@ const router = Router() throw new Error("This should never happen: failed to deserialize session"); } const retVal = await session.getHandle(req.body.userContext); // : string; - res.json({ retVal, updatedSession: { ...session } }); + res.json({ retVal, updatedSession: serializeResponseSession(session) }); logOverrideEvent("sessionobject.gethandle", "RES", retVal); } catch (e) { @@ -302,7 +310,7 @@ const router = Router() throw new Error("This should never happen: failed to deserialize session"); } const retVal = await session.getAllSessionTokensDangerously(); // : Promise<{}>; - res.json({ retVal, updatedSession: { ...session } }); + res.json({ retVal, updatedSession: serializeResponseSession(session) }); logOverrideEvent("sessionobject.getallsessiontokensdangerously", "RES", retVal); } catch (e) { @@ -319,7 +327,7 @@ const router = Router() throw new Error("This should never happen: failed to deserialize session"); } const retVal = await session.getAccessToken(req.body.userContext); // : string; - res.json({ retVal, updatedSession: { ...session } }); + res.json({ retVal, updatedSession: serializeResponseSession(session) }); logOverrideEvent("sessionobject.getaccesstoken", "RES", retVal); } catch (e) { @@ -339,7 +347,7 @@ const router = Router() req.body.accessTokenPayloadUpdate, req.body.userContext ); // : Promise; - res.json({ retVal, updatedSession: { ...session } }); + res.json({ retVal, updatedSession: serializeResponseSession(session) }); logOverrideEvent("sessionobject.mergeintoaccesstokenpayload", "RES", retVal); } catch (e) { @@ -356,7 +364,7 @@ const router = Router() throw new Error("This should never happen: failed to deserialize session"); } const retVal = await session.getTimeCreated(req.body.userContext); // : Promise; - res.json({ retVal, updatedSession: { ...session } }); + res.json({ retVal, updatedSession: serializeResponseSession(session) }); logOverrideEvent("sessionobject.gettimecreated", "RES", retVal); } catch (e) { @@ -373,7 +381,7 @@ const router = Router() throw new Error("This should never happen: failed to deserialize session"); } const retVal = await session.getExpiry(req.body.userContext); // : Promise; - res.json({ retVal, updatedSession: { ...session } }); + res.json({ retVal, updatedSession: serializeResponseSession(session) }); logOverrideEvent("sessionobject.getexpiry", "RES", retVal); } catch (e) { @@ -393,7 +401,7 @@ const router = Router() req.body.claimValidators.map(deserializeValidator), req.body.userContext ); // : Promise; - res.json({ retVal, updatedSession: { ...session } }); + res.json({ retVal, updatedSession: serializeResponseSession(session) }); logOverrideEvent("sessionobject.assertclaims", "RES", retVal); } catch (e) { @@ -411,7 +419,7 @@ const router = Router() } const retVal = await session.fetchAndSetClaim(deserializeClaim(req.body.claim), req.body.userContext); // : Promise; - res.json({ retVal, updatedSession: { ...session } }); + res.json({ retVal, updatedSession: serializeResponseSession(session) }); logOverrideEvent("sessionobject.fetchandsetclaim", "RES", retVal); } catch (e) { @@ -432,7 +440,7 @@ const router = Router() req.body.value, req.body.userContext ); // : Promise; - res.json({ retVal, updatedSession: { ...session } }); + res.json({ retVal, updatedSession: serializeResponseSession(session) }); logOverrideEvent("sessionobject.setclaimvalue", "RES", retVal); } catch (e) { @@ -449,7 +457,7 @@ const router = Router() throw new Error("This should never happen: failed to deserialize session"); } await session.removeClaim(deserializeClaim(req.body.claim), req.body.userContext); // : Promise; - res.json({ updatedSession: { ...session } }); + res.json({ updatedSession: serializeResponseSession(session) }); logOverrideEvent("sessionobject.removeClaim", "RES", undefined); } catch (e) { @@ -466,7 +474,7 @@ const router = Router() throw new Error("This should never happen: failed to deserialize session"); } const retVal = await session.getClaimValue(deserializeClaim(req.body.claim), req.body.userContext); // : Promise; - res.json({ retVal, updatedSession: { ...session } }); + res.json({ retVal, updatedSession: serializeResponseSession(session) }); logOverrideEvent("sessionobject.getclaimvalue", "RES", retVal); } catch (e) { diff --git a/test/test-server/src/utils.ts b/test/test-server/src/utils.ts index 3830825a5..6bd729018 100644 --- a/test/test-server/src/utils.ts +++ b/test/test-server/src/utils.ts @@ -137,6 +137,22 @@ export async function convertRequestSessionToSessionObject( return tokens; } +export function serializeResponseSession(session: Session.SessionContainer) { + const tokens = session.getAllSessionTokensDangerously(); + return { + accessToken: session.getAccessToken(), + frontToken: tokens.frontToken, + refreshToken: (session as any).refreshToken, + antiCsrfToken: tokens.antiCsrfToken, + sessionHandle: session.getHandle(), + userId: session.getUserId(), + recipeUserId: session.getRecipeUserId(), + userDataInAccessToken: session.getAccessTokenPayload(), + accessTokenUpdated: tokens.accessAndFrontTokenUpdated, + tenantId: session.getTenantId(), + }; +} + export async function serializeResponse(req, res, response) { const fdiVersion: string = req.headers["fdi-version"] as string;