@authowl/react 0.24.4 → 0.25.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import { AuthConfig, Locale, AuthOwlClient, PublicConfig, ConsentStatus, OrganizationInvitationDetails, OrganizationDetails, OrganizationMembership, HasParams, AuthUser, AuthClientError, InvitationRecipientHint, SessionState, Organization, AuthOwlErrorCode, LastUsedSignInMethod } from '@authowl/core';
2
+ import { AuthConfig, Locale, AuthOwlClient, PublicConfig, ConsentStatus, OrganizationInvitationDetails, OrganizationDetails, OrganizationMembership, HasParams, AuthUser, AuthClientError, InvitationRecipientHint, SessionState, AuthActionResult, Organization, AuthOwlErrorCode, LastUsedSignInMethod } from '@authowl/core';
3
3
  export { AuthOwlError, AuthPasskey, ConsentStatus, HasParams, InvalidKeyError, Organization, OrganizationDetails, OrganizationInvitation, OrganizationMember, OrganizationMemberWithUser, OrganizationMembership, OrganizationRoleSummary, OrganizationTeam, OrganizationTeamMember, OrganizationUserInvitation, PublicConfig, RateLimitedError, createMembershipHas, membershipHas, membershipHasPermission, membershipHasTeam } from '@authowl/core';
4
4
 
