@oxyhq/services 5.16.39 → 5.16.41

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.
Files changed (267) hide show
  1. package/lib/commonjs/adapters/expo/crypto.js +56 -0
  2. package/lib/commonjs/adapters/expo/crypto.js.map +1 -0
  3. package/lib/commonjs/adapters/expo/fetch.js +30 -0
  4. package/lib/commonjs/adapters/expo/fetch.js.map +1 -0
  5. package/lib/commonjs/adapters/expo/index.js +48 -0
  6. package/lib/commonjs/adapters/expo/index.js.map +1 -0
  7. package/lib/commonjs/adapters/expo/storage.js +201 -0
  8. package/lib/commonjs/adapters/expo/storage.js.map +1 -0
  9. package/lib/commonjs/adapters/index.js +41 -0
  10. package/lib/commonjs/adapters/index.js.map +1 -0
  11. package/lib/commonjs/adapters/node/crypto.js +40 -0
  12. package/lib/commonjs/adapters/node/crypto.js.map +1 -0
  13. package/lib/commonjs/adapters/node/fetch.js +62 -0
  14. package/lib/commonjs/adapters/node/fetch.js.map +1 -0
  15. package/lib/commonjs/adapters/node/index.js +34 -0
  16. package/lib/commonjs/adapters/node/index.js.map +1 -0
  17. package/lib/commonjs/adapters/node/storage.js +163 -0
  18. package/lib/commonjs/adapters/node/storage.js.map +1 -0
  19. package/lib/commonjs/core/identity-session/DeviceManager.js +237 -0
  20. package/lib/commonjs/core/identity-session/DeviceManager.js.map +1 -0
  21. package/lib/commonjs/core/identity-session/INTEGRATION_GUIDE.md +287 -0
  22. package/lib/commonjs/core/identity-session/IdentityManager.js +400 -0
  23. package/lib/commonjs/core/identity-session/IdentityManager.js.map +1 -0
  24. package/lib/commonjs/core/identity-session/IdentitySessionCore.js +394 -0
  25. package/lib/commonjs/core/identity-session/IdentitySessionCore.js.map +1 -0
  26. package/lib/commonjs/core/identity-session/RefreshManager.js +137 -0
  27. package/lib/commonjs/core/identity-session/RefreshManager.js.map +1 -0
  28. package/lib/commonjs/core/identity-session/SessionManager.js +427 -0
  29. package/lib/commonjs/core/identity-session/SessionManager.js.map +1 -0
  30. package/lib/commonjs/core/identity-session/createIdentitySessionCore.js +24 -0
  31. package/lib/commonjs/core/identity-session/createIdentitySessionCore.js.map +1 -0
  32. package/lib/commonjs/core/identity-session/errors.js +176 -0
  33. package/lib/commonjs/core/identity-session/errors.js.map +1 -0
  34. package/lib/commonjs/core/identity-session/index.js +80 -0
  35. package/lib/commonjs/core/identity-session/index.js.map +1 -0
  36. package/lib/commonjs/core/identity-session/types.js +2 -0
  37. package/lib/commonjs/core/identity-session/types.js.map +1 -0
  38. package/lib/commonjs/core/index.js +2 -21
  39. package/lib/commonjs/core/index.js.map +1 -1
  40. package/lib/commonjs/index.js +58 -8
  41. package/lib/commonjs/index.js.map +1 -1
  42. package/lib/commonjs/models/interfaces.js +7 -0
  43. package/lib/commonjs/models/interfaces.js.map +1 -1
  44. package/lib/commonjs/ui/context/OxyContext.js +434 -820
  45. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  46. package/lib/commonjs/ui/hooks/useAvatarPicker.js +52 -0
  47. package/lib/commonjs/ui/hooks/useAvatarPicker.js.map +1 -0
  48. package/lib/commonjs/ui/hooks/useIdentityTransfer.js +125 -0
  49. package/lib/commonjs/ui/hooks/useIdentityTransfer.js.map +1 -0
  50. package/lib/commonjs/ui/hooks/useTransferCodesPersistence.js +81 -0
  51. package/lib/commonjs/ui/hooks/useTransferCodesPersistence.js.map +1 -0
  52. package/lib/commonjs/ui/screens/AccountCenterScreen.js +7 -2
  53. package/lib/commonjs/ui/screens/AccountCenterScreen.js.map +1 -1
  54. package/lib/commonjs/ui/screens/AccountSettingsScreen.js +12 -5
  55. package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
  56. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +2 -2
  57. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -1
  58. package/lib/commonjs/ui/screens/ProfileScreen.js +6 -6
  59. package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
  60. package/lib/commonjs/ui/utils/sessionHelpers.js +7 -1
  61. package/lib/commonjs/ui/utils/sessionHelpers.js.map +1 -1
  62. package/lib/commonjs/utils/index.js +0 -7
  63. package/lib/commonjs/utils/index.js.map +1 -1
  64. package/lib/commonjs/utils/sessionUtils.js +8 -1
  65. package/lib/commonjs/utils/sessionUtils.js.map +1 -1
  66. package/lib/module/adapters/expo/crypto.js +51 -0
  67. package/lib/module/adapters/expo/crypto.js.map +1 -0
  68. package/lib/module/adapters/expo/fetch.js +26 -0
  69. package/lib/module/adapters/expo/fetch.js.map +1 -0
  70. package/lib/module/adapters/expo/index.js +45 -0
  71. package/lib/module/adapters/expo/index.js.map +1 -0
  72. package/lib/module/adapters/expo/storage.js +198 -0
  73. package/lib/module/adapters/expo/storage.js.map +1 -0
  74. package/lib/module/adapters/index.js +38 -0
  75. package/lib/module/adapters/index.js.map +1 -0
  76. package/lib/module/adapters/node/crypto.js +36 -0
  77. package/lib/module/adapters/node/crypto.js.map +1 -0
  78. package/lib/module/adapters/node/fetch.js +57 -0
  79. package/lib/module/adapters/node/fetch.js.map +1 -0
  80. package/lib/module/adapters/node/index.js +31 -0
  81. package/lib/module/adapters/node/index.js.map +1 -0
  82. package/lib/module/adapters/node/storage.js +159 -0
  83. package/lib/module/adapters/node/storage.js.map +1 -0
  84. package/lib/module/core/identity-session/DeviceManager.js +232 -0
  85. package/lib/module/core/identity-session/DeviceManager.js.map +1 -0
  86. package/lib/module/core/identity-session/INTEGRATION_GUIDE.md +287 -0
  87. package/lib/module/core/identity-session/IdentityManager.js +395 -0
  88. package/lib/module/core/identity-session/IdentityManager.js.map +1 -0
  89. package/lib/module/core/identity-session/IdentitySessionCore.js +390 -0
  90. package/lib/module/core/identity-session/IdentitySessionCore.js.map +1 -0
  91. package/lib/module/core/identity-session/RefreshManager.js +132 -0
  92. package/lib/module/core/identity-session/RefreshManager.js.map +1 -0
  93. package/lib/module/core/identity-session/SessionManager.js +422 -0
  94. package/lib/module/core/identity-session/SessionManager.js.map +1 -0
  95. package/lib/module/core/identity-session/createIdentitySessionCore.js +21 -0
  96. package/lib/module/core/identity-session/createIdentitySessionCore.js.map +1 -0
  97. package/lib/module/core/identity-session/errors.js +170 -0
  98. package/lib/module/core/identity-session/errors.js.map +1 -0
  99. package/lib/module/core/identity-session/index.js +17 -0
  100. package/lib/module/core/identity-session/index.js.map +1 -0
  101. package/lib/module/core/identity-session/types.js +2 -0
  102. package/lib/module/core/identity-session/types.js.map +1 -0
  103. package/lib/module/core/index.js +2 -3
  104. package/lib/module/core/index.js.map +1 -1
  105. package/lib/module/index.js +12 -2
  106. package/lib/module/index.js.map +1 -1
  107. package/lib/module/models/interfaces.js +7 -0
  108. package/lib/module/models/interfaces.js.map +1 -1
  109. package/lib/module/ui/context/OxyContext.js +436 -822
  110. package/lib/module/ui/context/OxyContext.js.map +1 -1
  111. package/lib/module/ui/hooks/useAvatarPicker.js +48 -0
  112. package/lib/module/ui/hooks/useAvatarPicker.js.map +1 -0
  113. package/lib/module/ui/hooks/useIdentityTransfer.js +121 -0
  114. package/lib/module/ui/hooks/useIdentityTransfer.js.map +1 -0
  115. package/lib/module/ui/hooks/useTransferCodesPersistence.js +77 -0
  116. package/lib/module/ui/hooks/useTransferCodesPersistence.js.map +1 -0
  117. package/lib/module/ui/screens/AccountCenterScreen.js +7 -2
  118. package/lib/module/ui/screens/AccountCenterScreen.js.map +1 -1
  119. package/lib/module/ui/screens/AccountSettingsScreen.js +12 -5
  120. package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
  121. package/lib/module/ui/screens/AccountSwitcherScreen.js +2 -2
  122. package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
  123. package/lib/module/ui/screens/ProfileScreen.js +6 -6
  124. package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
  125. package/lib/module/ui/utils/sessionHelpers.js +7 -1
  126. package/lib/module/ui/utils/sessionHelpers.js.map +1 -1
  127. package/lib/module/utils/index.js +2 -1
  128. package/lib/module/utils/index.js.map +1 -1
  129. package/lib/module/utils/sessionUtils.js +8 -1
  130. package/lib/module/utils/sessionUtils.js.map +1 -1
  131. package/lib/typescript/adapters/expo/crypto.d.ts +17 -0
  132. package/lib/typescript/adapters/expo/crypto.d.ts.map +1 -0
  133. package/lib/typescript/adapters/expo/fetch.d.ts +16 -0
  134. package/lib/typescript/adapters/expo/fetch.d.ts.map +1 -0
  135. package/lib/typescript/adapters/expo/index.d.ts +23 -0
  136. package/lib/typescript/adapters/expo/index.d.ts.map +1 -0
  137. package/lib/typescript/adapters/expo/storage.d.ts +23 -0
  138. package/lib/typescript/adapters/expo/storage.d.ts.map +1 -0
  139. package/lib/typescript/adapters/index.d.ts +13 -0
  140. package/lib/typescript/adapters/index.d.ts.map +1 -0
  141. package/lib/typescript/adapters/node/crypto.d.ts +17 -0
  142. package/lib/typescript/adapters/node/crypto.d.ts.map +1 -0
  143. package/lib/typescript/adapters/node/fetch.d.ts +16 -0
  144. package/lib/typescript/adapters/node/fetch.d.ts.map +1 -0
  145. package/lib/typescript/adapters/node/index.d.ts +23 -0
  146. package/lib/typescript/adapters/node/index.d.ts.map +1 -0
  147. package/lib/typescript/adapters/node/storage.d.ts +23 -0
  148. package/lib/typescript/adapters/node/storage.d.ts.map +1 -0
  149. package/lib/typescript/core/identity-session/DeviceManager.d.ts +64 -0
  150. package/lib/typescript/core/identity-session/DeviceManager.d.ts.map +1 -0
  151. package/lib/typescript/core/identity-session/IdentityManager.d.ts +88 -0
  152. package/lib/typescript/core/identity-session/IdentityManager.d.ts.map +1 -0
  153. package/lib/typescript/core/identity-session/IdentitySessionCore.d.ts +141 -0
  154. package/lib/typescript/core/identity-session/IdentitySessionCore.d.ts.map +1 -0
  155. package/lib/typescript/core/identity-session/RefreshManager.d.ts +36 -0
  156. package/lib/typescript/core/identity-session/RefreshManager.d.ts.map +1 -0
  157. package/lib/typescript/core/identity-session/SessionManager.d.ts +104 -0
  158. package/lib/typescript/core/identity-session/SessionManager.d.ts.map +1 -0
  159. package/lib/typescript/core/identity-session/createIdentitySessionCore.d.ts +11 -0
  160. package/lib/typescript/core/identity-session/createIdentitySessionCore.d.ts.map +1 -0
  161. package/lib/typescript/core/identity-session/errors.d.ts +63 -0
  162. package/lib/typescript/core/identity-session/errors.d.ts.map +1 -0
  163. package/lib/typescript/core/identity-session/index.d.ts +14 -0
  164. package/lib/typescript/core/identity-session/index.d.ts.map +1 -0
  165. package/lib/typescript/core/identity-session/types.d.ts +196 -0
  166. package/lib/typescript/core/identity-session/types.d.ts.map +1 -0
  167. package/lib/typescript/core/index.d.ts +1 -3
  168. package/lib/typescript/core/index.d.ts.map +1 -1
  169. package/lib/typescript/core/mixins/index.d.ts +2 -2
  170. package/lib/typescript/index.d.ts +3 -2
  171. package/lib/typescript/index.d.ts.map +1 -1
  172. package/lib/typescript/models/interfaces.d.ts +5 -36
  173. package/lib/typescript/models/interfaces.d.ts.map +1 -1
  174. package/lib/typescript/models/session.d.ts +3 -16
  175. package/lib/typescript/models/session.d.ts.map +1 -1
  176. package/lib/typescript/ui/context/OxyContext.d.ts +2 -25
  177. package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
  178. package/lib/typescript/ui/hooks/mutations/useAccountMutations.d.ts +7 -8
  179. package/lib/typescript/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
  180. package/lib/typescript/ui/hooks/mutations/useServicesMutations.d.ts +1 -1
  181. package/lib/typescript/ui/hooks/mutations/useServicesMutations.d.ts.map +1 -1
  182. package/lib/typescript/ui/hooks/queries/useAccountQueries.d.ts +5 -5
  183. package/lib/typescript/ui/hooks/queries/useAccountQueries.d.ts.map +1 -1
  184. package/lib/typescript/ui/hooks/useAvatarPicker.d.ts +18 -0
  185. package/lib/typescript/ui/hooks/useAvatarPicker.d.ts.map +1 -0
  186. package/lib/typescript/ui/hooks/useIdentityTransfer.d.ts +24 -0
  187. package/lib/typescript/ui/hooks/useIdentityTransfer.d.ts.map +1 -0
  188. package/lib/typescript/ui/hooks/useTransferCodesPersistence.d.ts +6 -0
  189. package/lib/typescript/ui/hooks/useTransferCodesPersistence.d.ts.map +1 -0
  190. package/lib/typescript/ui/screens/AccountCenterScreen.d.ts.map +1 -1
  191. package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
  192. package/lib/typescript/ui/utils/sessionHelpers.d.ts +1 -0
  193. package/lib/typescript/ui/utils/sessionHelpers.d.ts.map +1 -1
  194. package/lib/typescript/utils/index.d.ts +0 -2
  195. package/lib/typescript/utils/index.d.ts.map +1 -1
  196. package/lib/typescript/utils/sessionUtils.d.ts.map +1 -1
  197. package/package.json +1 -1
  198. package/src/adapters/expo/crypto.ts +55 -0
  199. package/src/adapters/expo/fetch.ts +28 -0
  200. package/src/adapters/expo/index.ts +51 -0
  201. package/src/adapters/expo/storage.ts +228 -0
  202. package/src/adapters/index.ts +40 -0
  203. package/src/adapters/node/crypto.ts +39 -0
  204. package/src/adapters/node/fetch.ts +59 -0
  205. package/src/adapters/node/index.ts +37 -0
  206. package/src/adapters/node/storage.ts +170 -0
  207. package/src/core/identity-session/DeviceManager.ts +273 -0
  208. package/src/core/identity-session/INTEGRATION_GUIDE.md +287 -0
  209. package/src/core/identity-session/IdentityManager.ts +474 -0
  210. package/src/core/identity-session/IdentitySessionCore.ts +464 -0
  211. package/src/core/identity-session/RefreshManager.ts +189 -0
  212. package/src/core/identity-session/SessionManager.ts +500 -0
  213. package/src/core/identity-session/createIdentitySessionCore.ts +19 -0
  214. package/src/core/identity-session/errors.ts +197 -0
  215. package/src/core/identity-session/index.ts +15 -0
  216. package/src/core/identity-session/types.ts +188 -0
  217. package/src/core/index.ts +3 -4
  218. package/src/index.ts +28 -3
  219. package/src/models/interfaces.ts +12 -39
  220. package/src/models/session.ts +6 -16
  221. package/src/ui/context/OxyContext.tsx +442 -871
  222. package/src/ui/hooks/auth/index.ts +1 -0
  223. package/src/ui/hooks/useAvatarPicker.ts +62 -0
  224. package/src/ui/hooks/useIdentityTransfer.ts +135 -0
  225. package/src/ui/hooks/useTransferCodesPersistence.ts +80 -0
  226. package/src/ui/screens/AccountCenterScreen.tsx +7 -2
  227. package/src/ui/screens/AccountSettingsScreen.tsx +15 -8
  228. package/src/ui/screens/AccountSwitcherScreen.tsx +2 -2
  229. package/src/ui/screens/ProfileScreen.tsx +10 -10
  230. package/src/ui/utils/sessionHelpers.ts +7 -0
  231. package/src/utils/index.ts +1 -2
  232. package/src/utils/sessionUtils.ts +8 -0
  233. package/lib/commonjs/ui/context/hooks/useAuthOperations.js +0 -704
  234. package/lib/commonjs/ui/context/hooks/useAuthOperations.js.map +0 -1
  235. package/lib/commonjs/ui/context/hooks/useDeviceManagement.js +0 -73
  236. package/lib/commonjs/ui/context/hooks/useDeviceManagement.js.map +0 -1
  237. package/lib/commonjs/ui/hooks/useDeviceManagement.js +0 -73
  238. package/lib/commonjs/ui/hooks/useDeviceManagement.js.map +0 -1
  239. package/lib/commonjs/ui/hooks/useSessionManagement.js +0 -281
  240. package/lib/commonjs/ui/hooks/useSessionManagement.js.map +0 -1
  241. package/lib/commonjs/utils/deviceManager.js +0 -177
  242. package/lib/commonjs/utils/deviceManager.js.map +0 -1
  243. package/lib/module/ui/context/hooks/useAuthOperations.js +0 -698
  244. package/lib/module/ui/context/hooks/useAuthOperations.js.map +0 -1
  245. package/lib/module/ui/context/hooks/useDeviceManagement.js +0 -68
  246. package/lib/module/ui/context/hooks/useDeviceManagement.js.map +0 -1
  247. package/lib/module/ui/hooks/useDeviceManagement.js +0 -68
  248. package/lib/module/ui/hooks/useDeviceManagement.js.map +0 -1
  249. package/lib/module/ui/hooks/useSessionManagement.js +0 -276
  250. package/lib/module/ui/hooks/useSessionManagement.js.map +0 -1
  251. package/lib/module/utils/deviceManager.js +0 -171
  252. package/lib/module/utils/deviceManager.js.map +0 -1
  253. package/lib/typescript/ui/context/hooks/useAuthOperations.d.ts +0 -59
  254. package/lib/typescript/ui/context/hooks/useAuthOperations.d.ts.map +0 -1
  255. package/lib/typescript/ui/context/hooks/useDeviceManagement.d.ts +0 -27
  256. package/lib/typescript/ui/context/hooks/useDeviceManagement.d.ts.map +0 -1
  257. package/lib/typescript/ui/hooks/useDeviceManagement.d.ts +0 -27
  258. package/lib/typescript/ui/hooks/useDeviceManagement.d.ts.map +0 -1
  259. package/lib/typescript/ui/hooks/useSessionManagement.d.ts +0 -41
  260. package/lib/typescript/ui/hooks/useSessionManagement.d.ts.map +0 -1
  261. package/lib/typescript/utils/deviceManager.d.ts +0 -66
  262. package/lib/typescript/utils/deviceManager.d.ts.map +0 -1
  263. package/src/ui/context/hooks/useAuthOperations.ts +0 -773
  264. package/src/ui/context/hooks/useDeviceManagement.ts +0 -108
  265. package/src/ui/hooks/useDeviceManagement.ts +0 -108
  266. package/src/ui/hooks/useSessionManagement.ts +0 -401
  267. package/src/utils/deviceManager.ts +0 -198
@@ -6,3 +6,4 @@ export type { UsernameValidationResult } from './useUsernameValidation';
6
6
 
7
7
 
8
8
 
9
+
@@ -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={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
- await updateProfileMutation.mutateAsync({ linksMetadata: tempLinksWithMetadata });
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.charAt(0).toUpperCase()}
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
 
@@ -1,5 +1,4 @@
1
- export { DeviceManager } from './deviceManager';
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