@oxy.so/services 4.0.7 → 6.1.0
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/README.md +2 -2
- package/lib/commonjs/assets/assets/signIn/slide-1.jpg +0 -0
- package/lib/commonjs/assets/assets/signIn/slide-1.jpg.d.ts +3 -0
- package/lib/commonjs/assets/assets/signIn/slide-2.jpg +0 -0
- package/lib/commonjs/assets/assets/signIn/slide-2.jpg.d.ts +3 -0
- package/lib/commonjs/assets/assets/signIn/slide-3.jpg +0 -0
- package/lib/commonjs/assets/assets/signIn/slide-3.jpg.d.ts +3 -0
- package/lib/commonjs/assets/assets/signIn/slide-4.jpg +0 -0
- package/lib/commonjs/assets/assets/signIn/slide-4.jpg.d.ts +3 -0
- package/lib/commonjs/assets/signIn/slide-1.jpg +0 -0
- package/lib/commonjs/assets/signIn/slide-2.jpg +0 -0
- package/lib/commonjs/assets/signIn/slide-3.jpg +0 -0
- package/lib/commonjs/assets/signIn/slide-4.jpg +0 -0
- package/lib/commonjs/index.js +77 -8
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/ui/components/OxyAccountDialogScreen.js +11 -58
- package/lib/commonjs/ui/components/OxyAccountDialogScreen.js.map +1 -1
- package/lib/commonjs/ui/components/OxyAuthChooser.js +36 -45
- package/lib/commonjs/ui/components/OxyAuthChooser.js.map +1 -1
- package/lib/commonjs/ui/components/OxyProvider.js +0 -2
- package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
- package/lib/commonjs/ui/components/ProfileButton.js.map +1 -1
- package/lib/commonjs/ui/components/authChooser/AccountsMenuView.js +30 -16
- package/lib/commonjs/ui/components/authChooser/AccountsMenuView.js.map +1 -1
- package/lib/commonjs/ui/components/authChooser/primitives.js +7 -52
- package/lib/commonjs/ui/components/authChooser/primitives.js.map +1 -1
- package/lib/commonjs/ui/components/authChooser/signInFailureMessage.js +1 -7
- package/lib/commonjs/ui/components/authChooser/signInFailureMessage.js.map +1 -1
- package/lib/commonjs/ui/components/authChooser/styles.js +0 -31
- package/lib/commonjs/ui/components/authChooser/styles.js.map +1 -1
- package/lib/commonjs/ui/components/authChooser/types.js +2 -2
- package/lib/commonjs/ui/components/authChooser/types.js.map +1 -1
- package/lib/commonjs/ui/components/oauthNavigation.js +1 -1
- package/lib/commonjs/ui/components/signIn/InlineCommonsQr.js +161 -0
- package/lib/commonjs/ui/components/signIn/InlineCommonsQr.js.map +1 -0
- package/lib/commonjs/ui/components/signIn/OxyAccountPicker.js +111 -0
- package/lib/commonjs/ui/components/signIn/OxyAccountPicker.js.map +1 -0
- package/lib/commonjs/ui/components/signIn/OxyAuthScreen.js +160 -0
- package/lib/commonjs/ui/components/signIn/OxyAuthScreen.js.map +1 -0
- package/lib/commonjs/ui/components/signIn/OxyCreateAccountPanel.js +236 -0
- package/lib/commonjs/ui/components/signIn/OxyCreateAccountPanel.js.map +1 -0
- package/lib/commonjs/ui/components/signIn/OxyDeleteAccountPanel.js +114 -0
- package/lib/commonjs/ui/components/signIn/OxyDeleteAccountPanel.js.map +1 -0
- package/lib/commonjs/ui/components/signIn/OxyLinkCommonsPanel.js +275 -0
- package/lib/commonjs/ui/components/signIn/OxyLinkCommonsPanel.js.map +1 -0
- package/lib/commonjs/ui/components/signIn/OxyRecoverAccountPanel.js +170 -0
- package/lib/commonjs/ui/components/signIn/OxyRecoverAccountPanel.js.map +1 -0
- package/lib/commonjs/ui/components/signIn/OxySignInPanel.js +371 -0
- package/lib/commonjs/ui/components/signIn/OxySignInPanel.js.map +1 -0
- package/lib/commonjs/ui/components/signIn/OxySignUpPanel.js +78 -0
- package/lib/commonjs/ui/components/signIn/OxySignUpPanel.js.map +1 -0
- package/lib/commonjs/ui/components/signIn/accountFlowParts.js +244 -0
- package/lib/commonjs/ui/components/signIn/accountFlowParts.js.map +1 -0
- package/lib/commonjs/ui/components/signIn/artwork.js +21 -0
- package/lib/commonjs/ui/components/signIn/artwork.js.map +1 -0
- package/lib/commonjs/ui/components/signIn/passkeyError.js +46 -0
- package/lib/commonjs/ui/components/signIn/passkeyError.js.map +1 -0
- package/lib/commonjs/ui/components/signIn/signInMethods.js +46 -0
- package/lib/commonjs/ui/components/signIn/signInMethods.js.map +1 -0
- package/lib/commonjs/ui/context/OxyContext.js +16 -16
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/context/commitSessionFlow.js +0 -43
- package/lib/commonjs/ui/context/commitSessionFlow.js.map +1 -1
- package/lib/commonjs/ui/context/passkeyFlow.js +22 -0
- package/lib/commonjs/ui/context/passkeyFlow.js.map +1 -1
- package/lib/commonjs/ui/hooks/accountDialogSnapshot.js +15 -1
- package/lib/commonjs/ui/hooks/accountDialogSnapshot.js.map +1 -1
- package/lib/commonjs/ui/hooks/useDeviceSwitcher.js +1 -3
- package/lib/commonjs/ui/hooks/useDeviceSwitcher.js.map +1 -1
- package/lib/commonjs/ui/oauth/browserAuthTransport.js +11 -4
- package/lib/commonjs/ui/oauth/browserAuthTransport.js.map +1 -1
- package/lib/commonjs/ui/oauth/oauthHandshake.js +3 -0
- package/lib/commonjs/ui/oauth/oauthHandshake.js.map +1 -1
- package/lib/commonjs/ui/oauth/oauthPopup.js +2 -3
- package/lib/commonjs/ui/oauth/oauthPopup.js.map +1 -1
- package/lib/commonjs/ui/screens/EditProfileFieldScreen.js +0 -23
- package/lib/commonjs/ui/screens/EditProfileFieldScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/EditProfileScreen.js +0 -8
- package/lib/commonjs/ui/screens/EditProfileScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/ManageAccountScreen.js +3 -4
- package/lib/commonjs/ui/screens/ManageAccountScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/trust/TrustLeaderboardScreen.js +1 -1
- package/lib/commonjs/ui/screens/trust/TrustLeaderboardScreen.js.map +1 -1
- package/lib/commonjs/ui/session/authStore.js +0 -21
- package/lib/commonjs/ui/session/authStore.js.map +1 -1
- package/lib/commonjs/ui/utils/accountDeletionHandoff.js +2 -2
- package/lib/commonjs/ui/utils/accountDeletionHandoff.js.map +1 -1
- package/lib/module/assets/assets/signIn/slide-1.jpg +0 -0
- package/lib/module/assets/assets/signIn/slide-1.jpg.d.ts +3 -0
- package/lib/module/assets/assets/signIn/slide-2.jpg +0 -0
- package/lib/module/assets/assets/signIn/slide-2.jpg.d.ts +3 -0
- package/lib/module/assets/assets/signIn/slide-3.jpg +0 -0
- package/lib/module/assets/assets/signIn/slide-3.jpg.d.ts +3 -0
- package/lib/module/assets/assets/signIn/slide-4.jpg +0 -0
- package/lib/module/assets/assets/signIn/slide-4.jpg.d.ts +3 -0
- package/lib/module/assets/signIn/slide-1.jpg +0 -0
- package/lib/module/assets/signIn/slide-2.jpg +0 -0
- package/lib/module/assets/signIn/slide-3.jpg +0 -0
- package/lib/module/assets/signIn/slide-4.jpg +0 -0
- package/lib/module/index.js +14 -6
- package/lib/module/index.js.map +1 -1
- package/lib/module/ui/components/OxyAccountDialogScreen.js +14 -59
- package/lib/module/ui/components/OxyAccountDialogScreen.js.map +1 -1
- package/lib/module/ui/components/OxyAuthChooser.js +37 -46
- package/lib/module/ui/components/OxyAuthChooser.js.map +1 -1
- package/lib/module/ui/components/OxyProvider.js +0 -2
- package/lib/module/ui/components/OxyProvider.js.map +1 -1
- package/lib/module/ui/components/ProfileButton.js.map +1 -1
- package/lib/module/ui/components/authChooser/AccountsMenuView.js +22 -10
- package/lib/module/ui/components/authChooser/AccountsMenuView.js.map +1 -1
- package/lib/module/ui/components/authChooser/primitives.js +1 -44
- package/lib/module/ui/components/authChooser/primitives.js.map +1 -1
- package/lib/module/ui/components/authChooser/signInFailureMessage.js +1 -7
- package/lib/module/ui/components/authChooser/signInFailureMessage.js.map +1 -1
- package/lib/module/ui/components/authChooser/styles.js +0 -31
- package/lib/module/ui/components/authChooser/styles.js.map +1 -1
- package/lib/module/ui/components/authChooser/types.js +2 -2
- package/lib/module/ui/components/authChooser/types.js.map +1 -1
- package/lib/module/ui/components/oauthNavigation.js +1 -1
- package/lib/module/ui/components/signIn/InlineCommonsQr.js +157 -0
- package/lib/module/ui/components/signIn/InlineCommonsQr.js.map +1 -0
- package/lib/module/ui/components/signIn/OxyAccountPicker.js +106 -0
- package/lib/module/ui/components/signIn/OxyAccountPicker.js.map +1 -0
- package/lib/module/ui/components/signIn/OxyAuthScreen.js +151 -0
- package/lib/module/ui/components/signIn/OxyAuthScreen.js.map +1 -0
- package/lib/module/ui/components/signIn/OxyCreateAccountPanel.js +231 -0
- package/lib/module/ui/components/signIn/OxyCreateAccountPanel.js.map +1 -0
- package/lib/module/ui/components/signIn/OxyDeleteAccountPanel.js +109 -0
- package/lib/module/ui/components/signIn/OxyDeleteAccountPanel.js.map +1 -0
- package/lib/module/ui/components/signIn/OxyLinkCommonsPanel.js +270 -0
- package/lib/module/ui/components/signIn/OxyLinkCommonsPanel.js.map +1 -0
- package/lib/module/ui/components/signIn/OxyRecoverAccountPanel.js +165 -0
- package/lib/module/ui/components/signIn/OxyRecoverAccountPanel.js.map +1 -0
- package/lib/module/ui/components/signIn/OxySignInPanel.js +366 -0
- package/lib/module/ui/components/signIn/OxySignInPanel.js.map +1 -0
- package/lib/module/ui/components/signIn/OxySignUpPanel.js +75 -0
- package/lib/module/ui/components/signIn/OxySignUpPanel.js.map +1 -0
- package/lib/module/ui/components/signIn/accountFlowParts.js +235 -0
- package/lib/module/ui/components/signIn/accountFlowParts.js.map +1 -0
- package/lib/module/ui/components/signIn/artwork.js +16 -0
- package/lib/module/ui/components/signIn/artwork.js.map +1 -0
- package/lib/module/ui/components/signIn/passkeyError.js +40 -0
- package/lib/module/ui/components/signIn/passkeyError.js.map +1 -0
- package/lib/module/ui/components/signIn/signInMethods.js +42 -0
- package/lib/module/ui/components/signIn/signInMethods.js.map +1 -0
- package/lib/module/ui/context/OxyContext.js +17 -17
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/context/commitSessionFlow.js +0 -42
- package/lib/module/ui/context/commitSessionFlow.js.map +1 -1
- package/lib/module/ui/context/passkeyFlow.js +21 -0
- package/lib/module/ui/context/passkeyFlow.js.map +1 -1
- package/lib/module/ui/hooks/accountDialogSnapshot.js +14 -1
- package/lib/module/ui/hooks/accountDialogSnapshot.js.map +1 -1
- package/lib/module/ui/hooks/useDeviceSwitcher.js +3 -5
- package/lib/module/ui/hooks/useDeviceSwitcher.js.map +1 -1
- package/lib/module/ui/oauth/browserAuthTransport.js +11 -4
- package/lib/module/ui/oauth/browserAuthTransport.js.map +1 -1
- package/lib/module/ui/oauth/oauthHandshake.js +3 -0
- package/lib/module/ui/oauth/oauthHandshake.js.map +1 -1
- package/lib/module/ui/oauth/oauthPopup.js +2 -3
- package/lib/module/ui/oauth/oauthPopup.js.map +1 -1
- package/lib/module/ui/screens/EditProfileFieldScreen.js +1 -24
- package/lib/module/ui/screens/EditProfileFieldScreen.js.map +1 -1
- package/lib/module/ui/screens/EditProfileScreen.js +0 -8
- package/lib/module/ui/screens/EditProfileScreen.js.map +1 -1
- package/lib/module/ui/screens/ManageAccountScreen.js +4 -5
- package/lib/module/ui/screens/ManageAccountScreen.js.map +1 -1
- package/lib/module/ui/screens/trust/TrustLeaderboardScreen.js +1 -1
- package/lib/module/ui/screens/trust/TrustLeaderboardScreen.js.map +1 -1
- package/lib/module/ui/session/authStore.js +1 -22
- package/lib/module/ui/session/authStore.js.map +1 -1
- package/lib/module/ui/utils/accountDeletionHandoff.js +3 -3
- package/lib/module/ui/utils/accountDeletionHandoff.js.map +1 -1
- package/lib/typescript/assets/signIn/slide-1.jpg.d.ts +3 -0
- package/lib/typescript/assets/signIn/slide-2.jpg.d.ts +3 -0
- package/lib/typescript/assets/signIn/slide-3.jpg.d.ts +3 -0
- package/lib/typescript/assets/signIn/slide-4.jpg.d.ts +3 -0
- package/lib/typescript/commonjs/index.d.ts +16 -2
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/OxyAccountDialogScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/OxyAuthChooser.d.ts +5 -12
- package/lib/typescript/commonjs/ui/components/OxyAuthChooser.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/OxyProvider.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/ProfileButton.d.ts +1 -1
- package/lib/typescript/commonjs/ui/components/ProfileButton.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/authChooser/AccountsMenuView.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/authChooser/primitives.d.ts +0 -19
- package/lib/typescript/commonjs/ui/components/authChooser/primitives.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/authChooser/signInFailureMessage.d.ts +1 -5
- package/lib/typescript/commonjs/ui/components/authChooser/signInFailureMessage.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/authChooser/styles.d.ts +0 -31
- package/lib/typescript/commonjs/ui/components/authChooser/styles.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/authChooser/types.d.ts +2 -7
- package/lib/typescript/commonjs/ui/components/authChooser/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/oauthNavigation.d.ts +1 -1
- package/lib/typescript/commonjs/ui/components/signIn/InlineCommonsQr.d.ts +20 -0
- package/lib/typescript/commonjs/ui/components/signIn/InlineCommonsQr.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/signIn/OxyAccountPicker.d.ts +34 -0
- package/lib/typescript/commonjs/ui/components/signIn/OxyAccountPicker.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/signIn/OxyAuthScreen.d.ts +43 -0
- package/lib/typescript/commonjs/ui/components/signIn/OxyAuthScreen.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/signIn/OxyCreateAccountPanel.d.ts +24 -0
- package/lib/typescript/commonjs/ui/components/signIn/OxyCreateAccountPanel.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/signIn/OxyDeleteAccountPanel.d.ts +16 -0
- package/lib/typescript/commonjs/ui/components/signIn/OxyDeleteAccountPanel.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/signIn/OxyLinkCommonsPanel.d.ts +21 -0
- package/lib/typescript/commonjs/ui/components/signIn/OxyLinkCommonsPanel.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/signIn/OxyRecoverAccountPanel.d.ts +20 -0
- package/lib/typescript/commonjs/ui/components/signIn/OxyRecoverAccountPanel.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/signIn/OxySignInPanel.d.ts +43 -0
- package/lib/typescript/commonjs/ui/components/signIn/OxySignInPanel.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/signIn/OxySignUpPanel.d.ts +17 -0
- package/lib/typescript/commonjs/ui/components/signIn/OxySignUpPanel.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/signIn/accountFlowParts.d.ts +60 -0
- package/lib/typescript/commonjs/ui/components/signIn/accountFlowParts.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/signIn/artwork.d.ts +8 -0
- package/lib/typescript/commonjs/ui/components/signIn/artwork.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/signIn/passkeyError.d.ts +16 -0
- package/lib/typescript/commonjs/ui/components/signIn/passkeyError.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/signIn/signInMethods.d.ts +39 -0
- package/lib/typescript/commonjs/ui/components/signIn/signInMethods.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/context/commitSessionFlow.d.ts +0 -40
- package/lib/typescript/commonjs/ui/context/commitSessionFlow.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/context/oxyContextTypes.d.ts +15 -10
- package/lib/typescript/commonjs/ui/context/oxyContextTypes.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/context/passkeyFlow.d.ts +16 -1
- package/lib/typescript/commonjs/ui/context/passkeyFlow.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/accountDialogSnapshot.d.ts +7 -1
- package/lib/typescript/commonjs/ui/hooks/accountDialogSnapshot.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useDeviceSwitcher.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/oauth/browserAuthTransport.d.ts +9 -0
- package/lib/typescript/commonjs/ui/oauth/browserAuthTransport.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/oauth/oauthHandshake.d.ts +3 -0
- package/lib/typescript/commonjs/ui/oauth/oauthHandshake.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/oauth/oauthPopup.d.ts +2 -3
- package/lib/typescript/commonjs/ui/oauth/oauthPopup.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/EditProfileFieldScreen.d.ts +1 -1
- package/lib/typescript/commonjs/ui/screens/EditProfileFieldScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/EditProfileScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/ManageAccountScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/session/authStore.d.ts +0 -30
- package/lib/typescript/commonjs/ui/session/authStore.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/types/navigation.d.ts +0 -26
- package/lib/typescript/commonjs/ui/types/navigation.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +16 -2
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/OxyAccountDialogScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/OxyAuthChooser.d.ts +5 -12
- package/lib/typescript/module/ui/components/OxyAuthChooser.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/OxyProvider.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/ProfileButton.d.ts +1 -1
- package/lib/typescript/module/ui/components/ProfileButton.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/authChooser/AccountsMenuView.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/authChooser/primitives.d.ts +0 -19
- package/lib/typescript/module/ui/components/authChooser/primitives.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/authChooser/signInFailureMessage.d.ts +1 -5
- package/lib/typescript/module/ui/components/authChooser/signInFailureMessage.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/authChooser/styles.d.ts +0 -31
- package/lib/typescript/module/ui/components/authChooser/styles.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/authChooser/types.d.ts +2 -7
- package/lib/typescript/module/ui/components/authChooser/types.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/oauthNavigation.d.ts +1 -1
- package/lib/typescript/module/ui/components/signIn/InlineCommonsQr.d.ts +20 -0
- package/lib/typescript/module/ui/components/signIn/InlineCommonsQr.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/signIn/OxyAccountPicker.d.ts +34 -0
- package/lib/typescript/module/ui/components/signIn/OxyAccountPicker.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/signIn/OxyAuthScreen.d.ts +43 -0
- package/lib/typescript/module/ui/components/signIn/OxyAuthScreen.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/signIn/OxyCreateAccountPanel.d.ts +24 -0
- package/lib/typescript/module/ui/components/signIn/OxyCreateAccountPanel.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/signIn/OxyDeleteAccountPanel.d.ts +16 -0
- package/lib/typescript/module/ui/components/signIn/OxyDeleteAccountPanel.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/signIn/OxyLinkCommonsPanel.d.ts +21 -0
- package/lib/typescript/module/ui/components/signIn/OxyLinkCommonsPanel.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/signIn/OxyRecoverAccountPanel.d.ts +20 -0
- package/lib/typescript/module/ui/components/signIn/OxyRecoverAccountPanel.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/signIn/OxySignInPanel.d.ts +43 -0
- package/lib/typescript/module/ui/components/signIn/OxySignInPanel.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/signIn/OxySignUpPanel.d.ts +17 -0
- package/lib/typescript/module/ui/components/signIn/OxySignUpPanel.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/signIn/accountFlowParts.d.ts +60 -0
- package/lib/typescript/module/ui/components/signIn/accountFlowParts.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/signIn/artwork.d.ts +8 -0
- package/lib/typescript/module/ui/components/signIn/artwork.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/signIn/passkeyError.d.ts +16 -0
- package/lib/typescript/module/ui/components/signIn/passkeyError.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/signIn/signInMethods.d.ts +39 -0
- package/lib/typescript/module/ui/components/signIn/signInMethods.d.ts.map +1 -0
- package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/module/ui/context/commitSessionFlow.d.ts +0 -40
- package/lib/typescript/module/ui/context/commitSessionFlow.d.ts.map +1 -1
- package/lib/typescript/module/ui/context/oxyContextTypes.d.ts +15 -10
- package/lib/typescript/module/ui/context/oxyContextTypes.d.ts.map +1 -1
- package/lib/typescript/module/ui/context/passkeyFlow.d.ts +16 -1
- package/lib/typescript/module/ui/context/passkeyFlow.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/accountDialogSnapshot.d.ts +7 -1
- package/lib/typescript/module/ui/hooks/accountDialogSnapshot.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useDeviceSwitcher.d.ts.map +1 -1
- package/lib/typescript/module/ui/oauth/browserAuthTransport.d.ts +9 -0
- package/lib/typescript/module/ui/oauth/browserAuthTransport.d.ts.map +1 -1
- package/lib/typescript/module/ui/oauth/oauthHandshake.d.ts +3 -0
- package/lib/typescript/module/ui/oauth/oauthHandshake.d.ts.map +1 -1
- package/lib/typescript/module/ui/oauth/oauthPopup.d.ts +2 -3
- package/lib/typescript/module/ui/oauth/oauthPopup.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/EditProfileFieldScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/EditProfileFieldScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/EditProfileScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/ManageAccountScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/session/authStore.d.ts +0 -30
- package/lib/typescript/module/ui/session/authStore.d.ts.map +1 -1
- package/lib/typescript/module/ui/types/navigation.d.ts +0 -26
- package/lib/typescript/module/ui/types/navigation.d.ts.map +1 -1
- package/package.json +4 -7
- package/src/assets/signIn/slide-1.jpg +0 -0
- package/src/assets/signIn/slide-1.jpg.d.ts +3 -0
- package/src/assets/signIn/slide-2.jpg +0 -0
- package/src/assets/signIn/slide-2.jpg.d.ts +3 -0
- package/src/assets/signIn/slide-3.jpg +0 -0
- package/src/assets/signIn/slide-3.jpg.d.ts +3 -0
- package/src/assets/signIn/slide-4.jpg +0 -0
- package/src/assets/signIn/slide-4.jpg.d.ts +3 -0
- package/src/index.ts +27 -7
- package/src/ui/components/OxyAccountDialogScreen.tsx +11 -72
- package/src/ui/components/OxyAuthChooser.tsx +37 -54
- package/src/ui/components/OxyProvider.tsx +0 -2
- package/src/ui/components/ProfileButton.tsx +1 -4
- package/src/ui/components/authChooser/AccountsMenuView.tsx +28 -8
- package/src/ui/components/authChooser/primitives.tsx +1 -39
- package/src/ui/components/authChooser/signInFailureMessage.ts +1 -7
- package/src/ui/components/authChooser/styles.ts +0 -31
- package/src/ui/components/authChooser/types.ts +2 -7
- package/src/ui/components/oauthNavigation.ts +1 -1
- package/src/ui/components/signIn/InlineCommonsQr.tsx +135 -0
- package/src/ui/components/signIn/OxyAccountPicker.tsx +129 -0
- package/src/ui/components/signIn/OxyAuthScreen.tsx +123 -0
- package/src/ui/components/signIn/OxyCreateAccountPanel.tsx +207 -0
- package/src/ui/components/signIn/OxyDeleteAccountPanel.tsx +106 -0
- package/src/ui/components/signIn/OxyLinkCommonsPanel.tsx +222 -0
- package/src/ui/components/signIn/OxyRecoverAccountPanel.tsx +154 -0
- package/src/ui/components/signIn/OxySignInPanel.tsx +392 -0
- package/src/ui/components/signIn/OxySignUpPanel.tsx +86 -0
- package/src/ui/components/signIn/accountFlowParts.tsx +204 -0
- package/src/ui/components/signIn/artwork.ts +13 -0
- package/src/ui/components/signIn/passkeyError.ts +44 -0
- package/src/ui/components/signIn/signInMethods.ts +51 -0
- package/src/ui/context/OxyContext.tsx +23 -19
- package/src/ui/context/__tests__/commitSessionFlow.test.ts +0 -89
- package/src/ui/context/__tests__/passkeyFlow.test.ts +59 -1
- package/src/ui/context/commitSessionFlow.ts +0 -61
- package/src/ui/context/oxyContextTypes.ts +16 -10
- package/src/ui/context/passkeyFlow.ts +28 -0
- package/src/ui/hooks/accountDialogSnapshot.ts +20 -1
- package/src/ui/hooks/useDeviceSwitcher.ts +3 -11
- package/src/ui/oauth/__tests__/browserAuthTransport.test.ts +21 -0
- package/src/ui/oauth/browserAuthTransport.ts +14 -4
- package/src/ui/oauth/oauthHandshake.ts +4 -1
- package/src/ui/oauth/oauthPopup.ts +2 -3
- package/src/ui/screens/EditProfileFieldScreen.tsx +1 -27
- package/src/ui/screens/EditProfileScreen.tsx +0 -6
- package/src/ui/screens/ManageAccountScreen.tsx +4 -5
- package/src/ui/screens/trust/TrustLeaderboardScreen.tsx +1 -1
- package/src/ui/session/authStore.ts +0 -37
- package/src/ui/types/navigation.ts +0 -26
- package/src/ui/utils/accountDeletionHandoff.ts +3 -3
- package/lib/commonjs/ui/components/authChooser/SignInEntryView.js +0 -132
- package/lib/commonjs/ui/components/authChooser/SignInEntryView.js.map +0 -1
- package/lib/commonjs/ui/components/authChooser/SignUpView.js +0 -77
- package/lib/commonjs/ui/components/authChooser/SignUpView.js.map +0 -1
- package/lib/commonjs/ui/components/passkeyHubPopup.js +0 -33
- package/lib/commonjs/ui/components/passkeyHubPopup.js.map +0 -1
- package/lib/commonjs/ui/oauth/legacyRedirectLanes.js +0 -48
- package/lib/commonjs/ui/oauth/legacyRedirectLanes.js.map +0 -1
- package/lib/module/ui/components/authChooser/SignInEntryView.js +0 -127
- package/lib/module/ui/components/authChooser/SignInEntryView.js.map +0 -1
- package/lib/module/ui/components/authChooser/SignUpView.js +0 -73
- package/lib/module/ui/components/authChooser/SignUpView.js.map +0 -1
- package/lib/module/ui/components/passkeyHubPopup.js +0 -29
- package/lib/module/ui/components/passkeyHubPopup.js.map +0 -1
- package/lib/module/ui/oauth/legacyRedirectLanes.js +0 -44
- package/lib/module/ui/oauth/legacyRedirectLanes.js.map +0 -1
- package/lib/typescript/commonjs/ui/components/authChooser/SignInEntryView.d.ts +0 -39
- package/lib/typescript/commonjs/ui/components/authChooser/SignInEntryView.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/components/authChooser/SignUpView.d.ts +0 -31
- package/lib/typescript/commonjs/ui/components/authChooser/SignUpView.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/components/passkeyHubPopup.d.ts +0 -23
- package/lib/typescript/commonjs/ui/components/passkeyHubPopup.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/oauth/legacyRedirectLanes.d.ts +0 -40
- package/lib/typescript/commonjs/ui/oauth/legacyRedirectLanes.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/authChooser/SignInEntryView.d.ts +0 -39
- package/lib/typescript/module/ui/components/authChooser/SignInEntryView.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/authChooser/SignUpView.d.ts +0 -31
- package/lib/typescript/module/ui/components/authChooser/SignUpView.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/passkeyHubPopup.d.ts +0 -23
- package/lib/typescript/module/ui/components/passkeyHubPopup.d.ts.map +0 -1
- package/lib/typescript/module/ui/oauth/legacyRedirectLanes.d.ts +0 -40
- package/lib/typescript/module/ui/oauth/legacyRedirectLanes.d.ts.map +0 -1
- package/src/ui/components/authChooser/SignInEntryView.tsx +0 -157
- package/src/ui/components/authChooser/SignUpView.tsx +0 -76
- package/src/ui/components/passkeyHubPopup.ts +0 -28
- package/src/ui/oauth/legacyRedirectLanes.ts +0 -43
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The message for a failed passkey sign-in, and whether it was rate-limited.
|
|
3
|
+
*
|
|
4
|
+
* A dismissed or timed-out browser prompt rejects with a `NotAllowedError` /
|
|
5
|
+
* `AbortError` DOMException, often re-wrapped by `@simplewebauthn/browser` as a
|
|
6
|
+
* `WebAuthnError` whose `cause` is the original — so the cancellation shape is
|
|
7
|
+
* looked for along the cause chain, and reported calmly instead of as the raw
|
|
8
|
+
* "The operation either timed out or was not allowed…".
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { Translate } from '../authChooser/types';
|
|
12
|
+
|
|
13
|
+
/** How long the surface waits after a 429 before it lets the person retry. */
|
|
14
|
+
export const RATE_LIMIT_SECONDS = 60;
|
|
15
|
+
|
|
16
|
+
function isCancellation(error: unknown): boolean {
|
|
17
|
+
let current: unknown = error;
|
|
18
|
+
for (let depth = 0; depth < 5 && current instanceof Error; depth += 1) {
|
|
19
|
+
if (current.name === 'NotAllowedError' || current.name === 'AbortError') return true;
|
|
20
|
+
// `@simplewebauthn/browser`'s stable code for an aborted ceremony.
|
|
21
|
+
if ((current as { code?: unknown }).code === 'ERROR_CEREMONY_ABORTED') return true;
|
|
22
|
+
current = (current as { cause?: unknown }).cause;
|
|
23
|
+
}
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** An HTTP status off a thrown SDK error (ApiError- or axios-shaped). */
|
|
28
|
+
function errorStatus(error: unknown): number | undefined {
|
|
29
|
+
return (
|
|
30
|
+
(error as { status?: number } | undefined)?.status ??
|
|
31
|
+
(error as { response?: { status?: number } } | undefined)?.response?.status
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function isRateLimited(error: unknown): boolean {
|
|
36
|
+
return errorStatus(error) === 429;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** The inline message for a passkey ceremony that did not sign anyone in. */
|
|
40
|
+
export function describePasskeyError(error: unknown, t: Translate): string {
|
|
41
|
+
if (isCancellation(error)) return t('signin.errors.passkeyCancelled');
|
|
42
|
+
if (error instanceof Error && error.message.trim().length > 0) return error.message;
|
|
43
|
+
return t('signin.errors.passkeyFailed');
|
|
44
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which sign-in methods a surface offers, from where it runs.
|
|
3
|
+
*
|
|
4
|
+
* One screen everywhere; only the transport behind each block changes:
|
|
5
|
+
*
|
|
6
|
+
* - auth.oxy.so (`page`) is where the web signs in: the embedded Commons QR
|
|
7
|
+
* (the split card's right column from `md`, "Continue with Oxy" below it),
|
|
8
|
+
* the username with its Continue, and the passkey — asserted right here,
|
|
9
|
+
* on the one origin every Oxy passkey belongs to;
|
|
10
|
+
* - an app's account dialog on the web (`dialog`) opens that screen in a
|
|
11
|
+
* window over the app ("Continue with Oxy"), like "Sign in with Google":
|
|
12
|
+
* the browser's session lives on auth.oxy.so, so every Oxy app shares it;
|
|
13
|
+
* - native signs in with Commons: "Continue with Oxy", or "Get Commons" on a
|
|
14
|
+
* device that has no Commons to continue with.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import type { CommonsAvailability } from '@oxy.so/core';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* `qr` — auth.oxy.so: the embedded QR from `md`, "Continue with Oxy" below.
|
|
21
|
+
* `window` — an app on the web: "Continue with Oxy" opens auth.oxy.so's window.
|
|
22
|
+
* `continue` — native "Continue with Oxy": Oxy picks the route (shared
|
|
23
|
+
* keychain, Commons on this device, a push, or the QR view).
|
|
24
|
+
* `get-commons` — native, and Commons is not installed here.
|
|
25
|
+
*/
|
|
26
|
+
export type CommonsEntry = 'qr' | 'window' | 'continue' | 'get-commons';
|
|
27
|
+
|
|
28
|
+
export interface SignInMethods {
|
|
29
|
+
commons: CommonsEntry;
|
|
30
|
+
/** The username and passkey block: only on auth.oxy.so. */
|
|
31
|
+
passkey: boolean;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface SignInSurfaceFacts {
|
|
35
|
+
/** Rendering in a browser (react-native-web), not a native app. */
|
|
36
|
+
web: boolean;
|
|
37
|
+
/** `page` is auth.oxy.so; `dialog` is an app's account dialog. */
|
|
38
|
+
host: 'dialog' | 'page';
|
|
39
|
+
/** The controller's native probe for an installed Commons. */
|
|
40
|
+
commonsAvailability: CommonsAvailability;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function resolveSignInMethods(facts: SignInSurfaceFacts): SignInMethods {
|
|
44
|
+
if (facts.web) {
|
|
45
|
+
return facts.host === 'page' ? { commons: 'qr', passkey: true } : { commons: 'window', passkey: false };
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
commons: facts.commonsAvailability === 'unavailable' ? 'get-commons' : 'continue',
|
|
49
|
+
passkey: false,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
@@ -9,7 +9,8 @@ import {
|
|
|
9
9
|
useState,
|
|
10
10
|
} from 'react';
|
|
11
11
|
import { Linking, Platform } from 'react-native';
|
|
12
|
-
import { OxyServices, oxyClient } from '@oxy.so/core';
|
|
12
|
+
import { DeviceManager, OxyServices, oxyClient, type OxyAuthScreen } from '@oxy.so/core';
|
|
13
|
+
import type { LoginSessionResult } from '@oxy.so/contracts';
|
|
13
14
|
import type {
|
|
14
15
|
User,
|
|
15
16
|
SessionLoginResponse,
|
|
@@ -31,7 +32,6 @@ import {
|
|
|
31
32
|
notifyAccountDialogVisibility,
|
|
32
33
|
} from '../navigation/accountDialogManager';
|
|
33
34
|
import { redirectToAuthorize } from '../components/oauthNavigation';
|
|
34
|
-
import { openPasskeyHubPopup } from '../components/passkeyHubPopup';
|
|
35
35
|
import {
|
|
36
36
|
startWebOAuthSignIn,
|
|
37
37
|
type StartWebOAuthSignInOptions,
|
|
@@ -149,7 +149,6 @@ export const OxyRuntimeProvider: React.FC<OxyRuntimeProviderProps> = ({
|
|
|
149
149
|
sessionMode = 'account',
|
|
150
150
|
webAuthMode = 'popup',
|
|
151
151
|
backgroundSession = false,
|
|
152
|
-
deviceCredentialStorage = 'persistent',
|
|
153
152
|
platformStorage,
|
|
154
153
|
onAuthStateChange,
|
|
155
154
|
onError,
|
|
@@ -170,17 +169,9 @@ export const OxyRuntimeProvider: React.FC<OxyRuntimeProviderProps> = ({
|
|
|
170
169
|
|
|
171
170
|
// The device-first persisted auth-state store (per-origin device credential on
|
|
172
171
|
// web; SecureStore session blob on native). Built ONCE per provider mount.
|
|
173
|
-
//
|
|
174
|
-
// `deviceCredentialStorage` is mount-time configuration for the same reason
|
|
175
|
-
// `sessionMode` is: it decides where the durable credential lives, and letting
|
|
176
|
-
// it change mid-flight would mean a session that started ephemeral could begin
|
|
177
|
-
// writing one.
|
|
178
172
|
const authStoreRef = useRef<AuthStateStore | null>(null);
|
|
179
173
|
if (!authStoreRef.current) {
|
|
180
|
-
authStoreRef.current = createPlatformAuthStateStore({
|
|
181
|
-
sessionMode,
|
|
182
|
-
storage: deviceCredentialStorage,
|
|
183
|
-
});
|
|
174
|
+
authStoreRef.current = createPlatformAuthStateStore({ sessionMode });
|
|
184
175
|
}
|
|
185
176
|
const authStore = authStoreRef.current;
|
|
186
177
|
|
|
@@ -730,7 +721,7 @@ export const OxyRuntimeProvider: React.FC<OxyRuntimeProviderProps> = ({
|
|
|
730
721
|
// Public `handleWebSession`: commit a session from the QR device flow. It is a
|
|
731
722
|
// deliberate sign-in on THIS device, so it activates the account.
|
|
732
723
|
const handleWebSession = useCallback(
|
|
733
|
-
async (session: SessionLoginResponse): Promise<void> => {
|
|
724
|
+
async (session: SessionLoginResponse | LoginSessionResult): Promise<void> => {
|
|
734
725
|
if (!session?.user || !session?.sessionId || !session.accessToken) {
|
|
735
726
|
throw new Error('Session response did not include a usable session');
|
|
736
727
|
}
|
|
@@ -794,6 +785,20 @@ export const OxyRuntimeProvider: React.FC<OxyRuntimeProviderProps> = ({
|
|
|
794
785
|
[webAuthMode, oxyServices, clientId, authorizeBaseUrl, isIdentityBound, user?.id],
|
|
795
786
|
);
|
|
796
787
|
|
|
788
|
+
// On the web an Oxy app signs in and creates accounts in auth.oxy.so's
|
|
789
|
+
// window over the app, like "Sign in with Google": the passkey belongs to
|
|
790
|
+
// that origin, and the browser's session lives there, shared by every Oxy
|
|
791
|
+
// app. A blocked window falls back to the same page in this tab.
|
|
792
|
+
const continueOnAuth = useCallback(
|
|
793
|
+
(screen: OxyAuthScreen): Promise<WebOAuthSignInResult> =>
|
|
794
|
+
startWebOAuthSignInForContext({
|
|
795
|
+
redirectUri: authRedirectUri ?? globalThis.location?.origin ?? '',
|
|
796
|
+
transport: 'popup',
|
|
797
|
+
screen,
|
|
798
|
+
}),
|
|
799
|
+
[startWebOAuthSignInForContext, authRedirectUri],
|
|
800
|
+
);
|
|
801
|
+
|
|
797
802
|
// ── Unified account dialog ─────────────────────────────────────────────────
|
|
798
803
|
// The single account-chooser + sign-in surface. Built ONCE per provider mount
|
|
799
804
|
// and bound to the live `oxyServices` + `sessionClient` + this provider's
|
|
@@ -863,11 +868,6 @@ export const OxyRuntimeProvider: React.FC<OxyRuntimeProviderProps> = ({
|
|
|
863
868
|
// controller short-circuits, so `redirectToAuthorize` never runs for the
|
|
864
869
|
// `oxycommons://` payload.
|
|
865
870
|
canOpenApp: isWebBrowser() ? undefined : (url) => Linking.canOpenURL(url),
|
|
866
|
-
// Web-only: lets `startPasskeyHubSignIn` open the auth.oxy.so passkey hub
|
|
867
|
-
// popup (b2) for a non-Oxy origin. `undefined` on native — there is no
|
|
868
|
-
// popup concept there, and off-origin passkey sign-in isn't reachable
|
|
869
|
-
// (Commons owns the native flow).
|
|
870
|
-
openPopup: isWebBrowser() ? openPasskeyHubPopup : undefined,
|
|
871
871
|
// Which surface a sign-in starts from — a FACT only this consumer can
|
|
872
872
|
// supply (headless core never touches a platform global). It decides
|
|
873
873
|
// whether automatic delivery may take the same-device Commons deep link;
|
|
@@ -983,7 +983,9 @@ export const OxyRuntimeProvider: React.FC<OxyRuntimeProviderProps> = ({
|
|
|
983
983
|
username: opts?.username,
|
|
984
984
|
deviceId: persisted?.deviceId,
|
|
985
985
|
deviceName: opts?.deviceName,
|
|
986
|
-
|
|
986
|
+
// The same shape every other sign-in path sends; the server only reads it
|
|
987
|
+
// to place a device that has no persisted id yet.
|
|
988
|
+
deviceFingerprint: opts?.deviceFingerprint ?? JSON.stringify(DeviceManager.getDeviceFingerprint()),
|
|
987
989
|
});
|
|
988
990
|
},
|
|
989
991
|
[oxyServices, authStore, commitSession],
|
|
@@ -1284,6 +1286,7 @@ export const OxyRuntimeProvider: React.FC<OxyRuntimeProviderProps> = ({
|
|
|
1284
1286
|
revokeSuspiciousSignIn,
|
|
1285
1287
|
handleWebSession,
|
|
1286
1288
|
startWebOAuthSignIn: startWebOAuthSignInForContext,
|
|
1289
|
+
continueOnAuth,
|
|
1287
1290
|
requestOAuthConsent: requestOAuthConsentForContext,
|
|
1288
1291
|
logout,
|
|
1289
1292
|
logoutAll,
|
|
@@ -1341,6 +1344,7 @@ export const OxyRuntimeProvider: React.FC<OxyRuntimeProviderProps> = ({
|
|
|
1341
1344
|
revokeSuspiciousSignIn,
|
|
1342
1345
|
handleWebSession,
|
|
1343
1346
|
startWebOAuthSignInForContext,
|
|
1347
|
+
continueOnAuth,
|
|
1344
1348
|
requestOAuthConsentForContext,
|
|
1345
1349
|
logout,
|
|
1346
1350
|
logoutAll,
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
import type { User } from '@oxy.so/core';
|
|
2
2
|
import { logger } from '@oxy.so/core';
|
|
3
|
-
import type { WebAuthMode } from '../../oauth/types';
|
|
4
3
|
import {
|
|
5
4
|
commitDeviceSetAndResolve,
|
|
6
|
-
maybeSyncHubAfterCommit,
|
|
7
5
|
type CommitDeviceSetAndResolveDeps,
|
|
8
|
-
type MaybeSyncHubAfterCommitDeps,
|
|
9
6
|
} from '../commitSessionFlow';
|
|
10
7
|
|
|
11
8
|
// A resolved promise chain (addCurrentAccount -> start -> syncFromClient) settles
|
|
@@ -206,92 +203,6 @@ describe('commitDeviceSetAndResolve — cold boot (activate: false)', () => {
|
|
|
206
203
|
});
|
|
207
204
|
});
|
|
208
205
|
|
|
209
|
-
/**
|
|
210
|
-
* Post-sign-in hub sync is a FULL-PAGE redirect to auth.oxy.so. It runs from the
|
|
211
|
-
* ONE commit funnel, so gating it here gates every commit path at once —
|
|
212
|
-
* `webAuthMode: 'popup'` must never bounce the tab, whichever path signed the
|
|
213
|
-
* user in (#691 phase 7).
|
|
214
|
-
*/
|
|
215
|
-
describe('maybeSyncHubAfterCommit — webAuthMode transport gate (#691 phase 7)', () => {
|
|
216
|
-
const buildHubDeps = (
|
|
217
|
-
overrides: Partial<MaybeSyncHubAfterCommitDeps> = {},
|
|
218
|
-
): MaybeSyncHubAfterCommitDeps => ({
|
|
219
|
-
activate: true,
|
|
220
|
-
hubSyncRequested: true,
|
|
221
|
-
hubSyncEnabled: true,
|
|
222
|
-
webAuthMode: 'redirect',
|
|
223
|
-
syncHub: jest.fn(async () => true),
|
|
224
|
-
...overrides,
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
it("redirect mode: syncs the hub after a deliberate sign-in (unchanged)", async () => {
|
|
228
|
-
const deps = buildHubDeps();
|
|
229
|
-
|
|
230
|
-
await expect(maybeSyncHubAfterCommit(deps)).resolves.toBe(true);
|
|
231
|
-
|
|
232
|
-
expect(deps.syncHub).toHaveBeenCalledTimes(1);
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
it('popup mode: NEVER syncs the hub, even on an otherwise-eligible sign-in', async () => {
|
|
236
|
-
const deps = buildHubDeps({ webAuthMode: 'popup' });
|
|
237
|
-
|
|
238
|
-
await expect(maybeSyncHubAfterCommit(deps)).resolves.toBe(false);
|
|
239
|
-
|
|
240
|
-
expect(deps.syncHub).not.toHaveBeenCalled();
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
it('popup mode: no commit path can opt back in', async () => {
|
|
244
|
-
// Every commit path differs only in `activate` / `hubSyncRequested`; the
|
|
245
|
-
// transport gate outranks all of them.
|
|
246
|
-
for (const activate of [true, false]) {
|
|
247
|
-
for (const hubSyncRequested of [true, false]) {
|
|
248
|
-
const deps = buildHubDeps({ webAuthMode: 'popup', activate, hubSyncRequested });
|
|
249
|
-
await expect(maybeSyncHubAfterCommit(deps)).resolves.toBe(false);
|
|
250
|
-
expect(deps.syncHub).not.toHaveBeenCalled();
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
it.each(['popup', 'redirect'] as const)(
|
|
256
|
-
'never syncs on a cold-boot restore, in either mode (%s)',
|
|
257
|
-
async (webAuthMode: WebAuthMode) => {
|
|
258
|
-
const deps = buildHubDeps({ webAuthMode, activate: false });
|
|
259
|
-
|
|
260
|
-
await expect(maybeSyncHubAfterCommit(deps)).resolves.toBe(false);
|
|
261
|
-
|
|
262
|
-
expect(deps.syncHub).not.toHaveBeenCalled();
|
|
263
|
-
},
|
|
264
|
-
);
|
|
265
|
-
|
|
266
|
-
it('redirect mode: honours the per-commit opt-out (account switch / popup OAuth lanes)', async () => {
|
|
267
|
-
const deps = buildHubDeps({ hubSyncRequested: false });
|
|
268
|
-
|
|
269
|
-
await expect(maybeSyncHubAfterCommit(deps)).resolves.toBe(false);
|
|
270
|
-
|
|
271
|
-
expect(deps.syncHub).not.toHaveBeenCalled();
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
it('redirect mode: honours the provider-level hubSync opt-out', async () => {
|
|
275
|
-
const deps = buildHubDeps({ hubSyncEnabled: false });
|
|
276
|
-
|
|
277
|
-
await expect(maybeSyncHubAfterCommit(deps)).resolves.toBe(false);
|
|
278
|
-
|
|
279
|
-
expect(deps.syncHub).not.toHaveBeenCalled();
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
it('redirect mode: a failing hub sync is non-fatal and never rejects', async () => {
|
|
283
|
-
const deps = buildHubDeps({
|
|
284
|
-
syncHub: jest.fn(async () => {
|
|
285
|
-
throw new Error('hub ticket failed');
|
|
286
|
-
}),
|
|
287
|
-
});
|
|
288
|
-
|
|
289
|
-
await expect(maybeSyncHubAfterCommit(deps)).resolves.toBe(false);
|
|
290
|
-
|
|
291
|
-
expect(deps.syncHub).toHaveBeenCalledTimes(1);
|
|
292
|
-
});
|
|
293
|
-
});
|
|
294
|
-
|
|
295
206
|
describe('commitDeviceSetAndResolve — deliberate sign-in (activate: true)', () => {
|
|
296
207
|
it('BLOCKS on the device-set reconcile before resolving auth (unchanged ordering)', async () => {
|
|
297
208
|
const order: string[] = [];
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
import type { LoginSessionResult } from '@oxy.so/contracts';
|
|
13
13
|
import {
|
|
14
14
|
runPasskeyLogin,
|
|
15
|
-
|
|
15
|
+
runPasskeyAdd,
|
|
16
|
+
runPasskeyRegisterSignIn,
|
|
16
17
|
PASSKEY_UNSUPPORTED_MESSAGE,
|
|
17
18
|
type RunPasskeyLoginDeps,
|
|
18
19
|
type RunPasskeyAddDeps,
|
|
@@ -179,3 +180,60 @@ describe('runPasskeyAdd', () => {
|
|
|
179
180
|
expect(deps.onLinked).not.toHaveBeenCalled();
|
|
180
181
|
});
|
|
181
182
|
});
|
|
183
|
+
|
|
184
|
+
describe('runPasskeyRegisterSignIn', () => {
|
|
185
|
+
it('runs options → ceremony → verify → commit, and commits the session it minted', async () => {
|
|
186
|
+
const order: string[] = [];
|
|
187
|
+
const commit = jest.fn(async (result: LoginSessionResult) => {
|
|
188
|
+
order.push('commit');
|
|
189
|
+
expect(result).toBe(sessionResult);
|
|
190
|
+
});
|
|
191
|
+
await runPasskeyRegisterSignIn({
|
|
192
|
+
isSupported: () => true,
|
|
193
|
+
getRegisterOptions: async () => {
|
|
194
|
+
order.push('register-options');
|
|
195
|
+
return { challenge: 'c' };
|
|
196
|
+
},
|
|
197
|
+
runCeremony: async (options) => {
|
|
198
|
+
order.push('ceremony');
|
|
199
|
+
expect(options).toEqual({ challenge: 'c' });
|
|
200
|
+
return { id: 'cred' };
|
|
201
|
+
},
|
|
202
|
+
registerVerify: async (response) => {
|
|
203
|
+
order.push('verify');
|
|
204
|
+
expect(response).toEqual({ id: 'cred' });
|
|
205
|
+
return sessionResult;
|
|
206
|
+
},
|
|
207
|
+
commit,
|
|
208
|
+
});
|
|
209
|
+
expect(order).toEqual(['register-options', 'ceremony', 'verify', 'commit']);
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it('refuses a verify that linked instead of signing in', async () => {
|
|
213
|
+
const commit = jest.fn();
|
|
214
|
+
await expect(
|
|
215
|
+
runPasskeyRegisterSignIn({
|
|
216
|
+
isSupported: () => true,
|
|
217
|
+
getRegisterOptions: async () => ({}),
|
|
218
|
+
runCeremony: async () => ({}),
|
|
219
|
+
registerVerify: async () => linkResult,
|
|
220
|
+
commit,
|
|
221
|
+
}),
|
|
222
|
+
).rejects.toThrow('without signing in');
|
|
223
|
+
expect(commit).not.toHaveBeenCalled();
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it('fails before any ceremony where passkeys are unsupported', async () => {
|
|
227
|
+
const getRegisterOptions = jest.fn();
|
|
228
|
+
await expect(
|
|
229
|
+
runPasskeyRegisterSignIn({
|
|
230
|
+
isSupported: () => false,
|
|
231
|
+
getRegisterOptions,
|
|
232
|
+
runCeremony: jest.fn(),
|
|
233
|
+
registerVerify: jest.fn(),
|
|
234
|
+
commit: jest.fn(),
|
|
235
|
+
}),
|
|
236
|
+
).rejects.toThrow(PASSKEY_UNSUPPORTED_MESSAGE);
|
|
237
|
+
expect(getRegisterOptions).not.toHaveBeenCalled();
|
|
238
|
+
});
|
|
239
|
+
});
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import type { User } from '@oxy.so/core';
|
|
2
2
|
import { logger as loggerUtil } from '@oxy.so/core';
|
|
3
|
-
import { allowsAutomaticIdpRedirect } from '../oauth/legacyRedirectLanes';
|
|
4
|
-
import type { WebAuthMode } from '../oauth/types';
|
|
5
|
-
import { isWebBrowser } from '../utils/isWebBrowser';
|
|
6
3
|
import { isUnauthorizedStatus } from './oxyContextHelpers';
|
|
7
4
|
|
|
8
5
|
const LOG_CONTEXT = { component: 'OxyContext', method: 'commitSession' } as const;
|
|
@@ -133,61 +130,3 @@ export async function commitDeviceSetAndResolve(
|
|
|
133
130
|
await hydrateAndResolve();
|
|
134
131
|
void reconcileDeviceSet().catch(logReconcileError);
|
|
135
132
|
}
|
|
136
|
-
|
|
137
|
-
export interface MaybeSyncHubAfterCommitDeps {
|
|
138
|
-
/** Deliberate sign-in (`true`) vs. a cold-boot / background commit (`false`). */
|
|
139
|
-
activate: boolean;
|
|
140
|
-
/** Per-commit opt-in — `commitSession`'s `options.hubSync`. */
|
|
141
|
-
hubSyncRequested: boolean;
|
|
142
|
-
/** Provider-level opt-out — `OxyProviderProps.hubSync`. */
|
|
143
|
-
hubSyncEnabled: boolean;
|
|
144
|
-
/**
|
|
145
|
-
* The provider's web sign-in transport — `OxyProviderProps.webAuthMode`.
|
|
146
|
-
* A first-class input: `'popup'` forbids the redirect outright.
|
|
147
|
-
*/
|
|
148
|
-
webAuthMode: WebAuthMode;
|
|
149
|
-
/**
|
|
150
|
-
* Starts the full-page hop to `auth.oxy.so/sync`; resolves `true` when the
|
|
151
|
-
* navigation was actually started.
|
|
152
|
-
*/
|
|
153
|
-
syncHub: () => Promise<boolean>;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Post-sign-in hub sync: plant this device's credential on the IdP hub so OTHER
|
|
158
|
-
* official origins can silently restore a session on their next cold boot.
|
|
159
|
-
*
|
|
160
|
-
* The tail of the ONE commit funnel (`commitSession`), extracted so every gate
|
|
161
|
-
* on this legacy lane lives — and is tested — in one place. Returns whether the
|
|
162
|
-
* full-page redirect was started; a failure is non-fatal and never propagates
|
|
163
|
-
* (the sign-in itself already succeeded).
|
|
164
|
-
*
|
|
165
|
-
* Four gates, all of which must pass:
|
|
166
|
-
* 1. `activate` — only a deliberate sign-in syncs; a cold-boot restore never does.
|
|
167
|
-
* 2. `hubSyncRequested` — the in-place lanes (account switch, popup OAuth) opt out.
|
|
168
|
-
* 3. `hubSyncEnabled` — the provider-level `hubSync` prop.
|
|
169
|
-
* 4. `allowsAutomaticIdpRedirect(webAuthMode)` — hub sync REPLACES the document
|
|
170
|
-
* with `auth.oxy.so`, so `webAuthMode: 'popup'` forbids it: a redirect that
|
|
171
|
-
* bounces the tab defeats the entire point of the mode, no matter which
|
|
172
|
-
* commit path produced the session (issue #691, "Cold boot and cross-domain
|
|
173
|
-
* behavior"). Redirect mode — the default and the compatibility path — is
|
|
174
|
-
* unchanged, and this whole function disappears with it in phase 7b.
|
|
175
|
-
*/
|
|
176
|
-
export async function maybeSyncHubAfterCommit(
|
|
177
|
-
deps: MaybeSyncHubAfterCommitDeps,
|
|
178
|
-
): Promise<boolean> {
|
|
179
|
-
const { activate, hubSyncRequested, hubSyncEnabled, webAuthMode, syncHub } = deps;
|
|
180
|
-
|
|
181
|
-
if (!activate || !hubSyncRequested || !hubSyncEnabled) return false;
|
|
182
|
-
if (!allowsAutomaticIdpRedirect(webAuthMode)) return false;
|
|
183
|
-
if (!isWebBrowser()) return false;
|
|
184
|
-
|
|
185
|
-
try {
|
|
186
|
-
return await syncHub();
|
|
187
|
-
} catch (hubError) {
|
|
188
|
-
if (__DEV__) {
|
|
189
|
-
loggerUtil.debug('Hub sync after sign-in failed (non-fatal)', LOG_CONTEXT, hubError);
|
|
190
|
-
}
|
|
191
|
-
return false;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
|
-
import type {
|
|
2
|
+
import type { LoginSessionResult } from '@oxy.so/contracts';
|
|
3
|
+
import type { OxyServices, User, SessionLoginResponse, AccountNode, CreateAccountInput, ClientSession, AccountDialogController, AccountDialogView, ApiError, SessionClient, SessionMode, OxyAuthScreen } from '@oxy.so/core';
|
|
3
4
|
import type { UseFollowHook } from '../hooks/useFollow.types';
|
|
4
5
|
import type { useLanguageManagement } from '../hooks/useLanguageManagement';
|
|
5
6
|
import type { RouteName } from '../navigation/routes';
|
|
@@ -104,7 +105,12 @@ export interface OxyContextState {
|
|
|
104
105
|
removePasskey: (credentialId: string) => Promise<void>;
|
|
105
106
|
|
|
106
107
|
revokeSuspiciousSignIn: () => Promise<void>;
|
|
107
|
-
|
|
108
|
+
/**
|
|
109
|
+
* Commit a session a first-party sign-in minted on THIS origin — an OAuth
|
|
110
|
+
* code exchange, or a passkey registration on auth.oxy.so (sign-up,
|
|
111
|
+
* recovery) — as the active one.
|
|
112
|
+
*/
|
|
113
|
+
handleWebSession: (session: SessionLoginResponse | LoginSessionResult) => Promise<void>;
|
|
108
114
|
|
|
109
115
|
/**
|
|
110
116
|
* Run a WEB third-party OAuth sign-in (authorization code + PKCE) end to end
|
|
@@ -124,6 +130,14 @@ export interface OxyContextState {
|
|
|
124
130
|
*/
|
|
125
131
|
startWebOAuthSignIn: (options: StartWebOAuthSignInOptions) => Promise<WebOAuthSignInResult>;
|
|
126
132
|
|
|
133
|
+
/**
|
|
134
|
+
* Sign in (`signin`), create an account (`signup`) or recover one
|
|
135
|
+
* (`recover`) in auth.oxy.so's window over the app, where the browser's
|
|
136
|
+
* shared Oxy session lives. Web only; call it from the press, so the window
|
|
137
|
+
* opens with the gesture.
|
|
138
|
+
*/
|
|
139
|
+
continueOnAuth: (screen: OxyAuthScreen) => Promise<WebOAuthSignInResult>;
|
|
140
|
+
|
|
127
141
|
/**
|
|
128
142
|
* Ask the already-authenticated user for explicit OAuth consent to exact
|
|
129
143
|
* application scopes. Must be called from a user gesture. Works on web and
|
|
@@ -219,14 +233,6 @@ export interface OxyRuntimeProviderProps {
|
|
|
219
233
|
* @default false
|
|
220
234
|
*/
|
|
221
235
|
backgroundSession?: boolean;
|
|
222
|
-
/**
|
|
223
|
-
* Whether this origin/app persists the durable device credential at all. See
|
|
224
|
-
* `OxyProviderProps.deviceCredentialStorage` for the full rule and the one
|
|
225
|
-
* caller of `'ephemeral'`.
|
|
226
|
-
*
|
|
227
|
-
* @default 'persistent'
|
|
228
|
-
*/
|
|
229
|
-
deviceCredentialStorage?: 'persistent' | 'ephemeral';
|
|
230
236
|
onAuthStateChange?: (user: User | null) => void;
|
|
231
237
|
onError?: (error: ApiError) => void;
|
|
232
238
|
/** Storage instance owned by the public provider; internal composition seam. */
|
|
@@ -115,3 +115,31 @@ export async function runPasskeyAdd(deps: RunPasskeyAddDeps): Promise<void> {
|
|
|
115
115
|
}
|
|
116
116
|
deps.onLinked();
|
|
117
117
|
}
|
|
118
|
+
|
|
119
|
+
/** Injected dependencies for {@link runPasskeyRegisterSignIn}. */
|
|
120
|
+
export interface RunPasskeyRegisterSignInDeps {
|
|
121
|
+
isSupported: () => boolean;
|
|
122
|
+
getRegisterOptions: () => Promise<unknown>;
|
|
123
|
+
runCeremony: (optionsJSON: unknown) => Promise<unknown>;
|
|
124
|
+
registerVerify: (response: unknown) => Promise<PasskeyRegisterVerifyResult>;
|
|
125
|
+
commit: (result: LoginSessionResult) => Promise<void>;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Register a passkey SIGNED OUT and sign in with the account it belongs to —
|
|
130
|
+
* a new passkey account (username + confirmed recovery email), or a recovery's
|
|
131
|
+
* new passkey (ADR 0029 D3). Options, ceremony, verify, then commit; the verify
|
|
132
|
+
* must mint a session, since there is no bearer to link to.
|
|
133
|
+
*/
|
|
134
|
+
export async function runPasskeyRegisterSignIn(deps: RunPasskeyRegisterSignInDeps): Promise<void> {
|
|
135
|
+
if (!deps.isSupported()) {
|
|
136
|
+
throw new Error(PASSKEY_UNSUPPORTED_MESSAGE);
|
|
137
|
+
}
|
|
138
|
+
const options = await deps.getRegisterOptions();
|
|
139
|
+
const response = await deps.runCeremony(options);
|
|
140
|
+
const result = await deps.registerVerify(response);
|
|
141
|
+
if (!('sessionId' in result)) {
|
|
142
|
+
throw new Error('The passkey was registered without signing in.');
|
|
143
|
+
}
|
|
144
|
+
await deps.commit(result);
|
|
145
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useCallback, useSyncExternalStore } from 'react';
|
|
2
|
+
import type { AccountDialogController, AccountDialogSnapshot } from '@oxy.so/core';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* The snapshot `useSyncExternalStore` reads before a controller exists.
|
|
@@ -36,6 +37,24 @@ export const EMPTY_ACCOUNT_DIALOG_SNAPSHOT: AccountDialogSnapshot = {
|
|
|
36
37
|
openedAt: null,
|
|
37
38
|
progress: 'idle',
|
|
38
39
|
attempt: 0,
|
|
40
|
+
inline: false,
|
|
39
41
|
},
|
|
40
42
|
commonsAvailability: 'unknown',
|
|
41
43
|
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Bind a surface to `controller`'s snapshot (the inert one while there is no
|
|
47
|
+
* controller). `getSnapshot` returns a stable reference between changes, so
|
|
48
|
+
* it is `useSyncExternalStore`-safe.
|
|
49
|
+
*/
|
|
50
|
+
export function useAccountDialogSnapshot(controller: AccountDialogController | null): AccountDialogSnapshot {
|
|
51
|
+
const subscribe = useCallback(
|
|
52
|
+
(listener: () => void) => (controller ? controller.subscribe(listener) : () => undefined),
|
|
53
|
+
[controller],
|
|
54
|
+
);
|
|
55
|
+
const getSnapshot = useCallback(
|
|
56
|
+
() => (controller ? controller.getSnapshot() : EMPTY_ACCOUNT_DIALOG_SNAPSHOT),
|
|
57
|
+
[controller],
|
|
58
|
+
);
|
|
59
|
+
return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
60
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useCallback, useMemo
|
|
1
|
+
import { useCallback, useMemo } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
buildSwitcherRows,
|
|
4
4
|
projectDevicePrincipals,
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
} from '@oxy.so/core';
|
|
8
8
|
import { useOxy } from '../context/OxyContext';
|
|
9
9
|
import { useI18n } from './useI18n';
|
|
10
|
-
import {
|
|
10
|
+
import { useAccountDialogSnapshot } from './accountDialogSnapshot';
|
|
11
11
|
|
|
12
12
|
export interface UseDeviceSwitcherResult {
|
|
13
13
|
/**
|
|
@@ -60,15 +60,7 @@ export function useDeviceSwitcher(): UseDeviceSwitcherResult {
|
|
|
60
60
|
const { accountDialogController: controller, oxyServices } = useOxy();
|
|
61
61
|
const { locale } = useI18n();
|
|
62
62
|
|
|
63
|
-
const
|
|
64
|
-
(listener: () => void) => (controller ? controller.subscribe(listener) : () => undefined),
|
|
65
|
-
[controller],
|
|
66
|
-
);
|
|
67
|
-
const getSnapshot = useCallback(
|
|
68
|
-
() => (controller ? controller.getSnapshot() : EMPTY_ACCOUNT_DIALOG_SNAPSHOT),
|
|
69
|
-
[controller],
|
|
70
|
-
);
|
|
71
|
-
const snapshot = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
63
|
+
const snapshot = useAccountDialogSnapshot(controller);
|
|
72
64
|
|
|
73
65
|
// `directory` is a stable reference between reads (`SessionClient` holds the
|
|
74
66
|
// one it applied), so this recomputes only when the device actually moved.
|
|
@@ -153,6 +153,27 @@ describe('startWebOAuthSignIn', () => {
|
|
|
153
153
|
expect(openSpy).toHaveBeenCalledTimes(1);
|
|
154
154
|
});
|
|
155
155
|
|
|
156
|
+
// An Oxy app's account dialog asks for the window whatever the provider's
|
|
157
|
+
// `webAuthMode`, and for the IdP screen the person lands on.
|
|
158
|
+
it('opens the window for `transport: popup` even in redirect mode, with its screen', async () => {
|
|
159
|
+
const context = makeContext({ mode: 'redirect' });
|
|
160
|
+
const popup = fakePopup();
|
|
161
|
+
const openSpy = jest.spyOn(window, 'open').mockReturnValue(popup as unknown as Window);
|
|
162
|
+
|
|
163
|
+
const pending = startWebOAuthSignIn(context, { redirectUri: REDIRECT_URI, transport: 'popup', screen: 'signup' });
|
|
164
|
+
const authorizeUrl = await waitForAuthorizeUrl(popup);
|
|
165
|
+
expect(authorizeUrl.searchParams.get('screen')).toBe('signup');
|
|
166
|
+
expect(authorizeUrl.searchParams.get('response_mode')).toBe('web_message');
|
|
167
|
+
dispatchFromPopup(
|
|
168
|
+
{ type: OXY_OAUTH_CODE_MESSAGE_TYPE, code: 'code-1', state: authorizeUrl.searchParams.get('state') },
|
|
169
|
+
popup,
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
await expect(pending).resolves.toEqual({ status: 'signed-in' });
|
|
173
|
+
expect(openSpy).toHaveBeenCalledTimes(1);
|
|
174
|
+
expect(mockRedirect).not.toHaveBeenCalled();
|
|
175
|
+
});
|
|
176
|
+
|
|
156
177
|
it('falls back to a full-page redirect when the popup was blocked', async () => {
|
|
157
178
|
const context = makeContext();
|
|
158
179
|
|