5
5
  type Appearance = {
@@ -508,9 +508,14 @@ type BackupCodesManagerProps = {
508
508
  };
509
509
  /**
510
510
  * Backup-codes management (B.5d): regenerate the signed-in user's single-use
511
- * backup codes (password-confirmed; the previous set stops working) and show
512
- * the new set ONCE. Renders nothing for users without 2FA enrolled - mount it
513
- * unconditionally in an account/security page alongside <MFAEnrollment/>.
511
+ * backup codes and show the new set ONCE. Renders nothing for users without 2FA
512
+ * enrolled - mount it unconditionally in an account/security page alongside
513
+ * <MFAEnrollment/>.
514
+ *
515
+ * Reissuing codes retires the old set, so the server treats it as a weakening
516
+ * action and can demand a second-factor proof on top of the password. That
517
+ * arrives as a code prompt and the request finishes on its own - see
518
+ * {@link useStepUpAction}.
514
519
  */
515
520
  declare function BackupCodesManager({ title }: BackupCodesManagerProps): React.JSX.Element | null;
516
521
 
@@ -673,22 +678,179 @@ type MFAEnrollmentProps = {
673
678
  */
674
679
  declare function MFAEnrollment({ onEnrolled, title }: MFAEnrollmentProps): React.JSX.Element;
675
680
 
681
+ /** Everything `run` needs besides the action itself. */
682
+ type SubmitActionOptions<T> = {
683
+ /** Generic, already-localized copy shown when the action fails. */
684
+ failure: string;
685
+ onSuccess?: (res: AuthActionResult<T>) => void | Promise<void>;
686
+ /**
687
+ * Override the default code-based error message for an endpoint-specific
688
+ * status (e.g. SSO's bare 404 = "no connection for this domain", which is
689
+ * not a global server code). Return a message to use, or null to fall back
690
+ * to the standard `useServerError` mapping.
691
+ */
692
+ mapError?: (error: AuthClientError) => string | null;
693
+ /**
694
+ * Take over a failure entirely instead of rendering it. Return true when the
695
+ * caller has handled the error by swapping the UI (the second-factor step-up
696
+ * prompt is the case this exists for), and no message is surfaced. Runs
697
+ * before `mapError`, which only ever produces text.
698
+ */
699
+ intercept?: (error: AuthClientError) => boolean;
700
+ /**
701
+ * Keep `pending` true after a SUCCESSFUL action instead of resetting it -
702
+ * for redirect-out actions (SSO) where the browser navigates away, so the
703
+ * spinner persists through the navigation instead of flashing back to idle.
704
+ * Error and throw paths still reset. Only safe when success always navigates
705
+ * away; a success that stays on the page would leave a stuck spinner (which
706
+ * is why magic-link/OTP, whose success swaps a view in place, do NOT set it).
707
+ */
708
+ keepPendingOnSuccess?: boolean;
709
+ };
710
+ type UseSubmitActionResult = {
711
+ /** True while an action is in flight (drives disabled buttons / busy labels). */
712
+ pending: boolean;
713
+ /** The last surfaced error message, or null. */
714
+ error: string | null;
715
+ /** Set/clear the error directly (e.g. an initial load outside `run`). */
716
+ setError: (message: string | null) => void;
717
+ /**
718
+ * Run a client action and own the loading/error skeleton: clear the error, set
719
+ * pending, await the action, surface `res.error` (or the thrown message) as
720
+ * `failure`, and invoke `onSuccess` only on a clean result. Every sign-in
721
+ * surface differs only in its action and success branch, so this keeps that
722
+ * envelope in one place. Generic in the action's data type, so `onSuccess`
723
+ * receives a fully-typed `res` without a cast.
724
+ */
725
+ run: <T>(action: () => Promise<AuthActionResult<T> | null | undefined>, opts: SubmitActionOptions<T>) => Promise<void>;
726
+ };
727
+
728
+ /**
729
+ * The server code for "prove the second factor before weakening it".
730
+ *
731
+ * Raised by the endpoints that can weaken an enrolled account - today
732
+ * `/two-factor/disable` and `/two-factor/generate-backup-codes` - when the
733
+ * session has not proved a factor in the last five minutes. Knowing the
734
+ * password is deliberately not enough: social sign-in, inbound SSO and a
735
+ * trusted device all mint a fresh session without ever running the challenge,
736
+ * so password-only would have voided the promise the second factor exists to
737
+ * make.
738
+ *
739
+ * Signing in again is NOT the remedy and must never be offered as one. A
740
+ * trusted device skips the challenge, so a second sign-in mints another
741
+ * unstamped session and the next attempt fails identically - an infinite
742
+ * bounce. The only way through is a code.
743
+ */
744
+ declare const SECOND_FACTOR_REQUIRED = "SECOND_FACTOR_REQUIRED";
745
+ type UseStepUpActionResult = Omit<UseSubmitActionResult, 'run'> & {
746
+ /**
747
+ * Run an action the server may gate behind a fresh second-factor proof.
748
+ *
749
+ * On `SECOND_FACTOR_REQUIRED` the attempt is PARKED rather than surfaced as an
750
+ * error, and `stepUpRequired` flips so the caller can render the code prompt.
751
+ * Every other failure behaves exactly as `useSubmitAction`'s `run`.
752
+ *
753
+ * ONE ATTEMPT AT A TIME per hook instance. The returned promise settles when
754
+ * the attempt is parked, NOT when the action finishes - so do not await it to
755
+ * mean "this completed"; use `onSuccess`. A second action gated while one is
756
+ * already parked is refused as an ordinary error rather than silently taking
757
+ * the first one's place. Call the hook once per action if you drive two.
758
+ */
759
+ run: UseSubmitActionResult['run'];
760
+ /** True while the server is waiting for a code before it will run the action. */
761
+ stepUpRequired: boolean;
762
+ /**
763
+ * Replay the parked attempt. Call this once a code has been accepted; the
764
+ * original inputs (password, options) are replayed exactly as submitted, so
765
+ * the user never retypes anything.
766
+ */
767
+ resume: () => void;
768
+ /** Abandon the parked attempt and leave step-up. */
769
+ cancel: () => void;
770
+ };
771
+ /**
772
+ * The park-prompt-replay envelope for a second-factor step-up.
773
+ *
774
+ * Wrap any action the server may gate behind a fresh proof, render
775
+ * `<MFAChallenge variant="step-up" onVerified={resume} />` while
776
+ * `stepUpRequired`, and the original request finishes on its own.
777
+ *
778
+ * Both surfaces that can trip the gate need the identical three moves - catch
779
+ * the code, collect a factor, re-run the untouched attempt - so it lives here
780
+ * rather than twice. The gate is reactive by necessity: nothing on the client
781
+ * can see whether this session carries a fresh assertion, so the only honest
782
+ * design is to try, and prompt when the server says to. A user who just cleared
783
+ * a challenge at sign-in therefore never sees the prompt at all.
784
+ */
785
+ declare function useStepUpAction(): UseStepUpActionResult;
786
+
787
+ type PasskeyOfferGateProps = {
788
+ /** The signed-in application. Rendered untouched in every other state. */
789
+ children: React.ReactNode;
790
+ /** Optional heading override, matching the other gates. */
791
+ title?: string;
792
+ };
793
+ /**
794
+ * Offers a passkey once, just after a user starts a signed-in session having
795
+ * arrived by some other method. Wrap your signed-in app, next to
796
+ * <ConsentGate/> and <MFARequiredGate/>; it is free to wrap unconditionally.
797
+ *
798
+ * WHY A GATE AND NOT A STEP INSIDE <SignIn/>. The natural-looking design - show
799
+ * the offer between a successful sign-in and the handoff - cannot work in the
800
+ * documented embed. `<SignedOut>` unmounts `<SignIn/>` on the very store update
801
+ * that makes the session usable, so by the time an offer could be rendered the
802
+ * component that would render it is gone: the prompt never appears and the
803
+ * sign-in handoff never completes. There is no post-success moment inside a
804
+ * sign-in form. There is one here, on the side that survives.
805
+ *
806
+ * It also puts the checks where the answers exist. A sign-in form asks
807
+ * "is this user 2FA-enrolled?" before any user is loaded, and gets `undefined` -
808
+ * which reads as "no" and defeats the check entirely. On this side the user is
809
+ * real. {@link usePasskeyOffer} owns which checks those are and why.
810
+ *
811
+ * NEVER BLOCKS. Children render immediately and keep rendering while the checks
812
+ * run; the offer replaces them only on confirmed evidence. This is an optional
813
+ * convenience, so every uncertainty - config still loading, the passkey list
814
+ * unreadable, storage refusing - resolves to "show the app". Blocking would add
815
+ * another bootstrap blank-flash to a surface that already has one.
816
+ */
817
+ declare function PasskeyOfferGate({ children, title }: PasskeyOfferGateProps): React.JSX.Element;
818
+
676
819
  type MFAChallengeProps = {
677
- /** Called once the challenge clears and a session is issued. */
820
+ /** Called once the factor is accepted (a session is issued on `sign-in`). */
678
821
  onVerified?: () => void | Promise<void>;
679
822
  /**
680
823
  * Allow the "trust this device" option when the project's posture permits it.
681
- * The server capability always wins over this presentation override.
824
+ * The server capability always wins over this presentation override. Ignored
825
+ * on `step-up`, where the server has no trust to grant.
682
826
  */
683
827
  allowTrustDevice?: boolean;
828
+ /**
829
+ * What this prompt is FOR, which decides its copy and whether device trust is
830
+ * on offer:
831
+ *
832
+ * - `sign-in` the session is withheld until the factor clears. The default.
833
+ * - `step-up` the user is ALREADY signed in and is re-proving the factor to
834
+ * authorize a change that would weaken it. The server's
835
+ * full-session branch returns the existing token and creates no
836
+ * session, so nothing here may read as signing in - and it
837
+ * cannot mint a trust cookie, so the checkbox is not offered.
838
+ */
839
+ variant?: 'sign-in' | 'step-up';
840
+ /** Abandon the prompt. Rendered as a Cancel control when provided. */
841
+ onCancel?: () => void;
684
842
  };
685
843
  /**
686
- * The sign-in second-factor prompt: a user with 2FA enrolled gets no session until
687
- * they clear this. Accepts a TOTP code or, as a fallback, a single-use backup code.
688
- * Rendered automatically by <SignIn/> when the server withholds the session behind
689
- * a 2FA challenge; also usable standalone.
844
+ * The second-factor prompt. Accepts a TOTP code or, as a fallback, a single-use
845
+ * backup code or an emailed code where the project's posture permits one.
846
+ *
847
+ * Serves two moments, which `variant` selects between. At `sign-in` a user with
848
+ * 2FA enrolled gets no session until they clear this, and <SignIn/> renders it
849
+ * automatically when the server withholds one. At `step-up` an already
850
+ * signed-in user re-proves the factor to authorize a change that would weaken
851
+ * it - the same three factors, different copy, and no device trust on offer.
690
852
  */
691
- declare function MFAChallenge({ onVerified, allowTrustDevice }: MFAChallengeProps): React.JSX.Element;
853
+ declare function MFAChallenge({ onVerified, allowTrustDevice, variant, onCancel, }: MFAChallengeProps): React.JSX.Element;
692
854
 
693
855
  type AuthOwlBadgeProps = {
694
856
  /** Override the link target (defaults to the AuthOwl site). */
@@ -968,4 +1130,4 @@ declare function GoogleOneTap({ disabled, nonce, autoSelect, cancelOnTapOutside,
968
1130
  */
969
1131
  declare function useLastUsedSignInMethod(): LastUsedSignInMethod | null;
970
1132
 
971
- export { type Appearance, AuthLoaded, type AuthLoadedProps, AuthLoading, type AuthLoadingProps, AuthOwlBadge, type AuthOwlBadgeProps, AuthOwlBranding, type AuthOwlBrandingProps, AuthOwlProvider, type AuthOwlProviderProps, type AutofillHost, BackupCodesManager, type BackupCodesManagerProps, Bidi, type ConfigState, ConsentDocLinks, type ConsentDocLinksProps, ConsentGate, type ConsentGateProps, CreateOrganization, type CreateOrganizationProps, DEFAULT_BRAND_COLOR, EmailOtpForm, type EmailOtpFormProps, ForgotPassword, type ForgotPasswordProps, GoogleOneTap, type GoogleOneTapDismissReason, type GoogleOneTapError, type GoogleOneTapErrorCode, type GoogleOneTapProps, type GoogleOneTapSkipReason, InvitationPrompt, type InvitationPromptStatus, KNOWN_METHODS, type KnownMethod, MFAChallenge, type MFAChallengeProps, MFAEnrollment, type MFAEnrollmentProps, MFARequiredGate, type MFARequiredGateProps, MagicLinkForm, type MagicLinkFormProps, OrganizationList, type OrganizationListProps, OrganizationProfile, type OrganizationProfileProps, type OrganizationProfileSection, OrganizationSwitcher, type OrganizationSwitcherProps, PasskeyButton, type PasskeyButtonProps, PasskeyManager, type PasskeyManagerProps, PhoneOTP, type PhoneOTPProps, PrivacyCenter, type PrivacyCenterProps, Protect, type ProtectProps, ResetPassword, type ResetPasswordProps, SignIn, type SignInPlan, type SignInProps, SignOutButton, type SignOutButtonProps, SignUp, type SignUpProps, SignedIn, type SignedInProps, SignedOut, type SignedOutProps, SocialButtons, type SocialButtonsProps, Spinner, type UseAccountResult, type UseAuthResult, type UseConsentResult, type UseEmailVerificationResult, type UseMFAResult, type UseOrganizationInvitationResult, type UseOrganizationResult, type UsePasskeysResult, type UsePasswordResetResult, type UsePrivacyResult, type UsePublicConfigResult, type UseSignInResult, type UseSignOutResult, type UseSignUpResult, type UseUserResult, type UseWaitlistResult, UserButton, UserProfile, type UserProfileProps, type UserProfileSection, VerificationPending, type VerificationPendingProps, VerifyEmail, type VerifyEmailProps, Waitlist, type WaitlistProps, emailAutocomplete, resolveSignInMethods, useAccount, useAuth, useAuthClient, useAuthOwlContext, useConsent, useEmailVerification, useInvitationRecipientHint, useLastUsedSignInMethod, useLocale, useMFA, useOrganization, useOrganizationInvitation, usePasskeys, usePasswordReset, usePrivacy, usePublicConfig, useSession, useSignIn, useSignOut, useSignUp, useUser, useWaitlist };
1133
+ export { type Appearance, AuthLoaded, type AuthLoadedProps, AuthLoading, type AuthLoadingProps, AuthOwlBadge, type AuthOwlBadgeProps, AuthOwlBranding, type AuthOwlBrandingProps, AuthOwlProvider, type AuthOwlProviderProps, type AutofillHost, BackupCodesManager, type BackupCodesManagerProps, Bidi, type ConfigState, ConsentDocLinks, type ConsentDocLinksProps, ConsentGate, type ConsentGateProps, CreateOrganization, type CreateOrganizationProps, DEFAULT_BRAND_COLOR, EmailOtpForm, type EmailOtpFormProps, ForgotPassword, type ForgotPasswordProps, GoogleOneTap, type GoogleOneTapDismissReason, type GoogleOneTapError, type GoogleOneTapErrorCode, type GoogleOneTapProps, type GoogleOneTapSkipReason, InvitationPrompt, type InvitationPromptStatus, KNOWN_METHODS, type KnownMethod, MFAChallenge, type MFAChallengeProps, MFAEnrollment, type MFAEnrollmentProps, MFARequiredGate, type MFARequiredGateProps, MagicLinkForm, type MagicLinkFormProps, OrganizationList, type OrganizationListProps, OrganizationProfile, type OrganizationProfileProps, type OrganizationProfileSection, OrganizationSwitcher, type OrganizationSwitcherProps, PasskeyButton, type PasskeyButtonProps, PasskeyManager, type PasskeyManagerProps, PasskeyOfferGate, type PasskeyOfferGateProps, PhoneOTP, type PhoneOTPProps, PrivacyCenter, type PrivacyCenterProps, Protect, type ProtectProps, ResetPassword, type ResetPasswordProps, SECOND_FACTOR_REQUIRED, SignIn, type SignInPlan, type SignInProps, SignOutButton, type SignOutButtonProps, SignUp, type SignUpProps, SignedIn, type SignedInProps, SignedOut, type SignedOutProps, SocialButtons, type SocialButtonsProps, Spinner, type UseAccountResult, type UseAuthResult, type UseConsentResult, type UseEmailVerificationResult, type UseMFAResult, type UseOrganizationInvitationResult, type UseOrganizationResult, type UsePasskeysResult, type UsePasswordResetResult, type UsePrivacyResult, type UsePublicConfigResult, type UseSignInResult, type UseSignOutResult, type UseSignUpResult, type UseStepUpActionResult, type UseUserResult, type UseWaitlistResult, UserButton, UserProfile, type UserProfileProps, type UserProfileSection, VerificationPending, type VerificationPendingProps, VerifyEmail, type VerifyEmailProps, Waitlist, type WaitlistProps, emailAutocomplete, resolveSignInMethods, useAccount, useAuth, useAuthClient, useAuthOwlContext, useConsent, useEmailVerification, useInvitationRecipientHint, useLastUsedSignInMethod, useLocale, useMFA, useOrganization, useOrganizationInvitation, usePasskeys, usePasswordReset, usePrivacy, usePublicConfig, useSession, useSignIn, useSignOut, useSignUp, useStepUpAction, useUser, useWaitlist };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import { AuthConfig, Locale, AuthOwlClient, PublicConfig, ConsentStatus, OrganizationInvitationDetails, OrganizationDetails, OrganizationMembership, HasParams, AuthUser, AuthClientError, InvitationRecipientHint, SessionState, Organization, AuthOwlErrorCode, LastUsedSignInMethod } from '@authowl/core';
2
+ import { AuthConfig, Locale, AuthOwlClient, PublicConfig, ConsentStatus, OrganizationInvitationDetails, OrganizationDetails, OrganizationMembership, HasParams, AuthUser, AuthClientError, InvitationRecipientHint, SessionState, AuthActionResult, Organization, AuthOwlErrorCode, LastUsedSignInMethod } from '@authowl/core';
3
3
  export { AuthOwlError, AuthPasskey, ConsentStatus, HasParams, InvalidKeyError, Organization, OrganizationDetails, OrganizationInvitation, OrganizationMember, OrganizationMemberWithUser, OrganizationMembership, OrganizationRoleSummary, OrganizationTeam, OrganizationTeamMember, OrganizationUserInvitation, PublicConfig, RateLimitedError, createMembershipHas, membershipHas, membershipHasPermission, membershipHasTeam } from '@authowl/core';
4
4
 
5
5
  type Appearance = {
@@ -508,9 +508,14 @@ type BackupCodesManagerProps = {
508
508
  };
509
509
  /**
510
510
  * Backup-codes management (B.5d): regenerate the signed-in user's single-use
511
- * backup codes (password-confirmed; the previous set stops working) and show
512
- * the new set ONCE. Renders nothing for users without 2FA enrolled - mount it
513
- * unconditionally in an account/security page alongside <MFAEnrollment/>.
511
+ * backup codes and show the new set ONCE. Renders nothing for users without 2FA
512
+ * enrolled - mount it unconditionally in an account/security page alongside
513
+ * <MFAEnrollment/>.
514
+ *
515
+ * Reissuing codes retires the old set, so the server treats it as a weakening
516
+ * action and can demand a second-factor proof on top of the password. That
517
+ * arrives as a code prompt and the request finishes on its own - see
518
+ * {@link useStepUpAction}.
514
519
  */
515
520
  declare function BackupCodesManager({ title }: BackupCodesManagerProps): React.JSX.Element | null;
516
521
 
@@ -673,22 +678,179 @@ type MFAEnrollmentProps = {
673
678
  */
674
679
  declare function MFAEnrollment({ onEnrolled, title }: MFAEnrollmentProps): React.JSX.Element;
675
680
 
681
+ /** Everything `run` needs besides the action itself. */
682
+ type SubmitActionOptions<T> = {
683
+ /** Generic, already-localized copy shown when the action fails. */
684
+ failure: string;
685
+ onSuccess?: (res: AuthActionResult<T>) => void | Promise<void>;
686
+ /**
687
+ * Override the default code-based error message for an endpoint-specific
688
+ * status (e.g. SSO's bare 404 = "no connection for this domain", which is
689
+ * not a global server code). Return a message to use, or null to fall back
690
+ * to the standard `useServerError` mapping.
691
+ */
692
+ mapError?: (error: AuthClientError) => string | null;
693
+ /**
694
+ * Take over a failure entirely instead of rendering it. Return true when the
695
+ * caller has handled the error by swapping the UI (the second-factor step-up
696
+ * prompt is the case this exists for), and no message is surfaced. Runs
697
+ * before `mapError`, which only ever produces text.
698
+ */
699
+ intercept?: (error: AuthClientError) => boolean;
700
+ /**
701
+ * Keep `pending` true after a SUCCESSFUL action instead of resetting it -
702
+ * for redirect-out actions (SSO) where the browser navigates away, so the
703
+ * spinner persists through the navigation instead of flashing back to idle.
704
+ * Error and throw paths still reset. Only safe when success always navigates
705
+ * away; a success that stays on the page would leave a stuck spinner (which
706
+ * is why magic-link/OTP, whose success swaps a view in place, do NOT set it).
707
+ */
708
+ keepPendingOnSuccess?: boolean;
709
+ };
710
+ type UseSubmitActionResult = {
711
+ /** True while an action is in flight (drives disabled buttons / busy labels). */
712
+ pending: boolean;
713
+ /** The last surfaced error message, or null. */
714
+ error: string | null;
715
+ /** Set/clear the error directly (e.g. an initial load outside `run`). */
716
+ setError: (message: string | null) => void;
717
+ /**
718
+ * Run a client action and own the loading/error skeleton: clear the error, set
719
+ * pending, await the action, surface `res.error` (or the thrown message) as
720
+ * `failure`, and invoke `onSuccess` only on a clean result. Every sign-in
721
+ * surface differs only in its action and success branch, so this keeps that
722
+ * envelope in one place. Generic in the action's data type, so `onSuccess`
723
+ * receives a fully-typed `res` without a cast.
724
+ */
725
+ run: <T>(action: () => Promise<AuthActionResult<T> | null | undefined>, opts: SubmitActionOptions<T>) => Promise<void>;
726
+ };
727
+
728
+ /**
729
+ * The server code for "prove the second factor before weakening it".
730
+ *
731
+ * Raised by the endpoints that can weaken an enrolled account - today
732
+ * `/two-factor/disable` and `/two-factor/generate-backup-codes` - when the
733
+ * session has not proved a factor in the last five minutes. Knowing the
734
+ * password is deliberately not enough: social sign-in, inbound SSO and a
735
+ * trusted device all mint a fresh session without ever running the challenge,
736
+ * so password-only would have voided the promise the second factor exists to
737
+ * make.
738
+ *
739
+ * Signing in again is NOT the remedy and must never be offered as one. A
740
+ * trusted device skips the challenge, so a second sign-in mints another
741
+ * unstamped session and the next attempt fails identically - an infinite
742
+ * bounce. The only way through is a code.
743
+ */
744
+ declare const SECOND_FACTOR_REQUIRED = "SECOND_FACTOR_REQUIRED";
745
+ type UseStepUpActionResult = Omit<UseSubmitActionResult, 'run'> & {
746
+ /**
747
+ * Run an action the server may gate behind a fresh second-factor proof.
748
+ *
749
+ * On `SECOND_FACTOR_REQUIRED` the attempt is PARKED rather than surfaced as an
750
+ * error, and `stepUpRequired` flips so the caller can render the code prompt.
751
+ * Every other failure behaves exactly as `useSubmitAction`'s `run`.
752
+ *
753
+ * ONE ATTEMPT AT A TIME per hook instance. The returned promise settles when
754
+ * the attempt is parked, NOT when the action finishes - so do not await it to
755
+ * mean "this completed"; use `onSuccess`. A second action gated while one is
756
+ * already parked is refused as an ordinary error rather than silently taking
757
+ * the first one's place. Call the hook once per action if you drive two.
758
+ */
759
+ run: UseSubmitActionResult['run'];
760
+ /** True while the server is waiting for a code before it will run the action. */
761
+ stepUpRequired: boolean;
762
+ /**
763
+ * Replay the parked attempt. Call this once a code has been accepted; the
764
+ * original inputs (password, options) are replayed exactly as submitted, so
765
+ * the user never retypes anything.
766
+ */
767
+ resume: () => void;
768
+ /** Abandon the parked attempt and leave step-up. */
769
+ cancel: () => void;
770
+ };
771
+ /**
772
+ * The park-prompt-replay envelope for a second-factor step-up.
773
+ *
774
+ * Wrap any action the server may gate behind a fresh proof, render
775
+ * `<MFAChallenge variant="step-up" onVerified={resume} />` while
776
+ * `stepUpRequired`, and the original request finishes on its own.
777
+ *
778
+ * Both surfaces that can trip the gate need the identical three moves - catch
779
+ * the code, collect a factor, re-run the untouched attempt - so it lives here
780
+ * rather than twice. The gate is reactive by necessity: nothing on the client
781
+ * can see whether this session carries a fresh assertion, so the only honest
782
+ * design is to try, and prompt when the server says to. A user who just cleared
783
+ * a challenge at sign-in therefore never sees the prompt at all.
784
+ */
785
+ declare function useStepUpAction(): UseStepUpActionResult;
786
+
787
+ type PasskeyOfferGateProps = {
788
+ /** The signed-in application. Rendered untouched in every other state. */
789
+ children: React.ReactNode;
790
+ /** Optional heading override, matching the other gates. */
791
+ title?: string;
792
+ };
793
+ /**
794
+ * Offers a passkey once, just after a user starts a signed-in session having
795
+ * arrived by some other method. Wrap your signed-in app, next to
796
+ * <ConsentGate/> and <MFARequiredGate/>; it is free to wrap unconditionally.
797
+ *
798
+ * WHY A GATE AND NOT A STEP INSIDE <SignIn/>. The natural-looking design - show
799
+ * the offer between a successful sign-in and the handoff - cannot work in the
800
+ * documented embed. `<SignedOut>` unmounts `<SignIn/>` on the very store update
801
+ * that makes the session usable, so by the time an offer could be rendered the
802
+ * component that would render it is gone: the prompt never appears and the
803
+ * sign-in handoff never completes. There is no post-success moment inside a
804
+ * sign-in form. There is one here, on the side that survives.
805
+ *
806
+ * It also puts the checks where the answers exist. A sign-in form asks
807
+ * "is this user 2FA-enrolled?" before any user is loaded, and gets `undefined` -
808
+ * which reads as "no" and defeats the check entirely. On this side the user is
809
+ * real. {@link usePasskeyOffer} owns which checks those are and why.
810
+ *
811
+ * NEVER BLOCKS. Children render immediately and keep rendering while the checks
812
+ * run; the offer replaces them only on confirmed evidence. This is an optional
813
+ * convenience, so every uncertainty - config still loading, the passkey list
814
+ * unreadable, storage refusing - resolves to "show the app". Blocking would add
815
+ * another bootstrap blank-flash to a surface that already has one.
816
+ */
817
+ declare function PasskeyOfferGate({ children, title }: PasskeyOfferGateProps): React.JSX.Element;
818
+
676
819
  type MFAChallengeProps = {
677
- /** Called once the challenge clears and a session is issued. */
820
+ /** Called once the factor is accepted (a session is issued on `sign-in`). */
678
821
  onVerified?: () => void | Promise<void>;
679
822
  /**
680
823
  * Allow the "trust this device" option when the project's posture permits it.
681
- * The server capability always wins over this presentation override.
824
+ * The server capability always wins over this presentation override. Ignored
825
+ * on `step-up`, where the server has no trust to grant.
682
826
  */
683
827
  allowTrustDevice?: boolean;
828
+ /**
829
+ * What this prompt is FOR, which decides its copy and whether device trust is
830
+ * on offer:
831
+ *
832
+ * - `sign-in` the session is withheld until the factor clears. The default.
833
+ * - `step-up` the user is ALREADY signed in and is re-proving the factor to
834
+ * authorize a change that would weaken it. The server's
835
+ * full-session branch returns the existing token and creates no
836
+ * session, so nothing here may read as signing in - and it
837
+ * cannot mint a trust cookie, so the checkbox is not offered.
838
+ */
839
+ variant?: 'sign-in' | 'step-up';
840
+ /** Abandon the prompt. Rendered as a Cancel control when provided. */
841
+ onCancel?: () => void;
684
842
  };
685
843
  /**
686
- * The sign-in second-factor prompt: a user with 2FA enrolled gets no session until
687
- * they clear this. Accepts a TOTP code or, as a fallback, a single-use backup code.
688
- * Rendered automatically by <SignIn/> when the server withholds the session behind
689
- * a 2FA challenge; also usable standalone.
844
+ * The second-factor prompt. Accepts a TOTP code or, as a fallback, a single-use
845
+ * backup code or an emailed code where the project's posture permits one.
846
+ *
847
+ * Serves two moments, which `variant` selects between. At `sign-in` a user with
848
+ * 2FA enrolled gets no session until they clear this, and <SignIn/> renders it
849
+ * automatically when the server withholds one. At `step-up` an already
850
+ * signed-in user re-proves the factor to authorize a change that would weaken
851
+ * it - the same three factors, different copy, and no device trust on offer.
690
852
  */
691
- declare function MFAChallenge({ onVerified, allowTrustDevice }: MFAChallengeProps): React.JSX.Element;
853
+ declare function MFAChallenge({ onVerified, allowTrustDevice, variant, onCancel, }: MFAChallengeProps): React.JSX.Element;
692
854
 
693
855
  type AuthOwlBadgeProps = {
694
856
  /** Override the link target (defaults to the AuthOwl site). */
@@ -968,4 +1130,4 @@ declare function GoogleOneTap({ disabled, nonce, autoSelect, cancelOnTapOutside,
968
1130
  */
969
1131
  declare function useLastUsedSignInMethod(): LastUsedSignInMethod | null;
970
1132
 
971
- export { type Appearance, AuthLoaded, type AuthLoadedProps, AuthLoading, type AuthLoadingProps, AuthOwlBadge, type AuthOwlBadgeProps, AuthOwlBranding, type AuthOwlBrandingProps, AuthOwlProvider, type AuthOwlProviderProps, type AutofillHost, BackupCodesManager, type BackupCodesManagerProps, Bidi, type ConfigState, ConsentDocLinks, type ConsentDocLinksProps, ConsentGate, type ConsentGateProps, CreateOrganization, type CreateOrganizationProps, DEFAULT_BRAND_COLOR, EmailOtpForm, type EmailOtpFormProps, ForgotPassword, type ForgotPasswordProps, GoogleOneTap, type GoogleOneTapDismissReason, type GoogleOneTapError, type GoogleOneTapErrorCode, type GoogleOneTapProps, type GoogleOneTapSkipReason, InvitationPrompt, type InvitationPromptStatus, KNOWN_METHODS, type KnownMethod, MFAChallenge, type MFAChallengeProps, MFAEnrollment, type MFAEnrollmentProps, MFARequiredGate, type MFARequiredGateProps, MagicLinkForm, type MagicLinkFormProps, OrganizationList, type OrganizationListProps, OrganizationProfile, type OrganizationProfileProps, type OrganizationProfileSection, OrganizationSwitcher, type OrganizationSwitcherProps, PasskeyButton, type PasskeyButtonProps, PasskeyManager, type PasskeyManagerProps, PhoneOTP, type PhoneOTPProps, PrivacyCenter, type PrivacyCenterProps, Protect, type ProtectProps, ResetPassword, type ResetPasswordProps, SignIn, type SignInPlan, type SignInProps, SignOutButton, type SignOutButtonProps, SignUp, type SignUpProps, SignedIn, type SignedInProps, SignedOut, type SignedOutProps, SocialButtons, type SocialButtonsProps, Spinner, type UseAccountResult, type UseAuthResult, type UseConsentResult, type UseEmailVerificationResult, type UseMFAResult, type UseOrganizationInvitationResult, type UseOrganizationResult, type UsePasskeysResult, type UsePasswordResetResult, type UsePrivacyResult, type UsePublicConfigResult, type UseSignInResult, type UseSignOutResult, type UseSignUpResult, type UseUserResult, type UseWaitlistResult, UserButton, UserProfile, type UserProfileProps, type UserProfileSection, VerificationPending, type VerificationPendingProps, VerifyEmail, type VerifyEmailProps, Waitlist, type WaitlistProps, emailAutocomplete, resolveSignInMethods, useAccount, useAuth, useAuthClient, useAuthOwlContext, useConsent, useEmailVerification, useInvitationRecipientHint, useLastUsedSignInMethod, useLocale, useMFA, useOrganization, useOrganizationInvitation, usePasskeys, usePasswordReset, usePrivacy, usePublicConfig, useSession, useSignIn, useSignOut, useSignUp, useUser, useWaitlist };
1133
+ export { type Appearance, AuthLoaded, type AuthLoadedProps, AuthLoading, type AuthLoadingProps, AuthOwlBadge, type AuthOwlBadgeProps, AuthOwlBranding, type AuthOwlBrandingProps, AuthOwlProvider, type AuthOwlProviderProps, type AutofillHost, BackupCodesManager, type BackupCodesManagerProps, Bidi, type ConfigState, ConsentDocLinks, type ConsentDocLinksProps, ConsentGate, type ConsentGateProps, CreateOrganization, type CreateOrganizationProps, DEFAULT_BRAND_COLOR, EmailOtpForm, type EmailOtpFormProps, ForgotPassword, type ForgotPasswordProps, GoogleOneTap, type GoogleOneTapDismissReason, type GoogleOneTapError, type GoogleOneTapErrorCode, type GoogleOneTapProps, type GoogleOneTapSkipReason, InvitationPrompt, type InvitationPromptStatus, KNOWN_METHODS, type KnownMethod, MFAChallenge, type MFAChallengeProps, MFAEnrollment, type MFAEnrollmentProps, MFARequiredGate, type MFARequiredGateProps, MagicLinkForm, type MagicLinkFormProps, OrganizationList, type OrganizationListProps, OrganizationProfile, type OrganizationProfileProps, type OrganizationProfileSection, OrganizationSwitcher, type OrganizationSwitcherProps, PasskeyButton, type PasskeyButtonProps, PasskeyManager, type PasskeyManagerProps, PasskeyOfferGate, type PasskeyOfferGateProps, PhoneOTP, type PhoneOTPProps, PrivacyCenter, type PrivacyCenterProps, Protect, type ProtectProps, ResetPassword, type ResetPasswordProps, SECOND_FACTOR_REQUIRED, SignIn, type SignInPlan, type SignInProps, SignOutButton, type SignOutButtonProps, SignUp, type SignUpProps, SignedIn, type SignedInProps, SignedOut, type SignedOutProps, SocialButtons, type SocialButtonsProps, Spinner, type UseAccountResult, type UseAuthResult, type UseConsentResult, type UseEmailVerificationResult, type UseMFAResult, type UseOrganizationInvitationResult, type UseOrganizationResult, type UsePasskeysResult, type UsePasswordResetResult, type UsePrivacyResult, type UsePublicConfigResult, type UseSignInResult, type UseSignOutResult, type UseSignUpResult, type UseStepUpActionResult, type UseUserResult, type UseWaitlistResult, UserButton, UserProfile, type UserProfileProps, type UserProfileSection, VerificationPending, type VerificationPendingProps, VerifyEmail, type VerifyEmailProps, Waitlist, type WaitlistProps, emailAutocomplete, resolveSignInMethods, useAccount, useAuth, useAuthClient, useAuthOwlContext, useConsent, useEmailVerification, useInvitationRecipientHint, useLastUsedSignInMethod, useLocale, useMFA, useOrganization, useOrganizationInvitation, usePasskeys, usePasswordReset, usePrivacy, usePublicConfig, useSession, useSignIn, useSignOut, useSignUp, useStepUpAction, useUser, useWaitlist };