{"version":3,"file":"HeadlessMagicLinkClient.mjs","sources":["../../../../../../../core/src/HeadlessClients/HeadlessMagicLinkClient.ts"],"sourcesContent":["import { IConsumerSubscriptionService } from '..';\nimport { IDFPProtectedAuthProvider } from '../DFPProtectedAuthProvider';\nimport { INetworkClient } from '../NetworkClient';\nimport { IPKCEManager } from '../PKCEManager';\nimport {\n  IHeadlessMagicLinksClient,\n  MagicLinksAuthenticateOptions,\n  MagicLinksAuthenticateResponse,\n  MagicLinksLoginOrCreateOptions,\n  MagicLinksLoginOrCreateResponse,\n  MagicLinksSendOptions,\n  MagicLinksSendResponse,\n  ResponseCommon,\n  StytchProjectConfigurationInput,\n} from '../public';\nimport { omitUser, WithUser } from '../utils';\nimport { validateInDev } from '../utils/dev';\n\ntype DynamicConfig = Promise<{\n  pkceRequiredForEmailMagicLinks: boolean;\n}>;\n\nconst DefaultDynamicConfig = Promise.resolve({\n  pkceRequiredForEmailMagicLinks: false,\n});\n\nexport class HeadlessMagicLinksClient<TProjectConfiguration extends StytchProjectConfigurationInput>\n  implements IHeadlessMagicLinksClient<TProjectConfiguration>\n{\n  email: {\n    loginOrCreate: (email: string, options?: MagicLinksLoginOrCreateOptions) => Promise<ResponseCommon>;\n    send: (email: string, options?: MagicLinksSendOptions) => Promise<ResponseCommon>;\n  };\n\n  authenticate: (\n    token: string,\n    options: MagicLinksAuthenticateOptions,\n  ) => Promise<MagicLinksAuthenticateResponse<TProjectConfiguration>>;\n\n  constructor(\n    private _networkClient: INetworkClient,\n    private _subscriptionService: IConsumerSubscriptionService<TProjectConfiguration>,\n    private _pkceManager: IPKCEManager,\n    private _passwordResetPKCEManager: IPKCEManager,\n    private _config: DynamicConfig = DefaultDynamicConfig,\n    private dfpProtectedAuth: IDFPProtectedAuthProvider,\n  ) {\n    this.email = {\n      loginOrCreate: async (email: string, options: MagicLinksLoginOrCreateOptions = {}): Promise<ResponseCommon> => {\n        const { pkceRequiredForEmailMagicLinks } = await this._config;\n\n        let code_challenge: string | undefined = undefined;\n        if (pkceRequiredForEmailMagicLinks) {\n          code_challenge = await this.getCodeChallenge();\n        }\n\n        const { dfp_telemetry_id, captcha_token } = await this.dfpProtectedAuth.getDFPTelemetryIDAndCaptcha();\n        const requestBody = {\n          ...options,\n          email,\n          code_challenge,\n          captcha_token,\n          dfp_telemetry_id,\n        };\n        return this._networkClient.retriableFetchSDK<MagicLinksLoginOrCreateResponse>({\n          url: '/magic_links/email/login_or_create',\n          body: requestBody,\n          method: 'POST',\n          retryCallback: this.dfpProtectedAuth.retryWithCaptchaAndDFP,\n        });\n      },\n\n      send: async (email: string, options: MagicLinksSendOptions = {}): Promise<ResponseCommon> => {\n        const { pkceRequiredForEmailMagicLinks } = await this._config;\n\n        let code_challenge: string | undefined = undefined;\n        if (pkceRequiredForEmailMagicLinks) {\n          code_challenge = await this.getCodeChallenge();\n        }\n        const { dfp_telemetry_id, captcha_token } = await this.dfpProtectedAuth.getDFPTelemetryIDAndCaptcha();\n        const requestBody = {\n          ...options,\n          email,\n          code_challenge,\n          captcha_token,\n          dfp_telemetry_id,\n        };\n        const isLoggedIn = !!this._subscriptionService.getSession();\n\n        const endpoint = isLoggedIn ? '/magic_links/email/send/secondary' : '/magic_links/email/send/primary';\n\n        return this._networkClient.retriableFetchSDK<MagicLinksSendResponse>({\n          url: endpoint,\n          body: requestBody,\n          method: 'POST',\n          retryCallback: this.dfpProtectedAuth.retryWithCaptchaAndDFP,\n        });\n      },\n    };\n\n    this.authenticate = this._subscriptionService.withUpdateSession(\n      async (token: string, options: MagicLinksAuthenticateOptions) => {\n        validateInDev(\n          'stytch.magicLinks.authenticate',\n          { token, ...options },\n          {\n            token: 'string',\n            session_duration_minutes: 'number',\n          },\n        );\n\n        // When a user resets their password with PKCE turned on, they create a pkPair in the 'passwords' namespace.\n        // However, when the user gets the reset password email, they have the option to log in without a password.\n        // This redirects them to the magic link authenticate flow, which automatically looks for the pkce code_verifier\n        // in the 'magic_links' namespace, breaking the flow. Unfortunately we won't know for sure in the eml authenticate call\n        // whether or not the user is coming from a password reset flow. To handle this, we have to try to authenticate with\n        // both the 'passwords' and 'magic_links' code_verifiers.\n        const passwordResetPKPair = await this._passwordResetPKCEManager.getPKPair();\n\n        let resp: WithUser<MagicLinksAuthenticateResponse<TProjectConfiguration>> | null = null;\n\n        if (passwordResetPKPair?.code_verifier) {\n          try {\n            resp = await this.handlePKCEForAuthenticate(this._passwordResetPKCEManager, { token, ...options });\n          } catch (e) {\n            if ((e as Error).message.includes('pkce')) {\n              // If pkce-related error, fall back to magic links code_verifier\n              // eslint-disable-next-line no-console\n              console.log(\n                'Authenticate with passwords pkce namespace failed. Falling back to authenticate with magic_links namespace.',\n              );\n            } else {\n              throw e;\n            }\n          }\n        }\n\n        if (!resp) {\n          resp = await this.handlePKCEForAuthenticate(this._pkceManager, { token, ...options });\n        }\n\n        return omitUser(resp);\n      },\n    );\n  }\n\n  private async getCodeChallenge(): Promise<string> {\n    let keyPair = await this._pkceManager.getPKPair();\n    if (keyPair) {\n      return keyPair.code_challenge;\n    }\n    keyPair = await this._pkceManager.startPKCETransaction();\n    return keyPair.code_challenge;\n  }\n\n  private async handlePKCEForAuthenticate(\n    pkceManager: IPKCEManager,\n    data: MagicLinksAuthenticateOptions & { token: string },\n  ): Promise<WithUser<MagicLinksAuthenticateResponse<TProjectConfiguration>>> {\n    const pkPair = await pkceManager.getPKPair();\n\n    const requestBody = {\n      code_verifier: pkPair?.code_verifier,\n      ...data,\n    };\n\n    const resp = await this._networkClient.fetchSDK<WithUser<MagicLinksAuthenticateResponse<TProjectConfiguration>>>({\n      url: '/magic_links/authenticate',\n      body: requestBody,\n      method: 'POST',\n    });\n\n    pkceManager.clearPKPair();\n\n    return resp;\n  }\n}\n"],"names":["DefaultDynamicConfig","Promise","resolve","pkceRequiredForEmailMagicLinks","HeadlessMagicLinksClient","email","authenticate","_config","dfpProtectedAuth","_networkClient","_subscriptionService","_pkceManager","_passwordResetPKCEManager","loginOrCreate","options","code_challenge","undefined","getCodeChallenge","dfp_telemetry_id","captcha_token","getDFPTelemetryIDAndCaptcha","requestBody","retriableFetchSDK","url","body","method","retryCallback","retryWithCaptchaAndDFP","send","isLoggedIn","getSession","endpoint","withUpdateSession","token","validateInDev","session_duration_minutes","passwordResetPKPair","getPKPair","resp","code_verifier","handlePKCEForAuthenticate","e","message","includes","console","log","omitUser","keyPair","startPKCETransaction","pkceManager","data","pkPair","fetchSDK","clearPKPair"],"mappings":"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"}