@oxyhq/services 5.13.0 → 5.13.2
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 +71 -0
- package/lib/commonjs/core/HttpClient.js +238 -0
- package/lib/commonjs/core/HttpClient.js.map +1 -0
- package/lib/commonjs/core/OxyServices.js +530 -332
- package/lib/commonjs/core/OxyServices.js.map +1 -1
- package/lib/commonjs/core/RequestManager.js +199 -0
- package/lib/commonjs/core/RequestManager.js.map +1 -0
- package/lib/commonjs/core/index.js +38 -1
- package/lib/commonjs/core/index.js.map +1 -1
- package/lib/commonjs/i18n/index.js +37 -1
- package/lib/commonjs/i18n/index.js.map +1 -1
- package/lib/commonjs/i18n/locales/ar-SA.json +128 -0
- package/lib/commonjs/i18n/locales/ca-ES.json +128 -0
- package/lib/commonjs/i18n/locales/de-DE.json +128 -0
- package/lib/commonjs/i18n/locales/en-US.json +85 -12
- package/lib/commonjs/i18n/locales/es-ES.json +58 -6
- package/lib/commonjs/i18n/locales/fr-FR.json +128 -0
- package/lib/commonjs/i18n/locales/it-IT.json +128 -0
- package/lib/commonjs/i18n/locales/ja-JP.json +127 -0
- package/lib/commonjs/i18n/locales/ko-KR.json +128 -0
- package/lib/commonjs/i18n/locales/pt-PT.json +128 -0
- package/lib/commonjs/i18n/locales/zh-CN.json +128 -0
- package/lib/commonjs/index.js +36 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/ui/components/Avatar.js +94 -27
- package/lib/commonjs/ui/components/Avatar.js.map +1 -1
- package/lib/commonjs/ui/components/FollowButton.js +1 -0
- package/lib/commonjs/ui/components/FollowButton.js.map +1 -1
- package/lib/commonjs/ui/components/FontLoader.js +22 -42
- package/lib/commonjs/ui/components/FontLoader.js.map +1 -1
- package/lib/commonjs/ui/components/OxyProvider.js +5 -8
- package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
- package/lib/commonjs/ui/components/StepBasedScreen.js +64 -44
- package/lib/commonjs/ui/components/StepBasedScreen.js.map +1 -1
- package/lib/commonjs/ui/components/internal/GroupedPillButtons.js +14 -35
- package/lib/commonjs/ui/components/internal/GroupedPillButtons.js.map +1 -1
- package/lib/commonjs/ui/components/internal/PinInput.js +2 -2
- package/lib/commonjs/ui/components/internal/PinInput.js.map +1 -1
- package/lib/commonjs/ui/components/internal/TextField.js +13 -8
- package/lib/commonjs/ui/components/internal/TextField.js.map +1 -1
- package/lib/commonjs/ui/context/OxyContext.js +443 -371
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/hooks/useSessionSocket.js +80 -22
- package/lib/commonjs/ui/hooks/useSessionSocket.js.map +1 -1
- package/lib/commonjs/ui/index.js +4 -1
- package/lib/commonjs/ui/index.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js +32 -2
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +101 -59
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/FileManagementScreen.js +3 -2
- package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/LanguageSelectorScreen.js +75 -117
- package/lib/commonjs/ui/screens/LanguageSelectorScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SignInScreen.js +43 -50
- package/lib/commonjs/ui/screens/SignInScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SignUpScreen.js +14 -16
- package/lib/commonjs/ui/screens/SignUpScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js +188 -142
- package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js +10 -10
- package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js.map +1 -1
- package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js +2 -4
- package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/RecoverRequestStep.js +45 -25
- package/lib/commonjs/ui/screens/steps/RecoverRequestStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/RecoverResetPasswordStep.js +88 -53
- package/lib/commonjs/ui/screens/steps/RecoverResetPasswordStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/RecoverSuccessStep.js +79 -58
- package/lib/commonjs/ui/screens/steps/RecoverSuccessStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/RecoverVerifyStep.js +61 -52
- package/lib/commonjs/ui/screens/steps/RecoverVerifyStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/SignInPasswordStep.js +218 -39
- package/lib/commonjs/ui/screens/steps/SignInPasswordStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/SignInTotpStep.js +77 -50
- package/lib/commonjs/ui/screens/steps/SignInTotpStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/SignInUsernameStep.js +424 -71
- package/lib/commonjs/ui/screens/steps/SignInUsernameStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/SignUpIdentityStep.js +55 -30
- package/lib/commonjs/ui/screens/steps/SignUpIdentityStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/SignUpSecurityStep.js +64 -46
- package/lib/commonjs/ui/screens/steps/SignUpSecurityStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/SignUpSummaryStep.js +84 -146
- package/lib/commonjs/ui/screens/steps/SignUpSummaryStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/SignUpWelcomeStep.js +113 -34
- package/lib/commonjs/ui/screens/steps/SignUpWelcomeStep.js.map +1 -1
- package/lib/commonjs/ui/stores/accountStore.js +237 -0
- package/lib/commonjs/ui/stores/accountStore.js.map +1 -0
- package/lib/commonjs/ui/stores/authStore.js +17 -20
- package/lib/commonjs/ui/stores/authStore.js.map +1 -1
- package/lib/commonjs/ui/styles/authStyles.js +16 -8
- package/lib/commonjs/ui/styles/authStyles.js.map +1 -1
- package/lib/commonjs/ui/styles/index.js +11 -0
- package/lib/commonjs/ui/styles/index.js.map +1 -1
- package/lib/commonjs/ui/styles/spacing.js +51 -0
- package/lib/commonjs/ui/styles/spacing.js.map +1 -0
- package/lib/commonjs/utils/asyncUtils.js +9 -22
- package/lib/commonjs/utils/asyncUtils.js.map +1 -1
- package/lib/commonjs/utils/cache.js +259 -0
- package/lib/commonjs/utils/cache.js.map +1 -0
- package/lib/commonjs/utils/index.js +99 -0
- package/lib/commonjs/utils/index.js.map +1 -1
- package/lib/commonjs/utils/languageUtils.js +159 -0
- package/lib/commonjs/utils/languageUtils.js.map +1 -0
- package/lib/commonjs/utils/requestUtils.js +217 -0
- package/lib/commonjs/utils/requestUtils.js.map +1 -0
- package/lib/commonjs/utils/sessionUtils.js +191 -0
- package/lib/commonjs/utils/sessionUtils.js.map +1 -0
- package/lib/commonjs/utils/validationUtils.js +1 -1
- package/lib/module/core/HttpClient.js +232 -0
- package/lib/module/core/HttpClient.js.map +1 -0
- package/lib/module/core/OxyServices.js +528 -326
- package/lib/module/core/OxyServices.js.map +1 -1
- package/lib/module/core/RequestManager.js +194 -0
- package/lib/module/core/RequestManager.js.map +1 -0
- package/lib/module/core/index.js +2 -0
- package/lib/module/core/index.js.map +1 -1
- package/lib/module/i18n/index.js +37 -1
- package/lib/module/i18n/index.js.map +1 -1
- package/lib/module/i18n/locales/ar-SA.json +128 -0
- package/lib/module/i18n/locales/ca-ES.json +128 -0
- package/lib/module/i18n/locales/de-DE.json +128 -0
- package/lib/module/i18n/locales/en-US.json +85 -12
- package/lib/module/i18n/locales/es-ES.json +58 -6
- package/lib/module/i18n/locales/fr-FR.json +128 -0
- package/lib/module/i18n/locales/it-IT.json +128 -0
- package/lib/module/i18n/locales/ja-JP.json +127 -0
- package/lib/module/i18n/locales/ko-KR.json +128 -0
- package/lib/module/i18n/locales/pt-PT.json +128 -0
- package/lib/module/i18n/locales/zh-CN.json +128 -0
- package/lib/module/index.js +2 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/ui/components/Avatar.js +94 -27
- package/lib/module/ui/components/Avatar.js.map +1 -1
- package/lib/module/ui/components/FollowButton.js +1 -0
- package/lib/module/ui/components/FollowButton.js.map +1 -1
- package/lib/module/ui/components/FontLoader.js +23 -43
- package/lib/module/ui/components/FontLoader.js.map +1 -1
- package/lib/module/ui/components/OxyProvider.js +6 -8
- package/lib/module/ui/components/OxyProvider.js.map +1 -1
- package/lib/module/ui/components/StepBasedScreen.js +65 -45
- package/lib/module/ui/components/StepBasedScreen.js.map +1 -1
- package/lib/module/ui/components/internal/GroupedPillButtons.js +14 -35
- package/lib/module/ui/components/internal/GroupedPillButtons.js.map +1 -1
- package/lib/module/ui/components/internal/PinInput.js +2 -2
- package/lib/module/ui/components/internal/PinInput.js.map +1 -1
- package/lib/module/ui/components/internal/TextField.js +13 -8
- package/lib/module/ui/components/internal/TextField.js.map +1 -1
- package/lib/module/ui/context/OxyContext.js +442 -370
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/hooks/useSessionSocket.js +80 -22
- package/lib/module/ui/hooks/useSessionSocket.js.map +1 -1
- package/lib/module/ui/index.js +4 -2
- package/lib/module/ui/index.js.map +1 -1
- package/lib/module/ui/screens/AccountSettingsScreen.js +33 -2
- package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/module/ui/screens/AccountSwitcherScreen.js +102 -60
- package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
- package/lib/module/ui/screens/FileManagementScreen.js +3 -2
- package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
- package/lib/module/ui/screens/LanguageSelectorScreen.js +73 -117
- package/lib/module/ui/screens/LanguageSelectorScreen.js.map +1 -1
- package/lib/module/ui/screens/SignInScreen.js +44 -51
- package/lib/module/ui/screens/SignInScreen.js.map +1 -1
- package/lib/module/ui/screens/SignUpScreen.js +14 -16
- package/lib/module/ui/screens/SignUpScreen.js.map +1 -1
- package/lib/module/ui/screens/WelcomeNewUserScreen.js +187 -143
- package/lib/module/ui/screens/WelcomeNewUserScreen.js.map +1 -1
- package/lib/module/ui/screens/internal/SignInPasswordStep.js +10 -10
- package/lib/module/ui/screens/internal/SignInPasswordStep.js.map +1 -1
- package/lib/module/ui/screens/internal/SignInUsernameStep.js +2 -4
- package/lib/module/ui/screens/internal/SignInUsernameStep.js.map +1 -1
- package/lib/module/ui/screens/steps/RecoverRequestStep.js +45 -25
- package/lib/module/ui/screens/steps/RecoverRequestStep.js.map +1 -1
- package/lib/module/ui/screens/steps/RecoverResetPasswordStep.js +89 -54
- package/lib/module/ui/screens/steps/RecoverResetPasswordStep.js.map +1 -1
- package/lib/module/ui/screens/steps/RecoverSuccessStep.js +80 -59
- package/lib/module/ui/screens/steps/RecoverSuccessStep.js.map +1 -1
- package/lib/module/ui/screens/steps/RecoverVerifyStep.js +62 -53
- package/lib/module/ui/screens/steps/RecoverVerifyStep.js.map +1 -1
- package/lib/module/ui/screens/steps/SignInPasswordStep.js +219 -40
- package/lib/module/ui/screens/steps/SignInPasswordStep.js.map +1 -1
- package/lib/module/ui/screens/steps/SignInTotpStep.js +78 -51
- package/lib/module/ui/screens/steps/SignInTotpStep.js.map +1 -1
- package/lib/module/ui/screens/steps/SignInUsernameStep.js +426 -73
- package/lib/module/ui/screens/steps/SignInUsernameStep.js.map +1 -1
- package/lib/module/ui/screens/steps/SignUpIdentityStep.js +55 -30
- package/lib/module/ui/screens/steps/SignUpIdentityStep.js.map +1 -1
- package/lib/module/ui/screens/steps/SignUpSecurityStep.js +65 -47
- package/lib/module/ui/screens/steps/SignUpSecurityStep.js.map +1 -1
- package/lib/module/ui/screens/steps/SignUpSummaryStep.js +84 -146
- package/lib/module/ui/screens/steps/SignUpSummaryStep.js.map +1 -1
- package/lib/module/ui/screens/steps/SignUpWelcomeStep.js +114 -35
- package/lib/module/ui/screens/steps/SignUpWelcomeStep.js.map +1 -1
- package/lib/module/ui/stores/accountStore.js +229 -0
- package/lib/module/ui/stores/accountStore.js.map +1 -0
- package/lib/module/ui/stores/authStore.js +17 -20
- package/lib/module/ui/stores/authStore.js.map +1 -1
- package/lib/module/ui/styles/authStyles.js +16 -8
- package/lib/module/ui/styles/authStyles.js.map +1 -1
- package/lib/module/ui/styles/index.js +1 -0
- package/lib/module/ui/styles/index.js.map +1 -1
- package/lib/module/ui/styles/spacing.js +48 -0
- package/lib/module/ui/styles/spacing.js.map +1 -0
- package/lib/module/utils/asyncUtils.js +10 -22
- package/lib/module/utils/asyncUtils.js.map +1 -1
- package/lib/module/utils/cache.js +250 -0
- package/lib/module/utils/cache.js.map +1 -0
- package/lib/module/utils/index.js +7 -0
- package/lib/module/utils/index.js.map +1 -1
- package/lib/module/utils/languageUtils.js +151 -0
- package/lib/module/utils/languageUtils.js.map +1 -0
- package/lib/module/utils/requestUtils.js +210 -0
- package/lib/module/utils/requestUtils.js.map +1 -0
- package/lib/module/utils/sessionUtils.js +180 -0
- package/lib/module/utils/sessionUtils.js.map +1 -0
- package/lib/module/utils/validationUtils.js +1 -1
- package/lib/typescript/core/HttpClient.d.ts +64 -0
- package/lib/typescript/core/HttpClient.d.ts.map +1 -0
- package/lib/typescript/core/OxyServices.d.ts +86 -73
- package/lib/typescript/core/OxyServices.d.ts.map +1 -1
- package/lib/typescript/core/RequestManager.d.ts +67 -0
- package/lib/typescript/core/RequestManager.d.ts.map +1 -0
- package/lib/typescript/core/index.d.ts +2 -0
- package/lib/typescript/core/index.d.ts.map +1 -1
- package/lib/typescript/i18n/index.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +2 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/models/interfaces.d.ts +15 -0
- package/lib/typescript/models/interfaces.d.ts.map +1 -1
- package/lib/typescript/models/session.d.ts +1 -0
- package/lib/typescript/models/session.d.ts.map +1 -1
- package/lib/typescript/ui/components/Avatar.d.ts +6 -7
- package/lib/typescript/ui/components/Avatar.d.ts.map +1 -1
- package/lib/typescript/ui/components/FollowButton.d.ts.map +1 -1
- package/lib/typescript/ui/components/FontLoader.d.ts +3 -3
- package/lib/typescript/ui/components/FontLoader.d.ts.map +1 -1
- package/lib/typescript/ui/components/OxyProvider.d.ts +2 -2
- package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -1
- package/lib/typescript/ui/components/StepBasedScreen.d.ts.map +1 -1
- package/lib/typescript/ui/components/internal/GroupedPillButtons.d.ts.map +1 -1
- package/lib/typescript/ui/components/internal/TextField.d.ts.map +1 -1
- package/lib/typescript/ui/context/OxyContext.d.ts +5 -0
- package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/useSessionSocket.d.ts.map +1 -1
- package/lib/typescript/ui/index.d.ts +2 -2
- package/lib/typescript/ui/index.d.ts.map +1 -1
- package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/AccountSwitcherScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/LanguageSelectorScreen.d.ts +3 -3
- package/lib/typescript/ui/screens/LanguageSelectorScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/SignInScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/SignUpScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/WelcomeNewUserScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/internal/SignInPasswordStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/RecoverRequestStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/RecoverResetPasswordStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/RecoverSuccessStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/RecoverVerifyStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/SignInPasswordStep.d.ts +2 -0
- package/lib/typescript/ui/screens/steps/SignInPasswordStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/SignInTotpStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/SignInUsernameStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/SignUpIdentityStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/SignUpSecurityStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/SignUpSummaryStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/SignUpWelcomeStep.d.ts.map +1 -1
- package/lib/typescript/ui/stores/accountStore.d.ts +34 -0
- package/lib/typescript/ui/stores/accountStore.d.ts.map +1 -0
- package/lib/typescript/ui/stores/authStore.d.ts +7 -3
- package/lib/typescript/ui/stores/authStore.d.ts.map +1 -1
- package/lib/typescript/ui/styles/authStyles.d.ts +19 -2
- package/lib/typescript/ui/styles/authStyles.d.ts.map +1 -1
- package/lib/typescript/ui/styles/index.d.ts +1 -0
- package/lib/typescript/ui/styles/index.d.ts.map +1 -1
- package/lib/typescript/ui/styles/spacing.d.ts +43 -0
- package/lib/typescript/ui/styles/spacing.d.ts.map +1 -0
- package/lib/typescript/utils/asyncUtils.d.ts +2 -0
- package/lib/typescript/utils/asyncUtils.d.ts.map +1 -1
- package/lib/typescript/utils/cache.d.ts +128 -0
- package/lib/typescript/utils/cache.d.ts.map +1 -0
- package/lib/typescript/utils/index.d.ts +4 -0
- package/lib/typescript/utils/index.d.ts.map +1 -1
- package/lib/typescript/utils/languageUtils.d.ts +38 -0
- package/lib/typescript/utils/languageUtils.d.ts.map +1 -0
- package/lib/typescript/utils/requestUtils.d.ts +122 -0
- package/lib/typescript/utils/requestUtils.d.ts.map +1 -0
- package/lib/typescript/utils/sessionUtils.d.ts +55 -0
- package/lib/typescript/utils/sessionUtils.d.ts.map +1 -0
- package/lib/typescript/utils/validationUtils.d.ts +1 -1
- package/package.json +1 -1
- package/src/core/HttpClient.ts +277 -0
- package/src/core/OxyServices.ts +461 -352
- package/src/core/RequestManager.ts +240 -0
- package/src/core/index.ts +10 -0
- package/src/i18n/index.ts +36 -0
- package/src/i18n/locales/ar-SA.json +128 -0
- package/src/i18n/locales/ca-ES.json +128 -0
- package/src/i18n/locales/de-DE.json +128 -0
- package/src/i18n/locales/en-US.json +85 -12
- package/src/i18n/locales/es-ES.json +58 -6
- package/src/i18n/locales/fr-FR.json +128 -0
- package/src/i18n/locales/it-IT.json +128 -0
- package/src/i18n/locales/ja-JP.json +127 -0
- package/src/i18n/locales/ko-KR.json +128 -0
- package/src/i18n/locales/pt-PT.json +128 -0
- package/src/i18n/locales/zh-CN.json +128 -0
- package/src/index.ts +10 -0
- package/src/models/interfaces.ts +19 -0
- package/src/models/session.ts +1 -1
- package/src/ui/components/Avatar.tsx +151 -35
- package/src/ui/components/FollowButton.tsx +1 -0
- package/src/ui/components/FontLoader.tsx +17 -37
- package/src/ui/components/OxyProvider.tsx +14 -13
- package/src/ui/components/StepBasedScreen.tsx +66 -43
- package/src/ui/components/internal/GroupedPillButtons.tsx +15 -31
- package/src/ui/components/internal/PinInput.tsx +2 -2
- package/src/ui/components/internal/TextField.tsx +7 -6
- package/src/ui/context/OxyContext.tsx +441 -326
- package/src/ui/hooks/useSessionSocket.ts +72 -18
- package/src/ui/index.ts +4 -1
- package/src/ui/screens/AccountSettingsScreen.tsx +34 -2
- package/src/ui/screens/AccountSwitcherScreen.tsx +102 -68
- package/src/ui/screens/FileManagementScreen.tsx +16 -16
- package/src/ui/screens/LanguageSelectorScreen.tsx +86 -143
- package/src/ui/screens/SignInScreen.tsx +59 -43
- package/src/ui/screens/SignUpScreen.tsx +14 -15
- package/src/ui/screens/WelcomeNewUserScreen.tsx +153 -105
- package/src/ui/screens/internal/SignInPasswordStep.tsx +4 -6
- package/src/ui/screens/internal/SignInUsernameStep.tsx +1 -1
- package/src/ui/screens/steps/RecoverRequestStep.tsx +34 -24
- package/src/ui/screens/steps/RecoverResetPasswordStep.tsx +65 -36
- package/src/ui/screens/steps/RecoverSuccessStep.tsx +71 -47
- package/src/ui/screens/steps/RecoverVerifyStep.tsx +60 -50
- package/src/ui/screens/steps/SignInPasswordStep.tsx +190 -32
- package/src/ui/screens/steps/SignInTotpStep.tsx +68 -34
- package/src/ui/screens/steps/SignInUsernameStep.tsx +446 -63
- package/src/ui/screens/steps/SignUpIdentityStep.tsx +49 -35
- package/src/ui/screens/steps/SignUpSecurityStep.tsx +56 -39
- package/src/ui/screens/steps/SignUpSummaryStep.tsx +99 -89
- package/src/ui/screens/steps/SignUpWelcomeStep.tsx +88 -20
- package/src/ui/stores/accountStore.ts +285 -0
- package/src/ui/stores/authStore.ts +16 -19
- package/src/ui/styles/authStyles.ts +16 -8
- package/src/ui/styles/index.ts +1 -0
- package/src/ui/styles/spacing.ts +46 -0
- package/src/utils/asyncUtils.ts +10 -24
- package/src/utils/cache.ts +264 -0
- package/src/utils/index.ts +19 -0
- package/src/utils/languageUtils.ts +174 -0
- package/src/utils/requestUtils.ts +234 -0
- package/src/utils/sessionUtils.ts +206 -0
- package/src/utils/validationUtils.ts +1 -1
|
@@ -5,16 +5,37 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.useOxy = exports.default = exports.OxyProvider = exports.OxyContextProvider = void 0;
|
|
7
7
|
var _react = require("react");
|
|
8
|
-
var _reactNative = require("react-native");
|
|
9
8
|
var _core = require("../../core");
|
|
9
|
+
var _sessionUtils = require("../../utils/sessionUtils");
|
|
10
10
|
var _deviceManager = require("../../utils/deviceManager");
|
|
11
11
|
var _useSessionSocket = require("../hooks/useSessionSocket");
|
|
12
12
|
var _sonner = require("../../lib/sonner");
|
|
13
13
|
var _authStore = require("../stores/authStore");
|
|
14
|
+
var _languageUtils = require("../../utils/languageUtils");
|
|
14
15
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
15
16
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); } // Define the context shape
|
|
16
17
|
// NOTE: We intentionally avoid importing useFollow here to prevent a require cycle.
|
|
17
18
|
// If consumers relied on `const { useFollow } = useOxy()`, we provide a lazy proxy below.
|
|
19
|
+
// Empty follow hook fallback
|
|
20
|
+
const createEmptyFollowHook = () => {
|
|
21
|
+
const emptyResult = {
|
|
22
|
+
isFollowing: false,
|
|
23
|
+
isLoading: false,
|
|
24
|
+
error: null,
|
|
25
|
+
toggleFollow: async () => {},
|
|
26
|
+
setFollowStatus: () => {},
|
|
27
|
+
fetchStatus: async () => {},
|
|
28
|
+
clearError: () => {},
|
|
29
|
+
followerCount: null,
|
|
30
|
+
followingCount: null,
|
|
31
|
+
isLoadingCounts: false,
|
|
32
|
+
fetchUserCounts: async () => {},
|
|
33
|
+
setFollowerCount: () => {},
|
|
34
|
+
setFollowingCount: () => {}
|
|
35
|
+
};
|
|
36
|
+
return () => emptyResult;
|
|
37
|
+
};
|
|
38
|
+
|
|
18
39
|
// Create the context with default values
|
|
19
40
|
const OxyContext = /*#__PURE__*/(0, _react.createContext)(null);
|
|
20
41
|
|
|
@@ -67,6 +88,8 @@ const getStorage = async () => {
|
|
|
67
88
|
const getStorageKeys = (prefix = 'oxy_session') => ({
|
|
68
89
|
activeSessionId: `${prefix}_active_session_id`,
|
|
69
90
|
// Only store the active session ID
|
|
91
|
+
sessionIds: `${prefix}_session_ids`,
|
|
92
|
+
// Store all session IDs for quick account loading
|
|
70
93
|
language: `${prefix}_language` // Store the selected language
|
|
71
94
|
});
|
|
72
95
|
const OxyProvider = ({
|
|
@@ -106,43 +129,87 @@ const OxyProvider = ({
|
|
|
106
129
|
const [minimalUser, setMinimalUser] = (0, _react.useState)(null);
|
|
107
130
|
const [sessions, setSessions] = (0, _react.useState)([]);
|
|
108
131
|
const [activeSessionId, setActiveSessionId] = (0, _react.useState)(null);
|
|
132
|
+
|
|
133
|
+
// Track in-flight refresh to prevent duplicate calls
|
|
134
|
+
const refreshInFlightRef = (0, _react.useRef)(null);
|
|
109
135
|
const [storage, setStorage] = (0, _react.useState)(null);
|
|
110
136
|
const [currentLanguage, setCurrentLanguage] = (0, _react.useState)('en-US');
|
|
111
137
|
|
|
112
|
-
//
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
138
|
+
// Storage keys (memoized to prevent infinite loops) - declared early for use in helpers
|
|
139
|
+
const keys = (0, _react.useMemo)(() => getStorageKeys(storageKeyPrefix), [storageKeyPrefix]);
|
|
140
|
+
|
|
141
|
+
// Helper to apply language preference from user/server
|
|
142
|
+
const applyLanguagePreference = (0, _react.useCallback)(async user => {
|
|
143
|
+
const userLanguage = user?.language;
|
|
144
|
+
if (!userLanguage || !storage) return;
|
|
145
|
+
try {
|
|
146
|
+
const serverLang = (0, _languageUtils.normalizeLanguageCode)(userLanguage);
|
|
147
|
+
await storage.setItem(keys.language, serverLang);
|
|
148
|
+
setCurrentLanguage(serverLang);
|
|
149
|
+
} catch (e) {
|
|
150
|
+
if (__DEV__) {
|
|
151
|
+
console.warn('Failed to apply server language preference', e);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}, [storage, keys.language]);
|
|
155
|
+
const mapSessionsToClient = (0, _react.useCallback)((sessions, fallbackDeviceId, fallbackUserId) => {
|
|
156
|
+
return sessions.map(s => ({
|
|
157
|
+
sessionId: s.sessionId,
|
|
158
|
+
deviceId: s.deviceId || fallbackDeviceId || '',
|
|
159
|
+
expiresAt: s.expiresAt || new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(),
|
|
160
|
+
lastActive: s.lastActive || new Date().toISOString(),
|
|
161
|
+
userId: s.user?.id || s.userId || s.user?._id?.toString() || fallbackUserId || '',
|
|
162
|
+
isCurrent: Boolean(s.isCurrent)
|
|
163
|
+
}));
|
|
130
164
|
}, []);
|
|
131
|
-
// Add a new state to track token restoration
|
|
132
|
-
const [tokenReady, setTokenReady] = (0, _react.useState)(false);
|
|
133
165
|
|
|
134
|
-
//
|
|
135
|
-
const
|
|
166
|
+
// Save all session IDs to storage for quick loading on initialization
|
|
167
|
+
const saveSessionIds = (0, _react.useCallback)(async sessionIds => {
|
|
168
|
+
if (!storage) return;
|
|
169
|
+
try {
|
|
170
|
+
const uniqueIds = Array.from(new Set(sessionIds));
|
|
171
|
+
await storage.setItem(keys.sessionIds, JSON.stringify(uniqueIds));
|
|
172
|
+
} catch (err) {
|
|
173
|
+
if (__DEV__) {
|
|
174
|
+
console.warn('Failed to save session IDs:', err);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}, [storage, keys.sessionIds]);
|
|
178
|
+
const updateSessions = (0, _react.useCallback)((newSessions, mergeWithExisting = false) => {
|
|
179
|
+
setSessions(prevSessions => {
|
|
180
|
+
const sessionsToProcess = mergeWithExisting ? (0, _sessionUtils.mergeSessions)(prevSessions, newSessions, activeSessionId, false) : (0, _sessionUtils.normalizeAndSortSessions)(newSessions, activeSessionId, false);
|
|
181
|
+
|
|
182
|
+
// Save all session IDs to storage
|
|
183
|
+
if (storage) {
|
|
184
|
+
const allSessionIds = sessionsToProcess.map(s => s.sessionId);
|
|
185
|
+
saveSessionIds(allSessionIds).catch(() => {
|
|
186
|
+
// Ignore errors - non-critical
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
return (0, _sessionUtils.sessionsArraysEqual)(prevSessions, sessionsToProcess) ? prevSessions : sessionsToProcess;
|
|
190
|
+
});
|
|
191
|
+
}, [activeSessionId, storage, saveSessionIds]);
|
|
136
192
|
|
|
137
|
-
//
|
|
193
|
+
// Token ready state - start optimistically so children render immediately
|
|
194
|
+
const [tokenReady, setTokenReady] = (0, _react.useState)(true);
|
|
195
|
+
|
|
196
|
+
// Clear all storage
|
|
138
197
|
const clearAllStorage = (0, _react.useCallback)(async () => {
|
|
139
198
|
if (!storage) return;
|
|
140
199
|
try {
|
|
141
200
|
await storage.removeItem(keys.activeSessionId);
|
|
201
|
+
await storage.removeItem(keys.sessionIds);
|
|
142
202
|
} catch (err) {
|
|
143
|
-
|
|
203
|
+
if (__DEV__) {
|
|
204
|
+
console.error('Clear storage error:', err);
|
|
205
|
+
}
|
|
206
|
+
onError?.({
|
|
207
|
+
message: 'Failed to clear storage',
|
|
208
|
+
code: 'STORAGE_ERROR',
|
|
209
|
+
status: 500
|
|
210
|
+
});
|
|
144
211
|
}
|
|
145
|
-
}, [storage, keys]);
|
|
212
|
+
}, [storage, keys, onError]);
|
|
146
213
|
|
|
147
214
|
// Initialize storage
|
|
148
215
|
(0, _react.useEffect)(() => {
|
|
@@ -151,34 +218,80 @@ const OxyProvider = ({
|
|
|
151
218
|
const platformStorage = await getStorage();
|
|
152
219
|
setStorage(platformStorage);
|
|
153
220
|
} catch (error) {
|
|
154
|
-
|
|
221
|
+
const errorMessage = error instanceof Error ? error.message : 'Failed to initialize storage';
|
|
155
222
|
_authStore.useAuthStore.setState({
|
|
156
|
-
error:
|
|
223
|
+
error: errorMessage
|
|
224
|
+
});
|
|
225
|
+
onError?.({
|
|
226
|
+
message: errorMessage,
|
|
227
|
+
code: 'STORAGE_INIT_ERROR',
|
|
228
|
+
status: 500
|
|
157
229
|
});
|
|
158
230
|
}
|
|
159
231
|
};
|
|
160
232
|
initStorage();
|
|
161
|
-
}, []);
|
|
233
|
+
}, [onError]);
|
|
162
234
|
|
|
163
235
|
// Initialize authentication state
|
|
236
|
+
// Note: We don't set isLoading during initialization to avoid showing spinners
|
|
237
|
+
// Children render immediately and can check isTokenReady/isAuthenticated themselves
|
|
164
238
|
(0, _react.useEffect)(() => {
|
|
165
239
|
const initAuth = async () => {
|
|
166
240
|
if (!storage) return;
|
|
167
|
-
|
|
168
|
-
isLoading: true
|
|
169
|
-
});
|
|
241
|
+
// Don't set isLoading during initialization - let it happen in background
|
|
170
242
|
try {
|
|
171
|
-
setTokenReady(false);
|
|
172
|
-
|
|
173
243
|
// Load saved language preference
|
|
174
244
|
const savedLanguageRaw = await storage.getItem(keys.language);
|
|
175
|
-
const savedLanguage = normalizeLanguageCode(savedLanguageRaw) || savedLanguageRaw;
|
|
245
|
+
const savedLanguage = (0, _languageUtils.normalizeLanguageCode)(savedLanguageRaw) || savedLanguageRaw;
|
|
176
246
|
if (savedLanguage) {
|
|
177
247
|
setCurrentLanguage(savedLanguage);
|
|
178
248
|
}
|
|
179
249
|
|
|
250
|
+
// Load all stored session IDs and validate them
|
|
251
|
+
const storedSessionIdsJson = await storage.getItem(keys.sessionIds);
|
|
252
|
+
const storedSessionIds = storedSessionIdsJson ? JSON.parse(storedSessionIdsJson) : [];
|
|
253
|
+
|
|
180
254
|
// Try to restore active session from storage
|
|
181
255
|
const storedActiveSessionId = await storage.getItem(keys.activeSessionId);
|
|
256
|
+
const validSessions = [];
|
|
257
|
+
|
|
258
|
+
// If we have stored session IDs, validate them (even without active session)
|
|
259
|
+
if (storedSessionIds.length > 0) {
|
|
260
|
+
if (__DEV__) {
|
|
261
|
+
console.log('Loading stored sessions on init:', storedSessionIds.length);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Validate each stored session ID and build session list
|
|
265
|
+
for (const sessionId of storedSessionIds) {
|
|
266
|
+
try {
|
|
267
|
+
const validation = await oxyServices.validateSession(sessionId, {
|
|
268
|
+
useHeaderValidation: true
|
|
269
|
+
});
|
|
270
|
+
if (validation.valid && validation.user) {
|
|
271
|
+
validSessions.push({
|
|
272
|
+
sessionId,
|
|
273
|
+
userId: validation.user.id?.toString() || '',
|
|
274
|
+
deviceId: '',
|
|
275
|
+
expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(),
|
|
276
|
+
lastActive: new Date().toISOString(),
|
|
277
|
+
isCurrent: sessionId === storedActiveSessionId
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
} catch (e) {
|
|
281
|
+
// Session invalid, skip it
|
|
282
|
+
if (__DEV__) {
|
|
283
|
+
console.warn('Session validation failed for:', sessionId, e);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// Update sessions list with validated sessions (even if no active session)
|
|
289
|
+
if (validSessions.length > 0) {
|
|
290
|
+
updateSessions(validSessions, false);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// If we have an active session, authenticate with it
|
|
182
295
|
if (storedActiveSessionId) {
|
|
183
296
|
try {
|
|
184
297
|
const validation = await oxyServices.validateSession(storedActiveSessionId, {
|
|
@@ -194,86 +307,66 @@ const OxyProvider = ({
|
|
|
194
307
|
username: fullUser.username,
|
|
195
308
|
avatar: fullUser.avatar
|
|
196
309
|
});
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
console.warn('Failed to
|
|
310
|
+
await applyLanguagePreference(fullUser);
|
|
311
|
+
try {
|
|
312
|
+
const deviceSessions = await oxyServices.getDeviceSessions(storedActiveSessionId);
|
|
313
|
+
const allDeviceSessions = mapSessionsToClient(deviceSessions, undefined, fullUser.id);
|
|
314
|
+
updateSessions(allDeviceSessions, true);
|
|
315
|
+
} catch (e) {
|
|
316
|
+
if (__DEV__) {
|
|
317
|
+
console.warn('Failed to get device sessions on init, falling back to user sessions:', e);
|
|
205
318
|
}
|
|
319
|
+
const serverSessions = await oxyServices.getSessionsBySessionId(storedActiveSessionId);
|
|
320
|
+
updateSessions(mapSessionsToClient(serverSessions, undefined, fullUser.id), false);
|
|
206
321
|
}
|
|
207
|
-
const serverSessions = await oxyServices.getSessionsBySessionId(storedActiveSessionId);
|
|
208
|
-
const clientSessions = serverSessions.map(s => ({
|
|
209
|
-
sessionId: s.sessionId,
|
|
210
|
-
deviceId: s.deviceId,
|
|
211
|
-
expiresAt: s.expiresAt || new Date().toISOString(),
|
|
212
|
-
lastActive: s.lastActive || new Date().toISOString(),
|
|
213
|
-
userId: s.userId || fullUser.id
|
|
214
|
-
}));
|
|
215
|
-
setSessions(clientSessions);
|
|
216
322
|
onAuthStateChange?.(fullUser);
|
|
217
323
|
} else {
|
|
218
|
-
|
|
324
|
+
// Active session invalid, remove it but keep other sessions
|
|
325
|
+
await storage.removeItem(keys.activeSessionId);
|
|
326
|
+
// Update session list to remove invalid active session
|
|
327
|
+
updateSessions(validSessions.filter(s => s.sessionId !== storedActiveSessionId), false);
|
|
219
328
|
}
|
|
220
329
|
} catch (e) {
|
|
221
|
-
|
|
222
|
-
|
|
330
|
+
if (__DEV__) {
|
|
331
|
+
console.error('Active session validation error', e);
|
|
332
|
+
}
|
|
333
|
+
// Remove invalid active session but keep other sessions
|
|
334
|
+
await storage.removeItem(keys.activeSessionId);
|
|
335
|
+
updateSessions(validSessions.filter(s => s.sessionId !== storedActiveSessionId), false);
|
|
223
336
|
}
|
|
224
337
|
}
|
|
225
338
|
setTokenReady(true);
|
|
226
339
|
} catch (e) {
|
|
227
|
-
|
|
340
|
+
if (__DEV__) {
|
|
341
|
+
console.error('Auth init error', e);
|
|
342
|
+
}
|
|
228
343
|
await clearAllStorage();
|
|
229
|
-
|
|
230
|
-
_authStore.useAuthStore.setState({
|
|
231
|
-
isLoading: false
|
|
232
|
-
});
|
|
344
|
+
setTokenReady(true);
|
|
233
345
|
}
|
|
234
346
|
};
|
|
235
347
|
initAuth();
|
|
236
|
-
}, [storage, oxyServices, keys, onAuthStateChange, loginSuccess, clearAllStorage]);
|
|
237
|
-
|
|
238
|
-
// Remove invalid session - refresh sessions from backend
|
|
239
|
-
const removeInvalidSession = (0, _react.useCallback)(async sessionId => {
|
|
240
|
-
// Remove from local state
|
|
241
|
-
const filteredSessions = sessions.filter(s => s.sessionId !== sessionId);
|
|
242
|
-
setSessions(filteredSessions);
|
|
243
|
-
|
|
244
|
-
// If there are other sessions, switch to the first one
|
|
245
|
-
if (filteredSessions.length > 0) {
|
|
246
|
-
await switchToSession(filteredSessions[0].sessionId);
|
|
247
|
-
} else {
|
|
248
|
-
// No valid sessions left
|
|
249
|
-
setActiveSessionId(null);
|
|
250
|
-
logoutStore();
|
|
251
|
-
setMinimalUser(null);
|
|
252
|
-
await storage?.removeItem(keys.activeSessionId);
|
|
253
|
-
if (onAuthStateChange) {
|
|
254
|
-
onAuthStateChange(null);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
}, [sessions, storage, keys, onAuthStateChange, logoutStore]);
|
|
348
|
+
}, [storage, oxyServices, keys, onAuthStateChange, loginSuccess, clearAllStorage, applyLanguagePreference, mapSessionsToClient, updateSessions]);
|
|
258
349
|
|
|
259
350
|
// Save active session ID to storage (only session ID, no user data)
|
|
260
351
|
const saveActiveSessionId = (0, _react.useCallback)(async sessionId => {
|
|
261
352
|
if (!storage) return;
|
|
262
353
|
await storage.setItem(keys.activeSessionId, sessionId);
|
|
263
354
|
}, [storage, keys.activeSessionId]);
|
|
264
|
-
|
|
265
|
-
// Switch to a different session
|
|
266
355
|
const switchToSession = (0, _react.useCallback)(async sessionId => {
|
|
267
356
|
try {
|
|
268
|
-
|
|
269
|
-
|
|
357
|
+
const validation = await oxyServices.validateSession(sessionId, {
|
|
358
|
+
useHeaderValidation: true
|
|
270
359
|
});
|
|
271
|
-
|
|
272
|
-
|
|
360
|
+
if (!validation.valid) {
|
|
361
|
+
updateSessions(sessions.filter(s => s.sessionId !== sessionId), false);
|
|
362
|
+
throw new Error('Session is invalid or expired');
|
|
363
|
+
}
|
|
364
|
+
if (!validation.user) {
|
|
365
|
+
throw new Error('User data not available from session validation');
|
|
366
|
+
}
|
|
367
|
+
const fullUser = validation.user;
|
|
273
368
|
await oxyServices.getTokenBySession(sessionId);
|
|
274
|
-
|
|
275
|
-
// Load full user data
|
|
276
|
-
const fullUser = await oxyServices.getUserBySession(sessionId);
|
|
369
|
+
setTokenReady(true);
|
|
277
370
|
setActiveSessionId(sessionId);
|
|
278
371
|
loginSuccess(fullUser);
|
|
279
372
|
setMinimalUser({
|
|
@@ -282,32 +375,52 @@ const OxyProvider = ({
|
|
|
282
375
|
avatar: fullUser.avatar
|
|
283
376
|
});
|
|
284
377
|
await saveActiveSessionId(sessionId);
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
378
|
+
await applyLanguagePreference(fullUser);
|
|
379
|
+
oxyServices.getDeviceSessions(sessionId).then(deviceSessions => {
|
|
380
|
+
const allDeviceSessions = mapSessionsToClient(deviceSessions, undefined, fullUser.id);
|
|
381
|
+
updateSessions(allDeviceSessions, true);
|
|
382
|
+
}).catch(error => {
|
|
383
|
+
if (__DEV__) console.warn('Failed to get device sessions after switch:', error);
|
|
384
|
+
});
|
|
385
|
+
onAuthStateChange?.(fullUser);
|
|
386
|
+
} catch (error) {
|
|
387
|
+
const isInvalidSession = error?.response?.status === 401 || error?.message?.includes('Invalid or expired session') || error?.message?.includes('Session is invalid');
|
|
388
|
+
if (isInvalidSession) {
|
|
389
|
+
updateSessions(sessions.filter(s => s.sessionId !== sessionId), false);
|
|
390
|
+
if (sessionId === activeSessionId && sessions.length > 1) {
|
|
391
|
+
const otherSessions = sessions.filter(s => s.sessionId !== sessionId);
|
|
392
|
+
for (const otherSession of otherSessions) {
|
|
393
|
+
try {
|
|
394
|
+
const otherValidation = await oxyServices.validateSession(otherSession.sessionId, {
|
|
395
|
+
useHeaderValidation: true
|
|
396
|
+
});
|
|
397
|
+
if (otherValidation.valid) {
|
|
398
|
+
await switchToSession(otherSession.sessionId);
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
} catch {
|
|
402
|
+
// Continue to next session
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
293
406
|
}
|
|
294
407
|
}
|
|
295
|
-
|
|
296
|
-
|
|
408
|
+
const errorMessage = error instanceof Error ? error.message : 'Failed to switch session';
|
|
409
|
+
if (__DEV__) {
|
|
410
|
+
console.error('Switch session error:', error);
|
|
297
411
|
}
|
|
298
|
-
} catch (error) {
|
|
299
|
-
console.error('Switch session error:', error);
|
|
300
412
|
_authStore.useAuthStore.setState({
|
|
301
|
-
error:
|
|
413
|
+
error: errorMessage
|
|
302
414
|
});
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
415
|
+
onError?.({
|
|
416
|
+
message: errorMessage,
|
|
417
|
+
code: isInvalidSession ? 'INVALID_SESSION' : 'SESSION_SWITCH_ERROR',
|
|
418
|
+
status: isInvalidSession ? 401 : 500
|
|
306
419
|
});
|
|
420
|
+
setTokenReady(false);
|
|
421
|
+
throw error; // Re-throw so calling code can handle it
|
|
307
422
|
}
|
|
308
|
-
}, [oxyServices, onAuthStateChange, loginSuccess, saveActiveSessionId]);
|
|
309
|
-
|
|
310
|
-
// Login method - only store session ID, retrieve data from backend
|
|
423
|
+
}, [oxyServices, onAuthStateChange, loginSuccess, saveActiveSessionId, applyLanguagePreference, mapSessionsToClient, onError, activeSessionId, sessions]);
|
|
311
424
|
const login = (0, _react.useCallback)(async (username, password, deviceName) => {
|
|
312
425
|
if (!storage) throw new Error('Storage not initialized');
|
|
313
426
|
_authStore.useAuthStore.setState({
|
|
@@ -315,59 +428,71 @@ const OxyProvider = ({
|
|
|
315
428
|
error: null
|
|
316
429
|
});
|
|
317
430
|
try {
|
|
318
|
-
// Get device fingerprint for enhanced device identification
|
|
319
431
|
const deviceFingerprint = _deviceManager.DeviceManager.getDeviceFingerprint();
|
|
320
|
-
|
|
321
|
-
// Get or generate persistent device info
|
|
322
432
|
const deviceInfo = await _deviceManager.DeviceManager.getDeviceInfo();
|
|
323
|
-
console.log('Auth - Using device fingerprint:', deviceFingerprint);
|
|
324
|
-
console.log('Auth - Using device ID:', deviceInfo.deviceId);
|
|
325
433
|
const response = await oxyServices.signIn(username, password, deviceName || deviceInfo.deviceName || _deviceManager.DeviceManager.getDefaultDeviceName(), deviceFingerprint);
|
|
326
434
|
|
|
327
435
|
// Handle MFA requirement
|
|
328
|
-
if (response && response.mfaRequired) {
|
|
329
|
-
const
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
throw
|
|
436
|
+
if (response && 'mfaRequired' in response && response.mfaRequired) {
|
|
437
|
+
const mfaError = new Error('Multi-factor authentication required');
|
|
438
|
+
mfaError.code = 'MFA_REQUIRED';
|
|
439
|
+
mfaError.mfaToken = response.mfaToken;
|
|
440
|
+
mfaError.expiresAt = response.expiresAt;
|
|
441
|
+
throw mfaError;
|
|
334
442
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
// Load sessions from backend
|
|
349
|
-
const serverSessions = await oxyServices.getSessionsBySessionId(response.sessionId);
|
|
350
|
-
const clientSessions = serverSessions.map(serverSession => ({
|
|
351
|
-
sessionId: serverSession.sessionId,
|
|
352
|
-
deviceId: serverSession.deviceId,
|
|
353
|
-
expiresAt: serverSession.expiresAt || new Date().toISOString(),
|
|
354
|
-
lastActive: serverSession.lastActive || new Date().toISOString(),
|
|
355
|
-
userId: serverSession.userId || fullUser.id
|
|
356
|
-
}));
|
|
357
|
-
setSessions(clientSessions);
|
|
358
|
-
if (onAuthStateChange) {
|
|
359
|
-
onAuthStateChange(fullUser);
|
|
443
|
+
const sessionResponse = response;
|
|
444
|
+
await oxyServices.getTokenBySession(sessionResponse.sessionId);
|
|
445
|
+
const fullUser = await oxyServices.getUserBySession(sessionResponse.sessionId);
|
|
446
|
+
let allDeviceSessions = [];
|
|
447
|
+
try {
|
|
448
|
+
const deviceSessions = await oxyServices.getDeviceSessions(sessionResponse.sessionId);
|
|
449
|
+
allDeviceSessions = mapSessionsToClient(deviceSessions, sessionResponse.deviceId, fullUser.id);
|
|
450
|
+
} catch (error) {
|
|
451
|
+
if (__DEV__) {
|
|
452
|
+
console.warn('Failed to get device sessions, falling back to user sessions:', error);
|
|
453
|
+
}
|
|
454
|
+
const serverSessions = await oxyServices.getSessionsBySessionId(sessionResponse.sessionId);
|
|
455
|
+
allDeviceSessions = mapSessionsToClient(serverSessions, undefined, fullUser.id);
|
|
360
456
|
}
|
|
457
|
+
const userUserId = fullUser.id?.toString();
|
|
458
|
+
const existingSession = allDeviceSessions.find(s => s.userId?.toString() === userUserId && s.sessionId !== sessionResponse.sessionId);
|
|
459
|
+
if (existingSession) {
|
|
460
|
+
try {
|
|
461
|
+
await oxyServices.logoutSession(sessionResponse.sessionId, sessionResponse.sessionId);
|
|
462
|
+
} catch (logoutError) {
|
|
463
|
+
if (__DEV__) {
|
|
464
|
+
console.warn('Failed to logout duplicate session:', logoutError);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
await switchToSession(existingSession.sessionId);
|
|
468
|
+
loginSuccess(fullUser);
|
|
469
|
+
setMinimalUser(sessionResponse.user);
|
|
470
|
+
updateSessions(allDeviceSessions.filter(s => s.sessionId !== sessionResponse.sessionId), false);
|
|
471
|
+
onAuthStateChange?.(fullUser);
|
|
472
|
+
return fullUser;
|
|
473
|
+
}
|
|
474
|
+
setActiveSessionId(sessionResponse.sessionId);
|
|
475
|
+
await saveActiveSessionId(sessionResponse.sessionId);
|
|
476
|
+
loginSuccess(fullUser);
|
|
477
|
+
setMinimalUser(sessionResponse.user);
|
|
478
|
+
updateSessions(allDeviceSessions, true);
|
|
479
|
+
onAuthStateChange?.(fullUser);
|
|
361
480
|
return fullUser;
|
|
362
481
|
} catch (error) {
|
|
363
|
-
|
|
482
|
+
const errorMessage = error instanceof Error ? error.message : 'Login failed';
|
|
483
|
+
loginFailure(errorMessage);
|
|
484
|
+
onError?.({
|
|
485
|
+
message: errorMessage,
|
|
486
|
+
code: 'LOGIN_ERROR',
|
|
487
|
+
status: 401
|
|
488
|
+
});
|
|
364
489
|
throw error;
|
|
365
490
|
} finally {
|
|
366
491
|
_authStore.useAuthStore.setState({
|
|
367
492
|
isLoading: false
|
|
368
493
|
});
|
|
369
494
|
}
|
|
370
|
-
}, [storage, oxyServices, saveActiveSessionId, loginSuccess,
|
|
495
|
+
}, [storage, oxyServices, saveActiveSessionId, loginSuccess, onAuthStateChange, loginFailure, mapSessionsToClient, onError, sessions, switchToSession]);
|
|
371
496
|
|
|
372
497
|
// Logout method
|
|
373
498
|
const logout = (0, _react.useCallback)(async targetSessionId => {
|
|
@@ -375,18 +500,12 @@ const OxyProvider = ({
|
|
|
375
500
|
try {
|
|
376
501
|
const sessionToLogout = targetSessionId || activeSessionId;
|
|
377
502
|
await oxyServices.logoutSession(activeSessionId, sessionToLogout);
|
|
378
|
-
|
|
379
|
-
// Remove session from local state
|
|
380
503
|
const filteredSessions = sessions.filter(s => s.sessionId !== sessionToLogout);
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
// If logging out active session
|
|
504
|
+
updateSessions(filteredSessions, false);
|
|
384
505
|
if (sessionToLogout === activeSessionId) {
|
|
385
506
|
if (filteredSessions.length > 0) {
|
|
386
|
-
// Switch to another session
|
|
387
507
|
await switchToSession(filteredSessions[0].sessionId);
|
|
388
508
|
} else {
|
|
389
|
-
// No sessions left
|
|
390
509
|
setActiveSessionId(null);
|
|
391
510
|
logoutStore();
|
|
392
511
|
setMinimalUser(null);
|
|
@@ -397,74 +516,57 @@ const OxyProvider = ({
|
|
|
397
516
|
}
|
|
398
517
|
}
|
|
399
518
|
} catch (error) {
|
|
400
|
-
|
|
519
|
+
const errorMessage = error instanceof Error ? error.message : 'Logout failed';
|
|
520
|
+
if (__DEV__) {
|
|
521
|
+
console.error('Logout error:', error);
|
|
522
|
+
}
|
|
401
523
|
_authStore.useAuthStore.setState({
|
|
402
|
-
error:
|
|
524
|
+
error: errorMessage
|
|
525
|
+
});
|
|
526
|
+
onError?.({
|
|
527
|
+
message: errorMessage,
|
|
528
|
+
code: 'LOGOUT_ERROR',
|
|
529
|
+
status: 500
|
|
403
530
|
});
|
|
404
531
|
}
|
|
405
|
-
}, [activeSessionId, oxyServices, sessions, switchToSession, logoutStore,
|
|
406
|
-
|
|
407
|
-
// Logout all sessions
|
|
532
|
+
}, [activeSessionId, oxyServices, sessions, switchToSession, logoutStore, storage, keys.activeSessionId, onAuthStateChange, onError]);
|
|
408
533
|
const logoutAll = (0, _react.useCallback)(async () => {
|
|
409
|
-
console.log('logoutAll called with activeSessionId:', activeSessionId);
|
|
410
534
|
if (!activeSessionId) {
|
|
411
|
-
|
|
535
|
+
const error = new Error('No active session found');
|
|
412
536
|
_authStore.useAuthStore.setState({
|
|
413
|
-
error:
|
|
537
|
+
error: error.message
|
|
414
538
|
});
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
_authStore.useAuthStore.setState({
|
|
420
|
-
error: 'Service not available'
|
|
539
|
+
onError?.({
|
|
540
|
+
message: error.message,
|
|
541
|
+
code: 'NO_SESSION_ERROR',
|
|
542
|
+
status: 404
|
|
421
543
|
});
|
|
422
|
-
throw
|
|
544
|
+
throw error;
|
|
423
545
|
}
|
|
424
546
|
try {
|
|
425
|
-
console.log('Calling oxyServices.logoutAllSessions with sessionId:', activeSessionId);
|
|
426
547
|
await oxyServices.logoutAllSessions(activeSessionId);
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
// Clear all local data
|
|
430
|
-
setSessions([]);
|
|
548
|
+
updateSessions([], false);
|
|
431
549
|
setActiveSessionId(null);
|
|
432
550
|
logoutStore();
|
|
433
551
|
setMinimalUser(null);
|
|
434
552
|
await clearAllStorage();
|
|
435
|
-
|
|
436
|
-
if (onAuthStateChange) {
|
|
437
|
-
onAuthStateChange(null);
|
|
438
|
-
console.log('Auth state change callback called');
|
|
439
|
-
}
|
|
553
|
+
onAuthStateChange?.(null);
|
|
440
554
|
} catch (error) {
|
|
441
|
-
|
|
555
|
+
const errorMessage = error instanceof Error ? error.message : 'Logout all failed';
|
|
442
556
|
_authStore.useAuthStore.setState({
|
|
443
|
-
error:
|
|
557
|
+
error: errorMessage
|
|
558
|
+
});
|
|
559
|
+
onError?.({
|
|
560
|
+
message: errorMessage,
|
|
561
|
+
code: 'LOGOUT_ALL_ERROR',
|
|
562
|
+
status: 500
|
|
444
563
|
});
|
|
445
564
|
throw error;
|
|
446
565
|
}
|
|
447
|
-
}, [activeSessionId, oxyServices, logoutStore,
|
|
566
|
+
}, [activeSessionId, oxyServices, logoutStore, clearAllStorage, onAuthStateChange, onError]);
|
|
448
567
|
|
|
449
|
-
//
|
|
450
|
-
|
|
451
|
-
const restoreToken = async () => {
|
|
452
|
-
if (activeSessionId && oxyServices) {
|
|
453
|
-
try {
|
|
454
|
-
await oxyServices.getTokenBySession(activeSessionId);
|
|
455
|
-
setTokenReady(true);
|
|
456
|
-
} catch (err) {
|
|
457
|
-
// If token restoration fails, force logout
|
|
458
|
-
await logout();
|
|
459
|
-
setTokenReady(false);
|
|
460
|
-
}
|
|
461
|
-
} else {
|
|
462
|
-
setTokenReady(true); // No session, so token is not needed
|
|
463
|
-
}
|
|
464
|
-
};
|
|
465
|
-
restoreToken();
|
|
466
|
-
// Only run when activeSessionId or oxyServices changes
|
|
467
|
-
}, [activeSessionId, oxyServices, logout]);
|
|
568
|
+
// Token restoration is handled in initAuth and switchToSession
|
|
569
|
+
// No separate effect needed - children render immediately with isTokenReady available
|
|
468
570
|
|
|
469
571
|
// Sign up method
|
|
470
572
|
const signUp = (0, _react.useCallback)(async (username, email, password) => {
|
|
@@ -474,23 +576,24 @@ const OxyProvider = ({
|
|
|
474
576
|
error: null
|
|
475
577
|
});
|
|
476
578
|
try {
|
|
477
|
-
|
|
478
|
-
const response = await oxyServices.signUp(username, email, password);
|
|
479
|
-
console.log('SignUp successful:', response);
|
|
480
|
-
|
|
481
|
-
// Now log the user in to create a session
|
|
482
|
-
// This will handle the session creation and device registration
|
|
579
|
+
await oxyServices.signUp(username, email, password);
|
|
483
580
|
const user = await login(username, password);
|
|
484
581
|
return user;
|
|
485
582
|
} catch (error) {
|
|
486
|
-
|
|
583
|
+
const errorMessage = error instanceof Error ? error.message : 'Sign up failed';
|
|
584
|
+
loginFailure(errorMessage);
|
|
585
|
+
onError?.({
|
|
586
|
+
message: errorMessage,
|
|
587
|
+
code: 'SIGNUP_ERROR',
|
|
588
|
+
status: 400
|
|
589
|
+
});
|
|
487
590
|
throw error;
|
|
488
591
|
} finally {
|
|
489
592
|
_authStore.useAuthStore.setState({
|
|
490
593
|
isLoading: false
|
|
491
594
|
});
|
|
492
595
|
}
|
|
493
|
-
}, [storage, oxyServices, login, loginFailure]);
|
|
596
|
+
}, [storage, oxyServices, login, loginFailure, onError]);
|
|
494
597
|
|
|
495
598
|
// Complete MFA login by verifying TOTP
|
|
496
599
|
const completeMfaLogin = (0, _react.useCallback)(async (mfaToken, code) => {
|
|
@@ -515,116 +618,106 @@ const OxyProvider = ({
|
|
|
515
618
|
username: fullUser.username,
|
|
516
619
|
avatar: fullUser.avatar
|
|
517
620
|
});
|
|
518
|
-
|
|
519
|
-
if (fullUser?.language) {
|
|
520
|
-
try {
|
|
521
|
-
const serverLang = normalizeLanguageCode(fullUser.language) || fullUser.language;
|
|
522
|
-
await storage.setItem(keys.language, serverLang);
|
|
523
|
-
setCurrentLanguage(serverLang);
|
|
524
|
-
} catch (e) {
|
|
525
|
-
console.warn('Failed to apply server language on MFA login', e);
|
|
526
|
-
}
|
|
527
|
-
}
|
|
621
|
+
await applyLanguagePreference(fullUser);
|
|
528
622
|
|
|
529
|
-
//
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
setSessions(clientSessions);
|
|
539
|
-
// Apply server language if present
|
|
540
|
-
if (fullUser?.language) {
|
|
541
|
-
try {
|
|
542
|
-
await storage.setItem(keys.language, fullUser.language);
|
|
543
|
-
setCurrentLanguage(fullUser.language);
|
|
544
|
-
} catch (e) {
|
|
545
|
-
console.warn('Failed to apply server language on MFA login', e);
|
|
623
|
+
// Get all device sessions to support multiple accounts
|
|
624
|
+
try {
|
|
625
|
+
const deviceSessions = await oxyServices.getDeviceSessions(response.sessionId);
|
|
626
|
+
const allDeviceSessions = mapSessionsToClient(deviceSessions, undefined, fullUser.id);
|
|
627
|
+
updateSessions(allDeviceSessions, true);
|
|
628
|
+
} catch (error) {
|
|
629
|
+
// Fallback to user sessions if device sessions fail
|
|
630
|
+
if (__DEV__) {
|
|
631
|
+
console.warn('Failed to get device sessions for MFA, falling back to user sessions:', error);
|
|
546
632
|
}
|
|
633
|
+
const serverSessions = await oxyServices.getSessionsBySessionId(response.sessionId);
|
|
634
|
+
const userSessions = mapSessionsToClient(serverSessions, undefined, fullUser.id);
|
|
635
|
+
updateSessions(userSessions, true);
|
|
547
636
|
}
|
|
548
|
-
|
|
637
|
+
onAuthStateChange?.(fullUser);
|
|
549
638
|
return fullUser;
|
|
550
639
|
} catch (error) {
|
|
551
|
-
|
|
640
|
+
const errorMessage = error instanceof Error ? error.message : 'MFA verification failed';
|
|
641
|
+
loginFailure(errorMessage);
|
|
642
|
+
onError?.({
|
|
643
|
+
message: errorMessage,
|
|
644
|
+
code: 'MFA_ERROR',
|
|
645
|
+
status: 401
|
|
646
|
+
});
|
|
552
647
|
throw error;
|
|
553
648
|
} finally {
|
|
554
649
|
_authStore.useAuthStore.setState({
|
|
555
650
|
isLoading: false
|
|
556
651
|
});
|
|
557
652
|
}
|
|
558
|
-
}, [storage, oxyServices, loginSuccess, loginFailure, saveActiveSessionId, onAuthStateChange]);
|
|
559
|
-
|
|
560
|
-
// Switch session method
|
|
653
|
+
}, [storage, oxyServices, loginSuccess, loginFailure, saveActiveSessionId, onAuthStateChange, applyLanguagePreference, onError]);
|
|
561
654
|
const switchSession = (0, _react.useCallback)(async sessionId => {
|
|
562
655
|
await switchToSession(sessionId);
|
|
563
656
|
}, [switchToSession]);
|
|
564
|
-
|
|
565
|
-
// Remove session method
|
|
566
657
|
const removeSession = (0, _react.useCallback)(async sessionId => {
|
|
567
658
|
await logout(sessionId);
|
|
568
659
|
}, [logout]);
|
|
569
|
-
|
|
570
|
-
// Refresh sessions method
|
|
571
660
|
const refreshSessions = (0, _react.useCallback)(async () => {
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
661
|
+
if (!activeSessionId) return;
|
|
662
|
+
|
|
663
|
+
// If a refresh is already in progress, return the existing promise
|
|
664
|
+
if (refreshInFlightRef.current) {
|
|
665
|
+
return refreshInFlightRef.current;
|
|
576
666
|
}
|
|
577
|
-
try {
|
|
578
|
-
console.log('refreshSessions: Calling getSessionsBySessionId...');
|
|
579
|
-
const serverSessions = await oxyServices.getSessionsBySessionId(activeSessionId);
|
|
580
|
-
console.log('refreshSessions: Server sessions received:', serverSessions);
|
|
581
|
-
|
|
582
|
-
// Update local sessions with server data
|
|
583
|
-
const updatedSessions = serverSessions.map(serverSession => ({
|
|
584
|
-
sessionId: serverSession.sessionId,
|
|
585
|
-
deviceId: serverSession.deviceId,
|
|
586
|
-
expiresAt: serverSession.expiresAt || new Date().toISOString(),
|
|
587
|
-
lastActive: serverSession.lastActive || new Date().toISOString(),
|
|
588
|
-
userId: serverSession.userId || user?.id
|
|
589
|
-
}));
|
|
590
|
-
console.log('refreshSessions: Updated sessions:', updatedSessions);
|
|
591
|
-
setSessions(updatedSessions);
|
|
592
|
-
console.log('refreshSessions: Sessions updated in state');
|
|
593
|
-
} catch (error) {
|
|
594
|
-
console.error('Refresh sessions error:', error);
|
|
595
667
|
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
const
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
});
|
|
606
|
-
console.log('Found valid session, switching to:', session.sessionId);
|
|
607
|
-
await switchToSession(session.sessionId);
|
|
608
|
-
return; // Successfully switched to another session
|
|
609
|
-
} catch (sessionError) {
|
|
610
|
-
console.log('Session validation failed for:', session.sessionId, sessionError);
|
|
611
|
-
continue; // Try next session
|
|
612
|
-
}
|
|
668
|
+
// Create the refresh promise
|
|
669
|
+
const refreshPromise = (async () => {
|
|
670
|
+
try {
|
|
671
|
+
const deviceSessions = await oxyServices.getDeviceSessions(activeSessionId);
|
|
672
|
+
const allDeviceSessions = mapSessionsToClient(deviceSessions, undefined, user?.id);
|
|
673
|
+
updateSessions(allDeviceSessions, true);
|
|
674
|
+
} catch (error) {
|
|
675
|
+
if (__DEV__) {
|
|
676
|
+
console.warn('Failed to refresh device sessions, falling back to user sessions:', error);
|
|
613
677
|
}
|
|
614
|
-
|
|
678
|
+
try {
|
|
679
|
+
const serverSessions = await oxyServices.getSessionsBySessionId(activeSessionId);
|
|
680
|
+
const userSessions = mapSessionsToClient(serverSessions, undefined, user?.id);
|
|
681
|
+
updateSessions(userSessions, true);
|
|
682
|
+
} catch (fallbackError) {
|
|
683
|
+
if (__DEV__) {
|
|
684
|
+
console.error('Refresh sessions error:', fallbackError);
|
|
685
|
+
}
|
|
615
686
|
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
687
|
+
// If the current session is invalid, try to find another valid session
|
|
688
|
+
if (sessions.length > 1) {
|
|
689
|
+
const otherSessions = sessions.filter(s => s.sessionId !== activeSessionId);
|
|
690
|
+
for (const session of otherSessions) {
|
|
691
|
+
try {
|
|
692
|
+
const validation = await oxyServices.validateSession(session.sessionId, {
|
|
693
|
+
useHeaderValidation: true
|
|
694
|
+
});
|
|
695
|
+
if (validation.valid) {
|
|
696
|
+
await switchToSession(session.sessionId);
|
|
697
|
+
return;
|
|
698
|
+
}
|
|
699
|
+
} catch {
|
|
700
|
+
continue;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
// No valid sessions found, clear all
|
|
706
|
+
updateSessions([], false);
|
|
707
|
+
setActiveSessionId(null);
|
|
708
|
+
logoutStore();
|
|
709
|
+
setMinimalUser(null);
|
|
710
|
+
await clearAllStorage();
|
|
711
|
+
onAuthStateChange?.(null);
|
|
712
|
+
}
|
|
713
|
+
} finally {
|
|
714
|
+
// Clear the in-flight ref when done
|
|
715
|
+
refreshInFlightRef.current = null;
|
|
625
716
|
}
|
|
626
|
-
}
|
|
627
|
-
|
|
717
|
+
})();
|
|
718
|
+
refreshInFlightRef.current = refreshPromise;
|
|
719
|
+
return refreshPromise;
|
|
720
|
+
}, [activeSessionId, oxyServices, user?.id, updateSessions, sessions, switchToSession, logoutStore, clearAllStorage, onAuthStateChange, mapSessionsToClient]);
|
|
628
721
|
|
|
629
722
|
// Device management methods
|
|
630
723
|
const getDeviceSessions = (0, _react.useCallback)(async () => {
|
|
@@ -632,58 +725,67 @@ const OxyProvider = ({
|
|
|
632
725
|
try {
|
|
633
726
|
return await oxyServices.getDeviceSessions(activeSessionId);
|
|
634
727
|
} catch (error) {
|
|
635
|
-
|
|
728
|
+
const errorMessage = error instanceof Error ? error.message : 'Failed to get device sessions';
|
|
729
|
+
onError?.({
|
|
730
|
+
message: errorMessage,
|
|
731
|
+
code: 'GET_DEVICE_SESSIONS_ERROR',
|
|
732
|
+
status: 500
|
|
733
|
+
});
|
|
636
734
|
throw error;
|
|
637
735
|
}
|
|
638
|
-
}, [activeSessionId, oxyServices]);
|
|
736
|
+
}, [activeSessionId, oxyServices, onError]);
|
|
639
737
|
const logoutAllDeviceSessions = (0, _react.useCallback)(async () => {
|
|
640
738
|
if (!activeSessionId) throw new Error('No active session');
|
|
641
739
|
try {
|
|
642
740
|
await oxyServices.logoutAllDeviceSessions(activeSessionId);
|
|
643
|
-
|
|
644
|
-
// Clear all local sessions since we logged out from all devices
|
|
645
|
-
setSessions([]);
|
|
741
|
+
updateSessions([], false);
|
|
646
742
|
setActiveSessionId(null);
|
|
647
743
|
logoutStore();
|
|
648
744
|
setMinimalUser(null);
|
|
649
745
|
await clearAllStorage();
|
|
650
|
-
|
|
651
|
-
onAuthStateChange(null);
|
|
652
|
-
}
|
|
746
|
+
onAuthStateChange?.(null);
|
|
653
747
|
} catch (error) {
|
|
654
|
-
|
|
748
|
+
const errorMessage = error instanceof Error ? error.message : 'Failed to logout all device sessions';
|
|
749
|
+
onError?.({
|
|
750
|
+
message: errorMessage,
|
|
751
|
+
code: 'LOGOUT_ALL_DEVICES_ERROR',
|
|
752
|
+
status: 500
|
|
753
|
+
});
|
|
655
754
|
throw error;
|
|
656
755
|
}
|
|
657
|
-
}, [activeSessionId, oxyServices, logoutStore,
|
|
756
|
+
}, [activeSessionId, oxyServices, logoutStore, clearAllStorage, onAuthStateChange, onError]);
|
|
658
757
|
const updateDeviceName = (0, _react.useCallback)(async deviceName => {
|
|
659
758
|
if (!activeSessionId) throw new Error('No active session');
|
|
660
759
|
try {
|
|
661
760
|
await oxyServices.updateDeviceName(activeSessionId, deviceName);
|
|
662
|
-
|
|
663
|
-
// Update local device info
|
|
664
761
|
await _deviceManager.DeviceManager.updateDeviceName(deviceName);
|
|
665
762
|
} catch (error) {
|
|
666
|
-
|
|
763
|
+
const errorMessage = error instanceof Error ? error.message : 'Failed to update device name';
|
|
764
|
+
onError?.({
|
|
765
|
+
message: errorMessage,
|
|
766
|
+
code: 'UPDATE_DEVICE_NAME_ERROR',
|
|
767
|
+
status: 500
|
|
768
|
+
});
|
|
667
769
|
throw error;
|
|
668
770
|
}
|
|
669
|
-
}, [activeSessionId, oxyServices]);
|
|
771
|
+
}, [activeSessionId, oxyServices, onError]);
|
|
670
772
|
|
|
671
773
|
// Language management method
|
|
672
774
|
const setLanguage = (0, _react.useCallback)(async languageId => {
|
|
673
775
|
if (!storage) throw new Error('Storage not initialized');
|
|
674
776
|
try {
|
|
675
|
-
// Save language preference
|
|
676
777
|
await storage.setItem(keys.language, languageId);
|
|
677
778
|
setCurrentLanguage(languageId);
|
|
678
|
-
console.log(`Language changed to ${languageId}`);
|
|
679
|
-
|
|
680
|
-
// TODO: Here you can add any additional logic needed for app-wide language updates
|
|
681
|
-
// such as updating i18n configuration, refreshing translations, etc.
|
|
682
779
|
} catch (error) {
|
|
683
|
-
|
|
780
|
+
const errorMessage = error instanceof Error ? error.message : 'Failed to save language preference';
|
|
781
|
+
onError?.({
|
|
782
|
+
message: errorMessage,
|
|
783
|
+
code: 'LANGUAGE_SAVE_ERROR',
|
|
784
|
+
status: 500
|
|
785
|
+
});
|
|
684
786
|
throw error;
|
|
685
787
|
}
|
|
686
|
-
}, [storage, keys.language]);
|
|
788
|
+
}, [storage, keys.language, onError]);
|
|
687
789
|
|
|
688
790
|
// Bottom sheet control methods
|
|
689
791
|
const showBottomSheet = (0, _react.useCallback)(screenOrConfig => {
|
|
@@ -698,9 +800,8 @@ const OxyProvider = ({
|
|
|
698
800
|
} else if (bottomSheetRef.current.present) {
|
|
699
801
|
if (__DEV__) console.log('Presenting bottom sheet');
|
|
700
802
|
bottomSheetRef.current.present();
|
|
701
|
-
} else {
|
|
803
|
+
} else if (__DEV__) {
|
|
702
804
|
console.warn('No expand or present method available on bottomSheetRef');
|
|
703
|
-
if (__DEV__) console.log('Available methods on bottomSheetRef.current:', Object.keys(bottomSheetRef.current));
|
|
704
805
|
}
|
|
705
806
|
|
|
706
807
|
// Then navigate to the specified screen if provided
|
|
@@ -718,10 +819,8 @@ const OxyProvider = ({
|
|
|
718
819
|
}
|
|
719
820
|
}, 100);
|
|
720
821
|
}
|
|
721
|
-
} else {
|
|
722
|
-
console.warn('bottomSheetRef is not available');
|
|
723
|
-
console.warn('To fix this, ensure you pass a bottomSheetRef to OxyProvider:');
|
|
724
|
-
console.warn('<OxyProvider baseURL="..." bottomSheetRef={yourBottomSheetRef}>');
|
|
822
|
+
} else if (__DEV__) {
|
|
823
|
+
console.warn('bottomSheetRef is not available. Pass a bottomSheetRef to OxyProvider.');
|
|
725
824
|
}
|
|
726
825
|
}, [bottomSheetRef]);
|
|
727
826
|
const hideBottomSheet = (0, _react.useCallback)(() => {
|
|
@@ -754,41 +853,22 @@ const OxyProvider = ({
|
|
|
754
853
|
if (mod && typeof mod.useFollow === 'function') {
|
|
755
854
|
return mod.useFollow(userId);
|
|
756
855
|
}
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
error: null,
|
|
762
|
-
toggleFollow: async () => {},
|
|
763
|
-
setFollowStatus: () => {},
|
|
764
|
-
fetchStatus: async () => {},
|
|
765
|
-
clearError: () => {},
|
|
766
|
-
followerCount: null,
|
|
767
|
-
followingCount: null,
|
|
768
|
-
isLoadingCounts: false,
|
|
769
|
-
fetchUserCounts: async () => {},
|
|
770
|
-
setFollowerCount: () => {},
|
|
771
|
-
setFollowingCount: () => {}
|
|
772
|
-
};
|
|
856
|
+
if (__DEV__) {
|
|
857
|
+
console.warn('useFollow module did not export a function as expected');
|
|
858
|
+
}
|
|
859
|
+
return createEmptyFollowHook()(userId);
|
|
773
860
|
} catch (e) {
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
error: null,
|
|
779
|
-
toggleFollow: async () => {},
|
|
780
|
-
setFollowStatus: () => {},
|
|
781
|
-
fetchStatus: async () => {},
|
|
782
|
-
clearError: () => {},
|
|
783
|
-
followerCount: null,
|
|
784
|
-
followingCount: null,
|
|
785
|
-
isLoadingCounts: false,
|
|
786
|
-
fetchUserCounts: async () => {},
|
|
787
|
-
setFollowerCount: () => {},
|
|
788
|
-
setFollowingCount: () => {}
|
|
789
|
-
};
|
|
861
|
+
if (__DEV__) {
|
|
862
|
+
console.warn('Failed to dynamically load useFollow hook:', e);
|
|
863
|
+
}
|
|
864
|
+
return createEmptyFollowHook()(userId);
|
|
790
865
|
}
|
|
791
866
|
};
|
|
867
|
+
|
|
868
|
+
// Compute language metadata from currentLanguage
|
|
869
|
+
const languageMetadata = (0, _react.useMemo)(() => (0, _languageUtils.getLanguageMetadata)(currentLanguage), [currentLanguage]);
|
|
870
|
+
const languageName = (0, _react.useMemo)(() => (0, _languageUtils.getLanguageName)(currentLanguage), [currentLanguage]);
|
|
871
|
+
const nativeLanguageName = (0, _react.useMemo)(() => (0, _languageUtils.getNativeLanguageName)(currentLanguage), [currentLanguage]);
|
|
792
872
|
const contextValue = (0, _react.useMemo)(() => ({
|
|
793
873
|
user,
|
|
794
874
|
minimalUser,
|
|
@@ -796,8 +876,12 @@ const OxyProvider = ({
|
|
|
796
876
|
activeSessionId,
|
|
797
877
|
isAuthenticated,
|
|
798
878
|
isLoading,
|
|
879
|
+
isTokenReady: tokenReady,
|
|
799
880
|
error,
|
|
800
881
|
currentLanguage,
|
|
882
|
+
currentLanguageMetadata: languageMetadata,
|
|
883
|
+
currentLanguageName: languageName,
|
|
884
|
+
currentNativeLanguageName: nativeLanguageName,
|
|
801
885
|
login,
|
|
802
886
|
logout,
|
|
803
887
|
logoutAll,
|
|
@@ -819,21 +903,9 @@ const OxyProvider = ({
|
|
|
819
903
|
// Only depend on user ID, not the entire user object
|
|
820
904
|
minimalUser?.id, sessions.length,
|
|
821
905
|
// Only depend on sessions count, not the entire array
|
|
822
|
-
activeSessionId, isAuthenticated, isLoading, error, currentLanguage, login, logout, logoutAll, signUp, completeMfaLogin, switchSession, removeSession, refreshSessions, setLanguage, getDeviceSessions, logoutAllDeviceSessions, updateDeviceName, oxyServices, bottomSheetRef, showBottomSheet, hideBottomSheet]);
|
|
823
|
-
|
|
824
|
-
//
|
|
825
|
-
if (!tokenReady) {
|
|
826
|
-
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
827
|
-
style: {
|
|
828
|
-
flex: 1,
|
|
829
|
-
justifyContent: 'center',
|
|
830
|
-
alignItems: 'center'
|
|
831
|
-
},
|
|
832
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
833
|
-
children: "Loading authentication..."
|
|
834
|
-
})
|
|
835
|
-
});
|
|
836
|
-
}
|
|
906
|
+
activeSessionId, isAuthenticated, isLoading, tokenReady, error, currentLanguage, languageMetadata, languageName, nativeLanguageName, login, logout, logoutAll, signUp, completeMfaLogin, switchSession, removeSession, refreshSessions, setLanguage, getDeviceSessions, logoutAllDeviceSessions, updateDeviceName, oxyServices, bottomSheetRef, showBottomSheet, hideBottomSheet]);
|
|
907
|
+
|
|
908
|
+
// Always render children - let the consuming app decide how to handle token loading state
|
|
837
909
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(OxyContext.Provider, {
|
|
838
910
|
value: contextValue,
|
|
839
911
|
children: children
|