@oxyhq/services 5.16.44 → 5.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -10
- package/lib/commonjs/core/OxyServices.js +1 -1
- package/lib/commonjs/core/index.js +20 -15
- package/lib/commonjs/core/index.js.map +1 -1
- package/lib/commonjs/core/mixins/OxyServices.auth.js +36 -53
- package/lib/commonjs/core/mixins/OxyServices.auth.js.map +1 -1
- package/lib/commonjs/core/mixins/OxyServices.user.js +10 -17
- package/lib/commonjs/core/mixins/OxyServices.user.js.map +1 -1
- package/lib/commonjs/core/services/TokenService.js +27 -13
- package/lib/commonjs/core/services/TokenService.js.map +1 -1
- package/lib/commonjs/crypto/index.js +0 -16
- package/lib/commonjs/crypto/index.js.map +1 -1
- package/lib/commonjs/crypto/keyManager.js +21 -22
- package/lib/commonjs/crypto/keyManager.js.map +1 -1
- package/lib/commonjs/crypto/polyfill.js +1 -10
- package/lib/commonjs/crypto/polyfill.js.map +1 -1
- package/lib/commonjs/crypto/signatureService.js +18 -32
- package/lib/commonjs/crypto/signatureService.js.map +1 -1
- package/lib/commonjs/index.js +13 -134
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/models/interfaces.js +0 -7
- package/lib/commonjs/models/interfaces.js.map +1 -1
- package/lib/commonjs/node/index.js +1 -10
- package/lib/commonjs/node/index.js.map +1 -1
- package/lib/commonjs/ui/components/BottomSheetRouter.js +1 -9
- package/lib/commonjs/ui/components/BottomSheetRouter.js.map +1 -1
- package/lib/commonjs/ui/components/OxyProvider.js +9 -20
- package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
- package/lib/commonjs/ui/context/OxyContext.js +779 -450
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/context/hooks/useAuthOperations.js +551 -0
- package/lib/commonjs/ui/context/hooks/useAuthOperations.js.map +1 -0
- package/lib/commonjs/ui/context/hooks/useDeviceManagement.js +73 -0
- package/lib/commonjs/ui/context/hooks/useDeviceManagement.js.map +1 -0
- package/lib/commonjs/ui/context/hooks/useStorage.js +79 -0
- package/lib/commonjs/ui/context/hooks/useStorage.js.map +1 -0
- package/lib/commonjs/ui/hooks/index.js +0 -20
- package/lib/commonjs/ui/hooks/index.js.map +1 -1
- package/lib/commonjs/ui/hooks/mutations/index.js +0 -12
- package/lib/commonjs/ui/hooks/mutations/index.js.map +1 -1
- package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js +23 -74
- package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js.map +1 -1
- package/lib/commonjs/ui/hooks/queries/index.js +0 -12
- package/lib/commonjs/ui/hooks/queries/index.js.map +1 -1
- package/lib/commonjs/ui/hooks/queries/queryKeys.js +1 -3
- package/lib/commonjs/ui/hooks/queries/queryKeys.js.map +1 -1
- package/lib/commonjs/ui/hooks/queries/useAccountQueries.js +28 -64
- package/lib/commonjs/ui/hooks/queries/useAccountQueries.js.map +1 -1
- package/lib/commonjs/ui/hooks/queries/useServicesQueries.js +6 -4
- package/lib/commonjs/ui/hooks/queries/useServicesQueries.js.map +1 -1
- package/lib/commonjs/ui/hooks/useDeviceManagement.js +73 -0
- package/lib/commonjs/ui/hooks/useDeviceManagement.js.map +1 -0
- package/lib/commonjs/ui/hooks/useProfileEditing.js +5 -3
- package/lib/commonjs/ui/hooks/useProfileEditing.js.map +1 -1
- package/lib/commonjs/ui/hooks/useSessionManagement.js +284 -0
- package/lib/commonjs/ui/hooks/useSessionManagement.js.map +1 -0
- package/lib/commonjs/ui/index.js +2 -10
- package/lib/commonjs/ui/index.js.map +1 -1
- package/lib/commonjs/ui/navigation/routes.js +1 -5
- package/lib/commonjs/ui/navigation/routes.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountCenterScreen.js +4 -9
- package/lib/commonjs/ui/screens/AccountCenterScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js +19 -37
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +5 -5
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/OxyAuthScreen.js +15 -2
- package/lib/commonjs/ui/screens/OxyAuthScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/PrivacySettingsScreen.js +97 -76
- package/lib/commonjs/ui/screens/PrivacySettingsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/ProfileScreen.js +6 -6
- package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
- package/lib/commonjs/ui/stores/authStore.js +6 -54
- package/lib/commonjs/ui/stores/authStore.js.map +1 -1
- package/lib/commonjs/ui/styles/spacing.js +2 -54
- package/lib/commonjs/ui/styles/spacing.js.map +1 -1
- package/lib/commonjs/ui/utils/avatarUtils.js +12 -9
- package/lib/commonjs/ui/utils/avatarUtils.js.map +1 -1
- package/lib/commonjs/ui/utils/sessionHelpers.js +1 -7
- package/lib/commonjs/ui/utils/sessionHelpers.js.map +1 -1
- package/lib/commonjs/utils/deviceManager.js +177 -0
- package/lib/commonjs/utils/deviceManager.js.map +1 -0
- package/lib/commonjs/utils/errorUtils.js +0 -13
- package/lib/commonjs/utils/errorUtils.js.map +1 -1
- package/lib/commonjs/utils/index.js +7 -0
- package/lib/commonjs/utils/index.js.map +1 -1
- package/lib/commonjs/utils/sessionUtils.js +1 -8
- package/lib/commonjs/utils/sessionUtils.js.map +1 -1
- package/lib/commonjs/utils/validationUtils.js +1 -15
- package/lib/commonjs/utils/validationUtils.js.map +1 -1
- package/lib/module/core/OxyServices.js +1 -1
- package/lib/module/core/index.js +4 -6
- package/lib/module/core/index.js.map +1 -1
- package/lib/module/core/mixins/OxyServices.auth.js +36 -53
- package/lib/module/core/mixins/OxyServices.auth.js.map +1 -1
- package/lib/module/core/mixins/OxyServices.user.js +10 -17
- package/lib/module/core/mixins/OxyServices.user.js.map +1 -1
- package/lib/module/core/services/TokenService.js +27 -13
- package/lib/module/core/services/TokenService.js.map +1 -1
- package/lib/module/crypto/index.js +0 -3
- package/lib/module/crypto/index.js.map +1 -1
- package/lib/module/crypto/keyManager.js +21 -22
- package/lib/module/crypto/keyManager.js.map +1 -1
- package/lib/module/crypto/polyfill.js +1 -2
- package/lib/module/crypto/polyfill.js.map +1 -1
- package/lib/module/crypto/signatureService.js +18 -32
- package/lib/module/crypto/signatureService.js.map +1 -1
- package/lib/module/index.js +7 -19
- package/lib/module/index.js.map +1 -1
- package/lib/module/models/interfaces.js +0 -7
- package/lib/module/models/interfaces.js.map +1 -1
- package/lib/module/node/index.js +0 -3
- package/lib/module/node/index.js.map +1 -1
- package/lib/module/ui/components/BottomSheetRouter.js +2 -6
- package/lib/module/ui/components/BottomSheetRouter.js.map +1 -1
- package/lib/module/ui/components/OxyProvider.js +9 -20
- package/lib/module/ui/components/OxyProvider.js.map +1 -1
- package/lib/module/ui/context/OxyContext.js +779 -450
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/context/hooks/useAuthOperations.js +545 -0
- package/lib/module/ui/context/hooks/useAuthOperations.js.map +1 -0
- package/lib/module/ui/context/hooks/useDeviceManagement.js +68 -0
- package/lib/module/ui/context/hooks/useDeviceManagement.js.map +1 -0
- package/lib/module/ui/context/hooks/useStorage.js +74 -0
- package/lib/module/ui/context/hooks/useStorage.js.map +1 -0
- package/lib/module/ui/hooks/index.js +0 -1
- package/lib/module/ui/hooks/index.js.map +1 -1
- package/lib/module/ui/hooks/mutations/index.js +1 -1
- package/lib/module/ui/hooks/mutations/index.js.map +1 -1
- package/lib/module/ui/hooks/mutations/useAccountMutations.js +21 -71
- package/lib/module/ui/hooks/mutations/useAccountMutations.js.map +1 -1
- package/lib/module/ui/hooks/queries/index.js +1 -1
- package/lib/module/ui/hooks/queries/index.js.map +1 -1
- package/lib/module/ui/hooks/queries/queryKeys.js +1 -3
- package/lib/module/ui/hooks/queries/queryKeys.js.map +1 -1
- package/lib/module/ui/hooks/queries/useAccountQueries.js +27 -61
- package/lib/module/ui/hooks/queries/useAccountQueries.js.map +1 -1
- package/lib/module/ui/hooks/queries/useServicesQueries.js +6 -4
- package/lib/module/ui/hooks/queries/useServicesQueries.js.map +1 -1
- package/lib/module/ui/hooks/useDeviceManagement.js +68 -0
- package/lib/module/ui/hooks/useDeviceManagement.js.map +1 -0
- package/lib/module/ui/hooks/useProfileEditing.js +5 -3
- package/lib/module/ui/hooks/useProfileEditing.js.map +1 -1
- package/lib/module/ui/hooks/useSessionManagement.js +279 -0
- package/lib/module/ui/hooks/useSessionManagement.js.map +1 -0
- package/lib/module/ui/index.js +1 -2
- package/lib/module/ui/index.js.map +1 -1
- package/lib/module/ui/navigation/routes.js +1 -5
- package/lib/module/ui/navigation/routes.js.map +1 -1
- package/lib/module/ui/screens/AccountCenterScreen.js +4 -9
- package/lib/module/ui/screens/AccountCenterScreen.js.map +1 -1
- package/lib/module/ui/screens/AccountSettingsScreen.js +19 -37
- package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/module/ui/screens/AccountSwitcherScreen.js +5 -5
- package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
- package/lib/module/ui/screens/OxyAuthScreen.js +15 -2
- package/lib/module/ui/screens/OxyAuthScreen.js.map +1 -1
- package/lib/module/ui/screens/PrivacySettingsScreen.js +98 -77
- package/lib/module/ui/screens/PrivacySettingsScreen.js.map +1 -1
- package/lib/module/ui/screens/ProfileScreen.js +6 -6
- package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
- package/lib/module/ui/stores/authStore.js +6 -54
- package/lib/module/ui/stores/authStore.js.map +1 -1
- package/lib/module/ui/styles/spacing.js +2 -6
- package/lib/module/ui/styles/spacing.js.map +1 -1
- package/lib/module/ui/utils/avatarUtils.js +12 -9
- package/lib/module/ui/utils/avatarUtils.js.map +1 -1
- package/lib/module/ui/utils/sessionHelpers.js +1 -7
- package/lib/module/ui/utils/sessionHelpers.js.map +1 -1
- package/lib/module/utils/deviceManager.js +171 -0
- package/lib/module/utils/deviceManager.js.map +1 -0
- package/lib/module/utils/errorUtils.js +0 -7
- package/lib/module/utils/errorUtils.js.map +1 -1
- package/lib/module/utils/index.js +1 -2
- package/lib/module/utils/index.js.map +1 -1
- package/lib/module/utils/sessionUtils.js +1 -8
- package/lib/module/utils/sessionUtils.js.map +1 -1
- package/lib/module/utils/validationUtils.js +0 -13
- package/lib/module/utils/validationUtils.js.map +1 -1
- package/lib/typescript/core/OxyServices.d.ts +1 -1
- package/lib/typescript/core/index.d.ts +3 -3
- package/lib/typescript/core/index.d.ts.map +1 -1
- package/lib/typescript/core/mixins/OxyServices.auth.d.ts +21 -44
- package/lib/typescript/core/mixins/OxyServices.auth.d.ts.map +1 -1
- package/lib/typescript/core/mixins/OxyServices.user.d.ts +1 -0
- package/lib/typescript/core/mixins/OxyServices.user.d.ts.map +1 -1
- package/lib/typescript/core/mixins/index.d.ts +8 -15
- package/lib/typescript/core/mixins/index.d.ts.map +1 -1
- package/lib/typescript/core/services/TokenService.d.ts.map +1 -1
- package/lib/typescript/crypto/index.d.ts +0 -1
- package/lib/typescript/crypto/index.d.ts.map +1 -1
- package/lib/typescript/crypto/keyManager.d.ts +2 -15
- package/lib/typescript/crypto/keyManager.d.ts.map +1 -1
- package/lib/typescript/crypto/polyfill.d.ts +1 -2
- package/lib/typescript/crypto/polyfill.d.ts.map +1 -1
- package/lib/typescript/crypto/signatureService.d.ts +0 -13
- package/lib/typescript/crypto/signatureService.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +7 -12
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/models/interfaces.d.ts +36 -5
- package/lib/typescript/models/interfaces.d.ts.map +1 -1
- package/lib/typescript/models/session.d.ts +18 -3
- package/lib/typescript/models/session.d.ts.map +1 -1
- package/lib/typescript/node/index.d.ts +0 -1
- package/lib/typescript/node/index.d.ts.map +1 -1
- package/lib/typescript/ui/components/BottomSheetRouter.d.ts +0 -5
- package/lib/typescript/ui/components/BottomSheetRouter.d.ts.map +1 -1
- package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -1
- package/lib/typescript/ui/components/TextField/Addons/Outline.d.ts +2 -2
- package/lib/typescript/ui/components/TextField/helpers.d.ts +2 -2
- package/lib/typescript/ui/components/TextField/types.d.ts +0 -1
- package/lib/typescript/ui/components/TextField/types.d.ts.map +1 -1
- package/lib/typescript/ui/context/OxyContext.d.ts +28 -5
- package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/ui/context/hooks/useAuthOperations.d.ts +59 -0
- package/lib/typescript/ui/context/hooks/useAuthOperations.d.ts.map +1 -0
- package/lib/typescript/ui/context/hooks/useDeviceManagement.d.ts +27 -0
- package/lib/typescript/ui/context/hooks/useDeviceManagement.d.ts.map +1 -0
- package/lib/typescript/ui/context/hooks/useStorage.d.ts +22 -0
- package/lib/typescript/ui/context/hooks/useStorage.d.ts.map +1 -0
- package/lib/typescript/ui/hooks/index.d.ts +0 -1
- package/lib/typescript/ui/hooks/index.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/mutations/index.d.ts +1 -1
- package/lib/typescript/ui/hooks/mutations/index.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/mutations/useAccountMutations.d.ts +8 -19
- package/lib/typescript/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/mutations/useServicesMutations.d.ts +1 -1
- package/lib/typescript/ui/hooks/mutations/useServicesMutations.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/queries/index.d.ts +1 -1
- package/lib/typescript/ui/hooks/queries/index.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/queries/queryKeys.d.ts +0 -2
- package/lib/typescript/ui/hooks/queries/queryKeys.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/queries/useAccountQueries.d.ts +5 -17
- package/lib/typescript/ui/hooks/queries/useAccountQueries.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/queries/useServicesQueries.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/useDeviceManagement.d.ts +27 -0
- package/lib/typescript/ui/hooks/useDeviceManagement.d.ts.map +1 -0
- package/lib/typescript/ui/hooks/useProfileEditing.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/useSessionManagement.d.ts +41 -0
- package/lib/typescript/ui/hooks/useSessionManagement.d.ts.map +1 -0
- package/lib/typescript/ui/index.d.ts +0 -1
- package/lib/typescript/ui/index.d.ts.map +1 -1
- package/lib/typescript/ui/navigation/routes.d.ts +1 -1
- package/lib/typescript/ui/navigation/routes.d.ts.map +1 -1
- package/lib/typescript/ui/screens/AccountCenterScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/OxyAuthScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/PrivacySettingsScreen.d.ts.map +1 -1
- package/lib/typescript/ui/stores/authStore.d.ts +1 -8
- package/lib/typescript/ui/stores/authStore.d.ts.map +1 -1
- package/lib/typescript/ui/styles/spacing.d.ts +0 -5
- package/lib/typescript/ui/styles/spacing.d.ts.map +1 -1
- package/lib/typescript/ui/utils/avatarUtils.d.ts +4 -1
- package/lib/typescript/ui/utils/avatarUtils.d.ts.map +1 -1
- package/lib/typescript/ui/utils/sessionHelpers.d.ts +0 -1
- package/lib/typescript/ui/utils/sessionHelpers.d.ts.map +1 -1
- package/lib/typescript/utils/deviceManager.d.ts +66 -0
- package/lib/typescript/utils/deviceManager.d.ts.map +1 -0
- package/lib/typescript/utils/errorUtils.d.ts +0 -6
- package/lib/typescript/utils/errorUtils.d.ts.map +1 -1
- package/lib/typescript/utils/index.d.ts +2 -0
- package/lib/typescript/utils/index.d.ts.map +1 -1
- package/lib/typescript/utils/sessionUtils.d.ts.map +1 -1
- package/lib/typescript/utils/validationUtils.d.ts +0 -8
- package/lib/typescript/utils/validationUtils.d.ts.map +1 -1
- package/package.json +1 -6
- package/src/core/OxyServices.ts +1 -1
- package/src/core/index.ts +5 -8
- package/src/core/mixins/OxyServices.auth.ts +44 -87
- package/src/core/mixins/OxyServices.user.ts +10 -18
- package/src/core/services/TokenService.ts +27 -16
- package/src/crypto/index.ts +1 -3
- package/src/crypto/keyManager.ts +21 -30
- package/src/crypto/polyfill.ts +1 -2
- package/src/crypto/signatureService.ts +19 -43
- package/src/index.ts +6 -41
- package/src/models/interfaces.ts +39 -12
- package/src/models/session.ts +19 -7
- package/src/node/index.ts +0 -3
- package/src/ui/components/BottomSheetRouter.tsx +1 -6
- package/src/ui/components/OxyProvider.tsx +10 -17
- package/src/ui/components/TextField/Addons/Outline.tsx +2 -2
- package/src/ui/components/TextField/helpers.tsx +2 -2
- package/src/ui/components/TextField/types.tsx +1 -1
- package/src/ui/context/OxyContext.tsx +831 -463
- package/src/ui/context/hooks/useAuthOperations.ts +620 -0
- package/src/ui/context/hooks/useDeviceManagement.ts +108 -0
- package/src/ui/context/hooks/useStorage.ts +104 -0
- package/src/ui/hooks/index.ts +1 -2
- package/src/ui/hooks/mutations/index.ts +0 -2
- package/src/ui/hooks/mutations/useAccountMutations.ts +20 -66
- package/src/ui/hooks/queries/index.ts +0 -2
- package/src/ui/hooks/queries/queryKeys.ts +0 -2
- package/src/ui/hooks/queries/useAccountQueries.ts +19 -53
- package/src/ui/hooks/queries/useServicesQueries.ts +5 -5
- package/src/ui/hooks/useDeviceManagement.ts +108 -0
- package/src/ui/hooks/useProfileEditing.ts +3 -3
- package/src/ui/hooks/useSessionManagement.ts +405 -0
- package/src/ui/index.ts +1 -2
- package/src/ui/navigation/routes.ts +2 -6
- package/src/ui/screens/AccountCenterScreen.tsx +4 -9
- package/src/ui/screens/AccountSettingsScreen.tsx +31 -49
- package/src/ui/screens/AccountSwitcherScreen.tsx +5 -5
- package/src/ui/screens/OxyAuthScreen.tsx +19 -4
- package/src/ui/screens/PrivacySettingsScreen.tsx +101 -67
- package/src/ui/screens/ProfileScreen.tsx +10 -10
- package/src/ui/stores/authStore.ts +8 -48
- package/src/ui/styles/spacing.ts +2 -15
- package/src/ui/utils/avatarUtils.ts +21 -19
- package/src/ui/utils/sessionHelpers.ts +0 -7
- package/src/utils/__tests__/validationUtils.test.ts +1 -16
- package/src/utils/deviceManager.ts +198 -0
- package/src/utils/errorUtils.ts +1 -8
- package/src/utils/index.ts +2 -1
- package/src/utils/sessionUtils.ts +0 -8
- package/src/utils/validationUtils.ts +0 -12
- package/lib/commonjs/adapters/expo/crypto.js +0 -56
- package/lib/commonjs/adapters/expo/crypto.js.map +0 -1
- package/lib/commonjs/adapters/expo/fetch.js +0 -30
- package/lib/commonjs/adapters/expo/fetch.js.map +0 -1
- package/lib/commonjs/adapters/expo/index.js +0 -48
- package/lib/commonjs/adapters/expo/index.js.map +0 -1
- package/lib/commonjs/adapters/expo/storage.js +0 -201
- package/lib/commonjs/adapters/expo/storage.js.map +0 -1
- package/lib/commonjs/adapters/index.js +0 -48
- package/lib/commonjs/adapters/index.js.map +0 -1
- package/lib/commonjs/adapters/node/crypto.js +0 -40
- package/lib/commonjs/adapters/node/crypto.js.map +0 -1
- package/lib/commonjs/adapters/node/fetch.js +0 -62
- package/lib/commonjs/adapters/node/fetch.js.map +0 -1
- package/lib/commonjs/adapters/node/index.js +0 -34
- package/lib/commonjs/adapters/node/index.js.map +0 -1
- package/lib/commonjs/adapters/node/storage.js +0 -163
- package/lib/commonjs/adapters/node/storage.js.map +0 -1
- package/lib/commonjs/core/identity-session/DeviceManager.js +0 -237
- package/lib/commonjs/core/identity-session/DeviceManager.js.map +0 -1
- package/lib/commonjs/core/identity-session/INTEGRATION_GUIDE.md +0 -287
- package/lib/commonjs/core/identity-session/IdentityManager.js +0 -400
- package/lib/commonjs/core/identity-session/IdentityManager.js.map +0 -1
- package/lib/commonjs/core/identity-session/IdentitySessionCore.js +0 -394
- package/lib/commonjs/core/identity-session/IdentitySessionCore.js.map +0 -1
- package/lib/commonjs/core/identity-session/RefreshManager.js +0 -137
- package/lib/commonjs/core/identity-session/RefreshManager.js.map +0 -1
- package/lib/commonjs/core/identity-session/SessionManager.js +0 -427
- package/lib/commonjs/core/identity-session/SessionManager.js.map +0 -1
- package/lib/commonjs/core/identity-session/createIdentitySessionCore.js +0 -24
- package/lib/commonjs/core/identity-session/createIdentitySessionCore.js.map +0 -1
- package/lib/commonjs/core/identity-session/errors.js +0 -176
- package/lib/commonjs/core/identity-session/errors.js.map +0 -1
- package/lib/commonjs/core/identity-session/index.js +0 -80
- package/lib/commonjs/core/identity-session/index.js.map +0 -1
- package/lib/commonjs/core/identity-session/types.js +0 -2
- package/lib/commonjs/core/identity-session/types.js.map +0 -1
- package/lib/commonjs/crypto/README.md +0 -142
- package/lib/commonjs/crypto/core.js +0 -147
- package/lib/commonjs/crypto/core.js.map +0 -1
- package/lib/commonjs/node/signatureService.js +0 -107
- package/lib/commonjs/node/signatureService.js.map +0 -1
- package/lib/commonjs/ui/hooks/auth/index.js +0 -37
- package/lib/commonjs/ui/hooks/auth/index.js.map +0 -1
- package/lib/commonjs/ui/hooks/auth/useUsernameValidation.js +0 -171
- package/lib/commonjs/ui/hooks/auth/useUsernameValidation.js.map +0 -1
- package/lib/commonjs/ui/hooks/useAvatarPicker.js +0 -52
- package/lib/commonjs/ui/hooks/useAvatarPicker.js.map +0 -1
- package/lib/commonjs/ui/hooks/useIdentityTransfer.js +0 -125
- package/lib/commonjs/ui/hooks/useIdentityTransfer.js.map +0 -1
- package/lib/commonjs/ui/hooks/useTransferCodesPersistence.js +0 -81
- package/lib/commonjs/ui/hooks/useTransferCodesPersistence.js.map +0 -1
- package/lib/commonjs/ui/hooks/useTransferQueries.js +0 -85
- package/lib/commonjs/ui/hooks/useTransferQueries.js.map +0 -1
- package/lib/commonjs/ui/stores/transferStore.js +0 -157
- package/lib/commonjs/ui/stores/transferStore.js.map +0 -1
- package/lib/module/adapters/expo/crypto.js +0 -51
- package/lib/module/adapters/expo/crypto.js.map +0 -1
- package/lib/module/adapters/expo/fetch.js +0 -26
- package/lib/module/adapters/expo/fetch.js.map +0 -1
- package/lib/module/adapters/expo/index.js +0 -45
- package/lib/module/adapters/expo/index.js.map +0 -1
- package/lib/module/adapters/expo/storage.js +0 -198
- package/lib/module/adapters/expo/storage.js.map +0 -1
- package/lib/module/adapters/index.js +0 -45
- package/lib/module/adapters/index.js.map +0 -1
- package/lib/module/adapters/node/crypto.js +0 -36
- package/lib/module/adapters/node/crypto.js.map +0 -1
- package/lib/module/adapters/node/fetch.js +0 -57
- package/lib/module/adapters/node/fetch.js.map +0 -1
- package/lib/module/adapters/node/index.js +0 -31
- package/lib/module/adapters/node/index.js.map +0 -1
- package/lib/module/adapters/node/storage.js +0 -159
- package/lib/module/adapters/node/storage.js.map +0 -1
- package/lib/module/core/identity-session/DeviceManager.js +0 -232
- package/lib/module/core/identity-session/DeviceManager.js.map +0 -1
- package/lib/module/core/identity-session/INTEGRATION_GUIDE.md +0 -287
- package/lib/module/core/identity-session/IdentityManager.js +0 -395
- package/lib/module/core/identity-session/IdentityManager.js.map +0 -1
- package/lib/module/core/identity-session/IdentitySessionCore.js +0 -390
- package/lib/module/core/identity-session/IdentitySessionCore.js.map +0 -1
- package/lib/module/core/identity-session/RefreshManager.js +0 -132
- package/lib/module/core/identity-session/RefreshManager.js.map +0 -1
- package/lib/module/core/identity-session/SessionManager.js +0 -422
- package/lib/module/core/identity-session/SessionManager.js.map +0 -1
- package/lib/module/core/identity-session/createIdentitySessionCore.js +0 -21
- package/lib/module/core/identity-session/createIdentitySessionCore.js.map +0 -1
- package/lib/module/core/identity-session/errors.js +0 -170
- package/lib/module/core/identity-session/errors.js.map +0 -1
- package/lib/module/core/identity-session/index.js +0 -17
- package/lib/module/core/identity-session/index.js.map +0 -1
- package/lib/module/core/identity-session/types.js +0 -2
- package/lib/module/core/identity-session/types.js.map +0 -1
- package/lib/module/crypto/README.md +0 -142
- package/lib/module/crypto/core.js +0 -133
- package/lib/module/crypto/core.js.map +0 -1
- package/lib/module/node/signatureService.js +0 -101
- package/lib/module/node/signatureService.js.map +0 -1
- package/lib/module/ui/hooks/auth/index.js +0 -7
- package/lib/module/ui/hooks/auth/index.js.map +0 -1
- package/lib/module/ui/hooks/auth/useUsernameValidation.js +0 -167
- package/lib/module/ui/hooks/auth/useUsernameValidation.js.map +0 -1
- package/lib/module/ui/hooks/useAvatarPicker.js +0 -48
- package/lib/module/ui/hooks/useAvatarPicker.js.map +0 -1
- package/lib/module/ui/hooks/useIdentityTransfer.js +0 -121
- package/lib/module/ui/hooks/useIdentityTransfer.js.map +0 -1
- package/lib/module/ui/hooks/useTransferCodesPersistence.js +0 -77
- package/lib/module/ui/hooks/useTransferCodesPersistence.js.map +0 -1
- package/lib/module/ui/hooks/useTransferQueries.js +0 -80
- package/lib/module/ui/hooks/useTransferQueries.js.map +0 -1
- package/lib/module/ui/stores/transferStore.js +0 -152
- package/lib/module/ui/stores/transferStore.js.map +0 -1
- package/lib/typescript/adapters/expo/crypto.d.ts +0 -17
- package/lib/typescript/adapters/expo/crypto.d.ts.map +0 -1
- package/lib/typescript/adapters/expo/fetch.d.ts +0 -16
- package/lib/typescript/adapters/expo/fetch.d.ts.map +0 -1
- package/lib/typescript/adapters/expo/index.d.ts +0 -23
- package/lib/typescript/adapters/expo/index.d.ts.map +0 -1
- package/lib/typescript/adapters/expo/storage.d.ts +0 -23
- package/lib/typescript/adapters/expo/storage.d.ts.map +0 -1
- package/lib/typescript/adapters/index.d.ts +0 -17
- package/lib/typescript/adapters/index.d.ts.map +0 -1
- package/lib/typescript/adapters/node/crypto.d.ts +0 -17
- package/lib/typescript/adapters/node/crypto.d.ts.map +0 -1
- package/lib/typescript/adapters/node/fetch.d.ts +0 -16
- package/lib/typescript/adapters/node/fetch.d.ts.map +0 -1
- package/lib/typescript/adapters/node/index.d.ts +0 -23
- package/lib/typescript/adapters/node/index.d.ts.map +0 -1
- package/lib/typescript/adapters/node/storage.d.ts +0 -23
- package/lib/typescript/adapters/node/storage.d.ts.map +0 -1
- package/lib/typescript/core/identity-session/DeviceManager.d.ts +0 -64
- package/lib/typescript/core/identity-session/DeviceManager.d.ts.map +0 -1
- package/lib/typescript/core/identity-session/IdentityManager.d.ts +0 -88
- package/lib/typescript/core/identity-session/IdentityManager.d.ts.map +0 -1
- package/lib/typescript/core/identity-session/IdentitySessionCore.d.ts +0 -141
- package/lib/typescript/core/identity-session/IdentitySessionCore.d.ts.map +0 -1
- package/lib/typescript/core/identity-session/RefreshManager.d.ts +0 -36
- package/lib/typescript/core/identity-session/RefreshManager.d.ts.map +0 -1
- package/lib/typescript/core/identity-session/SessionManager.d.ts +0 -104
- package/lib/typescript/core/identity-session/SessionManager.d.ts.map +0 -1
- package/lib/typescript/core/identity-session/createIdentitySessionCore.d.ts +0 -11
- package/lib/typescript/core/identity-session/createIdentitySessionCore.d.ts.map +0 -1
- package/lib/typescript/core/identity-session/errors.d.ts +0 -63
- package/lib/typescript/core/identity-session/errors.d.ts.map +0 -1
- package/lib/typescript/core/identity-session/index.d.ts +0 -14
- package/lib/typescript/core/identity-session/index.d.ts.map +0 -1
- package/lib/typescript/core/identity-session/types.d.ts +0 -196
- package/lib/typescript/core/identity-session/types.d.ts.map +0 -1
- package/lib/typescript/crypto/core.d.ts +0 -56
- package/lib/typescript/crypto/core.d.ts.map +0 -1
- package/lib/typescript/node/signatureService.d.ts +0 -55
- package/lib/typescript/node/signatureService.d.ts.map +0 -1
- package/lib/typescript/ui/hooks/auth/index.d.ts +0 -6
- package/lib/typescript/ui/hooks/auth/index.d.ts.map +0 -1
- package/lib/typescript/ui/hooks/auth/useUsernameValidation.d.ts +0 -32
- package/lib/typescript/ui/hooks/auth/useUsernameValidation.d.ts.map +0 -1
- package/lib/typescript/ui/hooks/useAvatarPicker.d.ts +0 -18
- package/lib/typescript/ui/hooks/useAvatarPicker.d.ts.map +0 -1
- package/lib/typescript/ui/hooks/useIdentityTransfer.d.ts +0 -24
- package/lib/typescript/ui/hooks/useIdentityTransfer.d.ts.map +0 -1
- package/lib/typescript/ui/hooks/useTransferCodesPersistence.d.ts +0 -6
- package/lib/typescript/ui/hooks/useTransferCodesPersistence.d.ts.map +0 -1
- package/lib/typescript/ui/hooks/useTransferQueries.d.ts +0 -26
- package/lib/typescript/ui/hooks/useTransferQueries.d.ts.map +0 -1
- package/lib/typescript/ui/stores/transferStore.d.ts +0 -36
- package/lib/typescript/ui/stores/transferStore.d.ts.map +0 -1
- package/src/adapters/expo/crypto.ts +0 -55
- package/src/adapters/expo/fetch.ts +0 -28
- package/src/adapters/expo/index.ts +0 -51
- package/src/adapters/expo/storage.ts +0 -228
- package/src/adapters/index.ts +0 -48
- package/src/adapters/node/crypto.ts +0 -39
- package/src/adapters/node/fetch.ts +0 -59
- package/src/adapters/node/index.ts +0 -37
- package/src/adapters/node/storage.ts +0 -170
- package/src/core/identity-session/DeviceManager.ts +0 -273
- package/src/core/identity-session/INTEGRATION_GUIDE.md +0 -287
- package/src/core/identity-session/IdentityManager.ts +0 -474
- package/src/core/identity-session/IdentitySessionCore.ts +0 -464
- package/src/core/identity-session/RefreshManager.ts +0 -189
- package/src/core/identity-session/SessionManager.ts +0 -500
- package/src/core/identity-session/createIdentitySessionCore.ts +0 -19
- package/src/core/identity-session/errors.ts +0 -197
- package/src/core/identity-session/index.ts +0 -15
- package/src/core/identity-session/types.ts +0 -188
- package/src/crypto/README.md +0 -142
- package/src/crypto/__tests__/core.test.ts +0 -203
- package/src/crypto/core.ts +0 -142
- package/src/node/signatureService.ts +0 -126
- package/src/ui/hooks/auth/index.ts +0 -9
- package/src/ui/hooks/auth/useUsernameValidation.ts +0 -177
- package/src/ui/hooks/useAvatarPicker.ts +0 -62
- package/src/ui/hooks/useIdentityTransfer.ts +0 -135
- package/src/ui/hooks/useTransferCodesPersistence.ts +0 -80
- package/src/ui/hooks/useTransferQueries.ts +0 -102
- package/src/ui/stores/transferStore.ts +0 -201
|
@@ -5,6 +5,7 @@ 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");
|
|
8
9
|
var _core = require("../../core");
|
|
9
10
|
var _sonner = require("../../lib/sonner");
|
|
10
11
|
var _authStore = require("../stores/authStore");
|
|
@@ -12,20 +13,48 @@ var _shallow = require("zustand/react/shallow");
|
|
|
12
13
|
var _useSessionSocket = require("../hooks/useSessionSocket");
|
|
13
14
|
var _useStorage = require("../hooks/useStorage");
|
|
14
15
|
var _useLanguageManagement = require("../hooks/useLanguageManagement");
|
|
16
|
+
var _useSessionManagement = require("../hooks/useSessionManagement");
|
|
17
|
+
var _useAuthOperations = require("./hooks/useAuthOperations");
|
|
18
|
+
var _useDeviceManagement = require("../hooks/useDeviceManagement");
|
|
15
19
|
var _storageHelpers = require("../utils/storageHelpers");
|
|
16
20
|
var _errorHandlers = require("../utils/errorHandlers");
|
|
17
21
|
var _bottomSheetManager = require("../navigation/bottomSheetManager");
|
|
18
22
|
var _reactQuery = require("@tanstack/react-query");
|
|
23
|
+
var _queries = require("../hooks/queries");
|
|
19
24
|
var _queryClient = require("../hooks/queryClient");
|
|
20
|
-
var
|
|
25
|
+
var _crypto = require("../../crypto");
|
|
26
|
+
var _i18n = require("../../i18n");
|
|
27
|
+
var _avatarUtils = require("../utils/avatarUtils");
|
|
21
28
|
var _accountStore = require("../stores/accountStore");
|
|
22
|
-
var
|
|
23
|
-
var _useTransferQueries = require("../hooks/useTransferQueries");
|
|
24
|
-
var _useTransferCodesPersistence = require("../hooks/useTransferCodesPersistence");
|
|
25
|
-
var _useIdentityTransfer = require("../hooks/useIdentityTransfer");
|
|
26
|
-
var _useAvatarPicker = require("../hooks/useAvatarPicker");
|
|
29
|
+
var _loggerUtils = require("../../utils/loggerUtils");
|
|
27
30
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
28
31
|
const OxyContext = /*#__PURE__*/(0, _react.createContext)(null);
|
|
32
|
+
let cachedUseFollowHook = null;
|
|
33
|
+
const loadUseFollowHook = () => {
|
|
34
|
+
if (cachedUseFollowHook) {
|
|
35
|
+
return cachedUseFollowHook;
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
39
|
+
const {
|
|
40
|
+
useFollow
|
|
41
|
+
} = require('../hooks/useFollow');
|
|
42
|
+
cachedUseFollowHook = useFollow;
|
|
43
|
+
return cachedUseFollowHook;
|
|
44
|
+
} catch (error) {
|
|
45
|
+
if (__DEV__) {
|
|
46
|
+
_loggerUtils.logger.warn('useFollow hook is not available. Please import useFollow from @oxyhq/services directly.', {
|
|
47
|
+
component: 'OxyContext',
|
|
48
|
+
method: 'loadUseFollowHook'
|
|
49
|
+
}, error);
|
|
50
|
+
}
|
|
51
|
+
const fallback = () => {
|
|
52
|
+
throw new Error('useFollow hook is only available in the UI bundle. Import it from @oxyhq/services.');
|
|
53
|
+
};
|
|
54
|
+
cachedUseFollowHook = fallback;
|
|
55
|
+
return cachedUseFollowHook;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
29
58
|
const OxyProvider = ({
|
|
30
59
|
children,
|
|
31
60
|
oxyServices: providedOxyServices,
|
|
@@ -48,8 +77,7 @@ const OxyProvider = ({
|
|
|
48
77
|
}
|
|
49
78
|
const oxyServices = oxyServicesRef.current;
|
|
50
79
|
const {
|
|
51
|
-
|
|
52
|
-
isAuthenticated: isAuthenticatedFromStore,
|
|
80
|
+
isAuthenticated,
|
|
53
81
|
isLoading,
|
|
54
82
|
error,
|
|
55
83
|
loginSuccess,
|
|
@@ -61,7 +89,6 @@ const OxyProvider = ({
|
|
|
61
89
|
setIdentitySynced,
|
|
62
90
|
setSyncing
|
|
63
91
|
} = (0, _authStore.useAuthStore)((0, _shallow.useShallow)(state => ({
|
|
64
|
-
user: state.user,
|
|
65
92
|
isAuthenticated: state.isAuthenticated,
|
|
66
93
|
isLoading: state.isLoading,
|
|
67
94
|
error: state.error,
|
|
@@ -75,6 +102,7 @@ const OxyProvider = ({
|
|
|
75
102
|
setSyncing: state.setSyncing
|
|
76
103
|
})));
|
|
77
104
|
const [tokenReady, setTokenReady] = (0, _react.useState)(true);
|
|
105
|
+
const initializedRef = (0, _react.useRef)(false);
|
|
78
106
|
const setAuthState = _authStore.useAuthStore.setState;
|
|
79
107
|
const logger = (0, _react.useCallback)((message, err) => {
|
|
80
108
|
if (__DEV__) {
|
|
@@ -94,29 +122,48 @@ const OxyProvider = ({
|
|
|
94
122
|
logger
|
|
95
123
|
});
|
|
96
124
|
|
|
97
|
-
//
|
|
98
|
-
|
|
99
|
-
const [isCoreInitialized, setIsCoreInitialized] = (0, _react.useState)(false);
|
|
125
|
+
// Identity integrity check and auto-restore on startup
|
|
126
|
+
// Skip on web platform - identity storage is only available on native platforms
|
|
100
127
|
(0, _react.useEffect)(() => {
|
|
101
|
-
|
|
102
|
-
|
|
128
|
+
if (!storage || !isStorageReady) return;
|
|
129
|
+
if (_reactNative.Platform.OS === 'web') return; // Identity operations are native-only
|
|
130
|
+
|
|
131
|
+
const checkAndRestoreIdentity = async () => {
|
|
103
132
|
try {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
133
|
+
// Check if identity exists and verify integrity
|
|
134
|
+
const hasIdentity = await _crypto.KeyManager.hasIdentity();
|
|
135
|
+
if (hasIdentity) {
|
|
136
|
+
const isValid = await _crypto.KeyManager.verifyIdentityIntegrity();
|
|
137
|
+
if (!isValid) {
|
|
138
|
+
// Try to restore from backup
|
|
139
|
+
const restored = await _crypto.KeyManager.restoreIdentityFromBackup();
|
|
140
|
+
if (__DEV__) {
|
|
141
|
+
logger(restored ? 'Identity restored from backup successfully' : 'Identity integrity check failed - user may need to restore from backup file');
|
|
142
|
+
}
|
|
143
|
+
} else {
|
|
144
|
+
// Identity is valid - ensure backup is up to date
|
|
145
|
+
await _crypto.KeyManager.backupIdentity();
|
|
146
|
+
}
|
|
147
|
+
} else {
|
|
148
|
+
// No identity - try to restore from backup
|
|
149
|
+
const restored = await _crypto.KeyManager.restoreIdentityFromBackup();
|
|
150
|
+
if (restored && __DEV__) {
|
|
151
|
+
logger('Identity restored from backup on startup');
|
|
152
|
+
}
|
|
108
153
|
}
|
|
109
154
|
} catch (error) {
|
|
110
155
|
if (__DEV__) {
|
|
111
|
-
logger('
|
|
156
|
+
logger('Error during identity integrity check', error);
|
|
112
157
|
}
|
|
158
|
+
// Don't block app startup - user can recover with backup file
|
|
113
159
|
}
|
|
114
160
|
};
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
161
|
+
checkAndRestoreIdentity();
|
|
162
|
+
}, [storage, isStorageReady, logger]);
|
|
163
|
+
|
|
164
|
+
// Offline queuing is now handled by TanStack Query mutations
|
|
165
|
+
// No need for custom offline queue
|
|
166
|
+
|
|
120
167
|
const {
|
|
121
168
|
currentLanguage,
|
|
122
169
|
metadata: currentLanguageMetadata,
|
|
@@ -131,112 +178,79 @@ const OxyProvider = ({
|
|
|
131
178
|
logger
|
|
132
179
|
});
|
|
133
180
|
const queryClient = (0, _reactQuery.useQueryClient)();
|
|
181
|
+
const {
|
|
182
|
+
sessions,
|
|
183
|
+
activeSessionId,
|
|
184
|
+
setActiveSessionId,
|
|
185
|
+
updateSessions,
|
|
186
|
+
switchSession,
|
|
187
|
+
refreshSessions,
|
|
188
|
+
clearSessionState,
|
|
189
|
+
saveActiveSessionId,
|
|
190
|
+
trackRemovedSession
|
|
191
|
+
} = (0, _useSessionManagement.useSessionManagement)({
|
|
192
|
+
oxyServices,
|
|
193
|
+
storage,
|
|
194
|
+
storageKeyPrefix,
|
|
195
|
+
loginSuccess,
|
|
196
|
+
logoutStore,
|
|
197
|
+
applyLanguagePreference,
|
|
198
|
+
onAuthStateChange,
|
|
199
|
+
onError,
|
|
200
|
+
setAuthError: message => setAuthState({
|
|
201
|
+
error: message
|
|
202
|
+
}),
|
|
203
|
+
logger,
|
|
204
|
+
setTokenReady,
|
|
205
|
+
queryClient
|
|
206
|
+
});
|
|
134
207
|
|
|
135
|
-
//
|
|
136
|
-
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
208
|
+
// Get current user from query (no persistent cache - always fetch fresh)
|
|
209
|
+
// Services never caches profile - always fetch from backend
|
|
210
|
+
const {
|
|
211
|
+
data: userData
|
|
212
|
+
} = (0, _queries.useCurrentUser)({
|
|
213
|
+
enabled: isAuthenticated && !!activeSessionId
|
|
214
|
+
});
|
|
215
|
+
const user = userData ?? null;
|
|
216
|
+
const {
|
|
217
|
+
createIdentity,
|
|
218
|
+
importIdentity: importIdentityBase,
|
|
219
|
+
signIn,
|
|
220
|
+
logout,
|
|
221
|
+
logoutAll,
|
|
222
|
+
hasIdentity,
|
|
223
|
+
getPublicKey,
|
|
224
|
+
isIdentitySynced,
|
|
225
|
+
syncIdentity: syncIdentityBase
|
|
226
|
+
} = (0, _useAuthOperations.useAuthOperations)({
|
|
227
|
+
oxyServices,
|
|
228
|
+
storage,
|
|
229
|
+
sessions,
|
|
230
|
+
activeSessionId,
|
|
231
|
+
setActiveSessionId,
|
|
232
|
+
updateSessions,
|
|
233
|
+
saveActiveSessionId,
|
|
234
|
+
clearSessionState,
|
|
235
|
+
switchSession,
|
|
236
|
+
applyLanguagePreference,
|
|
237
|
+
onAuthStateChange,
|
|
238
|
+
onError,
|
|
239
|
+
loginSuccess,
|
|
240
|
+
loginFailure,
|
|
241
|
+
logoutStore,
|
|
242
|
+
setAuthState,
|
|
243
|
+
setIdentitySynced,
|
|
244
|
+
setSyncing,
|
|
245
|
+
logger
|
|
246
|
+
});
|
|
171
247
|
|
|
172
|
-
//
|
|
173
|
-
(0, _react.
|
|
174
|
-
if (!identityCore || !isCoreInitialized) return;
|
|
175
|
-
const unsubscribe = identityCore.subscribe(event => {
|
|
176
|
-
if (event.type === 'session:created' || event.type === 'session:refreshed' || event.type === 'session:invalidated' || event.type === 'session:all-invalidated') {
|
|
177
|
-
loadSessionsFromCore();
|
|
178
|
-
}
|
|
179
|
-
});
|
|
180
|
-
return unsubscribe;
|
|
181
|
-
}, [identityCore, isCoreInitialized, loadSessionsFromCore]);
|
|
182
|
-
|
|
183
|
-
// Identity operations using core
|
|
184
|
-
const hasIdentity = (0, _react.useCallback)(async () => {
|
|
185
|
-
if (!identityCore || !isCoreInitialized) return false;
|
|
186
|
-
return await identityCore.hasIdentity();
|
|
187
|
-
}, [identityCore, isCoreInitialized]);
|
|
188
|
-
const getPublicKey = (0, _react.useCallback)(async () => {
|
|
189
|
-
if (!identityCore || !isCoreInitialized) return null;
|
|
190
|
-
return await identityCore.getPublicKey();
|
|
191
|
-
}, [identityCore, isCoreInitialized]);
|
|
192
|
-
const isIdentitySynced = (0, _react.useCallback)(async () => {
|
|
193
|
-
if (!storage) return false;
|
|
194
|
-
const synced = await storage.getItem('oxy_identity_synced');
|
|
195
|
-
return synced === 'true';
|
|
196
|
-
}, [storage]);
|
|
197
|
-
const createIdentity = (0, _react.useCallback)(async username => {
|
|
198
|
-
if (!identityCore || !isCoreInitialized) {
|
|
199
|
-
throw new Error('Identity core not initialized');
|
|
200
|
-
}
|
|
201
|
-
setSyncing(true);
|
|
202
|
-
try {
|
|
203
|
-
// Create identity using core
|
|
204
|
-
const identity = await identityCore.createIdentity(username);
|
|
248
|
+
// syncIdentity - TanStack Query handles offline mutations automatically
|
|
249
|
+
const syncIdentity = (0, _react.useCallback)(() => syncIdentityBase(), [syncIdentityBase]);
|
|
205
250
|
|
|
206
|
-
|
|
207
|
-
let synced = false;
|
|
208
|
-
try {
|
|
209
|
-
const {
|
|
210
|
-
signature,
|
|
211
|
-
publicKey,
|
|
212
|
-
timestamp
|
|
213
|
-
} = await identityCore.createRegistrationSignature();
|
|
214
|
-
const result = await oxyServices.register(publicKey, signature, timestamp, username);
|
|
215
|
-
if (result?.user) {
|
|
216
|
-
loginSuccess(result.user);
|
|
217
|
-
synced = true;
|
|
218
|
-
await storage?.setItem('oxy_identity_synced', 'true');
|
|
219
|
-
setIdentitySynced(true);
|
|
220
|
-
}
|
|
221
|
-
} catch (error) {
|
|
222
|
-
// Registration failed (likely offline) - identity still created locally
|
|
223
|
-
if (__DEV__) {
|
|
224
|
-
logger('Failed to register identity with backend (offline mode)', error);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
return {
|
|
228
|
-
synced
|
|
229
|
-
};
|
|
230
|
-
} finally {
|
|
231
|
-
setSyncing(false);
|
|
232
|
-
}
|
|
233
|
-
}, [identityCore, isCoreInitialized, oxyServices, storage, loginSuccess, setIdentitySynced, setSyncing, logger]);
|
|
251
|
+
// Wrapper for importIdentity to handle legacy calls gracefully
|
|
234
252
|
const importIdentity = (0, _react.useCallback)(async (backupData, password) => {
|
|
235
|
-
|
|
236
|
-
throw new Error('Identity core not initialized');
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
// Handle legacy calls with single string argument
|
|
253
|
+
// Handle legacy calls with single string argument (old recovery phrase signature)
|
|
240
254
|
if (typeof backupData === 'string') {
|
|
241
255
|
throw new Error('Recovery phrase import is no longer supported. Please use backup file import or QR code transfer instead.');
|
|
242
256
|
}
|
|
@@ -245,279 +259,63 @@ const OxyProvider = ({
|
|
|
245
259
|
if (!password || typeof password !== 'string') {
|
|
246
260
|
throw new Error('Password is required for backup file import.');
|
|
247
261
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
// Import identity using core
|
|
251
|
-
const identity = await identityCore.importIdentity(backupData, password);
|
|
252
|
-
|
|
253
|
-
// Try to register with backend if not already registered
|
|
254
|
-
let synced = false;
|
|
255
|
-
try {
|
|
256
|
-
const {
|
|
257
|
-
signature,
|
|
258
|
-
publicKey,
|
|
259
|
-
timestamp
|
|
260
|
-
} = await identityCore.createRegistrationSignature();
|
|
261
|
-
const result = await oxyServices.register(publicKey, signature, timestamp);
|
|
262
|
-
if (result?.user) {
|
|
263
|
-
loginSuccess(result.user);
|
|
264
|
-
synced = true;
|
|
265
|
-
await storage?.setItem('oxy_identity_synced', 'true');
|
|
266
|
-
setIdentitySynced(true);
|
|
267
|
-
}
|
|
268
|
-
} catch (error) {
|
|
269
|
-
// Check if user already exists (409 conflict)
|
|
270
|
-
if (error?.status === 409) {
|
|
271
|
-
// User already registered - try to sign in instead
|
|
272
|
-
try {
|
|
273
|
-
await signIn();
|
|
274
|
-
synced = true;
|
|
275
|
-
await storage?.setItem('oxy_identity_synced', 'true');
|
|
276
|
-
setIdentitySynced(true);
|
|
277
|
-
} catch (signInError) {
|
|
278
|
-
if (__DEV__) {
|
|
279
|
-
logger('Failed to sign in after import', signInError);
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
} else if (__DEV__) {
|
|
283
|
-
logger('Failed to register identity with backend (offline mode)', error);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
return {
|
|
287
|
-
synced
|
|
288
|
-
};
|
|
289
|
-
} finally {
|
|
290
|
-
setSyncing(false);
|
|
291
|
-
}
|
|
292
|
-
}, [identityCore, isCoreInitialized, oxyServices, storage, loginSuccess, setIdentitySynced, setSyncing, logger]);
|
|
293
|
-
const syncIdentity = (0, _react.useCallback)(async username => {
|
|
294
|
-
if (!identityCore || !isCoreInitialized) {
|
|
295
|
-
throw new Error('Identity core not initialized');
|
|
296
|
-
}
|
|
297
|
-
const publicKey = await identityCore.getPublicKey();
|
|
298
|
-
if (!publicKey) {
|
|
299
|
-
throw new Error('No identity found');
|
|
300
|
-
}
|
|
301
|
-
setSyncing(true);
|
|
302
|
-
try {
|
|
303
|
-
const {
|
|
304
|
-
signature,
|
|
305
|
-
publicKey: pk,
|
|
306
|
-
timestamp
|
|
307
|
-
} = await identityCore.createRegistrationSignature();
|
|
308
|
-
const result = await oxyServices.register(pk, signature, timestamp, username);
|
|
309
|
-
if (result?.user) {
|
|
310
|
-
loginSuccess(result.user);
|
|
311
|
-
await storage?.setItem('oxy_identity_synced', 'true');
|
|
312
|
-
setIdentitySynced(true);
|
|
313
|
-
return result.user;
|
|
314
|
-
}
|
|
315
|
-
throw new Error('Registration failed');
|
|
316
|
-
} catch (error) {
|
|
317
|
-
// Check if user already exists (409 conflict) - try to sign in
|
|
318
|
-
if (error?.status === 409) {
|
|
319
|
-
const user = await signIn();
|
|
320
|
-
await storage?.setItem('oxy_identity_synced', 'true');
|
|
321
|
-
setIdentitySynced(true);
|
|
322
|
-
return user;
|
|
323
|
-
}
|
|
324
|
-
throw error;
|
|
325
|
-
} finally {
|
|
326
|
-
setSyncing(false);
|
|
327
|
-
}
|
|
328
|
-
}, [identityCore, isCoreInitialized, oxyServices, storage, loginSuccess, setIdentitySynced, setSyncing]);
|
|
329
|
-
const signIn = (0, _react.useCallback)(async deviceName => {
|
|
330
|
-
if (!identityCore || !isCoreInitialized) {
|
|
331
|
-
throw new Error('Identity core not initialized');
|
|
332
|
-
}
|
|
333
|
-
setAuthState({
|
|
334
|
-
isLoading: true
|
|
335
|
-
});
|
|
336
|
-
try {
|
|
337
|
-
// Create session using core
|
|
338
|
-
const session = await identityCore.createSession(deviceName);
|
|
339
|
-
|
|
340
|
-
// Get user from OxyServices
|
|
341
|
-
const user = await oxyServices.getUserBySession(session.sessionId);
|
|
342
|
-
if (!user) {
|
|
343
|
-
throw new Error('Failed to get user data');
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
// Set token in OxyServices
|
|
347
|
-
if (session.accessToken) {
|
|
348
|
-
oxyServices.setTokens(session.accessToken, session.refreshToken || undefined);
|
|
349
|
-
}
|
|
262
|
+
return importIdentityBase(backupData, password);
|
|
263
|
+
}, [importIdentityBase]);
|
|
350
264
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
await applyLanguagePreference(user);
|
|
356
|
-
setTokenReady(true);
|
|
357
|
-
return user;
|
|
358
|
-
} catch (error) {
|
|
359
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
360
|
-
loginFailure(errorMessage);
|
|
361
|
-
throw error;
|
|
362
|
-
} finally {
|
|
363
|
-
setAuthState({
|
|
364
|
-
isLoading: false
|
|
365
|
-
});
|
|
366
|
-
}
|
|
367
|
-
}, [identityCore, isCoreInitialized, oxyServices, loginSuccess, loginFailure, setAuthState, loadSessionsFromCore, onAuthStateChange, applyLanguagePreference, setTokenReady]);
|
|
368
|
-
|
|
369
|
-
// Session management functions
|
|
370
|
-
const clearSessionState = (0, _react.useCallback)(async () => {
|
|
371
|
-
setSessions([]);
|
|
372
|
-
setActiveSessionId(null);
|
|
373
|
-
logoutStore();
|
|
374
|
-
onAuthStateChange?.(null);
|
|
375
|
-
|
|
376
|
-
// Clear TanStack Query cache
|
|
265
|
+
// Clear all account data when identity is lost (for accounts app)
|
|
266
|
+
// In accounts app, identity = account, so losing identity means losing everything
|
|
267
|
+
const clearAllAccountData = (0, _react.useCallback)(async () => {
|
|
268
|
+
// Clear TanStack Query cache (in-memory)
|
|
377
269
|
queryClient.clear();
|
|
378
270
|
|
|
379
|
-
// Clear persisted query cache
|
|
271
|
+
// Clear persisted query cache
|
|
380
272
|
if (storage) {
|
|
381
273
|
try {
|
|
382
274
|
await (0, _queryClient.clearQueryCache)(storage);
|
|
383
|
-
await storage.removeItem(storageKeys.activeSessionId);
|
|
384
|
-
await storage.removeItem(storageKeys.sessionIds);
|
|
385
|
-
await storage.removeItem('oxy_identity_synced').catch(() => {});
|
|
386
275
|
} catch (error) {
|
|
387
|
-
|
|
388
|
-
logger('Failed to clear session storage', error);
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
}, [logoutStore, onAuthStateChange, queryClient, storage, storageKeys, logger]);
|
|
393
|
-
const logout = (0, _react.useCallback)(async targetSessionId => {
|
|
394
|
-
if (!identityCore || !isCoreInitialized) return;
|
|
395
|
-
try {
|
|
396
|
-
await identityCore.invalidateSession(targetSessionId);
|
|
397
|
-
await loadSessionsFromCore();
|
|
398
|
-
await clearSessionState();
|
|
399
|
-
setTokenReady(false);
|
|
400
|
-
} catch (error) {
|
|
401
|
-
if (__DEV__) {
|
|
402
|
-
logger('Failed to logout', error);
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
}, [identityCore, isCoreInitialized, loadSessionsFromCore, clearSessionState, setTokenReady, logger]);
|
|
406
|
-
const logoutAll = (0, _react.useCallback)(async () => {
|
|
407
|
-
if (!identityCore || !isCoreInitialized) return;
|
|
408
|
-
try {
|
|
409
|
-
await identityCore.invalidateAllSessions();
|
|
410
|
-
await loadSessionsFromCore();
|
|
411
|
-
await clearSessionState();
|
|
412
|
-
setTokenReady(false);
|
|
413
|
-
} catch (error) {
|
|
414
|
-
if (__DEV__) {
|
|
415
|
-
logger('Failed to logout all', error);
|
|
276
|
+
logger('Failed to clear persisted query cache', error);
|
|
416
277
|
}
|
|
417
278
|
}
|
|
418
|
-
}, [identityCore, isCoreInitialized, loadSessionsFromCore, clearSessionState, setTokenReady, logger]);
|
|
419
|
-
const switchSession = (0, _react.useCallback)(async sessionId => {
|
|
420
|
-
if (!identityCore || !isCoreInitialized) {
|
|
421
|
-
throw new Error('Identity core not initialized');
|
|
422
|
-
}
|
|
423
|
-
try {
|
|
424
|
-
// Validate session
|
|
425
|
-
const validation = await oxyServices.validateSession(sessionId, {
|
|
426
|
-
useHeaderValidation: true
|
|
427
|
-
});
|
|
428
|
-
if (!validation?.valid || !validation.user) {
|
|
429
|
-
throw new Error('Session is invalid or expired');
|
|
430
|
-
}
|
|
431
|
-
const user = validation.user;
|
|
432
279
|
|
|
433
|
-
|
|
434
|
-
await oxyServices.getTokenBySession(sessionId);
|
|
435
|
-
|
|
436
|
-
// Update active session in core
|
|
437
|
-
const sessionManager = identityCore.getSessionManager();
|
|
438
|
-
await sessionManager.setActiveSessionId(sessionId);
|
|
439
|
-
|
|
440
|
-
// Update local state
|
|
441
|
-
setActiveSessionId(sessionId);
|
|
442
|
-
loginSuccess(user);
|
|
443
|
-
await applyLanguagePreference(user);
|
|
444
|
-
onAuthStateChange?.(user);
|
|
445
|
-
setTokenReady(true);
|
|
446
|
-
await loadSessionsFromCore();
|
|
447
|
-
return user;
|
|
448
|
-
} catch (error) {
|
|
449
|
-
if ((0, _errorHandlers.isInvalidSessionError)(error)) {
|
|
450
|
-
// Remove invalid session from list
|
|
451
|
-
setSessions(prev => prev.filter(s => s.sessionId !== sessionId));
|
|
452
|
-
if (sessionId === activeSessionId) {
|
|
453
|
-
await clearSessionState();
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
throw error;
|
|
457
|
-
}
|
|
458
|
-
}, [identityCore, isCoreInitialized, oxyServices, loginSuccess, applyLanguagePreference, onAuthStateChange, setTokenReady, loadSessionsFromCore, activeSessionId, clearSessionState]);
|
|
459
|
-
const refreshSessions = (0, _react.useCallback)(async () => {
|
|
460
|
-
if (!identityCore || !isCoreInitialized || !activeSessionId) return;
|
|
461
|
-
try {
|
|
462
|
-
// Refresh current session
|
|
463
|
-
await identityCore.refreshSession();
|
|
464
|
-
|
|
465
|
-
// Reload sessions from core
|
|
466
|
-
await loadSessionsFromCore();
|
|
467
|
-
} catch (error) {
|
|
468
|
-
if ((0, _errorHandlers.isInvalidSessionError)(error)) {
|
|
469
|
-
await clearSessionState();
|
|
470
|
-
} else if (__DEV__) {
|
|
471
|
-
logger('Failed to refresh sessions', error);
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
}, [identityCore, isCoreInitialized, activeSessionId, loadSessionsFromCore, clearSessionState, logger]);
|
|
475
|
-
|
|
476
|
-
// Device management functions
|
|
477
|
-
const getDeviceSessions = (0, _react.useCallback)(async () => {
|
|
478
|
-
if (!activeSessionId) throw new Error('No active session');
|
|
479
|
-
return await oxyServices.getDeviceSessions(activeSessionId);
|
|
480
|
-
}, [activeSessionId, oxyServices]);
|
|
481
|
-
const logoutAllDeviceSessions = (0, _react.useCallback)(async () => {
|
|
482
|
-
if (!activeSessionId) throw new Error('No active session');
|
|
483
|
-
await oxyServices.logoutAllDeviceSessions(activeSessionId);
|
|
280
|
+
// Clear session state (sessions, activeSessionId, storage)
|
|
484
281
|
await clearSessionState();
|
|
485
|
-
}, [activeSessionId, oxyServices, clearSessionState]);
|
|
486
|
-
const updateDeviceName = (0, _react.useCallback)(async deviceName => {
|
|
487
|
-
if (!identityCore || !isCoreInitialized || !activeSessionId) {
|
|
488
|
-
throw new Error('Identity core not initialized or no active session');
|
|
489
|
-
}
|
|
490
|
-
await oxyServices.updateDeviceName(activeSessionId, deviceName);
|
|
491
282
|
|
|
492
|
-
//
|
|
493
|
-
const deviceManager = identityCore.getDeviceManager();
|
|
494
|
-
await deviceManager.updateDeviceName(deviceName);
|
|
495
|
-
}, [identityCore, isCoreInitialized, activeSessionId, oxyServices]);
|
|
496
|
-
(0, _useTransferCodesPersistence.useTransferCodesPersistence)(storageKeyPrefix);
|
|
497
|
-
const clearAllAccountData = (0, _react.useCallback)(async () => {
|
|
498
|
-
if (__DEV__) logger('Clearing all account data - identity changed or lost');
|
|
499
|
-
queryClient.clear();
|
|
500
|
-
await clearSessionState();
|
|
283
|
+
// Clear identity sync state from storage
|
|
501
284
|
if (storage) {
|
|
502
285
|
try {
|
|
503
|
-
await (0, _queryClient.clearQueryCache)(storage);
|
|
504
286
|
await storage.removeItem('oxy_identity_synced');
|
|
505
287
|
} catch (error) {
|
|
506
|
-
logger('Failed to clear
|
|
288
|
+
logger('Failed to clear identity sync state', error);
|
|
507
289
|
}
|
|
508
290
|
}
|
|
291
|
+
|
|
292
|
+
// Reset auth store identity sync state
|
|
509
293
|
_authStore.useAuthStore.getState().setIdentitySynced(false);
|
|
510
294
|
_authStore.useAuthStore.getState().setSyncing(false);
|
|
295
|
+
|
|
296
|
+
// Reset account store
|
|
511
297
|
_accountStore.useAccountStore.getState().reset();
|
|
512
|
-
|
|
298
|
+
|
|
299
|
+
// Clear HTTP service cache
|
|
513
300
|
oxyServices.clearCache();
|
|
514
|
-
|
|
515
|
-
}, [queryClient, storage, clearSessionState, logger, oxyServices, identityCore]);
|
|
301
|
+
}, [queryClient, storage, clearSessionState, logger, oxyServices]);
|
|
516
302
|
|
|
517
|
-
//
|
|
518
|
-
const getAllPendingTransfers = (0,
|
|
519
|
-
|
|
520
|
-
|
|
303
|
+
// Transfer code management functions (must be defined before deleteIdentityAndClearAccount)
|
|
304
|
+
const getAllPendingTransfers = (0, _react.useCallback)(() => {
|
|
305
|
+
const pending = [];
|
|
306
|
+
transferCodesRef.current.forEach((data, transferId) => {
|
|
307
|
+
if (data.state === 'pending') {
|
|
308
|
+
pending.push({
|
|
309
|
+
transferId,
|
|
310
|
+
data
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
return pending;
|
|
315
|
+
}, []);
|
|
316
|
+
const getActiveTransferId = (0, _react.useCallback)(() => {
|
|
317
|
+
return activeTransferIdRef.current;
|
|
318
|
+
}, []);
|
|
521
319
|
|
|
522
320
|
// Delete identity and clear all account data
|
|
523
321
|
// In accounts app, deleting identity means losing the account completely
|
|
@@ -539,112 +337,636 @@ const OxyProvider = ({
|
|
|
539
337
|
await clearAllAccountData();
|
|
540
338
|
|
|
541
339
|
// Then delete the identity keys
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
340
|
+
await _crypto.KeyManager.deleteIdentity(skipBackup, force, userConfirmed);
|
|
341
|
+
}, [clearAllAccountData, getAllPendingTransfers, getActiveTransferId]);
|
|
342
|
+
|
|
343
|
+
// Network reconnect sync - TanStack Query automatically retries mutations on reconnect
|
|
344
|
+
// We only need to sync identity if it's not synced
|
|
345
|
+
(0, _react.useEffect)(() => {
|
|
346
|
+
if (!storage) return;
|
|
347
|
+
let wasOffline = false;
|
|
348
|
+
let checkTimeout = null;
|
|
349
|
+
let lastReconnectionLog = 0;
|
|
350
|
+
const RECONNECTION_LOG_DEBOUNCE_MS = 5000; // 5 seconds
|
|
351
|
+
|
|
352
|
+
// Circuit breaker and exponential backoff state
|
|
353
|
+
const stateRef = {
|
|
354
|
+
consecutiveFailures: 0,
|
|
355
|
+
currentInterval: 10000,
|
|
356
|
+
// Start with 10 seconds
|
|
357
|
+
baseInterval: 10000,
|
|
358
|
+
// Base interval in milliseconds
|
|
359
|
+
maxInterval: 60000,
|
|
360
|
+
// Maximum interval (60 seconds)
|
|
361
|
+
maxFailures: 5 // Circuit breaker threshold
|
|
362
|
+
};
|
|
363
|
+
const scheduleNextCheck = () => {
|
|
364
|
+
if (checkTimeout) {
|
|
365
|
+
clearTimeout(checkTimeout);
|
|
366
|
+
}
|
|
367
|
+
checkTimeout = setTimeout(() => {
|
|
368
|
+
checkNetworkAndSync();
|
|
369
|
+
}, stateRef.currentInterval);
|
|
370
|
+
};
|
|
371
|
+
const checkNetworkAndSync = async () => {
|
|
372
|
+
try {
|
|
373
|
+
// Try a lightweight health check to see if we're online
|
|
374
|
+
await oxyServices.healthCheck().catch(() => {
|
|
375
|
+
wasOffline = true;
|
|
376
|
+
throw new Error('Health check failed');
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
// Health check succeeded - reset circuit breaker and backoff
|
|
380
|
+
if (stateRef.consecutiveFailures > 0) {
|
|
381
|
+
stateRef.consecutiveFailures = 0;
|
|
382
|
+
stateRef.currentInterval = stateRef.baseInterval;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// If we were offline and now we're online, sync identity if needed
|
|
386
|
+
if (wasOffline) {
|
|
387
|
+
const now = Date.now();
|
|
388
|
+
const timeSinceLastLog = now - lastReconnectionLog;
|
|
389
|
+
if (timeSinceLastLog >= RECONNECTION_LOG_DEBOUNCE_MS) {
|
|
390
|
+
logger('Network reconnected, checking identity sync...');
|
|
391
|
+
lastReconnectionLog = now;
|
|
392
|
+
|
|
393
|
+
// Sync identity first (if not synced)
|
|
394
|
+
try {
|
|
395
|
+
const hasIdentityValue = await hasIdentity();
|
|
396
|
+
if (hasIdentityValue) {
|
|
397
|
+
// Check sync status directly - sync if not explicitly 'true'
|
|
398
|
+
// undefined = not synced yet, 'false' = explicitly not synced, 'true' = synced
|
|
399
|
+
const syncStatus = await storage.getItem('oxy_identity_synced');
|
|
400
|
+
if (syncStatus !== 'true') {
|
|
401
|
+
await syncIdentity();
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
} catch (syncError) {
|
|
405
|
+
// Skip sync silently if username is required (expected when offline onboarding)
|
|
406
|
+
if (syncError?.code === 'USERNAME_REQUIRED' || syncError?.message === 'USERNAME_REQUIRED') {
|
|
407
|
+
if (__DEV__) {
|
|
408
|
+
_loggerUtils.logger.debug('Sync skipped - username required', {
|
|
409
|
+
component: 'OxyContext',
|
|
410
|
+
method: 'checkNetworkAndSync'
|
|
411
|
+
}, syncError);
|
|
412
|
+
}
|
|
413
|
+
// Don't log or show error - username will be set later
|
|
414
|
+
} else if (!(0, _errorHandlers.isTimeoutOrNetworkError)(syncError)) {
|
|
415
|
+
// Only log unexpected errors - timeouts/network issues are expected when offline
|
|
416
|
+
logger('Error syncing identity on reconnect', syncError);
|
|
417
|
+
} else if (__DEV__) {
|
|
418
|
+
_loggerUtils.logger.debug('Identity sync timeout (expected when offline)', {
|
|
419
|
+
component: 'OxyContext',
|
|
420
|
+
method: 'checkNetworkAndSync'
|
|
421
|
+
}, syncError);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// TanStack Query will automatically retry pending mutations
|
|
427
|
+
// Reset flag immediately after processing (whether logged or not)
|
|
428
|
+
wasOffline = false;
|
|
429
|
+
}
|
|
430
|
+
} catch (error) {
|
|
431
|
+
// Network check failed - we're offline
|
|
432
|
+
wasOffline = true;
|
|
433
|
+
|
|
434
|
+
// Increment failure count and apply exponential backoff
|
|
435
|
+
stateRef.consecutiveFailures++;
|
|
436
|
+
|
|
437
|
+
// Calculate new interval with exponential backoff, capped at maxInterval
|
|
438
|
+
const backoffMultiplier = Math.min(Math.pow(2, stateRef.consecutiveFailures - 1), stateRef.maxInterval / stateRef.baseInterval);
|
|
439
|
+
stateRef.currentInterval = Math.min(stateRef.baseInterval * backoffMultiplier, stateRef.maxInterval);
|
|
440
|
+
|
|
441
|
+
// If we hit the circuit breaker threshold, use max interval
|
|
442
|
+
if (stateRef.consecutiveFailures >= stateRef.maxFailures) {
|
|
443
|
+
stateRef.currentInterval = stateRef.maxInterval;
|
|
444
|
+
}
|
|
445
|
+
} finally {
|
|
446
|
+
// Always schedule next check (will use updated interval)
|
|
447
|
+
scheduleNextCheck();
|
|
448
|
+
}
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
// Check immediately
|
|
452
|
+
checkNetworkAndSync();
|
|
453
|
+
return () => {
|
|
454
|
+
if (checkTimeout) {
|
|
455
|
+
clearTimeout(checkTimeout);
|
|
456
|
+
}
|
|
457
|
+
};
|
|
458
|
+
}, [oxyServices, storage, syncIdentity, logger]);
|
|
459
|
+
const {
|
|
460
|
+
getDeviceSessions,
|
|
461
|
+
logoutAllDeviceSessions,
|
|
462
|
+
updateDeviceName
|
|
463
|
+
} = (0, _useDeviceManagement.useDeviceManagement)({
|
|
464
|
+
oxyServices,
|
|
465
|
+
activeSessionId,
|
|
466
|
+
onError,
|
|
467
|
+
clearSessionState,
|
|
468
|
+
logger
|
|
469
|
+
});
|
|
470
|
+
const useFollowHook = loadUseFollowHook();
|
|
548
471
|
const restoreSessionsFromStorage = (0, _react.useCallback)(async () => {
|
|
549
|
-
if (!
|
|
472
|
+
if (!storage) {
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
550
475
|
setTokenReady(false);
|
|
551
476
|
try {
|
|
552
|
-
await
|
|
553
|
-
const
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
try {
|
|
559
|
-
await switchSession(activeId);
|
|
560
|
-
} catch (switchError) {
|
|
561
|
-
if ((0, _errorHandlers.isTimeoutOrNetworkError)(switchError)) {
|
|
477
|
+
const storedSessionIdsJson = await storage.getItem(storageKeys.sessionIds);
|
|
478
|
+
const storedSessionIds = storedSessionIdsJson ? JSON.parse(storedSessionIdsJson) : [];
|
|
479
|
+
const storedActiveSessionId = await storage.getItem(storageKeys.activeSessionId);
|
|
480
|
+
const validSessions = [];
|
|
481
|
+
if (storedSessionIds.length > 0) {
|
|
482
|
+
for (const sessionId of storedSessionIds) {
|
|
562
483
|
try {
|
|
563
|
-
const validation = await oxyServices.validateSession(
|
|
564
|
-
useHeaderValidation:
|
|
484
|
+
const validation = await oxyServices.validateSession(sessionId, {
|
|
485
|
+
useHeaderValidation: true
|
|
565
486
|
});
|
|
566
487
|
if (validation?.valid && validation.user) {
|
|
567
|
-
|
|
488
|
+
const now = new Date();
|
|
489
|
+
validSessions.push({
|
|
490
|
+
sessionId,
|
|
491
|
+
deviceId: '',
|
|
492
|
+
expiresAt: new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000).toISOString(),
|
|
493
|
+
lastActive: now.toISOString(),
|
|
494
|
+
userId: validation.user.id?.toString() ?? '',
|
|
495
|
+
isCurrent: sessionId === storedActiveSessionId
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
} catch (validationError) {
|
|
499
|
+
// Silently handle expected errors (invalid sessions, timeouts, network issues) during restoration
|
|
500
|
+
// Only log unexpected errors
|
|
501
|
+
if (!(0, _errorHandlers.isInvalidSessionError)(validationError) && !(0, _errorHandlers.isTimeoutOrNetworkError)(validationError)) {
|
|
502
|
+
logger('Session validation failed during init', validationError);
|
|
503
|
+
} else if (__DEV__ && (0, _errorHandlers.isTimeoutOrNetworkError)(validationError)) {
|
|
504
|
+
// Only log timeouts in dev mode for debugging
|
|
505
|
+
_loggerUtils.logger.debug('Session validation timeout (expected when offline)', {
|
|
506
|
+
component: 'OxyContext',
|
|
507
|
+
method: 'restoreSessionsFromStorage'
|
|
508
|
+
}, validationError);
|
|
568
509
|
}
|
|
569
|
-
} catch {
|
|
570
|
-
// Offline - will sync when online
|
|
571
510
|
}
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
|
|
511
|
+
}
|
|
512
|
+
if (validSessions.length > 0) {
|
|
513
|
+
updateSessions(validSessions, {
|
|
514
|
+
merge: false
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
if (storedActiveSessionId) {
|
|
519
|
+
try {
|
|
520
|
+
await switchSession(storedActiveSessionId);
|
|
521
|
+
} catch (switchError) {
|
|
522
|
+
// Silently handle expected errors (invalid sessions, timeouts, network issues)
|
|
523
|
+
if ((0, _errorHandlers.isInvalidSessionError)(switchError)) {
|
|
524
|
+
await storage.removeItem(storageKeys.activeSessionId);
|
|
525
|
+
updateSessions(validSessions.filter(session => session.sessionId !== storedActiveSessionId), {
|
|
526
|
+
merge: false
|
|
527
|
+
});
|
|
528
|
+
// Don't log expected session errors during restoration
|
|
529
|
+
} else if ((0, _errorHandlers.isTimeoutOrNetworkError)(switchError)) {
|
|
530
|
+
// Timeout/network error - non-critical, don't block
|
|
531
|
+
if (__DEV__) {
|
|
532
|
+
_loggerUtils.logger.debug('Active session validation timeout (expected when offline)', {
|
|
533
|
+
component: 'OxyContext',
|
|
534
|
+
method: 'restoreSessionsFromStorage'
|
|
535
|
+
}, switchError);
|
|
536
|
+
}
|
|
537
|
+
} else {
|
|
538
|
+
// Only log unexpected errors
|
|
539
|
+
logger('Active session validation error', switchError);
|
|
540
|
+
}
|
|
575
541
|
}
|
|
576
542
|
}
|
|
577
543
|
} catch (error) {
|
|
578
|
-
if (__DEV__)
|
|
544
|
+
if (__DEV__) {
|
|
545
|
+
_loggerUtils.logger.error('Auth init error', error instanceof Error ? error : new Error(String(error)), {
|
|
546
|
+
component: 'OxyContext',
|
|
547
|
+
method: 'restoreSessionsFromStorage'
|
|
548
|
+
});
|
|
549
|
+
}
|
|
579
550
|
await clearSessionState();
|
|
580
551
|
} finally {
|
|
581
552
|
setTokenReady(true);
|
|
582
553
|
}
|
|
583
|
-
}, [
|
|
584
|
-
|
|
585
|
-
// Restore sessions when core is initialized
|
|
554
|
+
}, [clearSessionState, logger, oxyServices, storage, storageKeys.activeSessionId, storageKeys.sessionIds, switchSession, updateSessions]);
|
|
586
555
|
(0, _react.useEffect)(() => {
|
|
587
|
-
if (
|
|
588
|
-
|
|
556
|
+
if (!storage || initializedRef.current) {
|
|
557
|
+
return;
|
|
589
558
|
}
|
|
590
|
-
|
|
559
|
+
initializedRef.current = true;
|
|
560
|
+
void restoreSessionsFromStorage();
|
|
561
|
+
}, [restoreSessionsFromStorage, storage]);
|
|
591
562
|
const activeSession = activeSessionId ? sessions.find(session => session.sessionId === activeSessionId) : undefined;
|
|
592
563
|
const currentDeviceId = activeSession?.deviceId ?? null;
|
|
593
564
|
|
|
594
|
-
//
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
const
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
565
|
+
// Get userId from JWT token (MongoDB ObjectId) for socket room matching
|
|
566
|
+
const userId = oxyServices.getCurrentUserId();
|
|
567
|
+
|
|
568
|
+
// Transfer code storage interface
|
|
569
|
+
|
|
570
|
+
// Store transfer codes in memory for verification (also persisted to storage)
|
|
571
|
+
// Map: transferId -> TransferCodeData
|
|
572
|
+
const transferCodesRef = (0, _react.useRef)(new Map());
|
|
573
|
+
const activeTransferIdRef = (0, _react.useRef)(null);
|
|
574
|
+
const TRANSFER_CODES_STORAGE_KEY = `${storageKeyPrefix}_transfer_codes`;
|
|
575
|
+
const ACTIVE_TRANSFER_STORAGE_KEY = `${storageKeyPrefix}_active_transfer_id`;
|
|
576
|
+
|
|
577
|
+
// Load transfer codes from storage on startup
|
|
578
|
+
(0, _react.useEffect)(() => {
|
|
579
|
+
if (!storage || !isStorageReady) return;
|
|
580
|
+
const loadTransferCodes = async () => {
|
|
581
|
+
try {
|
|
582
|
+
// Load transfer codes
|
|
583
|
+
const storedCodes = await storage.getItem(TRANSFER_CODES_STORAGE_KEY);
|
|
584
|
+
if (storedCodes) {
|
|
585
|
+
const parsed = JSON.parse(storedCodes);
|
|
586
|
+
const now = Date.now();
|
|
587
|
+
const fifteenMinutes = 15 * 60 * 1000;
|
|
588
|
+
|
|
589
|
+
// Only restore non-expired pending transfers
|
|
590
|
+
Object.entries(parsed).forEach(([transferId, data]) => {
|
|
591
|
+
if (data.state === 'pending' && now - data.timestamp < fifteenMinutes) {
|
|
592
|
+
transferCodesRef.current.set(transferId, data);
|
|
593
|
+
if (__DEV__) {
|
|
594
|
+
logger('Restored pending transfer from storage', {
|
|
595
|
+
transferId
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
// Load active transfer ID
|
|
603
|
+
const activeTransferId = await storage.getItem(ACTIVE_TRANSFER_STORAGE_KEY);
|
|
604
|
+
if (activeTransferId) {
|
|
605
|
+
// Verify it's still valid
|
|
606
|
+
const transferData = transferCodesRef.current.get(activeTransferId);
|
|
607
|
+
if (transferData && transferData.state === 'pending') {
|
|
608
|
+
activeTransferIdRef.current = activeTransferId;
|
|
609
|
+
if (__DEV__) {
|
|
610
|
+
logger('Restored active transfer ID from storage', {
|
|
611
|
+
transferId: activeTransferId
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
} else {
|
|
615
|
+
// Clear invalid active transfer
|
|
616
|
+
await storage.removeItem(ACTIVE_TRANSFER_STORAGE_KEY);
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
} catch (error) {
|
|
620
|
+
if (__DEV__) {
|
|
621
|
+
logger('Failed to load transfer codes from storage', error);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
};
|
|
625
|
+
loadTransferCodes();
|
|
626
|
+
}, [storage, isStorageReady, logger, storageKeyPrefix]);
|
|
627
|
+
|
|
628
|
+
// Persist transfer codes to storage whenever they change
|
|
629
|
+
const persistTransferCodes = (0, _react.useCallback)(async () => {
|
|
630
|
+
if (!storage) return;
|
|
631
|
+
try {
|
|
632
|
+
const codesToStore = {};
|
|
633
|
+
transferCodesRef.current.forEach((value, key) => {
|
|
634
|
+
codesToStore[key] = value;
|
|
635
|
+
});
|
|
636
|
+
await storage.setItem(TRANSFER_CODES_STORAGE_KEY, JSON.stringify(codesToStore));
|
|
637
|
+
} catch (error) {
|
|
638
|
+
if (__DEV__) {
|
|
639
|
+
logger('Failed to persist transfer codes', error);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
}, [storage, logger]);
|
|
643
|
+
|
|
644
|
+
// Cleanup old transfer codes (older than 15 minutes)
|
|
645
|
+
(0, _react.useEffect)(() => {
|
|
646
|
+
const cleanup = setInterval(async () => {
|
|
647
|
+
const now = Date.now();
|
|
648
|
+
const fifteenMinutes = 15 * 60 * 1000;
|
|
649
|
+
let needsPersist = false;
|
|
650
|
+
transferCodesRef.current.forEach((value, key) => {
|
|
651
|
+
if (now - value.timestamp > fifteenMinutes) {
|
|
652
|
+
transferCodesRef.current.delete(key);
|
|
653
|
+
needsPersist = true;
|
|
654
|
+
if (__DEV__) {
|
|
655
|
+
logger('Cleaned up expired transfer code', {
|
|
656
|
+
transferId: key
|
|
657
|
+
});
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
});
|
|
661
|
+
|
|
662
|
+
// Clear active transfer if it was deleted
|
|
663
|
+
if (activeTransferIdRef.current && !transferCodesRef.current.has(activeTransferIdRef.current)) {
|
|
664
|
+
activeTransferIdRef.current = null;
|
|
665
|
+
if (storage) {
|
|
666
|
+
try {
|
|
667
|
+
await storage.removeItem(ACTIVE_TRANSFER_STORAGE_KEY);
|
|
668
|
+
} catch (error) {
|
|
669
|
+
// Ignore storage errors
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
if (needsPersist) {
|
|
674
|
+
await persistTransferCodes();
|
|
675
|
+
}
|
|
676
|
+
}, 60000); // Check every minute
|
|
677
|
+
|
|
678
|
+
return () => clearInterval(cleanup);
|
|
679
|
+
}, [logger, persistTransferCodes, storage]);
|
|
680
|
+
|
|
681
|
+
// Transfer code management functions
|
|
682
|
+
const storeTransferCode = (0, _react.useCallback)(async (transferId, code, sourceDeviceId, publicKey) => {
|
|
683
|
+
const transferData = {
|
|
684
|
+
code,
|
|
685
|
+
sourceDeviceId,
|
|
686
|
+
publicKey,
|
|
687
|
+
timestamp: Date.now(),
|
|
688
|
+
state: 'pending'
|
|
689
|
+
};
|
|
690
|
+
transferCodesRef.current.set(transferId, transferData);
|
|
691
|
+
activeTransferIdRef.current = transferId;
|
|
692
|
+
|
|
693
|
+
// Persist to storage
|
|
694
|
+
await persistTransferCodes();
|
|
695
|
+
if (storage) {
|
|
696
|
+
try {
|
|
697
|
+
await storage.setItem(ACTIVE_TRANSFER_STORAGE_KEY, transferId);
|
|
698
|
+
} catch (error) {
|
|
699
|
+
if (__DEV__) {
|
|
700
|
+
logger('Failed to persist active transfer ID', error);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
if (__DEV__) {
|
|
705
|
+
logger('Stored transfer code', {
|
|
706
|
+
transferId,
|
|
707
|
+
sourceDeviceId,
|
|
708
|
+
publicKey: publicKey.substring(0, 16) + '...'
|
|
709
|
+
});
|
|
710
|
+
}
|
|
711
|
+
}, [logger, persistTransferCodes, storage]);
|
|
712
|
+
const getTransferCode = (0, _react.useCallback)(transferId => {
|
|
713
|
+
return transferCodesRef.current.get(transferId) || null;
|
|
714
|
+
}, []);
|
|
715
|
+
const updateTransferState = (0, _react.useCallback)(async (transferId, state) => {
|
|
716
|
+
const transferData = transferCodesRef.current.get(transferId);
|
|
717
|
+
if (transferData) {
|
|
718
|
+
transferData.state = state;
|
|
719
|
+
transferCodesRef.current.set(transferId, transferData);
|
|
720
|
+
|
|
721
|
+
// Clear active transfer if completed or failed
|
|
722
|
+
if (state === 'completed' || state === 'failed') {
|
|
723
|
+
if (activeTransferIdRef.current === transferId) {
|
|
724
|
+
activeTransferIdRef.current = null;
|
|
725
|
+
if (storage) {
|
|
726
|
+
try {
|
|
727
|
+
await storage.removeItem(ACTIVE_TRANSFER_STORAGE_KEY);
|
|
728
|
+
} catch (error) {
|
|
729
|
+
// Ignore storage errors
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
await persistTransferCodes();
|
|
735
|
+
if (__DEV__) {
|
|
736
|
+
logger('Updated transfer state', {
|
|
737
|
+
transferId,
|
|
738
|
+
state
|
|
739
|
+
});
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
}, [logger, persistTransferCodes, storage]);
|
|
743
|
+
const clearTransferCode = (0, _react.useCallback)(async transferId => {
|
|
744
|
+
transferCodesRef.current.delete(transferId);
|
|
745
|
+
if (activeTransferIdRef.current === transferId) {
|
|
746
|
+
activeTransferIdRef.current = null;
|
|
747
|
+
if (storage) {
|
|
748
|
+
try {
|
|
749
|
+
await storage.removeItem(ACTIVE_TRANSFER_STORAGE_KEY);
|
|
750
|
+
} catch (error) {
|
|
751
|
+
// Ignore storage errors
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
await persistTransferCodes();
|
|
756
|
+
if (__DEV__) {
|
|
757
|
+
logger('Cleared transfer code', {
|
|
758
|
+
transferId
|
|
759
|
+
});
|
|
760
|
+
}
|
|
761
|
+
}, [logger, persistTransferCodes, storage]);
|
|
762
|
+
const refreshSessionsWithUser = (0, _react.useCallback)(() => refreshSessions(userId || undefined), [refreshSessions, userId]);
|
|
763
|
+
const handleSessionRemoved = (0, _react.useCallback)(sessionId => {
|
|
764
|
+
trackRemovedSession(sessionId);
|
|
765
|
+
}, [trackRemovedSession]);
|
|
766
|
+
const handleRemoteSignOut = (0, _react.useCallback)(() => {
|
|
767
|
+
_sonner.toast.info('You have been signed out remotely.');
|
|
768
|
+
logout().catch(remoteError => logger('Failed to process remote sign out', remoteError));
|
|
769
|
+
}, [logger, logout]);
|
|
770
|
+
const handleIdentityTransferComplete = (0, _react.useCallback)(async data => {
|
|
771
|
+
try {
|
|
772
|
+
logger('Received identity transfer complete notification', {
|
|
773
|
+
transferId: data.transferId,
|
|
774
|
+
sourceDeviceId: data.sourceDeviceId,
|
|
775
|
+
currentDeviceId,
|
|
776
|
+
hasActiveSession: activeSessionId !== null,
|
|
777
|
+
publicKey: data.publicKey.substring(0, 16) + '...'
|
|
778
|
+
});
|
|
779
|
+
const storedTransfer = getTransferCode(data.transferId);
|
|
780
|
+
if (!storedTransfer) {
|
|
781
|
+
logger('Transfer code not found for transferId', {
|
|
782
|
+
transferId: data.transferId
|
|
783
|
+
});
|
|
784
|
+
_sonner.toast.error('Transfer verification failed: Code not found. Identity will not be deleted.');
|
|
785
|
+
return;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
// Verify publicKey matches first (most important check)
|
|
789
|
+
const publicKeyMatches = data.publicKey === storedTransfer.publicKey;
|
|
790
|
+
if (!publicKeyMatches) {
|
|
791
|
+
logger('Public key mismatch for transfer', {
|
|
792
|
+
transferId: data.transferId,
|
|
793
|
+
receivedPublicKey: data.publicKey.substring(0, 16) + '...',
|
|
794
|
+
storedPublicKey: storedTransfer.publicKey.substring(0, 16) + '...'
|
|
795
|
+
});
|
|
796
|
+
_sonner.toast.error('Transfer verification failed: Public key mismatch. Identity will not be deleted.');
|
|
797
|
+
return;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
// Verify deviceId matches - very lenient since publicKey is the critical check
|
|
801
|
+
// If publicKey matches, we allow deletion even if deviceId doesn't match exactly
|
|
802
|
+
// This handles cases where deviceId might not be available or slightly different
|
|
803
|
+
const deviceIdMatches =
|
|
804
|
+
// Exact match
|
|
805
|
+
data.sourceDeviceId && data.sourceDeviceId === currentDeviceId ||
|
|
806
|
+
// Stored sourceDeviceId matches current deviceId
|
|
807
|
+
storedTransfer.sourceDeviceId && storedTransfer.sourceDeviceId === currentDeviceId;
|
|
808
|
+
|
|
809
|
+
// If publicKey matches, we're very lenient with deviceId - only warn but don't block
|
|
810
|
+
if (!deviceIdMatches && publicKeyMatches) {
|
|
811
|
+
logger('Device ID mismatch for transfer, but publicKey matches - proceeding with deletion', {
|
|
812
|
+
transferId: data.transferId,
|
|
813
|
+
receivedDeviceId: data.sourceDeviceId,
|
|
814
|
+
storedDeviceId: storedTransfer.sourceDeviceId,
|
|
815
|
+
currentDeviceId,
|
|
816
|
+
hasActiveSession: activeSessionId !== null
|
|
817
|
+
});
|
|
818
|
+
// Proceed with deletion - publicKey match is the critical verification
|
|
819
|
+
} else if (!deviceIdMatches && !publicKeyMatches) {
|
|
820
|
+
// Both don't match - this is suspicious, block deletion
|
|
821
|
+
logger('Device ID and publicKey mismatch for transfer', {
|
|
822
|
+
transferId: data.transferId,
|
|
823
|
+
receivedDeviceId: data.sourceDeviceId,
|
|
824
|
+
currentDeviceId
|
|
825
|
+
});
|
|
826
|
+
_sonner.toast.error('Transfer verification failed: Device and key mismatch. Identity will not be deleted.');
|
|
827
|
+
return;
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
// Verify transfer code matches (if provided)
|
|
831
|
+
// Transfer code is optional - if not provided, we still proceed if publicKey matches
|
|
832
|
+
if (data.transferCode) {
|
|
833
|
+
const codeMatches = data.transferCode.toUpperCase() === storedTransfer.code.toUpperCase();
|
|
834
|
+
if (!codeMatches) {
|
|
835
|
+
logger('Transfer code mismatch, but publicKey matches - proceeding with deletion', {
|
|
836
|
+
transferId: data.transferId,
|
|
837
|
+
receivedCode: data.transferCode,
|
|
838
|
+
storedCode: storedTransfer.code.substring(0, 2) + '****'
|
|
839
|
+
});
|
|
840
|
+
// Don't block - publicKey match is sufficient, code mismatch might be due to user error
|
|
841
|
+
// Log warning but proceed
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
// Check if transfer is too old (safety timeout - 10 minutes)
|
|
846
|
+
const transferAge = Date.now() - storedTransfer.timestamp;
|
|
847
|
+
const tenMinutes = 10 * 60 * 1000;
|
|
848
|
+
if (transferAge > tenMinutes) {
|
|
849
|
+
logger('Transfer confirmation received too late', {
|
|
850
|
+
transferId: data.transferId,
|
|
851
|
+
age: transferAge,
|
|
852
|
+
ageMinutes: Math.round(transferAge / 60000)
|
|
853
|
+
});
|
|
854
|
+
_sonner.toast.error('Transfer verification failed: Confirmation received too late. Identity will not be deleted.');
|
|
855
|
+
clearTransferCode(data.transferId);
|
|
856
|
+
return;
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
// NOTE: Target device verification already happened server-side when notifyTransferComplete was called
|
|
860
|
+
// The server verified that the target device is authenticated and has the matching public key
|
|
861
|
+
// Additional client-side verification is not necessary and would require source device authentication
|
|
862
|
+
// which may not be available. The existing checks (public key match, transfer code, device ID) are sufficient.
|
|
863
|
+
|
|
864
|
+
logger('All transfer verifications passed, deleting identity from source device', {
|
|
865
|
+
transferId: data.transferId,
|
|
866
|
+
sourceDeviceId: data.sourceDeviceId,
|
|
867
|
+
publicKey: data.publicKey.substring(0, 16) + '...'
|
|
868
|
+
});
|
|
869
|
+
try {
|
|
870
|
+
// Verify identity still exists before deletion (safety check)
|
|
871
|
+
const identityStillExists = await _crypto.KeyManager.hasIdentity();
|
|
872
|
+
if (!identityStillExists) {
|
|
873
|
+
logger('Identity already deleted - skipping deletion', {
|
|
874
|
+
transferId: data.transferId
|
|
875
|
+
});
|
|
876
|
+
await updateTransferState(data.transferId, 'completed');
|
|
877
|
+
await clearTransferCode(data.transferId);
|
|
878
|
+
return;
|
|
879
|
+
}
|
|
880
|
+
await deleteIdentityAndClearAccount(false, false, true);
|
|
881
|
+
|
|
882
|
+
// Verify identity was actually deleted
|
|
883
|
+
const identityDeleted = !(await _crypto.KeyManager.hasIdentity());
|
|
884
|
+
if (!identityDeleted) {
|
|
885
|
+
logger('Identity deletion failed - identity still exists', {
|
|
886
|
+
transferId: data.transferId
|
|
887
|
+
});
|
|
888
|
+
await updateTransferState(data.transferId, 'failed');
|
|
889
|
+
throw new Error('Identity deletion failed - identity still exists');
|
|
890
|
+
}
|
|
891
|
+
await updateTransferState(data.transferId, 'completed');
|
|
892
|
+
await clearTransferCode(data.transferId);
|
|
893
|
+
logger('Identity successfully deleted and transfer code cleared', {
|
|
894
|
+
transferId: data.transferId
|
|
895
|
+
});
|
|
896
|
+
_sonner.toast.success('Identity successfully transferred and removed from this device');
|
|
897
|
+
} catch (deleteError) {
|
|
898
|
+
logger('Error during identity deletion', deleteError);
|
|
899
|
+
await updateTransferState(data.transferId, 'failed');
|
|
900
|
+
throw deleteError;
|
|
901
|
+
}
|
|
902
|
+
} catch (error) {
|
|
903
|
+
logger('Failed to delete identity after transfer', error);
|
|
904
|
+
_sonner.toast.error(error?.message || 'Failed to remove identity from this device. Please try again manually from Security Settings.');
|
|
905
|
+
}
|
|
906
|
+
}, [deleteIdentityAndClearAccount, logger, getTransferCode, clearTransferCode, updateTransferState, currentDeviceId, activeSessionId, oxyServices]);
|
|
611
907
|
(0, _useSessionSocket.useSessionSocket)({
|
|
612
908
|
userId,
|
|
613
909
|
activeSessionId,
|
|
614
910
|
currentDeviceId,
|
|
615
|
-
refreshSessions,
|
|
911
|
+
refreshSessions: refreshSessionsWithUser,
|
|
616
912
|
logout,
|
|
617
913
|
clearSessionState,
|
|
618
914
|
baseURL: oxyServices.getBaseURL(),
|
|
619
915
|
getAccessToken: () => oxyServices.getAccessToken(),
|
|
620
916
|
getTransferCode: getTransferCode,
|
|
621
|
-
onRemoteSignOut:
|
|
622
|
-
|
|
623
|
-
logout().catch(err => logger('Failed to process remote sign out', err));
|
|
624
|
-
},
|
|
625
|
-
onSessionRemoved: sessionId => {
|
|
626
|
-
setSessions(prev => prev.filter(s => s.sessionId !== sessionId));
|
|
627
|
-
if (sessionId === activeSessionId) {
|
|
628
|
-
setActiveSessionId(null);
|
|
629
|
-
}
|
|
630
|
-
},
|
|
917
|
+
onRemoteSignOut: handleRemoteSignOut,
|
|
918
|
+
onSessionRemoved: handleSessionRemoved,
|
|
631
919
|
onIdentityTransferComplete: handleIdentityTransferComplete
|
|
632
920
|
});
|
|
633
|
-
const {
|
|
634
|
-
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
921
|
+
const switchSessionForContext = (0, _react.useCallback)(async sessionId => {
|
|
922
|
+
await switchSession(sessionId);
|
|
923
|
+
}, [switchSession]);
|
|
924
|
+
|
|
925
|
+
// Create showBottomSheet function that uses the global function
|
|
926
|
+
const showBottomSheetForContext = (0, _react.useCallback)(screenOrConfig => {
|
|
927
|
+
(0, _bottomSheetManager.showBottomSheet)(screenOrConfig);
|
|
928
|
+
}, []);
|
|
929
|
+
|
|
930
|
+
// Create openAvatarPicker function
|
|
931
|
+
const openAvatarPicker = (0, _react.useCallback)(() => {
|
|
932
|
+
showBottomSheetForContext({
|
|
933
|
+
screen: 'FileManagement',
|
|
934
|
+
props: {
|
|
935
|
+
selectMode: true,
|
|
936
|
+
multiSelect: false,
|
|
937
|
+
disabledMimeTypes: ['video/', 'audio/', 'application/pdf'],
|
|
938
|
+
afterSelect: 'none',
|
|
939
|
+
// Don't navigate away - stay on current screen
|
|
940
|
+
onSelect: async file => {
|
|
941
|
+
if (!file.contentType.startsWith('image/')) {
|
|
942
|
+
_sonner.toast.error((0, _i18n.translate)(currentLanguage, 'editProfile.toasts.selectImage') || 'Please select an image file');
|
|
943
|
+
return;
|
|
944
|
+
}
|
|
945
|
+
try {
|
|
946
|
+
// Update file visibility to public for avatar
|
|
947
|
+
await (0, _avatarUtils.updateAvatarVisibility)(file.id, oxyServices, 'OxyContext');
|
|
948
|
+
|
|
949
|
+
// Update user profile (handles query invalidation and accountStore update)
|
|
950
|
+
await (0, _avatarUtils.updateProfileWithAvatar)({
|
|
951
|
+
avatar: file.id
|
|
952
|
+
}, oxyServices, activeSessionId, queryClient, {
|
|
953
|
+
syncIdentity,
|
|
954
|
+
deviceId: currentDeviceId || undefined
|
|
955
|
+
});
|
|
956
|
+
_sonner.toast.success((0, _i18n.translate)(currentLanguage, 'editProfile.toasts.avatarUpdated') || 'Avatar updated');
|
|
957
|
+
} catch (e) {
|
|
958
|
+
_sonner.toast.error(e.message || (0, _i18n.translate)(currentLanguage, 'editProfile.toasts.updateAvatarFailed') || 'Failed to update avatar');
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
});
|
|
963
|
+
}, [oxyServices, currentLanguage, showBottomSheetForContext, activeSessionId, queryClient, syncIdentity]);
|
|
642
964
|
const contextValue = (0, _react.useMemo)(() => ({
|
|
643
965
|
user,
|
|
644
966
|
sessions,
|
|
645
967
|
activeSessionId,
|
|
646
968
|
currentDeviceId,
|
|
647
|
-
isAuthenticated
|
|
969
|
+
isAuthenticated,
|
|
648
970
|
isLoading,
|
|
649
971
|
isTokenReady: tokenReady,
|
|
650
972
|
isStorageReady,
|
|
@@ -661,15 +983,21 @@ const OxyProvider = ({
|
|
|
661
983
|
isIdentitySynced,
|
|
662
984
|
syncIdentity,
|
|
663
985
|
deleteIdentityAndClearAccount,
|
|
986
|
+
storeTransferCode,
|
|
987
|
+
getTransferCode,
|
|
988
|
+
clearTransferCode,
|
|
989
|
+
getAllPendingTransfers,
|
|
990
|
+
getActiveTransferId,
|
|
991
|
+
updateTransferState,
|
|
664
992
|
identitySyncState: {
|
|
665
993
|
isSynced: isIdentitySyncedStore ?? true,
|
|
666
994
|
isSyncing: isSyncing ?? false
|
|
667
995
|
},
|
|
668
996
|
logout,
|
|
669
997
|
logoutAll,
|
|
670
|
-
switchSession,
|
|
998
|
+
switchSession: switchSessionForContext,
|
|
671
999
|
removeSession: logout,
|
|
672
|
-
refreshSessions,
|
|
1000
|
+
refreshSessions: refreshSessionsWithUser,
|
|
673
1001
|
setLanguage,
|
|
674
1002
|
getDeviceSessions,
|
|
675
1003
|
logoutAllDeviceSessions,
|
|
@@ -677,9 +1005,10 @@ const OxyProvider = ({
|
|
|
677
1005
|
clearSessionState,
|
|
678
1006
|
clearAllAccountData,
|
|
679
1007
|
oxyServices,
|
|
680
|
-
|
|
1008
|
+
useFollow: useFollowHook,
|
|
1009
|
+
showBottomSheet: showBottomSheetForContext,
|
|
681
1010
|
openAvatarPicker
|
|
682
|
-
}), [activeSessionId, currentDeviceId, createIdentity, importIdentity, signIn, hasIdentity, getPublicKey, isIdentitySynced, syncIdentity, deleteIdentityAndClearAccount, isIdentitySyncedStore, isSyncing, currentLanguage, currentLanguageMetadata, currentLanguageName, currentNativeLanguageName, error, getDeviceSessions,
|
|
1011
|
+
}), [activeSessionId, currentDeviceId, createIdentity, importIdentity, signIn, hasIdentity, getPublicKey, isIdentitySynced, syncIdentity, deleteIdentityAndClearAccount, storeTransferCode, getTransferCode, clearTransferCode, getAllPendingTransfers, getActiveTransferId, updateTransferState, isIdentitySyncedStore, isSyncing, currentLanguage, currentLanguageMetadata, currentLanguageName, currentNativeLanguageName, error, getDeviceSessions, isAuthenticated, isLoading, logout, logoutAll, logoutAllDeviceSessions, oxyServices, refreshSessionsWithUser, sessions, setLanguage, switchSessionForContext, tokenReady, isStorageReady, updateDeviceName, clearAllAccountData, useFollowHook, user, showBottomSheetForContext, openAvatarPicker]);
|
|
683
1012
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(OxyContext.Provider, {
|
|
684
1013
|
value: contextValue,
|
|
685
1014
|
children: children
|