@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
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
|
+
import { useQueryClient } from '@tanstack/react-query';
|
|
3
|
+
import { toast } from '../../lib/sonner';
|
|
4
|
+
import { translate } from '../../i18n';
|
|
5
|
+
import type { RouteName } from '../navigation/routes';
|
|
6
|
+
import { showBottomSheet as globalShowBottomSheet } from '../navigation/bottomSheetManager';
|
|
7
|
+
import { updateAvatarVisibility, updateProfileWithAvatar } from '../utils/avatarUtils';
|
|
8
|
+
import type { OxyServices } from '../../core';
|
|
9
|
+
import type { User } from '../../models/interfaces';
|
|
10
|
+
|
|
11
|
+
interface UseAvatarPickerOptions {
|
|
12
|
+
oxyServices: OxyServices;
|
|
13
|
+
currentLanguage: string;
|
|
14
|
+
activeSessionId: string | null;
|
|
15
|
+
queryClient: ReturnType<typeof useQueryClient>;
|
|
16
|
+
syncIdentity: (username?: string) => Promise<User>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Hook to handle avatar picker functionality
|
|
21
|
+
*/
|
|
22
|
+
export function useAvatarPicker({
|
|
23
|
+
oxyServices,
|
|
24
|
+
currentLanguage,
|
|
25
|
+
activeSessionId,
|
|
26
|
+
queryClient,
|
|
27
|
+
syncIdentity,
|
|
28
|
+
}: UseAvatarPickerOptions) {
|
|
29
|
+
const openAvatarPicker = useCallback(() => {
|
|
30
|
+
globalShowBottomSheet({
|
|
31
|
+
screen: 'FileManagement' as RouteName,
|
|
32
|
+
props: {
|
|
33
|
+
selectMode: true,
|
|
34
|
+
multiSelect: false,
|
|
35
|
+
disabledMimeTypes: ['video/', 'audio/', 'application/pdf'],
|
|
36
|
+
afterSelect: 'none',
|
|
37
|
+
onSelect: async (file: any) => {
|
|
38
|
+
if (!file.contentType.startsWith('image/')) {
|
|
39
|
+
toast.error(translate(currentLanguage, 'editProfile.toasts.selectImage') || 'Please select an image file');
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
await updateAvatarVisibility(file.id, oxyServices, 'useAvatarPicker');
|
|
44
|
+
await updateProfileWithAvatar(
|
|
45
|
+
{ avatar: file.id },
|
|
46
|
+
oxyServices,
|
|
47
|
+
activeSessionId,
|
|
48
|
+
queryClient,
|
|
49
|
+
() => syncIdentity()
|
|
50
|
+
);
|
|
51
|
+
toast.success(translate(currentLanguage, 'editProfile.toasts.avatarUpdated') || 'Avatar updated');
|
|
52
|
+
} catch (e: any) {
|
|
53
|
+
toast.error(e.message || translate(currentLanguage, 'editProfile.toasts.updateAvatarFailed') || 'Failed to update avatar');
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
}, [oxyServices, currentLanguage, activeSessionId, queryClient, syncIdentity]);
|
|
59
|
+
|
|
60
|
+
return { openAvatarPicker };
|
|
61
|
+
}
|
|
62
|
+
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
|
+
import { toast } from '../../lib/sonner';
|
|
3
|
+
import { useTransferStore } from '../stores/transferStore';
|
|
4
|
+
import type { IdentitySessionCore } from '../../core/identity-session';
|
|
5
|
+
|
|
6
|
+
interface UseIdentityTransferOptions {
|
|
7
|
+
identityCore: IdentitySessionCore | null;
|
|
8
|
+
currentDeviceId: string | null;
|
|
9
|
+
activeSessionId: string | null;
|
|
10
|
+
getPublicKey: () => Promise<string | null>;
|
|
11
|
+
deleteIdentityAndClearAccount: (skipBackup?: boolean, force?: boolean, userConfirmed?: boolean) => Promise<void>;
|
|
12
|
+
logger: (message: string, err?: unknown) => void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Hook to handle identity transfer completion
|
|
17
|
+
* This hook processes the identity_transfer_complete event and deletes the identity from the source device
|
|
18
|
+
*/
|
|
19
|
+
export function useIdentityTransfer({
|
|
20
|
+
identityCore,
|
|
21
|
+
currentDeviceId,
|
|
22
|
+
activeSessionId,
|
|
23
|
+
getPublicKey,
|
|
24
|
+
deleteIdentityAndClearAccount,
|
|
25
|
+
logger,
|
|
26
|
+
}: UseIdentityTransferOptions) {
|
|
27
|
+
const getTransferCode = useTransferStore((state) => state.getTransferCode);
|
|
28
|
+
const clearTransferCode = useTransferStore((state) => state.clearTransferCode);
|
|
29
|
+
const updateTransferState = useTransferStore((state) => state.updateTransferState);
|
|
30
|
+
|
|
31
|
+
const handleIdentityTransferComplete = useCallback(
|
|
32
|
+
async (data: { transferId: string; sourceDeviceId: string; publicKey: string; transferCode?: string; completedAt: string }) => {
|
|
33
|
+
try {
|
|
34
|
+
logger('Received identity transfer complete notification', {
|
|
35
|
+
transferId: data.transferId,
|
|
36
|
+
sourceDeviceId: data.sourceDeviceId,
|
|
37
|
+
currentDeviceId,
|
|
38
|
+
hasActiveSession: activeSessionId !== null,
|
|
39
|
+
publicKey: data.publicKey.substring(0, 16) + '...',
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const storedTransfer = getTransferCode(data.transferId);
|
|
43
|
+
|
|
44
|
+
if (!storedTransfer) {
|
|
45
|
+
logger('Transfer code not found for transferId', { transferId: data.transferId });
|
|
46
|
+
toast.error('Transfer verification failed: Code not found. Identity will not be deleted.');
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const currentPublicKey = await getPublicKey();
|
|
51
|
+
if (!currentPublicKey) {
|
|
52
|
+
logger('No public key found on device - cannot verify transfer', { transferId: data.transferId });
|
|
53
|
+
toast.error('Transfer verification failed: No identity found on device. Identity will not be deleted.');
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const isSourceDevice = currentPublicKey === storedTransfer.publicKey;
|
|
58
|
+
if (!isSourceDevice) {
|
|
59
|
+
logger('Current device public key does not match stored transfer public key - this is not the source device', {
|
|
60
|
+
transferId: data.transferId,
|
|
61
|
+
currentPublicKey: currentPublicKey.substring(0, 16) + '...',
|
|
62
|
+
storedPublicKey: storedTransfer.publicKey.substring(0, 16) + '...',
|
|
63
|
+
});
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const publicKeyMatches = data.publicKey === storedTransfer.publicKey;
|
|
68
|
+
if (!publicKeyMatches) {
|
|
69
|
+
logger('Public key mismatch for transfer', {
|
|
70
|
+
transferId: data.transferId,
|
|
71
|
+
receivedPublicKey: data.publicKey.substring(0, 16) + '...',
|
|
72
|
+
storedPublicKey: storedTransfer.publicKey.substring(0, 16) + '...',
|
|
73
|
+
});
|
|
74
|
+
toast.error('Transfer verification failed: Public key mismatch. Identity will not be deleted.');
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const transferAge = Date.now() - storedTransfer.timestamp;
|
|
79
|
+
const tenMinutes = 10 * 60 * 1000;
|
|
80
|
+
if (transferAge > tenMinutes) {
|
|
81
|
+
logger('Transfer confirmation received too late', {
|
|
82
|
+
transferId: data.transferId,
|
|
83
|
+
age: transferAge,
|
|
84
|
+
ageMinutes: Math.round(transferAge / 60000),
|
|
85
|
+
});
|
|
86
|
+
toast.error('Transfer verification failed: Confirmation received too late. Identity will not be deleted.');
|
|
87
|
+
clearTransferCode(data.transferId);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
logger('All transfer verifications passed, deleting identity from source device', {
|
|
92
|
+
transferId: data.transferId,
|
|
93
|
+
sourceDeviceId: data.sourceDeviceId,
|
|
94
|
+
publicKey: data.publicKey.substring(0, 16) + '...',
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
const identityStillExists = identityCore ? await identityCore.hasIdentity() : false;
|
|
99
|
+
if (!identityStillExists) {
|
|
100
|
+
logger('Identity already deleted - skipping deletion', { transferId: data.transferId });
|
|
101
|
+
await updateTransferState(data.transferId, 'completed');
|
|
102
|
+
await clearTransferCode(data.transferId);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
await deleteIdentityAndClearAccount(false, false, true);
|
|
107
|
+
|
|
108
|
+
const identityDeleted = identityCore ? !(await identityCore.hasIdentity()) : true;
|
|
109
|
+
if (!identityDeleted) {
|
|
110
|
+
logger('Identity deletion failed - identity still exists', { transferId: data.transferId });
|
|
111
|
+
await updateTransferState(data.transferId, 'failed');
|
|
112
|
+
throw new Error('Identity deletion failed - identity still exists');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
await updateTransferState(data.transferId, 'completed');
|
|
116
|
+
await clearTransferCode(data.transferId);
|
|
117
|
+
|
|
118
|
+
logger('Identity successfully deleted and transfer code cleared', { transferId: data.transferId });
|
|
119
|
+
toast.success('Identity successfully transferred and removed from this device');
|
|
120
|
+
} catch (deleteError: any) {
|
|
121
|
+
logger('Error during identity deletion', deleteError);
|
|
122
|
+
await updateTransferState(data.transferId, 'failed');
|
|
123
|
+
throw deleteError;
|
|
124
|
+
}
|
|
125
|
+
} catch (error: any) {
|
|
126
|
+
logger('Failed to delete identity after transfer', error);
|
|
127
|
+
toast.error(error?.message || 'Failed to remove identity from this device. Please try again manually from Security Settings.');
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
[deleteIdentityAndClearAccount, logger, getTransferCode, clearTransferCode, updateTransferState, currentDeviceId, activeSessionId, getPublicKey, identityCore]
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
return { handleIdentityTransferComplete };
|
|
134
|
+
}
|
|
135
|
+
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import { useStorage } from './useStorage';
|
|
3
|
+
import { useTransferStore } from '../stores/transferStore';
|
|
4
|
+
|
|
5
|
+
const TRANSFER_CODES_STORAGE_KEY = 'oxy_transfer_codes';
|
|
6
|
+
const ACTIVE_TRANSFER_STORAGE_KEY = 'oxy_active_transfer_id';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Hook to handle persistence of transfer codes to storage
|
|
10
|
+
* This hook automatically loads transfer codes on mount and persists them when they change
|
|
11
|
+
*/
|
|
12
|
+
export function useTransferCodesPersistence(storageKeyPrefix: string = 'oxy_session') {
|
|
13
|
+
const TRANSFER_CODES_KEY = `${storageKeyPrefix}_transfer_codes`;
|
|
14
|
+
const ACTIVE_TRANSFER_KEY = `${storageKeyPrefix}_active_transfer_id`;
|
|
15
|
+
|
|
16
|
+
const { storage, isReady: isStorageReady } = useStorage();
|
|
17
|
+
|
|
18
|
+
const isRestored = useTransferStore((state) => state.isRestored);
|
|
19
|
+
const restoreFromStorage = useTransferStore((state) => state.restoreFromStorage);
|
|
20
|
+
const markRestored = useTransferStore((state) => state.markRestored);
|
|
21
|
+
const cleanupExpired = useTransferStore((state) => state.cleanupExpired);
|
|
22
|
+
const { transferCodes, activeTransferId } = useTransferStore((state) => ({
|
|
23
|
+
transferCodes: state.transferCodes,
|
|
24
|
+
activeTransferId: state.activeTransferId,
|
|
25
|
+
}));
|
|
26
|
+
|
|
27
|
+
// Load transfer codes from storage on startup (only once)
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
if (!storage || !isStorageReady || isRestored) return;
|
|
30
|
+
|
|
31
|
+
const loadTransferCodes = async () => {
|
|
32
|
+
try {
|
|
33
|
+
const storedCodes = await storage.getItem(TRANSFER_CODES_KEY);
|
|
34
|
+
const storedActiveTransferId = await storage.getItem(ACTIVE_TRANSFER_KEY);
|
|
35
|
+
|
|
36
|
+
const parsedCodes = storedCodes ? JSON.parse(storedCodes) : {};
|
|
37
|
+
const activeTransferId = storedActiveTransferId || null;
|
|
38
|
+
|
|
39
|
+
restoreFromStorage(parsedCodes, activeTransferId);
|
|
40
|
+
markRestored();
|
|
41
|
+
} catch (error) {
|
|
42
|
+
// Mark as restored even on error to prevent retries
|
|
43
|
+
markRestored();
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
loadTransferCodes();
|
|
48
|
+
}, [storage, isStorageReady, isRestored, restoreFromStorage, markRestored, TRANSFER_CODES_KEY, ACTIVE_TRANSFER_KEY]);
|
|
49
|
+
|
|
50
|
+
// Persist transfer codes to storage whenever store changes
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
if (!storage || !isStorageReady || !isRestored) return;
|
|
53
|
+
|
|
54
|
+
const persistTransferCodes = async () => {
|
|
55
|
+
try {
|
|
56
|
+
await storage.setItem(TRANSFER_CODES_KEY, JSON.stringify(transferCodes));
|
|
57
|
+
|
|
58
|
+
if (activeTransferId) {
|
|
59
|
+
await storage.setItem(ACTIVE_TRANSFER_KEY, activeTransferId);
|
|
60
|
+
} else {
|
|
61
|
+
await storage.removeItem(ACTIVE_TRANSFER_KEY);
|
|
62
|
+
}
|
|
63
|
+
} catch (error) {
|
|
64
|
+
// Silently fail - persistence errors are not critical
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
persistTransferCodes();
|
|
69
|
+
}, [transferCodes, activeTransferId, storage, isStorageReady, isRestored, TRANSFER_CODES_KEY, ACTIVE_TRANSFER_KEY]);
|
|
70
|
+
|
|
71
|
+
// Cleanup expired transfer codes (every minute)
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
const cleanup = setInterval(() => {
|
|
74
|
+
cleanupExpired();
|
|
75
|
+
}, 60000);
|
|
76
|
+
|
|
77
|
+
return () => clearInterval(cleanup);
|
|
78
|
+
}, [cleanupExpired]);
|
|
79
|
+
}
|
|
80
|
+
|
|
@@ -86,9 +86,14 @@ const AccountCenterScreen: React.FC<BaseScreenProps> = ({
|
|
|
86
86
|
return (
|
|
87
87
|
<View style={[styles.container, { backgroundColor }]}>
|
|
88
88
|
{/* Header with user profile */}
|
|
89
|
-
{user && (
|
|
89
|
+
{user && user.username && (
|
|
90
90
|
<ProfileCard
|
|
91
|
-
user={
|
|
91
|
+
user={{
|
|
92
|
+
username: user.username,
|
|
93
|
+
email: user.email,
|
|
94
|
+
name: user.name,
|
|
95
|
+
avatar: user.avatar,
|
|
96
|
+
}}
|
|
92
97
|
theme={normalizedTheme}
|
|
93
98
|
onEditPress={() => navigate?.('EditProfile', { activeTab: 'profile' })}
|
|
94
99
|
onClosePress={onClose}
|
|
@@ -229,7 +229,7 @@ const AccountSettingsScreen: React.FC<BaseScreenProps & { initialField?: string;
|
|
|
229
229
|
setUsername(finalUser.username || '');
|
|
230
230
|
setEmail(finalUser.email || '');
|
|
231
231
|
setBio(finalUser.bio || '');
|
|
232
|
-
setLocation(finalUser.location
|
|
232
|
+
setLocation(typeof finalUser.location === 'string' ? finalUser.location : '');
|
|
233
233
|
|
|
234
234
|
// Handle locations - convert single location to array format
|
|
235
235
|
if (finalUser.locations && Array.isArray(finalUser.locations)) {
|
|
@@ -239,7 +239,7 @@ const AccountSettingsScreen: React.FC<BaseScreenProps & { initialField?: string;
|
|
|
239
239
|
label: loc.label,
|
|
240
240
|
coordinates: loc.coordinates
|
|
241
241
|
})));
|
|
242
|
-
} else if (finalUser.location) {
|
|
242
|
+
} else if (finalUser.location && typeof finalUser.location === 'string') {
|
|
243
243
|
// Convert single location string to array format
|
|
244
244
|
setLocations([{
|
|
245
245
|
id: 'existing-0',
|
|
@@ -256,11 +256,11 @@ const AccountSettingsScreen: React.FC<BaseScreenProps & { initialField?: string;
|
|
|
256
256
|
setLinks(urls);
|
|
257
257
|
const metadataWithIds = finalUser.linksMetadata.map((link, index) => ({
|
|
258
258
|
...link,
|
|
259
|
-
id: link.id || `existing-${index}`
|
|
259
|
+
id: (link as any).id || `existing-${index}`
|
|
260
260
|
}));
|
|
261
261
|
setLinksMetadata(metadataWithIds);
|
|
262
262
|
} else if (Array.isArray(finalUser.links)) {
|
|
263
|
-
const simpleLinks = finalUser.links.map(l => typeof l === 'string' ? l : l.link).filter(Boolean);
|
|
263
|
+
const simpleLinks = finalUser.links.map(l => typeof l === 'string' ? l : (l as any).link).filter(Boolean) as string[];
|
|
264
264
|
setLinks(simpleLinks);
|
|
265
265
|
const linksWithMetadata = simpleLinks.map((url, index) => ({
|
|
266
266
|
url,
|
|
@@ -270,7 +270,7 @@ const AccountSettingsScreen: React.FC<BaseScreenProps & { initialField?: string;
|
|
|
270
270
|
id: `existing-${index}`
|
|
271
271
|
}));
|
|
272
272
|
setLinksMetadata(linksWithMetadata);
|
|
273
|
-
} else if (finalUser.website) {
|
|
273
|
+
} else if (finalUser.website && typeof finalUser.website === 'string') {
|
|
274
274
|
setLinks([finalUser.website]);
|
|
275
275
|
setLinksMetadata([{
|
|
276
276
|
url: finalUser.website,
|
|
@@ -388,7 +388,14 @@ const AccountSettingsScreen: React.FC<BaseScreenProps & { initialField?: string;
|
|
|
388
388
|
setLocations(tempLocations);
|
|
389
389
|
break;
|
|
390
390
|
case 'links':
|
|
391
|
-
|
|
391
|
+
// Ensure all links have required fields
|
|
392
|
+
const linksWithRequiredFields = tempLinksWithMetadata.map(link => ({
|
|
393
|
+
url: link.url,
|
|
394
|
+
title: link.title || link.url.replace(/^https?:\/\//, '').replace(/\/$/, ''),
|
|
395
|
+
description: link.description || `Link to ${link.url}`,
|
|
396
|
+
image: link.image,
|
|
397
|
+
}));
|
|
398
|
+
await updateProfileMutation.mutateAsync({ linksMetadata: linksWithRequiredFields });
|
|
392
399
|
setLinksMetadata(tempLinksWithMetadata);
|
|
393
400
|
setLinks(tempLinksWithMetadata.map(l => l.url));
|
|
394
401
|
break;
|
|
@@ -542,7 +549,7 @@ const AccountSettingsScreen: React.FC<BaseScreenProps & { initialField?: string;
|
|
|
542
549
|
label: loc.label,
|
|
543
550
|
coordinates: loc.coordinates
|
|
544
551
|
})));
|
|
545
|
-
} else if (currentUser.location) {
|
|
552
|
+
} else if (currentUser.location && typeof currentUser.location === 'string') {
|
|
546
553
|
setLocations([{
|
|
547
554
|
id: 'existing-0',
|
|
548
555
|
name: currentUser.location,
|
|
@@ -555,7 +562,7 @@ const AccountSettingsScreen: React.FC<BaseScreenProps & { initialField?: string;
|
|
|
555
562
|
if (currentUser.linksMetadata && Array.isArray(currentUser.linksMetadata)) {
|
|
556
563
|
setLinksMetadata(currentUser.linksMetadata.map((link, index) => ({
|
|
557
564
|
...link,
|
|
558
|
-
id: link.id || `existing-${index}`
|
|
565
|
+
id: (link as any).id || `existing-${index}`
|
|
559
566
|
})));
|
|
560
567
|
} else {
|
|
561
568
|
setLinksMetadata([]);
|
|
@@ -405,7 +405,7 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
|
|
|
405
405
|
) : (
|
|
406
406
|
<View style={styles.accountAvatarFallback}>
|
|
407
407
|
<Text style={styles.accountAvatarText}>
|
|
408
|
-
{displayName
|
|
408
|
+
{displayName?.charAt(0).toUpperCase() || '?'}
|
|
409
409
|
</Text>
|
|
410
410
|
</View>
|
|
411
411
|
)}
|
|
@@ -432,7 +432,7 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
|
|
|
432
432
|
</TouchableOpacity>
|
|
433
433
|
<TouchableOpacity
|
|
434
434
|
style={styles.removeButton}
|
|
435
|
-
onPress={() => handleRemoveSession(sessionWithUser.sessionId, displayName)}
|
|
435
|
+
onPress={() => handleRemoveSession(sessionWithUser.sessionId, displayName || 'this account')}
|
|
436
436
|
disabled={isSwitching || isRemoving}
|
|
437
437
|
>
|
|
438
438
|
{isRemoving ? (
|
|
@@ -121,7 +121,7 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ userId, username, theme,
|
|
|
121
121
|
id: `existing-${index}`
|
|
122
122
|
}));
|
|
123
123
|
setLinks(linksWithMetadata);
|
|
124
|
-
} else if (profileRes.website) {
|
|
124
|
+
} else if (profileRes.website && typeof profileRes.website === 'string') {
|
|
125
125
|
setLinks([{
|
|
126
126
|
url: profileRes.website,
|
|
127
127
|
title: profileRes.website.replace(/^https?:\/\//, '').replace(/\/$/, ''),
|
|
@@ -252,32 +252,32 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ userId, username, theme,
|
|
|
252
252
|
|
|
253
253
|
{/* Info Grid Row */}
|
|
254
254
|
<View style={styles.infoGrid}>
|
|
255
|
-
{profile?.createdAt
|
|
255
|
+
{profile?.createdAt ? (
|
|
256
256
|
<View style={styles.infoGridItem}>
|
|
257
257
|
<Ionicons name="calendar-outline" size={16} color={colors.secondaryText} style={{ marginRight: 6 }} />
|
|
258
258
|
<Text style={[styles.infoGridText, { color: colors.secondaryText }]}>
|
|
259
259
|
{t('profile.joinedOn', { date: new Date(profile.createdAt).toLocaleDateString() }) || `Joined ${new Date(profile.createdAt).toLocaleDateString()}`}
|
|
260
260
|
</Text>
|
|
261
261
|
</View>
|
|
262
|
-
)}
|
|
263
|
-
{profile?.location && (
|
|
262
|
+
) : null}
|
|
263
|
+
{profile?.location && typeof profile.location === 'string' ? (
|
|
264
264
|
<View style={styles.infoGridItem}>
|
|
265
265
|
<Ionicons name="location-outline" size={16} color={colors.secondaryText} style={{ marginRight: 6 }} />
|
|
266
266
|
<Text style={[styles.infoGridText, { color: colors.secondaryText }]} numberOfLines={1}>{profile.location}</Text>
|
|
267
267
|
</View>
|
|
268
|
-
)}
|
|
269
|
-
{profile?.website && (
|
|
268
|
+
) : null}
|
|
269
|
+
{profile?.website && typeof profile.website === 'string' ? (
|
|
270
270
|
<View style={styles.infoGridItem}>
|
|
271
271
|
<Ionicons name="globe-outline" size={16} color={colors.secondaryText} style={{ marginRight: 6 }} />
|
|
272
272
|
<Text style={[styles.infoGridText, { color: colors.secondaryText }]} numberOfLines={1}>{profile.website}</Text>
|
|
273
273
|
</View>
|
|
274
|
-
)}
|
|
275
|
-
{profile && 'company' in profile && typeof profile.company === 'string' && profile.company
|
|
274
|
+
) : null}
|
|
275
|
+
{profile && 'company' in profile && typeof profile.company === 'string' && profile.company ? (
|
|
276
276
|
<View style={styles.infoGridItem}>
|
|
277
277
|
<Ionicons name="business-outline" size={16} color={colors.secondaryText} style={{ marginRight: 6 }} />
|
|
278
|
-
<Text style={[styles.infoGridText, { color: colors.secondaryText }]} numberOfLines={1}>{profile.company}</Text>
|
|
278
|
+
<Text style={[styles.infoGridText, { color: colors.secondaryText }]} numberOfLines={1}>{profile.company as string}</Text>
|
|
279
279
|
</View>
|
|
280
|
-
)}
|
|
280
|
+
) : null}
|
|
281
281
|
{profile && 'jobTitle' in profile && typeof profile.jobTitle === 'string' && profile.jobTitle && (
|
|
282
282
|
<View style={styles.infoGridItem}>
|
|
283
283
|
<Ionicons name="briefcase-outline" size={16} color={colors.secondaryText} style={{ marginRight: 6 }} />
|
|
@@ -10,6 +10,7 @@ interface DeviceSession {
|
|
|
10
10
|
user?: { id?: string; _id?: { toString(): string } };
|
|
11
11
|
userId?: string;
|
|
12
12
|
isCurrent?: boolean;
|
|
13
|
+
deviceInfo?: import('../../core/identity-session/types').DeviceInfo;
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
export interface FetchSessionsWithFallbackOptions {
|
|
@@ -57,6 +58,12 @@ export const mapSessionsToClient = (
|
|
|
57
58
|
fallbackUserId ||
|
|
58
59
|
'',
|
|
59
60
|
isCurrent: Boolean(session.isCurrent),
|
|
61
|
+
deviceInfo: session.deviceInfo || {
|
|
62
|
+
deviceName: '',
|
|
63
|
+
deviceType: 'unknown',
|
|
64
|
+
platform: 'unknown',
|
|
65
|
+
lastActive: session.lastActive || now.toISOString(),
|
|
66
|
+
},
|
|
60
67
|
}));
|
|
61
68
|
};
|
|
62
69
|
|
package/src/utils/index.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
export type { DeviceFingerprint, StoredDeviceInfo } from './deviceManager';
|
|
1
|
+
// DeviceManager removed - use IdentitySessionCore.getDeviceManager() instead
|
|
3
2
|
|
|
4
3
|
// Request utilities
|
|
5
4
|
export { RequestDeduplicator, RequestQueue, SimpleLogger } from './requestUtils';
|
|
@@ -6,18 +6,26 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { ClientSession } from '../models/session';
|
|
9
|
+
import type { DeviceInfo } from '../core/identity-session/types';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Normalize a session to ensure all required fields are present
|
|
12
13
|
*/
|
|
13
14
|
export function normalizeSession(session: Partial<ClientSession> & { sessionId: string }): ClientSession {
|
|
14
15
|
const now = new Date().toISOString();
|
|
16
|
+
const defaultDeviceInfo: DeviceInfo = {
|
|
17
|
+
deviceName: '',
|
|
18
|
+
deviceType: 'unknown',
|
|
19
|
+
platform: 'unknown',
|
|
20
|
+
lastActive: now,
|
|
21
|
+
};
|
|
15
22
|
return {
|
|
16
23
|
sessionId: session.sessionId,
|
|
17
24
|
deviceId: session.deviceId || '',
|
|
18
25
|
expiresAt: session.expiresAt || now,
|
|
19
26
|
lastActive: session.lastActive || now,
|
|
20
27
|
userId: session.userId || '',
|
|
28
|
+
deviceInfo: session.deviceInfo || defaultDeviceInfo,
|
|
21
29
|
};
|
|
22
30
|
}
|
|
23
31
|
|