@oxyhq/services 5.16.40 → 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 -732
  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 -726
  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 -801
  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
@@ -1,801 +0,0 @@
1
- import { useCallback } from 'react';
2
- import type { ApiError, User } from '../../../models/interfaces';
3
- import type { AuthState } from '../../stores/authStore';
4
- import type { ClientSession, SessionLoginResponse } from '../../../models/session';
5
- import { DeviceManager } from '../../../utils/deviceManager';
6
- import { fetchSessionsWithFallback, mapSessionsToClient } from '../../utils/sessionHelpers';
7
- import { handleAuthError, isInvalidSessionError } from '../../utils/errorHandlers';
8
- import type { StorageInterface } from '../../utils/storageHelpers';
9
- import type { OxyServices } from '../../../core';
10
- import { KeyManager, SignatureService, type BackupData } from '../../../crypto';
11
-
12
- export interface UseAuthOperationsOptions {
13
- oxyServices: OxyServices;
14
- storage: StorageInterface | null;
15
- sessions: ClientSession[];
16
- activeSessionId: string | null;
17
- setActiveSessionId: (sessionId: string | null) => void;
18
- updateSessions: (sessions: ClientSession[], options?: { merge?: boolean }) => void;
19
- saveActiveSessionId: (sessionId: string) => Promise<void>;
20
- clearSessionState: () => Promise<void>;
21
- switchSession: (sessionId: string) => Promise<User>;
22
- applyLanguagePreference: (user: User) => Promise<void>;
23
- onAuthStateChange?: (user: User | null) => void;
24
- onError?: (error: ApiError) => void;
25
- loginSuccess: (user: User) => void;
26
- loginFailure: (message: string) => void;
27
- logoutStore: () => void;
28
- setAuthState: (state: Partial<AuthState>) => void;
29
- // Identity sync store actions
30
- setIdentitySynced: (synced: boolean) => void;
31
- setSyncing: (syncing: boolean) => void;
32
- logger?: (message: string, error?: unknown) => void;
33
- }
34
-
35
- export interface UseAuthOperationsResult {
36
- /** Create a new identity locally (offline-first) and optionally sync with server */
37
- createIdentity: (username?: string) => Promise<{ synced: boolean }>;
38
- /** Import an existing identity from backup file data */
39
- importIdentity: (backupData: BackupData, password: string) => Promise<{ synced: boolean }>;
40
- /** Sign in with existing identity on device */
41
- signIn: (deviceName?: string) => Promise<User>;
42
- /** Logout from current session */
43
- logout: (targetSessionId?: string) => Promise<void>;
44
- /** Logout from all sessions */
45
- logoutAll: () => Promise<void>;
46
- /** Check if device has an identity stored */
47
- hasIdentity: () => Promise<boolean>;
48
- /** Get the public key of the stored identity */
49
- getPublicKey: () => Promise<string | null>;
50
- /** Check if identity is synced with server */
51
- isIdentitySynced: () => Promise<boolean>;
52
- /** Sync local identity with server (when online) */
53
- syncIdentity: (username?: string) => Promise<User>;
54
- }
55
-
56
- const LOGIN_ERROR_CODE = 'LOGIN_ERROR';
57
- const REGISTER_ERROR_CODE = 'REGISTER_ERROR';
58
- const LOGOUT_ERROR_CODE = 'LOGOUT_ERROR';
59
- const LOGOUT_ALL_ERROR_CODE = 'LOGOUT_ALL_ERROR';
60
-
61
- /**
62
- * Authentication operations using public key cryptography.
63
- * No passwords required - identity is based on ECDSA key pairs.
64
- */
65
- export const useAuthOperations = ({
66
- oxyServices,
67
- storage,
68
- sessions,
69
- activeSessionId,
70
- setActiveSessionId,
71
- updateSessions,
72
- saveActiveSessionId,
73
- clearSessionState,
74
- switchSession,
75
- applyLanguagePreference,
76
- onAuthStateChange,
77
- onError,
78
- loginSuccess,
79
- loginFailure,
80
- logoutStore,
81
- setAuthState,
82
- setIdentitySynced,
83
- setSyncing,
84
- logger,
85
- }: UseAuthOperationsOptions): UseAuthOperationsResult => {
86
-
87
- /**
88
- * Clear session data if identity has changed
89
- * Internal helper to avoid code duplication
90
- */
91
- const clearSessionsIfIdentityChanged = useCallback(
92
- async (oldPublicKey: string | null, newPublicKey: string): Promise<void> => {
93
- if (oldPublicKey && oldPublicKey !== newPublicKey) {
94
- if (__DEV__ && logger) {
95
- logger('CRITICAL: Identity changed - clearing all session data', {
96
- oldPublicKey: oldPublicKey.substring(0, 16) + '...',
97
- newPublicKey: newPublicKey.substring(0, 16) + '...',
98
- });
99
- }
100
-
101
- // Clear all session state to prevent old identity's data from showing up
102
- await clearSessionState();
103
-
104
- // Logout from auth store (clears user, isAuthenticated, etc.)
105
- logoutStore();
106
-
107
- // Force KeyManager cache invalidation
108
- KeyManager.invalidateCache();
109
-
110
- if (__DEV__ && logger) {
111
- logger('Session state cleared for new identity');
112
- }
113
- }
114
- },
115
- [clearSessionState, logoutStore, logger]
116
- );
117
-
118
- /**
119
- * Internal function to perform challenge-response sign in (works offline)
120
- */
121
- const performSignIn = useCallback(
122
- async (publicKey: string): Promise<User> => {
123
- const deviceFingerprintObj = DeviceManager.getDeviceFingerprint();
124
- const deviceFingerprint = JSON.stringify(deviceFingerprintObj);
125
- const deviceInfo = await DeviceManager.getDeviceInfo();
126
- const deviceName = deviceInfo.deviceName || DeviceManager.getDefaultDeviceName();
127
-
128
- let challenge: string;
129
- let isOffline = false;
130
-
131
- // Try to request challenge from server (online)
132
- try {
133
- const challengeResponse = await oxyServices.requestChallenge(publicKey);
134
- challenge = challengeResponse.challenge;
135
- } catch (error) {
136
- // Network error - generate challenge locally for offline sign-in
137
- const errorMessage = error instanceof Error ? error.message : String(error);
138
- const isNetworkError =
139
- errorMessage.includes('Network') ||
140
- errorMessage.includes('network') ||
141
- errorMessage.includes('Failed to fetch') ||
142
- errorMessage.includes('fetch failed') ||
143
- (error as any)?.code === 'NETWORK_ERROR' ||
144
- (error as any)?.status === 0;
145
-
146
- if (isNetworkError) {
147
- if (__DEV__ && logger) {
148
- logger('Network unavailable, performing offline sign-in');
149
- }
150
- // Generate challenge locally
151
- challenge = await SignatureService.generateChallenge();
152
- isOffline = true;
153
- } else {
154
- // Re-throw non-network errors
155
- throw error;
156
- }
157
- }
158
-
159
- // Note: Biometric authentication check should be handled by the app layer
160
- // (e.g., accounts app) before calling signIn. The biometric preference is stored
161
- // in local storage as 'oxy_biometric_enabled' and can be checked there.
162
-
163
- // Sign the challenge
164
- const { challenge: signature, timestamp } = await SignatureService.signChallenge(challenge);
165
-
166
- let fullUser: User;
167
- let sessionResponse: SessionLoginResponse;
168
-
169
- if (isOffline) {
170
- // Offline sign-in: create local session and minimal user object
171
- if (__DEV__ && logger) {
172
- logger('Creating offline session');
173
- }
174
-
175
- // Generate a local session ID
176
- const localSessionId = `offline_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
177
- const localDeviceId = `device_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
178
- const expiresAt = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(); // 7 days
179
-
180
- // Create minimal user object with publicKey as id
181
- fullUser = {
182
- id: publicKey, // Use publicKey as id (per migration document)
183
- publicKey,
184
- username: '',
185
- privacySettings: {},
186
- } as User;
187
-
188
- sessionResponse = {
189
- sessionId: localSessionId,
190
- deviceId: localDeviceId,
191
- expiresAt,
192
- user: {
193
- id: publicKey,
194
- username: '',
195
- },
196
- };
197
-
198
- // Store offline session locally
199
- const offlineSession: ClientSession = {
200
- sessionId: localSessionId,
201
- deviceId: localDeviceId,
202
- expiresAt,
203
- lastActive: new Date().toISOString(),
204
- userId: publicKey,
205
- isCurrent: true,
206
- };
207
-
208
- setActiveSessionId(localSessionId);
209
- await saveActiveSessionId(localSessionId);
210
- updateSessions([offlineSession], { merge: true });
211
-
212
- // Mark session as offline for later sync
213
- if (storage) {
214
- await storage.setItem(`oxy_session_${localSessionId}_offline`, 'true');
215
- }
216
-
217
- if (__DEV__ && logger) {
218
- logger('Offline sign-in successful');
219
- }
220
- } else {
221
- // Online sign-in: use normal flow
222
- // Verify and create session
223
- sessionResponse = await oxyServices.verifyChallenge(
224
- publicKey,
225
- challenge,
226
- signature,
227
- timestamp,
228
- deviceName,
229
- deviceFingerprint,
230
- );
231
-
232
- // Get token for the session
233
- await oxyServices.getTokenBySession(sessionResponse.sessionId);
234
-
235
- // Get full user data
236
- fullUser = await oxyServices.getUserBySession(sessionResponse.sessionId);
237
-
238
- // IMPORTANT: user.id should be MongoDB ObjectId, not publicKey
239
- // The API should return the correct id (ObjectId) from the database
240
- // If it doesn't, we need to fix the API, not work around it here
241
- // Validate that id is ObjectId format (24 hex characters)
242
- if (fullUser.id && !/^[0-9a-fA-F]{24}$/.test(fullUser.id)) {
243
- console.warn('[useAuthOperations] User.id is not MongoDB ObjectId format:', {
244
- id: fullUser.id.substring(0, 20),
245
- publicKey: fullUser.publicKey.substring(0, 20),
246
- message: 'API should return MongoDB ObjectId as user.id, not publicKey'
247
- });
248
- // Don't override - let the API fix this issue
249
- }
250
-
251
- // Fetch device sessions
252
- let allDeviceSessions: ClientSession[] = [];
253
- try {
254
- allDeviceSessions = await fetchSessionsWithFallback(oxyServices, sessionResponse.sessionId, {
255
- fallbackDeviceId: sessionResponse.deviceId,
256
- fallbackUserId: fullUser.id,
257
- logger,
258
- });
259
- } catch (error) {
260
- if (__DEV__) {
261
- console.warn('Failed to fetch device sessions after login:', error);
262
- }
263
- }
264
-
265
- // Check for existing session for same user
266
- const existingSession = allDeviceSessions.find(
267
- (session) =>
268
- session.userId?.toString() === fullUser.id?.toString() &&
269
- session.sessionId !== sessionResponse.sessionId,
270
- );
271
-
272
- if (existingSession) {
273
- // Logout duplicate session
274
- try {
275
- await oxyServices.logoutSession(sessionResponse.sessionId, sessionResponse.sessionId);
276
- } catch (logoutError) {
277
- if (__DEV__) {
278
- console.warn('Failed to logout duplicate session:', logoutError);
279
- }
280
- }
281
- await switchSession(existingSession.sessionId);
282
- updateSessions(
283
- allDeviceSessions.filter((session) => session.sessionId !== sessionResponse.sessionId),
284
- { merge: false },
285
- );
286
- onAuthStateChange?.(fullUser);
287
- return fullUser;
288
- }
289
-
290
- setActiveSessionId(sessionResponse.sessionId);
291
- await saveActiveSessionId(sessionResponse.sessionId);
292
- updateSessions(allDeviceSessions, { merge: true });
293
- }
294
-
295
- await applyLanguagePreference(fullUser);
296
- loginSuccess(fullUser);
297
- onAuthStateChange?.(fullUser);
298
-
299
- return fullUser;
300
- },
301
- [
302
- applyLanguagePreference,
303
- logger,
304
- loginSuccess,
305
- onAuthStateChange,
306
- oxyServices,
307
- saveActiveSessionId,
308
- setActiveSessionId,
309
- switchSession,
310
- updateSessions,
311
- storage,
312
- ],
313
- );
314
-
315
- /**
316
- * Create a new identity (offline-first).
317
- *
318
- * Generates cryptographic keys locally without requiring server connection.
319
- * Identity is based on the public/private key pair - no username or email required.
320
- *
321
- * IMPORTANT: This function only clears session data if the identity actually changes
322
- * (i.e., a new key pair is generated). Retrying registration with the same identity
323
- * will NOT clear session data.
324
- *
325
- * @param username - Optional username to set during registration (if online)
326
- * @returns Object with synced status indicating if identity was registered with server
327
- */
328
- const createIdentity = useCallback(
329
- async (username?: string): Promise<{ synced: boolean }> => {
330
- if (!storage) throw new Error('Storage not initialized');
331
-
332
- setAuthState({ isLoading: true, error: null });
333
-
334
- try {
335
- // Get old public key before creating new identity
336
- // This is used to detect if identity actually changed
337
- const oldPublicKey = await KeyManager.getPublicKey().catch(() => null);
338
-
339
- if (__DEV__ && logger) {
340
- logger('Creating new identity', { hadPreviousIdentity: !!oldPublicKey });
341
- }
342
-
343
- // Generate new key pair directly (works offline)
344
- const { publicKey, privateKey } = await KeyManager.generateKeyPair();
345
- await KeyManager.importKeyPair(privateKey);
346
-
347
- if (__DEV__ && logger) {
348
- logger('Identity keys generated', { publicKey: publicKey.substring(0, 16) + '...' });
349
- }
350
-
351
- // Only clear sessions if identity actually changed
352
- // This prevents clearing sessions on registration retries
353
- await clearSessionsIfIdentityChanged(oldPublicKey, publicKey);
354
-
355
- // Mark as not synced initially
356
- await storage.setItem('oxy_identity_synced', 'false');
357
- setIdentitySynced(false);
358
-
359
- // If username provided, try to register immediately (online only)
360
- if (username) {
361
- // Validate username format before attempting registration
362
- const trimmedUsername = username.trim();
363
- if (trimmedUsername && /^[a-zA-Z0-9]{3,30}$/.test(trimmedUsername)) {
364
- try {
365
- const { signature, timestamp } = await SignatureService.createRegistrationSignature();
366
- await oxyServices.register(publicKey, signature, timestamp, trimmedUsername);
367
-
368
- // Mark as synced (Zustand store + storage)
369
- await storage.setItem('oxy_identity_synced', 'true');
370
- setIdentitySynced(true);
371
-
372
- if (__DEV__ && logger) {
373
- logger('Identity synced with server successfully with username');
374
- }
375
-
376
- return { synced: true };
377
- } catch (syncError) {
378
- // Offline or server error - identity created locally but not synced
379
- if (__DEV__ && logger) {
380
- logger('Identity created locally with username (offline), will sync when online', syncError);
381
- }
382
-
383
- return { synced: false };
384
- }
385
- } else {
386
- // Invalid username format - log the issue
387
- if (__DEV__ && logger) {
388
- logger('Invalid username format, identity created without username', {
389
- providedUsername: username.substring(0, 20),
390
- });
391
- }
392
- }
393
- }
394
-
395
- // No username provided or invalid format - defer registration until later
396
- if (__DEV__ && logger) {
397
- logger('Identity created locally without username, will register during sync');
398
- }
399
-
400
- return { synced: false };
401
- } catch (error) {
402
- // CRITICAL: Never delete identity on error - it may have been successfully created
403
- // Only log the error and let the user recover using their backup file
404
- // Identity deletion should ONLY happen when explicitly requested by the user
405
- if (__DEV__ && logger) {
406
- logger('Error during identity creation (identity may still exist):', error);
407
- }
408
-
409
- // Check if identity was actually created (keys exist)
410
- const hasIdentity = await KeyManager.hasIdentity().catch(() => false);
411
- if (hasIdentity) {
412
- // Identity exists - don't delete it! Just mark as not synced
413
- await storage.setItem('oxy_identity_synced', 'false').catch(() => {});
414
- setIdentitySynced(false);
415
- if (__DEV__ && logger) {
416
- logger('Identity was created but sync failed - user can sync later');
417
- }
418
- } else {
419
- // No identity exists - this was a generation failure, safe to clean up sync flag
420
- await storage.removeItem('oxy_identity_synced').catch(() => {});
421
- setIdentitySynced(false);
422
- }
423
-
424
- const message = handleAuthError(error, {
425
- defaultMessage: 'Failed to create identity',
426
- code: REGISTER_ERROR_CODE,
427
- onError,
428
- setAuthError: (msg: string) => setAuthState({ error: msg }),
429
- logger,
430
- });
431
- loginFailure(message);
432
- throw error;
433
- } finally {
434
- setAuthState({ isLoading: false });
435
- }
436
- },
437
- [oxyServices, storage, setAuthState, loginFailure, onError, logger, setIdentitySynced, clearSessionsIfIdentityChanged],
438
- );
439
-
440
- /**
441
- * Check if identity is synced with server (reads from storage for persistence)
442
- */
443
- const isIdentitySyncedFn = useCallback(async (): Promise<boolean> => {
444
- if (!storage) return true;
445
- const synced = await storage.getItem('oxy_identity_synced');
446
- const isSynced = synced !== 'false';
447
- setIdentitySynced(isSynced);
448
- return isSynced;
449
- }, [storage, setIdentitySynced]);
450
-
451
- /**
452
- * Sync local identity with server.
453
- *
454
- * Registers the identity with the server if not already registered.
455
- * This function is idempotent - calling it multiple times is safe.
456
- *
457
- * TanStack Query handles offline mutations automatically, so this will
458
- * retry automatically when connection is restored.
459
- *
460
- * @param username - Optional username to set during sync/registration
461
- * @returns User object after successful sync and sign-in
462
- */
463
- const syncIdentity = useCallback(
464
- async (username?: string): Promise<User> => {
465
- if (!storage) throw new Error('Storage not initialized');
466
-
467
- setAuthState({ isLoading: true, error: null });
468
- setSyncing(true);
469
-
470
- try {
471
- const publicKey = await KeyManager.getPublicKey();
472
- if (!publicKey) {
473
- throw new Error('No identity found on this device');
474
- }
475
-
476
- // Check if already synced
477
- const alreadySynced = await storage.getItem('oxy_identity_synced');
478
- if (alreadySynced === 'true') {
479
- setIdentitySynced(true);
480
- // Identity is already synced, just sign in
481
- return await performSignIn(publicKey);
482
- }
483
-
484
- // Check if already registered on server
485
- const { registered } = await oxyServices.checkPublicKeyRegistered(publicKey);
486
-
487
- if (!registered) {
488
- // Register with server (identity is just the publicKey)
489
- const { signature, timestamp } = await SignatureService.createRegistrationSignature();
490
- await oxyServices.register(publicKey, signature, timestamp, username);
491
- }
492
-
493
- // Mark as synced (Zustand store + storage)
494
- await storage.setItem('oxy_identity_synced', 'true');
495
- setIdentitySynced(true);
496
-
497
- // Sign in
498
- const user = await performSignIn(publicKey);
499
-
500
- // TanStack Query will automatically retry any pending mutations
501
-
502
- return user;
503
- } catch (error) {
504
- const message = handleAuthError(error, {
505
- defaultMessage: 'Failed to sync identity',
506
- code: REGISTER_ERROR_CODE,
507
- onError,
508
- setAuthError: (msg: string) => setAuthState({ error: msg }),
509
- logger,
510
- });
511
- loginFailure(message);
512
- throw error;
513
- } finally {
514
- setAuthState({ isLoading: false });
515
- setSyncing(false);
516
- }
517
- },
518
- [oxyServices, storage, setAuthState, performSignIn, loginFailure, onError, logger, setSyncing, setIdentitySynced],
519
- );
520
-
521
- /**
522
- * Import identity from encrypted backup file.
523
- *
524
- * Restores a previously created identity from an encrypted backup.
525
- * The backup is decrypted using the provided password.
526
- *
527
- * IMPORTANT: This function clears session data only if importing a different
528
- * identity than the one currently stored. Re-importing the same identity
529
- * will NOT clear session data.
530
- *
531
- * @param backupData - The encrypted backup data object
532
- * @param password - Password to decrypt the backup
533
- * @param username - Optional username to set during registration if not yet registered
534
- * @returns Object with synced status indicating if identity was registered with server
535
- */
536
- const importIdentity = useCallback(
537
- async (backupData: BackupData, password: string, username?: string): Promise<{ synced: boolean }> => {
538
- if (!storage) throw new Error('Storage not initialized');
539
-
540
- // Validate arguments - ensure backupData is an object, not a string (old signature)
541
- if (!backupData || typeof backupData !== 'object' || Array.isArray(backupData)) {
542
- throw new Error('Invalid backup data. Please use the backup file import feature.');
543
- }
544
-
545
- if (!backupData.encrypted || !backupData.salt || !backupData.iv || !backupData.publicKey) {
546
- throw new Error('Invalid backup data structure. Missing required fields.');
547
- }
548
-
549
- if (!password || typeof password !== 'string') {
550
- throw new Error('Password is required for backup file import.');
551
- }
552
-
553
- setAuthState({ isLoading: true, error: null });
554
-
555
- try {
556
- // Get old public key before importing identity
557
- // This is used to detect if identity actually changed
558
- const oldPublicKey = await KeyManager.getPublicKey().catch(() => null);
559
-
560
- if (__DEV__ && logger) {
561
- logger('Importing identity from backup', {
562
- hadPreviousIdentity: !!oldPublicKey,
563
- backupPublicKey: backupData.publicKey.substring(0, 16) + '...'
564
- });
565
- }
566
-
567
- // Decrypt private key from backup data
568
- const Crypto = await import('expo-crypto');
569
-
570
- // Convert hex strings to Uint8Array
571
- const saltBytes = new Uint8Array(
572
- backupData.salt.match(/.{1,2}/g)?.map(byte => parseInt(byte, 16)) || []
573
- );
574
- const ivBytes = new Uint8Array(
575
- backupData.iv.match(/.{1,2}/g)?.map(byte => parseInt(byte, 16)) || []
576
- );
577
-
578
- // Derive key from password (same algorithm as EncryptedBackupGenerator)
579
- const saltHex = Array.from(saltBytes).map(b => b.toString(16).padStart(2, '0')).join('');
580
- let key = password + saltHex;
581
- for (let i = 0; i < 10000; i++) {
582
- key = await Crypto.digestStringAsync(
583
- Crypto.CryptoDigestAlgorithm.SHA256,
584
- key
585
- );
586
- }
587
- const keyBytes = new Uint8Array(32);
588
- for (let i = 0; i < 64 && i < key.length; i += 2) {
589
- keyBytes[i / 2] = parseInt(key.substring(i, i + 2), 16);
590
- }
591
-
592
- // Decrypt private key (XOR decryption - same as encryption)
593
- const encryptedBytes = Buffer.from(backupData.encrypted, 'base64');
594
- const decryptedBytes = new Uint8Array(encryptedBytes.length);
595
- for (let i = 0; i < encryptedBytes.length; i++) {
596
- decryptedBytes[i] = encryptedBytes[i] ^ keyBytes[i % keyBytes.length] ^ ivBytes[i % ivBytes.length];
597
- }
598
- const privateKey = new TextDecoder().decode(decryptedBytes);
599
-
600
- // Import the key pair
601
- const publicKey = await KeyManager.importKeyPair(privateKey);
602
-
603
- if (__DEV__ && logger) {
604
- logger('Identity keys imported', { publicKey: publicKey.substring(0, 16) + '...' });
605
- }
606
-
607
- // Verify public key matches
608
- if (publicKey !== backupData.publicKey) {
609
- throw new Error('Backup file is corrupted or password is incorrect');
610
- }
611
-
612
- // Only clear sessions if identity actually changed
613
- // This prevents clearing sessions when re-importing the same identity
614
- await clearSessionsIfIdentityChanged(oldPublicKey, publicKey);
615
-
616
- // Mark as not synced initially (will check server status below)
617
- await storage.setItem('oxy_identity_synced', 'false');
618
- setIdentitySynced(false);
619
-
620
- // Try to sync with server
621
- try {
622
- // Check if this identity is already registered
623
- const { registered } = await oxyServices.checkPublicKeyRegistered(publicKey);
624
-
625
- if (registered) {
626
- // Identity exists on server, mark as synced
627
- await storage.setItem('oxy_identity_synced', 'true');
628
- setIdentitySynced(true);
629
- return { synced: true };
630
- } else {
631
- // Need to register this identity
632
- const { signature, timestamp } = await SignatureService.createRegistrationSignature();
633
- await oxyServices.register(publicKey, signature, timestamp, username);
634
-
635
- await storage.setItem('oxy_identity_synced', 'true');
636
- setIdentitySynced(true);
637
- return { synced: true };
638
- }
639
- } catch (syncError) {
640
- // Offline or server error - identity restored locally but not synced
641
- if (__DEV__) {
642
- console.log('[Auth] Identity imported locally, will sync when online:', syncError);
643
- }
644
- return { synced: false };
645
- }
646
- } catch (error) {
647
- const message = handleAuthError(error, {
648
- defaultMessage: 'Failed to import identity. Please check your password and backup file.',
649
- code: REGISTER_ERROR_CODE,
650
- onError,
651
- setAuthError: (msg: string) => setAuthState({ error: msg }),
652
- logger,
653
- });
654
- loginFailure(message);
655
- throw error;
656
- } finally {
657
- setAuthState({ isLoading: false });
658
- }
659
- },
660
- [oxyServices, storage, setAuthState, loginFailure, onError, logger, setIdentitySynced, clearSessionsIfIdentityChanged],
661
- );
662
-
663
- /**
664
- * Sign in with existing identity on device
665
- */
666
- const signIn = useCallback(
667
- async (deviceName?: string): Promise<User> => {
668
- if (!storage) throw new Error('Storage not initialized');
669
-
670
- setAuthState({ isLoading: true, error: null });
671
-
672
- try {
673
- // Get stored public key
674
- const publicKey = await KeyManager.getPublicKey();
675
- if (!publicKey) {
676
- throw new Error('No identity found on this device. Please create or import an identity.');
677
- }
678
-
679
- return await performSignIn(publicKey);
680
- } catch (error) {
681
- const message = handleAuthError(error, {
682
- defaultMessage: 'Sign in failed',
683
- code: LOGIN_ERROR_CODE,
684
- onError,
685
- setAuthError: (msg: string) => setAuthState({ error: msg }),
686
- logger,
687
- });
688
- loginFailure(message);
689
- throw error;
690
- } finally {
691
- setAuthState({ isLoading: false });
692
- }
693
- },
694
- [storage, setAuthState, performSignIn, loginFailure, onError, logger],
695
- );
696
-
697
- /**
698
- * Logout from session
699
- */
700
- const logout = useCallback(
701
- async (targetSessionId?: string): Promise<void> => {
702
- if (!activeSessionId) return;
703
-
704
- try {
705
- const sessionToLogout = targetSessionId || activeSessionId;
706
- await oxyServices.logoutSession(activeSessionId, sessionToLogout);
707
-
708
- const filteredSessions = sessions.filter((session) => session.sessionId !== sessionToLogout);
709
- updateSessions(filteredSessions, { merge: false });
710
-
711
- if (sessionToLogout === activeSessionId) {
712
- if (filteredSessions.length > 0) {
713
- await switchSession(filteredSessions[0].sessionId);
714
- } else {
715
- await clearSessionState();
716
- return;
717
- }
718
- }
719
- } catch (error) {
720
- const isInvalid = isInvalidSessionError(error);
721
-
722
- if (isInvalid && targetSessionId === activeSessionId) {
723
- await clearSessionState();
724
- return;
725
- }
726
-
727
- handleAuthError(error, {
728
- defaultMessage: 'Logout failed',
729
- code: LOGOUT_ERROR_CODE,
730
- onError,
731
- setAuthError: (msg: string) => setAuthState({ error: msg }),
732
- logger,
733
- status: isInvalid ? 401 : undefined,
734
- });
735
- }
736
- },
737
- [
738
- activeSessionId,
739
- clearSessionState,
740
- logger,
741
- onError,
742
- oxyServices,
743
- sessions,
744
- setAuthState,
745
- switchSession,
746
- updateSessions,
747
- ],
748
- );
749
-
750
- /**
751
- * Logout from all sessions
752
- */
753
- const logoutAll = useCallback(async (): Promise<void> => {
754
- if (!activeSessionId) {
755
- const error = new Error('No active session found');
756
- setAuthState({ error: error.message });
757
- onError?.({ message: error.message, code: LOGOUT_ALL_ERROR_CODE, status: 404 });
758
- throw error;
759
- }
760
-
761
- try {
762
- await oxyServices.logoutAllSessions(activeSessionId);
763
- await clearSessionState();
764
- } catch (error) {
765
- handleAuthError(error, {
766
- defaultMessage: 'Logout all failed',
767
- code: LOGOUT_ALL_ERROR_CODE,
768
- onError,
769
- setAuthError: (msg: string) => setAuthState({ error: msg }),
770
- logger,
771
- });
772
- throw error instanceof Error ? error : new Error('Logout all failed');
773
- }
774
- }, [activeSessionId, clearSessionState, logger, onError, oxyServices, setAuthState]);
775
-
776
- /**
777
- * Check if device has an identity stored
778
- */
779
- const hasIdentity = useCallback(async (): Promise<boolean> => {
780
- return KeyManager.hasIdentity();
781
- }, []);
782
-
783
- /**
784
- * Get the public key of the stored identity
785
- */
786
- const getPublicKey = useCallback(async (): Promise<string | null> => {
787
- return KeyManager.getPublicKey();
788
- }, []);
789
-
790
- return {
791
- createIdentity,
792
- importIdentity,
793
- signIn,
794
- logout,
795
- logoutAll,
796
- hasIdentity,
797
- getPublicKey,
798
- isIdentitySynced: isIdentitySyncedFn,
799
- syncIdentity,
800
- };
801
- };