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