{"version":3,"file":"usePromptPasskey.mjs","sources":["../../../../../../../../web/src/ui/hooks/usePromptPasskey.ts"],"sourcesContent":["import { useLingui } from '@lingui/react/macro';\nimport { DEFAULT_SESSION_DURATION_MINUTES } from '@stytch/core';\nimport { StytchEventType, StytchProjectConfigurationInput, WebAuthnAuthenticateResponse } from '@stytch/core/public';\nimport { useCallback, useEffect, useState } from 'react';\n\nimport { extractErrorMessage } from '../../utils/extractErrorMessage';\nimport { extractErrorType } from '../../utils/extractErrorType';\nimport {\n  AppScreens,\n  useConfig,\n  useErrorCallback,\n  useEventCallback,\n  useGlobalReducer,\n  useStytch,\n} from '../b2c/GlobalContextProvider';\nimport { hasProduct } from '../b2c/utils';\n\nconst MAX_ATTEMPTS = 5;\n\nexport type StartPasskeyAuth = () => Promise<WebAuthnAuthenticateResponse<StytchProjectConfigurationInput>>;\n\nexport const usePromptPasskey = ({\n  canAutofill,\n  shadowDOM,\n}: {\n  canAutofill: boolean;\n  shadowDOM: boolean;\n}): [startPasskeyAuth: StartPasskeyAuth, error: string | undefined] => {\n  const { t } = useLingui();\n  const stytchClient = useStytch();\n  const config = useConfig();\n  const hasPasskeys = hasProduct(config.products, 'passkeys');\n\n  const onEvent = useEventCallback();\n  const onError = useErrorCallback();\n  const [, dispatch] = useGlobalReducer();\n\n  const [error, setError] = useState<string>();\n\n  const startPasskeyAuth = useCallback(\n    async ({\n      conditionalMediation = false,\n      abortController,\n    }: {\n      conditionalMediation?: boolean;\n      abortController?: AbortController;\n    } = {}) => {\n      try {\n        const resp = await stytchClient.webauthn.authenticate({\n          domain: config.passkeyOptions?.domain,\n          session_duration_minutes: config.sessionOptions?.sessionDurationMinutes ?? DEFAULT_SESSION_DURATION_MINUTES,\n          conditional_mediation: conditionalMediation,\n          is_passkey: true,\n          signal: abortController?.signal,\n          disable_input_check: shadowDOM,\n        });\n\n        if (!resp) {\n          throw new Error('Empty response');\n        }\n\n        onEvent({ type: StytchEventType.PasskeyAuthenticate, data: resp });\n        dispatch({ type: 'transition', screen: AppScreens.PasskeyConfirmation });\n        return resp;\n      } catch (e) {\n        if (extractErrorType(e) === 'webauthn_registration_not_found') {\n          setError(\n            t({\n              id: 'error.passkeyRegistrationNotFound',\n              message:\n                'Passkey registration not found. You may have deleted the passkey from your account but not password manager. Please try again.',\n            }),\n          );\n        } else if (e instanceof Error && e.name === 'StytchAPIError') {\n          setError(\n            t({\n              id: 'error.passkeyUnknown',\n              message: 'Unknown error occurred during passkey authentication. Please try again.',\n            }),\n          );\n        }\n\n        const message = extractErrorMessage(e);\n        if (message) {\n          onError({ message });\n        }\n\n        throw e;\n      }\n    },\n    [\n      shadowDOM,\n      config.passkeyOptions?.domain,\n      config.sessionOptions?.sessionDurationMinutes,\n      dispatch,\n      onError,\n      onEvent,\n      stytchClient.webauthn,\n      t,\n    ],\n  );\n\n  useEffect(() => {\n    if (!hasPasskeys || !canAutofill) {\n      return;\n    }\n\n    // Skip passkey authentication in Storybook environment\n    if (process.env.STORYBOOK) {\n      return;\n    }\n\n    const abortController = new AbortController();\n    (async () => {\n      if (!(await stytchClient.webauthn.browserSupportsAutofill())) {\n        return;\n      }\n\n      for (let i = 0; i < MAX_ATTEMPTS; ++i) {\n        if (abortController.signal.aborted) {\n          return;\n        }\n\n        try {\n          await startPasskeyAuth({ abortController, conditionalMediation: true });\n          return;\n        } catch (e) {\n          // User denied permission\n          if (e instanceof DOMException && e.name === 'NotAllowedError') {\n            return;\n          }\n\n          // Otherwise swallow error\n        }\n      }\n    })();\n\n    return () => {\n      abortController.abort();\n    };\n  }, [canAutofill, hasPasskeys, startPasskeyAuth, stytchClient.webauthn]);\n\n  return [startPasskeyAuth, error];\n};\n"],"names":["MAX_ATTEMPTS","usePromptPasskey","canAutofill","shadowDOM","useLingui","stytchClient","useStytch","config","useConfig","hasPasskeys","hasProduct","products","onEvent","useEventCallback","onError","useErrorCallback","dispatch","useGlobalReducer","error","setError","useState","startPasskeyAuth","useCallback","conditionalMediation","abortController","resp","webauthn","authenticate","domain","passkeyOptions","session_duration_minutes","sessionOptions","sessionDurationMinutes","DEFAULT_SESSION_DURATION_MINUTES","conditional_mediation","is_passkey","signal","disable_input_check","Error","type","StytchEventType","PasskeyAuthenticate","data","screen","AppScreens","PasskeyConfirmation","e","extractErrorType","name","message","extractErrorMessage","useEffect","AbortController","browserSupportsAutofill","i","aborted","DOMException","abort"],"mappings":"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"}