@oxy.so/services 4.0.7 → 6.0.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 +1 -1
- 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 +45 -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 -44
- 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 +29 -8
- 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/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/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/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/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/ManageAccountScreen.js +2 -3
- 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 +1 -1
- 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 +7 -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 -45
- 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 +21 -2
- 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/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/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/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/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/ManageAccountScreen.js +3 -4
- 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 +2 -2
- 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 +8 -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 +3 -3
- 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/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/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 +8 -9
- package/lib/typescript/commonjs/ui/context/oxyContextTypes.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/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/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 +8 -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 +3 -3
- 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/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/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 +8 -9
- package/lib/typescript/module/ui/context/oxyContextTypes.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/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/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 +16 -7
- package/src/ui/components/OxyAccountDialogScreen.tsx +11 -72
- package/src/ui/components/OxyAuthChooser.tsx +37 -53
- package/src/ui/components/OxyProvider.tsx +0 -2
- package/src/ui/components/ProfileButton.tsx +1 -4
- package/src/ui/components/authChooser/AccountsMenuView.tsx +28 -1
- 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 +3 -3
- 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/OxySignInPanel.tsx +392 -0
- package/src/ui/components/signIn/OxySignUpPanel.tsx +86 -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 +21 -18
- package/src/ui/context/__tests__/commitSessionFlow.test.ts +0 -89
- package/src/ui/context/commitSessionFlow.ts +0 -61
- package/src/ui/context/oxyContextTypes.ts +9 -9
- 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/ManageAccountScreen.tsx +3 -4
- 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 +2 -2
- 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,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shell every Oxy sign-in screen shares — the in-app account dialog and
|
|
3
|
+
* every page of the auth.oxy.so IdP render these, so the two cannot drift:
|
|
4
|
+
*
|
|
5
|
+
* header the Oxy mark (56), then the title (48/800, tight) and a 18px
|
|
6
|
+
* description, 8 apart
|
|
7
|
+
* screen blocks 24 apart, at most 448 wide
|
|
8
|
+
* split from `md`, Bloom `AuthCard`'s split base — max 880, radius 24,
|
|
9
|
+
* 1px border, two equal columns, the right one on the secondary
|
|
10
|
+
* surface; below `md` the right column is dropped, not stacked
|
|
11
|
+
* loading an indeterminate spinner holding the screen's height
|
|
12
|
+
* terms one centred caption linking the Terms of Service and Privacy Policy
|
|
13
|
+
*
|
|
14
|
+
* Layout is NativeWind `className` (breakpoints included). Type stays on
|
|
15
|
+
* Bloom `Text`'s own ramp through `style` — a `className` there drops its
|
|
16
|
+
* default family — and colours come from the Bloom theme.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import type React from 'react';
|
|
20
|
+
import { ActivityIndicator, Linking, Text as RNText } from 'react-native';
|
|
21
|
+
import { View } from 'react-native-css/components';
|
|
22
|
+
import { useTheme } from '@oxy.so/bloom/theme';
|
|
23
|
+
import { Text } from '@oxy.so/bloom/typography';
|
|
24
|
+
import { useI18n } from '../../hooks/useI18n';
|
|
25
|
+
import { LogoIcon } from '../logo/LogoIcon';
|
|
26
|
+
|
|
27
|
+
const LOGO_HEIGHT = 56;
|
|
28
|
+
const TERMS_URL = 'https://oxy.so/company/transparency/policies/terms-of-service';
|
|
29
|
+
const PRIVACY_URL = 'https://oxy.so/company/transparency/policies/privacy';
|
|
30
|
+
|
|
31
|
+
const TITLE = { fontSize: 48, lineHeight: 48, fontWeight: '800', letterSpacing: -1.2 } as const;
|
|
32
|
+
const DESCRIPTION = { fontSize: 18, lineHeight: 28 } as const;
|
|
33
|
+
const TERMS = { fontSize: 14, lineHeight: 20, textAlign: 'center', paddingHorizontal: 24 } as const;
|
|
34
|
+
|
|
35
|
+
export interface OxyAuthScreenHeaderProps {
|
|
36
|
+
title: string;
|
|
37
|
+
description?: React.ReactNode;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** The Oxy mark over the screen's title and description. */
|
|
41
|
+
export const OxyAuthScreenHeader: React.FC<OxyAuthScreenHeaderProps> = ({ title, description }) => {
|
|
42
|
+
const theme = useTheme();
|
|
43
|
+
return (
|
|
44
|
+
<View className="gap-6">
|
|
45
|
+
<LogoIcon height={LOGO_HEIGHT} />
|
|
46
|
+
<View className="max-w-[90%] gap-2">
|
|
47
|
+
<Text accessibilityRole="header" style={[TITLE, { color: theme.colors.text }]}>
|
|
48
|
+
{title}
|
|
49
|
+
</Text>
|
|
50
|
+
{description != null && description !== '' ? (
|
|
51
|
+
typeof description === 'string' ? (
|
|
52
|
+
<Text style={[DESCRIPTION, { color: theme.colors.textSecondary }]}>
|
|
53
|
+
{description}
|
|
54
|
+
</Text>
|
|
55
|
+
) : (
|
|
56
|
+
description
|
|
57
|
+
)
|
|
58
|
+
) : null}
|
|
59
|
+
</View>
|
|
60
|
+
</View>
|
|
61
|
+
);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/** A sign-in screen's column: its blocks 24 apart. `className` extends it (the split's form column). */
|
|
65
|
+
export const OxyAuthScreen: React.FC<{ children: React.ReactNode; className?: string }> = ({ children, className }) => (
|
|
66
|
+
<View className={`w-full max-w-[448px] self-center gap-6 ${className ?? ''}`}>{children}</View>
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
/** The split card: `children` on the left and, from `md`, `aside` on the right. */
|
|
70
|
+
export const OxyAuthSplit: React.FC<{ children: React.ReactNode; aside: React.ReactNode }> = ({ children, aside }) => {
|
|
71
|
+
const theme = useTheme();
|
|
72
|
+
return (
|
|
73
|
+
<View
|
|
74
|
+
className="w-full self-center md:max-w-[880px] md:flex-row md:rounded-3xl md:border md:border-border md:bg-card md:overflow-hidden"
|
|
75
|
+
>
|
|
76
|
+
{/* Padding on an inner box: a padded flex item cannot shrink its base
|
|
77
|
+
size below its padding, which breaks the two equal tracks. */}
|
|
78
|
+
<View className="md:flex-1 md:basis-0 md:min-w-0">
|
|
79
|
+
<View className="md:p-8">{children}</View>
|
|
80
|
+
</View>
|
|
81
|
+
<View
|
|
82
|
+
className="hidden md:flex md:flex-1 md:basis-0 md:min-w-0 items-center justify-center overflow-hidden p-8"
|
|
83
|
+
style={{ backgroundColor: theme.colors.backgroundSecondary }}
|
|
84
|
+
>
|
|
85
|
+
{aside}
|
|
86
|
+
</View>
|
|
87
|
+
</View>
|
|
88
|
+
);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* The screen while there is nothing to show yet. React Native's own indicator:
|
|
93
|
+
* `@oxy.so/bloom/loading` can tree-shake to `undefined` in a rolldown-vite
|
|
94
|
+
* production bundle when co-imported with `@oxy.so/bloom/button`.
|
|
95
|
+
*/
|
|
96
|
+
export const OxyAuthLoading: React.FC = () => {
|
|
97
|
+
const theme = useTheme();
|
|
98
|
+
return (
|
|
99
|
+
<View className="min-h-[300px] items-center justify-center">
|
|
100
|
+
<ActivityIndicator size="large" color={theme.colors.primary} />
|
|
101
|
+
</View>
|
|
102
|
+
);
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
/** "By continuing, you agree to our Terms of Service and Privacy Policy." */
|
|
106
|
+
export const OxyAuthTerms: React.FC = () => {
|
|
107
|
+
const theme = useTheme();
|
|
108
|
+
const { t } = useI18n();
|
|
109
|
+
const link = { color: theme.colors.text, textDecorationLine: 'underline' as const };
|
|
110
|
+
return (
|
|
111
|
+
<Text style={[TERMS, { color: theme.colors.textSecondary }]}>
|
|
112
|
+
{t('signin.terms.before')}{' '}
|
|
113
|
+
<RNText accessibilityRole="link" style={link} onPress={() => void Linking.openURL(TERMS_URL)}>
|
|
114
|
+
{t('signin.terms.termsLink')}
|
|
115
|
+
</RNText>{' '}
|
|
116
|
+
{t('signin.terms.and')}{' '}
|
|
117
|
+
<RNText accessibilityRole="link" style={link} onPress={() => void Linking.openURL(PRIVACY_URL)}>
|
|
118
|
+
{t('signin.terms.privacyLink')}
|
|
119
|
+
</RNText>
|
|
120
|
+
.
|
|
121
|
+
</Text>
|
|
122
|
+
);
|
|
123
|
+
};
|
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE Oxy sign-in screen. The account dialog every Oxy app opens and the
|
|
3
|
+
* auth.oxy.so page render this one component; only where it is mounted
|
|
4
|
+
* differs (`host`).
|
|
5
|
+
*
|
|
6
|
+
* picker a returning device: "Choose an account", then "Use another account"
|
|
7
|
+
* entry the header, the Commons way in, and the way in for someone with no
|
|
8
|
+
* account. On auth.oxy.so (`page`) also the username with its
|
|
9
|
+
* Continue — a username-first passkey sign-in, which takes a
|
|
10
|
+
* platform passkey AND a hardware security key with no resident
|
|
11
|
+
* credential (a U2F key such as a Titan) — and "or continue with" the
|
|
12
|
+
* discoverable passkey. From `md` that page is Bloom `AuthCard`'s
|
|
13
|
+
* split card, with the embedded QR over its photo carousel in the
|
|
14
|
+
* right column; below `md` it is "Continue with Oxy" at the top.
|
|
15
|
+
* In an app's dialog on the web, "Continue with Oxy" opens that page
|
|
16
|
+
* in a window over the app, like "Sign in with Google": the browser's
|
|
17
|
+
* session lives on auth.oxy.so, so every Oxy app shares it. On
|
|
18
|
+
* native it is "Continue with Oxy" ("Get Commons" without Commons).
|
|
19
|
+
*
|
|
20
|
+
* `signInMethods.ts` owns which blocks a platform gets.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import type React from 'react';
|
|
24
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
25
|
+
import { Linking, Platform, Text as RNText, StyleSheet, View } from 'react-native';
|
|
26
|
+
import { View as CssView } from 'react-native-css/components';
|
|
27
|
+
import { AuthMediaCarousel } from '@oxy.so/bloom/auth-card';
|
|
28
|
+
import { Button } from '@oxy.so/bloom/button';
|
|
29
|
+
import { Divider } from '@oxy.so/bloom/divider';
|
|
30
|
+
import { RiKey2Line } from '@oxy.so/bloom/icons/RiKey2Line';
|
|
31
|
+
import { RiQrCodeLine } from '@oxy.so/bloom/icons/RiQrCodeLine';
|
|
32
|
+
import { useTheme } from '@oxy.so/bloom/theme';
|
|
33
|
+
import { TextField, TextFieldHint, TextFieldInput, TextFieldLabel } from '@oxy.so/bloom/text-field';
|
|
34
|
+
import { toast } from '@oxy.so/bloom/toast';
|
|
35
|
+
import { Text } from '@oxy.so/bloom/typography';
|
|
36
|
+
import type { SwitcherContextRow } from '@oxy.so/core';
|
|
37
|
+
import { useQueryClient } from '@tanstack/react-query';
|
|
38
|
+
import { useOxy } from '../../context/OxyContext';
|
|
39
|
+
import { useAccountDialogSnapshot } from '../../hooks/accountDialogSnapshot';
|
|
40
|
+
import { useDeviceSwitcher } from '../../hooks/useDeviceSwitcher';
|
|
41
|
+
import { useI18n } from '../../hooks/useI18n';
|
|
42
|
+
import { getCommonsAcquisitionUrl } from '../../utils/commonsStoreLinks';
|
|
43
|
+
import { isWebBrowser } from '../../utils/isWebBrowser';
|
|
44
|
+
import { SubtleLink } from '../authChooser/primitives';
|
|
45
|
+
import { SIGN_IN_SLIDES } from './artwork';
|
|
46
|
+
import { InlineCommonsQr } from './InlineCommonsQr';
|
|
47
|
+
import { OxyAccountPicker } from './OxyAccountPicker';
|
|
48
|
+
import { OxyAuthScreen, OxyAuthScreenHeader, OxyAuthSplit, OxyAuthTerms } from './OxyAuthScreen';
|
|
49
|
+
import { RATE_LIMIT_SECONDS, describePasskeyError, isRateLimited } from './passkeyError';
|
|
50
|
+
import { resolveSignInMethods } from './signInMethods';
|
|
51
|
+
|
|
52
|
+
export interface OxySignInPanelProps {
|
|
53
|
+
/** This screen signed the origin in. */
|
|
54
|
+
onSignedIn: () => void;
|
|
55
|
+
/** "New to Oxy? Create one". */
|
|
56
|
+
onCreateAccount: () => void;
|
|
57
|
+
/** "Lost your passkey? Recover your account" — auth.oxy.so's page only. */
|
|
58
|
+
onRecover?: () => void;
|
|
59
|
+
/** A handle to pre-fill, skipping the picker (a re-authentication). */
|
|
60
|
+
loginHint?: string;
|
|
61
|
+
/** The app being continued to, when there is one. */
|
|
62
|
+
appName?: string | null;
|
|
63
|
+
/**
|
|
64
|
+
* `dialog` — inside the account dialog, which the controller closes itself
|
|
65
|
+
* once a request it runs signs in, and where a request shows in place.
|
|
66
|
+
* `page` — a page of its own (auth.oxy.so): a request opens the dialog to
|
|
67
|
+
* show it, and its completion is reported through `onSignedIn` too.
|
|
68
|
+
*/
|
|
69
|
+
host?: 'dialog' | 'page';
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export const OxySignInPanel: React.FC<OxySignInPanelProps> = ({
|
|
73
|
+
onSignedIn,
|
|
74
|
+
onCreateAccount,
|
|
75
|
+
onRecover,
|
|
76
|
+
loginHint,
|
|
77
|
+
appName = null,
|
|
78
|
+
host = 'page',
|
|
79
|
+
}) => {
|
|
80
|
+
const theme = useTheme();
|
|
81
|
+
const { t } = useI18n();
|
|
82
|
+
const queryClient = useQueryClient();
|
|
83
|
+
const { accountDialogController: controller, openAccountDialog, signInWithPasskey, continueOnAuth } = useOxy();
|
|
84
|
+
const snapshot = useAccountDialogSnapshot(controller);
|
|
85
|
+
const { principals, activeContext } = useDeviceSwitcher();
|
|
86
|
+
|
|
87
|
+
const methods = resolveSignInMethods({
|
|
88
|
+
web: isWebBrowser(),
|
|
89
|
+
host,
|
|
90
|
+
commonsAvailability: snapshot.commonsAvailability,
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const [showForm, setShowForm] = useState(Boolean(loginHint));
|
|
94
|
+
const [identifier, setIdentifier] = useState(loginHint ?? '');
|
|
95
|
+
const [pending, setPending] = useState(false);
|
|
96
|
+
const [error, setError] = useState<string | null>(null);
|
|
97
|
+
const [rateLimitSeconds, setRateLimitSeconds] = useState(0);
|
|
98
|
+
const blocked = pending || rateLimitSeconds > 0;
|
|
99
|
+
|
|
100
|
+
// The countdown after a 429: one tick a second until the person may retry.
|
|
101
|
+
useEffect(() => {
|
|
102
|
+
if (rateLimitSeconds <= 0) return;
|
|
103
|
+
const timer = setTimeout(() => setRateLimitSeconds((seconds) => Math.max(0, seconds - 1)), 1000);
|
|
104
|
+
return () => clearTimeout(timer);
|
|
105
|
+
}, [rateLimitSeconds]);
|
|
106
|
+
|
|
107
|
+
// On a page, a request the controller runs (the embedded QR, or one shown in
|
|
108
|
+
// the dialog opened over it) finishes the page's sign-in too. Only one that
|
|
109
|
+
// STARTED here: a completion already on the controller is somebody else's.
|
|
110
|
+
const [mountedAttempt] = useState(snapshot.signIn.attempt);
|
|
111
|
+
const completedHere = snapshot.signIn.phase === 'completed' && snapshot.signIn.attempt !== mountedAttempt;
|
|
112
|
+
useEffect(() => {
|
|
113
|
+
if (host === 'page' && completedHere) onSignedIn();
|
|
114
|
+
}, [host, completedHere, onSignedIn]);
|
|
115
|
+
|
|
116
|
+
/** Show the request a controller call just started — the dialog is where it lives. */
|
|
117
|
+
const showRequest = useCallback(() => {
|
|
118
|
+
if (host === 'page') openAccountDialog('qr');
|
|
119
|
+
}, [host, openAccountDialog]);
|
|
120
|
+
|
|
121
|
+
// These open a window or leave the page, so they run straight from the
|
|
122
|
+
// press, before any await.
|
|
123
|
+
const continueWithOxy = () => {
|
|
124
|
+
void controller?.signInWithOxy();
|
|
125
|
+
showRequest();
|
|
126
|
+
};
|
|
127
|
+
const signInOnOxy = () => {
|
|
128
|
+
void continueOnAuth('signin').then((result) => {
|
|
129
|
+
if (result.status === 'signed-in') onSignedIn();
|
|
130
|
+
else if (result.status === 'failed') toast.error(t('signin.errors.failed'));
|
|
131
|
+
});
|
|
132
|
+
};
|
|
133
|
+
const useAnotherDevice = () => {
|
|
134
|
+
void controller?.showQr();
|
|
135
|
+
showRequest();
|
|
136
|
+
};
|
|
137
|
+
const getCommons = () => {
|
|
138
|
+
Promise.resolve()
|
|
139
|
+
.then(() => Linking.openURL(getCommonsAcquisitionUrl(Platform.OS)))
|
|
140
|
+
.catch(() => toast.error(t('accountSwitcher.linkOpenFailed')));
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const runPasskey = async (username: string | undefined, failToast: string) => {
|
|
144
|
+
if (blocked) return;
|
|
145
|
+
setError(null);
|
|
146
|
+
setPending(true);
|
|
147
|
+
try {
|
|
148
|
+
await signInWithPasskey({ username });
|
|
149
|
+
onSignedIn();
|
|
150
|
+
} catch (err) {
|
|
151
|
+
if (isRateLimited(err)) {
|
|
152
|
+
setRateLimitSeconds(RATE_LIMIT_SECONDS);
|
|
153
|
+
} else {
|
|
154
|
+
const message = describePasskeyError(err, t);
|
|
155
|
+
setError(message);
|
|
156
|
+
toast.error(failToast, { description: message });
|
|
157
|
+
}
|
|
158
|
+
} finally {
|
|
159
|
+
setPending(false);
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
const submitUsername = () => {
|
|
163
|
+
const username = identifier.trim();
|
|
164
|
+
if (username) void runPasskey(username, t('signin.errors.failed'));
|
|
165
|
+
else setError(t('signin.username.required'));
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
// A returning device starts at WHO. Not while adding an account from inside
|
|
169
|
+
// a signed-in app: the rows are the accounts it would add.
|
|
170
|
+
const pickerAllowed = host === 'dialog' ? !snapshot.hasSession : activeContext !== null;
|
|
171
|
+
const reauthenticate = (context: SwitcherContextRow) => {
|
|
172
|
+
setIdentifier(context.handle ?? '');
|
|
173
|
+
setShowForm(true);
|
|
174
|
+
};
|
|
175
|
+
const selectContext = async (context: SwitcherContextRow) => {
|
|
176
|
+
const outcome = await controller?.chooseContext(context.contextId).catch(() => 'failed' as const);
|
|
177
|
+
switch (outcome) {
|
|
178
|
+
case 'switched':
|
|
179
|
+
// Every account-scoped query now describes somebody else.
|
|
180
|
+
void queryClient.invalidateQueries();
|
|
181
|
+
onSignedIn();
|
|
182
|
+
return;
|
|
183
|
+
case 'current':
|
|
184
|
+
onSignedIn();
|
|
185
|
+
return;
|
|
186
|
+
case 'signing-in':
|
|
187
|
+
// The request for that account is running; it shows where requests do.
|
|
188
|
+
showRequest();
|
|
189
|
+
return;
|
|
190
|
+
case 'failed':
|
|
191
|
+
// The pair could not be activated as it stands: sign in as it explicitly.
|
|
192
|
+
if (methods.passkey && context.handle) reauthenticate(context);
|
|
193
|
+
else toast.error(t('accountSwitcher.toasts.activateFailed'));
|
|
194
|
+
return;
|
|
195
|
+
default:
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
const showsPicker = pickerAllowed && !showForm && principals.length > 0;
|
|
201
|
+
// auth.oxy.so's page is the split card from `md`.
|
|
202
|
+
const splits = methods.commons === 'qr';
|
|
203
|
+
|
|
204
|
+
if (showsPicker) {
|
|
205
|
+
return (
|
|
206
|
+
<OxyAccountPicker
|
|
207
|
+
principals={principals}
|
|
208
|
+
appName={appName}
|
|
209
|
+
signedOut={!snapshot.hasSession}
|
|
210
|
+
pendingContextId={snapshot.activatingContextId}
|
|
211
|
+
isLoading={snapshot.activatingContextId !== null}
|
|
212
|
+
onSelectContext={(context) => void selectContext(context)}
|
|
213
|
+
onUseAnother={() => {
|
|
214
|
+
setIdentifier('');
|
|
215
|
+
setShowForm(true);
|
|
216
|
+
}}
|
|
217
|
+
/>
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const shownError = rateLimitSeconds > 0 ? t('signin.errors.rateLimited', { seconds: rateLimitSeconds }) : error;
|
|
222
|
+
|
|
223
|
+
const adding = host === 'dialog' && snapshot.hasSession;
|
|
224
|
+
const title = adding ? t('signin.addAccountTitle') : t('signin.title');
|
|
225
|
+
const description = adding
|
|
226
|
+
? t('signin.addAccountSubtitle')
|
|
227
|
+
: appName
|
|
228
|
+
? t('signin.subtitleToApp', { app: appName })
|
|
229
|
+
: t('signin.subtitle');
|
|
230
|
+
const noAccount = (
|
|
231
|
+
<Text style={[styles.note, styles.noAccount, { color: theme.colors.textSecondary }]}>
|
|
232
|
+
{t('signin.noAccount')}{' '}
|
|
233
|
+
<RNText
|
|
234
|
+
accessibilityRole="link"
|
|
235
|
+
onPress={onCreateAccount}
|
|
236
|
+
style={[styles.noAccountLink, { color: theme.colors.text }]}
|
|
237
|
+
testID="create-account-link"
|
|
238
|
+
>
|
|
239
|
+
{t('signin.createAccount')}
|
|
240
|
+
</RNText>
|
|
241
|
+
</Text>
|
|
242
|
+
);
|
|
243
|
+
// One solid action per screen: the username's Continue when there is one.
|
|
244
|
+
const commonsAppearance = methods.passkey ? 'outline' : 'solid';
|
|
245
|
+
|
|
246
|
+
const continueWithOxyButton = (
|
|
247
|
+
<Button
|
|
248
|
+
appearance={commonsAppearance}
|
|
249
|
+
tone={commonsAppearance === 'solid' ? 'action' : 'neutral'}
|
|
250
|
+
size="lg"
|
|
251
|
+
fullWidth
|
|
252
|
+
onPress={methods.commons === 'window' ? signInOnOxy : continueWithOxy}
|
|
253
|
+
testID="continue-with-oxy"
|
|
254
|
+
>
|
|
255
|
+
{t('accountSwitcher.continueWithOxy')}
|
|
256
|
+
</Button>
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
const form = (
|
|
260
|
+
<OxyAuthScreen className={splits ? 'md:max-w-none' : undefined}>
|
|
261
|
+
<OxyAuthScreenHeader title={title} description={description} />
|
|
262
|
+
|
|
263
|
+
{/* Below `md` this screen is the phone a QR would be scanned with. */}
|
|
264
|
+
{splits ? <CssView className="md:hidden">{continueWithOxyButton}</CssView> : null}
|
|
265
|
+
|
|
266
|
+
{methods.commons === 'continue' || methods.commons === 'window' ? continueWithOxyButton : null}
|
|
267
|
+
{methods.commons === 'get-commons' ? (
|
|
268
|
+
<View style={styles.stack}>
|
|
269
|
+
<Text style={[styles.note, { color: theme.colors.textSecondary }]}>{t('accountSwitcher.commonsNotInstalled')}</Text>
|
|
270
|
+
<Button appearance="solid" tone="action" size="lg" fullWidth onPress={getCommons} testID="get-commons-button">
|
|
271
|
+
{t('accountSwitcher.getCommons')}
|
|
272
|
+
</Button>
|
|
273
|
+
</View>
|
|
274
|
+
) : null}
|
|
275
|
+
|
|
276
|
+
{methods.passkey ? (
|
|
277
|
+
<View style={styles.stack}>
|
|
278
|
+
<View style={styles.field}>
|
|
279
|
+
<TextFieldLabel nativeID="username-label">{t('signin.username.label')}</TextFieldLabel>
|
|
280
|
+
<TextField invalid={shownError !== null} disabled={blocked} radius={999} style={styles.input}>
|
|
281
|
+
<TextFieldInput
|
|
282
|
+
testID="username"
|
|
283
|
+
label={t('signin.username.label')}
|
|
284
|
+
value={identifier}
|
|
285
|
+
onValueChange={(value) => {
|
|
286
|
+
setIdentifier(value);
|
|
287
|
+
if (error) setError(null);
|
|
288
|
+
}}
|
|
289
|
+
placeholder={t('signin.username.placeholder')}
|
|
290
|
+
autoComplete="username"
|
|
291
|
+
autoCapitalize="none"
|
|
292
|
+
autoCorrect={false}
|
|
293
|
+
autoFocus={Platform.OS === 'web'}
|
|
294
|
+
returnKeyType="go"
|
|
295
|
+
onSubmitEditing={submitUsername}
|
|
296
|
+
aria-required
|
|
297
|
+
/>
|
|
298
|
+
</TextField>
|
|
299
|
+
{shownError ? <TextFieldHint invalid>{shownError}</TextFieldHint> : null}
|
|
300
|
+
</View>
|
|
301
|
+
{noAccount}
|
|
302
|
+
<Button
|
|
303
|
+
appearance="solid"
|
|
304
|
+
tone="action"
|
|
305
|
+
size="lg"
|
|
306
|
+
fullWidth
|
|
307
|
+
loading={pending}
|
|
308
|
+
disabled={blocked}
|
|
309
|
+
onPress={submitUsername}
|
|
310
|
+
testID="username-continue"
|
|
311
|
+
>
|
|
312
|
+
{t('signin.actions.continue')}
|
|
313
|
+
</Button>
|
|
314
|
+
</View>
|
|
315
|
+
) : null}
|
|
316
|
+
|
|
317
|
+
{/* The alternatives to the screen's primary way in, always under it. The
|
|
318
|
+
window an app opens on the web is where they all are. */}
|
|
319
|
+
{methods.commons === 'window' ? null : <Divider>{t('signin.orContinueWith')}</Divider>}
|
|
320
|
+
|
|
321
|
+
{methods.passkey ? (
|
|
322
|
+
<Button
|
|
323
|
+
appearance="outline"
|
|
324
|
+
tone="neutral"
|
|
325
|
+
size="lg"
|
|
326
|
+
fullWidth
|
|
327
|
+
leadingIcon={RiKey2Line}
|
|
328
|
+
disabled={blocked}
|
|
329
|
+
onPress={() => void runPasskey(undefined, t('signin.errors.failed'))}
|
|
330
|
+
testID="passkey-sign-in"
|
|
331
|
+
>
|
|
332
|
+
{t('signin.methods.passkey')}
|
|
333
|
+
</Button>
|
|
334
|
+
) : methods.commons === 'window' ? null : (
|
|
335
|
+
<Button
|
|
336
|
+
appearance="outline"
|
|
337
|
+
tone="neutral"
|
|
338
|
+
size="lg"
|
|
339
|
+
fullWidth
|
|
340
|
+
leadingIcon={RiQrCodeLine}
|
|
341
|
+
onPress={useAnotherDevice}
|
|
342
|
+
testID="scan-qr"
|
|
343
|
+
>
|
|
344
|
+
{t('accountSwitcher.scanQr')}
|
|
345
|
+
</Button>
|
|
346
|
+
)}
|
|
347
|
+
|
|
348
|
+
{methods.passkey ? null : noAccount}
|
|
349
|
+
{onRecover ? (
|
|
350
|
+
<SubtleLink label={t('signin.recoverLink')} theme={theme} onPress={onRecover} testID="recover-link" />
|
|
351
|
+
) : null}
|
|
352
|
+
<OxyAuthTerms />
|
|
353
|
+
</OxyAuthScreen>
|
|
354
|
+
);
|
|
355
|
+
|
|
356
|
+
if (!splits) return form;
|
|
357
|
+
return (
|
|
358
|
+
<OxyAuthSplit
|
|
359
|
+
aside={
|
|
360
|
+
<>
|
|
361
|
+
<AuthMediaCarousel slides={SIGN_IN_SLIDES} style={StyleSheet.absoluteFill} />
|
|
362
|
+
<InlineCommonsQr controller={controller} />
|
|
363
|
+
</>
|
|
364
|
+
}
|
|
365
|
+
>
|
|
366
|
+
{form}
|
|
367
|
+
</OxyAuthSplit>
|
|
368
|
+
);
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
const styles = StyleSheet.create({
|
|
372
|
+
stack: {
|
|
373
|
+
gap: 12,
|
|
374
|
+
},
|
|
375
|
+
field: {
|
|
376
|
+
gap: 6,
|
|
377
|
+
},
|
|
378
|
+
note: {
|
|
379
|
+
fontSize: 14,
|
|
380
|
+
lineHeight: 20,
|
|
381
|
+
textAlign: 'center',
|
|
382
|
+
},
|
|
383
|
+
noAccount: {
|
|
384
|
+
textAlign: 'left',
|
|
385
|
+
},
|
|
386
|
+
noAccountLink: {
|
|
387
|
+
textDecorationLine: 'underline',
|
|
388
|
+
},
|
|
389
|
+
input: {
|
|
390
|
+
height: 40,
|
|
391
|
+
},
|
|
392
|
+
});
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Account creation in the account dialog.
|
|
3
|
+
*
|
|
4
|
+
* On the web the account is made on auth.oxy.so, in its window over the app
|
|
5
|
+
* (`onCreateOnWeb`), and this app is signed in as it. On native, Commons
|
|
6
|
+
* creates the identity: straight in when it is installed, "Get Commons"
|
|
7
|
+
* otherwise.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type React from 'react';
|
|
11
|
+
import { useCallback } from 'react';
|
|
12
|
+
import { Linking, Platform } from 'react-native';
|
|
13
|
+
import { Button } from '@oxy.so/bloom/button';
|
|
14
|
+
import { RiKey2Line } from '@oxy.so/bloom/icons/RiKey2Line';
|
|
15
|
+
import { useTheme } from '@oxy.so/bloom/theme';
|
|
16
|
+
import { toast } from '@oxy.so/bloom/toast';
|
|
17
|
+
import { useOxy } from '../../context/OxyContext';
|
|
18
|
+
import { useAccountDialogSnapshot } from '../../hooks/accountDialogSnapshot';
|
|
19
|
+
import { useI18n } from '../../hooks/useI18n';
|
|
20
|
+
import { getCommonsAcquisitionUrl } from '../../utils/commonsStoreLinks';
|
|
21
|
+
import { isWebBrowser } from '../../utils/isWebBrowser';
|
|
22
|
+
import { SubtleLink } from '../authChooser/primitives';
|
|
23
|
+
import { OxyAuthScreen, OxyAuthScreenHeader, OxyAuthTerms } from './OxyAuthScreen';
|
|
24
|
+
|
|
25
|
+
/** Commons' own identity-creation deep link. */
|
|
26
|
+
const COMMONS_CREATE_IDENTITY_URL = 'oxycommons://create-identity';
|
|
27
|
+
|
|
28
|
+
export interface OxySignUpPanelProps {
|
|
29
|
+
/** "Already have an account? Sign in". */
|
|
30
|
+
onSignIn: () => void;
|
|
31
|
+
/** The web's one action: auth.oxy.so's sign-up, in its window. */
|
|
32
|
+
onCreateOnWeb: () => void;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const OxySignUpPanel: React.FC<OxySignUpPanelProps> = ({ onSignIn, onCreateOnWeb }) => {
|
|
36
|
+
const theme = useTheme();
|
|
37
|
+
const { t } = useI18n();
|
|
38
|
+
const { accountDialogController: controller } = useOxy();
|
|
39
|
+
const snapshot = useAccountDialogSnapshot(controller);
|
|
40
|
+
const web = isWebBrowser();
|
|
41
|
+
|
|
42
|
+
const openExternal = useCallback(
|
|
43
|
+
(url: string) => {
|
|
44
|
+
Promise.resolve()
|
|
45
|
+
.then(() => Linking.openURL(url))
|
|
46
|
+
.catch(() => toast.error(t('accountSwitcher.linkOpenFailed')));
|
|
47
|
+
},
|
|
48
|
+
[t],
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
const commonsInstalled = snapshot.commonsAvailability === 'available';
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<OxyAuthScreen>
|
|
55
|
+
<OxyAuthScreenHeader title={t('signup.title')} description={web ? t('signup.webSubtitle') : t('signup.subtitle')} />
|
|
56
|
+
{web ? (
|
|
57
|
+
<Button
|
|
58
|
+
appearance="solid"
|
|
59
|
+
tone="action"
|
|
60
|
+
size="lg"
|
|
61
|
+
fullWidth
|
|
62
|
+
leadingIcon={RiKey2Line}
|
|
63
|
+
onPress={onCreateOnWeb}
|
|
64
|
+
testID="signup-open-identity"
|
|
65
|
+
>
|
|
66
|
+
{t('signup.createAccount')}
|
|
67
|
+
</Button>
|
|
68
|
+
) : (
|
|
69
|
+
<Button
|
|
70
|
+
appearance="solid"
|
|
71
|
+
tone="action"
|
|
72
|
+
size="lg"
|
|
73
|
+
fullWidth
|
|
74
|
+
onPress={() =>
|
|
75
|
+
openExternal(commonsInstalled ? COMMONS_CREATE_IDENTITY_URL : getCommonsAcquisitionUrl(Platform.OS))
|
|
76
|
+
}
|
|
77
|
+
testID="signup-commons"
|
|
78
|
+
>
|
|
79
|
+
{commonsInstalled ? t('signup.createInCommons') : t('accountSwitcher.getCommons')}
|
|
80
|
+
</Button>
|
|
81
|
+
)}
|
|
82
|
+
<SubtleLink label={t('signup.backToSignInLink')} theme={theme} onPress={onSignIn} testID="back-to-sign-in" />
|
|
83
|
+
<OxyAuthTerms />
|
|
84
|
+
</OxyAuthScreen>
|
|
85
|
+
);
|
|
86
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The photos the sign-in split card's carousel turns through. Shipped with the
|
|
3
|
+
* SDK and imported like its icon fonts, so every host serves them from its own
|
|
4
|
+
* origin — nothing to allow in anyone's CSP.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { AuthMediaSlide } from '@oxy.so/bloom/auth-card';
|
|
8
|
+
import slide1 from '../../../assets/signIn/slide-1.jpg';
|
|
9
|
+
import slide2 from '../../../assets/signIn/slide-2.jpg';
|
|
10
|
+
import slide3 from '../../../assets/signIn/slide-3.jpg';
|
|
11
|
+
import slide4 from '../../../assets/signIn/slide-4.jpg';
|
|
12
|
+
|
|
13
|
+
export const SIGN_IN_SLIDES: AuthMediaSlide[] = [slide1, slide2, slide3, slide4].map((source) => ({ source }));
|
|
@@ -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
|
+
}
|