@oxyhq/services 5.17.17 → 5.17.18

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 (403) hide show
  1. package/README.md +32 -38
  2. package/lib/commonjs/core/CrossDomainAuth.js +277 -0
  3. package/lib/commonjs/core/CrossDomainAuth.js.map +1 -0
  4. package/lib/commonjs/core/HttpService.js +82 -15
  5. package/lib/commonjs/core/HttpService.js.map +1 -1
  6. package/lib/commonjs/core/OxyServices.base.js +11 -3
  7. package/lib/commonjs/core/OxyServices.base.js.map +1 -1
  8. package/lib/commonjs/core/OxyServices.js +4 -1
  9. package/lib/commonjs/core/OxyServices.js.map +1 -1
  10. package/lib/commonjs/core/index.js +30 -0
  11. package/lib/commonjs/core/index.js.map +1 -1
  12. package/lib/commonjs/core/mixins/OxyServices.assets.js +16 -3
  13. package/lib/commonjs/core/mixins/OxyServices.assets.js.map +1 -1
  14. package/lib/commonjs/core/mixins/OxyServices.auth.js +73 -32
  15. package/lib/commonjs/core/mixins/OxyServices.auth.js.map +1 -1
  16. package/lib/commonjs/core/mixins/OxyServices.fedcm.js +289 -0
  17. package/lib/commonjs/core/mixins/OxyServices.fedcm.js.map +1 -0
  18. package/lib/commonjs/core/mixins/OxyServices.popup.js +352 -0
  19. package/lib/commonjs/core/mixins/OxyServices.popup.js.map +1 -0
  20. package/lib/commonjs/core/mixins/OxyServices.redirect.js +378 -0
  21. package/lib/commonjs/core/mixins/OxyServices.redirect.js.map +1 -0
  22. package/lib/commonjs/core/mixins/OxyServices.user.js +35 -24
  23. package/lib/commonjs/core/mixins/OxyServices.user.js.map +1 -1
  24. package/lib/commonjs/core/mixins/index.js +27 -15
  25. package/lib/commonjs/core/mixins/index.js.map +1 -1
  26. package/lib/commonjs/crypto/index.js +30 -0
  27. package/lib/commonjs/crypto/index.js.map +1 -1
  28. package/lib/commonjs/crypto/keyManager.js +902 -0
  29. package/lib/commonjs/crypto/keyManager.js.map +1 -0
  30. package/lib/commonjs/crypto/polyfill.js +14 -5
  31. package/lib/commonjs/crypto/polyfill.js.map +1 -1
  32. package/lib/commonjs/crypto/recoveryPhrase.js +152 -0
  33. package/lib/commonjs/crypto/recoveryPhrase.js.map +1 -0
  34. package/lib/commonjs/crypto/signatureService.js +289 -0
  35. package/lib/commonjs/crypto/signatureService.js.map +1 -0
  36. package/lib/commonjs/i18n/locales/en-US.json +1 -1
  37. package/lib/commonjs/index.js +40 -26
  38. package/lib/commonjs/index.js.map +1 -1
  39. package/lib/commonjs/models/interfaces.js +0 -15
  40. package/lib/commonjs/models/interfaces.js.map +1 -1
  41. package/lib/commonjs/ui/components/BottomSheetRouter.js +9 -1
  42. package/lib/commonjs/ui/components/BottomSheetRouter.js.map +1 -1
  43. package/lib/commonjs/ui/components/Icon.js.map +1 -1
  44. package/lib/commonjs/ui/components/IconButton/utils.js.map +1 -1
  45. package/lib/commonjs/ui/components/OxyProvider.js +41 -11
  46. package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
  47. package/lib/commonjs/ui/components/TextField/Adornment/utils.js.map +1 -1
  48. package/lib/commonjs/ui/components/TextField/helpers.js.map +1 -1
  49. package/lib/commonjs/ui/components/TouchableRipple/utils.js.map +1 -1
  50. package/lib/commonjs/ui/components/Typography/AnimatedText.js.map +1 -1
  51. package/lib/commonjs/ui/context/OxyContext.js +110 -199
  52. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  53. package/lib/commonjs/ui/context/hooks/useAuthOperations.js +150 -19
  54. package/lib/commonjs/ui/context/hooks/useAuthOperations.js.map +1 -1
  55. package/lib/commonjs/ui/context/hooks/useSessionManagement.js +279 -0
  56. package/lib/commonjs/ui/context/hooks/useSessionManagement.js.map +1 -0
  57. package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js +79 -72
  58. package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js.map +1 -1
  59. package/lib/commonjs/ui/hooks/queries/useAccountQueries.js +38 -51
  60. package/lib/commonjs/ui/hooks/queries/useAccountQueries.js.map +1 -1
  61. package/lib/commonjs/ui/hooks/queries/useSecurityQueries.js +3 -3
  62. package/lib/commonjs/ui/hooks/queries/useSecurityQueries.js.map +1 -1
  63. package/lib/commonjs/ui/hooks/queries/useServicesQueries.js +18 -12
  64. package/lib/commonjs/ui/hooks/queries/useServicesQueries.js.map +1 -1
  65. package/lib/commonjs/ui/hooks/useProfileEditing.js +3 -5
  66. package/lib/commonjs/ui/hooks/useProfileEditing.js.map +1 -1
  67. package/lib/commonjs/ui/hooks/useSessionManagement.js +4 -8
  68. package/lib/commonjs/ui/hooks/useSessionManagement.js.map +1 -1
  69. package/lib/commonjs/ui/hooks/useSessionSocket.js +162 -315
  70. package/lib/commonjs/ui/hooks/useSessionSocket.js.map +1 -1
  71. package/lib/commonjs/ui/hooks/useStorage.js +24 -58
  72. package/lib/commonjs/ui/hooks/useStorage.js.map +1 -1
  73. package/lib/commonjs/ui/index.js +50 -21
  74. package/lib/commonjs/ui/index.js.map +1 -1
  75. package/lib/commonjs/ui/navigation/routes.js +5 -1
  76. package/lib/commonjs/ui/navigation/routes.js.map +1 -1
  77. package/lib/commonjs/ui/screens/AccountCenterScreen.js +2 -2
  78. package/lib/commonjs/ui/screens/AccountCenterScreen.js.map +1 -1
  79. package/lib/commonjs/ui/screens/AccountOverviewScreen.js.map +1 -1
  80. package/lib/commonjs/ui/screens/AccountSettingsScreen.js +29 -24
  81. package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
  82. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +3 -3
  83. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -1
  84. package/lib/commonjs/ui/screens/OxyAuthScreen.js +134 -66
  85. package/lib/commonjs/ui/screens/OxyAuthScreen.js.map +1 -1
  86. package/lib/commonjs/ui/screens/PrivacySettingsScreen.js +6 -13
  87. package/lib/commonjs/ui/screens/PrivacySettingsScreen.js.map +1 -1
  88. package/lib/commonjs/ui/stores/accountStore.js +2 -4
  89. package/lib/commonjs/ui/stores/accountStore.js.map +1 -1
  90. package/lib/commonjs/ui/stores/authStore.js +45 -32
  91. package/lib/commonjs/ui/stores/authStore.js.map +1 -1
  92. package/lib/commonjs/ui/styles/spacing.js +54 -2
  93. package/lib/commonjs/ui/styles/spacing.js.map +1 -1
  94. package/lib/commonjs/ui/utils/avatarUtils.js +37 -41
  95. package/lib/commonjs/ui/utils/avatarUtils.js.map +1 -1
  96. package/lib/commonjs/ui/utils/storageHelpers.js.map +1 -1
  97. package/lib/commonjs/utils/errorUtils.js +13 -0
  98. package/lib/commonjs/utils/errorUtils.js.map +1 -1
  99. package/lib/commonjs/utils/validationUtils.js +15 -1
  100. package/lib/commonjs/utils/validationUtils.js.map +1 -1
  101. package/lib/module/core/CrossDomainAuth.js +271 -0
  102. package/lib/module/core/CrossDomainAuth.js.map +1 -0
  103. package/lib/module/core/HttpService.js +82 -15
  104. package/lib/module/core/HttpService.js.map +1 -1
  105. package/lib/module/core/OxyServices.base.js +11 -4
  106. package/lib/module/core/OxyServices.base.js.map +1 -1
  107. package/lib/module/core/OxyServices.js +4 -1
  108. package/lib/module/core/OxyServices.js.map +1 -1
  109. package/lib/module/core/index.js +6 -1
  110. package/lib/module/core/index.js.map +1 -1
  111. package/lib/module/core/mixins/OxyServices.assets.js +16 -3
  112. package/lib/module/core/mixins/OxyServices.assets.js.map +1 -1
  113. package/lib/module/core/mixins/OxyServices.auth.js +73 -32
  114. package/lib/module/core/mixins/OxyServices.auth.js.map +1 -1
  115. package/lib/module/core/mixins/OxyServices.fedcm.js +286 -0
  116. package/lib/module/core/mixins/OxyServices.fedcm.js.map +1 -0
  117. package/lib/module/core/mixins/OxyServices.popup.js +349 -0
  118. package/lib/module/core/mixins/OxyServices.popup.js.map +1 -0
  119. package/lib/module/core/mixins/OxyServices.redirect.js +375 -0
  120. package/lib/module/core/mixins/OxyServices.redirect.js.map +1 -0
  121. package/lib/module/core/mixins/OxyServices.user.js +35 -24
  122. package/lib/module/core/mixins/OxyServices.user.js.map +1 -1
  123. package/lib/module/core/mixins/index.js +15 -3
  124. package/lib/module/core/mixins/index.js.map +1 -1
  125. package/lib/module/crypto/index.js +8 -4
  126. package/lib/module/crypto/index.js.map +1 -1
  127. package/lib/module/crypto/keyManager.js +899 -0
  128. package/lib/module/crypto/keyManager.js.map +1 -0
  129. package/lib/module/crypto/polyfill.js +6 -5
  130. package/lib/module/crypto/polyfill.js.map +1 -1
  131. package/lib/module/crypto/recoveryPhrase.js +147 -0
  132. package/lib/module/crypto/recoveryPhrase.js.map +1 -0
  133. package/lib/module/crypto/signatureService.js +286 -0
  134. package/lib/module/crypto/signatureService.js.map +1 -0
  135. package/lib/module/i18n/locales/en-US.json +1 -1
  136. package/lib/module/index.js +6 -9
  137. package/lib/module/index.js.map +1 -1
  138. package/lib/module/models/interfaces.js +0 -15
  139. package/lib/module/models/interfaces.js.map +1 -1
  140. package/lib/module/ui/components/BottomSheetRouter.js +6 -2
  141. package/lib/module/ui/components/BottomSheetRouter.js.map +1 -1
  142. package/lib/module/ui/components/Icon.js.map +1 -1
  143. package/lib/module/ui/components/IconButton/utils.js.map +1 -1
  144. package/lib/module/ui/components/OxyProvider.js +41 -11
  145. package/lib/module/ui/components/OxyProvider.js.map +1 -1
  146. package/lib/module/ui/components/TextField/Adornment/utils.js.map +1 -1
  147. package/lib/module/ui/components/TextField/helpers.js.map +1 -1
  148. package/lib/module/ui/components/TouchableRipple/utils.js.map +1 -1
  149. package/lib/module/ui/components/Typography/AnimatedText.js.map +1 -1
  150. package/lib/module/ui/context/OxyContext.js +112 -191
  151. package/lib/module/ui/context/OxyContext.js.map +1 -1
  152. package/lib/module/ui/context/hooks/useAuthOperations.js +150 -19
  153. package/lib/module/ui/context/hooks/useAuthOperations.js.map +1 -1
  154. package/lib/module/ui/context/hooks/useSessionManagement.js +274 -0
  155. package/lib/module/ui/context/hooks/useSessionManagement.js.map +1 -0
  156. package/lib/module/ui/hooks/mutations/useAccountMutations.js +80 -72
  157. package/lib/module/ui/hooks/mutations/useAccountMutations.js.map +1 -1
  158. package/lib/module/ui/hooks/queries/useAccountQueries.js +31 -44
  159. package/lib/module/ui/hooks/queries/useAccountQueries.js.map +1 -1
  160. package/lib/module/ui/hooks/queries/useSecurityQueries.js +1 -1
  161. package/lib/module/ui/hooks/queries/useSecurityQueries.js.map +1 -1
  162. package/lib/module/ui/hooks/queries/useServicesQueries.js +13 -7
  163. package/lib/module/ui/hooks/queries/useServicesQueries.js.map +1 -1
  164. package/lib/module/ui/hooks/useProfileEditing.js +3 -5
  165. package/lib/module/ui/hooks/useProfileEditing.js.map +1 -1
  166. package/lib/module/ui/hooks/useSessionManagement.js +4 -8
  167. package/lib/module/ui/hooks/useSessionManagement.js.map +1 -1
  168. package/lib/module/ui/hooks/useSessionSocket.js +162 -315
  169. package/lib/module/ui/hooks/useSessionSocket.js.map +1 -1
  170. package/lib/module/ui/hooks/useStorage.js +25 -59
  171. package/lib/module/ui/hooks/useStorage.js.map +1 -1
  172. package/lib/module/ui/index.js +15 -10
  173. package/lib/module/ui/index.js.map +1 -1
  174. package/lib/module/ui/navigation/routes.js +5 -1
  175. package/lib/module/ui/navigation/routes.js.map +1 -1
  176. package/lib/module/ui/screens/AccountCenterScreen.js +2 -2
  177. package/lib/module/ui/screens/AccountCenterScreen.js.map +1 -1
  178. package/lib/module/ui/screens/AccountOverviewScreen.js.map +1 -1
  179. package/lib/module/ui/screens/AccountSettingsScreen.js +29 -24
  180. package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
  181. package/lib/module/ui/screens/AccountSwitcherScreen.js +3 -3
  182. package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
  183. package/lib/module/ui/screens/OxyAuthScreen.js +135 -68
  184. package/lib/module/ui/screens/OxyAuthScreen.js.map +1 -1
  185. package/lib/module/ui/screens/PrivacySettingsScreen.js +6 -13
  186. package/lib/module/ui/screens/PrivacySettingsScreen.js.map +1 -1
  187. package/lib/module/ui/stores/accountStore.js +2 -4
  188. package/lib/module/ui/stores/accountStore.js.map +1 -1
  189. package/lib/module/ui/stores/authStore.js +45 -32
  190. package/lib/module/ui/stores/authStore.js.map +1 -1
  191. package/lib/module/ui/styles/spacing.js +6 -2
  192. package/lib/module/ui/styles/spacing.js.map +1 -1
  193. package/lib/module/ui/utils/avatarUtils.js +37 -40
  194. package/lib/module/ui/utils/avatarUtils.js.map +1 -1
  195. package/lib/module/ui/utils/storageHelpers.js.map +1 -1
  196. package/lib/module/utils/errorUtils.js +7 -0
  197. package/lib/module/utils/errorUtils.js.map +1 -1
  198. package/lib/module/utils/validationUtils.js +13 -0
  199. package/lib/module/utils/validationUtils.js.map +1 -1
  200. package/lib/typescript/core/CrossDomainAuth.d.ts +161 -0
  201. package/lib/typescript/core/CrossDomainAuth.d.ts.map +1 -0
  202. package/lib/typescript/core/HttpService.d.ts +1 -1
  203. package/lib/typescript/core/HttpService.d.ts.map +1 -1
  204. package/lib/typescript/core/OxyServices.base.d.ts +0 -6
  205. package/lib/typescript/core/OxyServices.base.d.ts.map +1 -1
  206. package/lib/typescript/core/OxyServices.d.ts +5 -36
  207. package/lib/typescript/core/OxyServices.d.ts.map +1 -1
  208. package/lib/typescript/core/index.d.ts +4 -0
  209. package/lib/typescript/core/index.d.ts.map +1 -1
  210. package/lib/typescript/core/mixins/OxyServices.analytics.d.ts.map +1 -1
  211. package/lib/typescript/core/mixins/OxyServices.assets.d.ts.map +1 -1
  212. package/lib/typescript/core/mixins/OxyServices.auth.d.ts +40 -20
  213. package/lib/typescript/core/mixins/OxyServices.auth.d.ts.map +1 -1
  214. package/lib/typescript/core/mixins/OxyServices.developer.d.ts.map +1 -1
  215. package/lib/typescript/core/mixins/OxyServices.devices.d.ts.map +1 -1
  216. package/lib/typescript/core/mixins/OxyServices.fedcm.d.ts +195 -0
  217. package/lib/typescript/core/mixins/OxyServices.fedcm.d.ts.map +1 -0
  218. package/lib/typescript/core/mixins/OxyServices.karma.d.ts.map +1 -1
  219. package/lib/typescript/core/mixins/OxyServices.language.d.ts.map +1 -1
  220. package/lib/typescript/core/mixins/OxyServices.location.d.ts.map +1 -1
  221. package/lib/typescript/core/mixins/OxyServices.payment.d.ts.map +1 -1
  222. package/lib/typescript/core/mixins/OxyServices.popup.d.ts +206 -0
  223. package/lib/typescript/core/mixins/OxyServices.popup.d.ts.map +1 -0
  224. package/lib/typescript/core/mixins/OxyServices.privacy.d.ts.map +1 -1
  225. package/lib/typescript/core/mixins/OxyServices.redirect.d.ts +246 -0
  226. package/lib/typescript/core/mixins/OxyServices.redirect.d.ts.map +1 -0
  227. package/lib/typescript/core/mixins/OxyServices.security.d.ts.map +1 -1
  228. package/lib/typescript/core/mixins/OxyServices.user.d.ts +6 -4
  229. package/lib/typescript/core/mixins/OxyServices.user.d.ts.map +1 -1
  230. package/lib/typescript/core/mixins/OxyServices.utility.d.ts.map +1 -1
  231. package/lib/typescript/core/mixins/index.d.ts +220 -8
  232. package/lib/typescript/core/mixins/index.d.ts.map +1 -1
  233. package/lib/typescript/crypto/index.d.ts +6 -3
  234. package/lib/typescript/crypto/index.d.ts.map +1 -1
  235. package/lib/typescript/crypto/keyManager.d.ts +190 -0
  236. package/lib/typescript/crypto/keyManager.d.ts.map +1 -0
  237. package/lib/typescript/crypto/polyfill.d.ts +4 -3
  238. package/lib/typescript/crypto/polyfill.d.ts.map +1 -1
  239. package/lib/typescript/crypto/recoveryPhrase.d.ts +59 -0
  240. package/lib/typescript/crypto/recoveryPhrase.d.ts.map +1 -0
  241. package/lib/typescript/crypto/signatureService.d.ts +87 -0
  242. package/lib/typescript/crypto/signatureService.d.ts.map +1 -0
  243. package/lib/typescript/index.d.ts +5 -6
  244. package/lib/typescript/index.d.ts.map +1 -1
  245. package/lib/typescript/models/interfaces.d.ts +2 -14
  246. package/lib/typescript/models/interfaces.d.ts.map +1 -1
  247. package/lib/typescript/models/session.d.ts +0 -9
  248. package/lib/typescript/models/session.d.ts.map +1 -1
  249. package/lib/typescript/types/bip39.d.ts +32 -0
  250. package/lib/typescript/ui/components/BottomSheetRouter.d.ts +5 -0
  251. package/lib/typescript/ui/components/BottomSheetRouter.d.ts.map +1 -1
  252. package/lib/typescript/ui/components/IconButton/utils.d.ts +1 -1
  253. package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -1
  254. package/lib/typescript/ui/components/TextField/Addons/Outline.d.ts +2 -2
  255. package/lib/typescript/ui/components/TextField/Adornment/utils.d.ts +1 -1
  256. package/lib/typescript/ui/components/TextField/Adornment/utils.d.ts.map +1 -1
  257. package/lib/typescript/ui/components/TextField/helpers.d.ts +8 -8
  258. package/lib/typescript/ui/components/TextField/types.d.ts +1 -0
  259. package/lib/typescript/ui/components/TextField/types.d.ts.map +1 -1
  260. package/lib/typescript/ui/components/types.d.ts +4 -0
  261. package/lib/typescript/ui/components/types.d.ts.map +1 -1
  262. package/lib/typescript/ui/context/OxyContext.d.ts +57 -3
  263. package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
  264. package/lib/typescript/ui/context/hooks/useAuthOperations.d.ts +10 -3
  265. package/lib/typescript/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
  266. package/lib/typescript/ui/context/hooks/useSessionManagement.d.ts +41 -0
  267. package/lib/typescript/ui/context/hooks/useSessionManagement.d.ts.map +1 -0
  268. package/lib/typescript/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
  269. package/lib/typescript/ui/hooks/queries/useAccountQueries.d.ts.map +1 -1
  270. package/lib/typescript/ui/hooks/queries/useServicesQueries.d.ts.map +1 -1
  271. package/lib/typescript/ui/hooks/useProfileEditing.d.ts.map +1 -1
  272. package/lib/typescript/ui/hooks/useSessionManagement.d.ts.map +1 -1
  273. package/lib/typescript/ui/hooks/useSessionSocket.d.ts +1 -2
  274. package/lib/typescript/ui/hooks/useSessionSocket.d.ts.map +1 -1
  275. package/lib/typescript/ui/hooks/useStorage.d.ts +3 -9
  276. package/lib/typescript/ui/hooks/useStorage.d.ts.map +1 -1
  277. package/lib/typescript/ui/index.d.ts +6 -2
  278. package/lib/typescript/ui/index.d.ts.map +1 -1
  279. package/lib/typescript/ui/navigation/routes.d.ts +1 -1
  280. package/lib/typescript/ui/navigation/routes.d.ts.map +1 -1
  281. package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
  282. package/lib/typescript/ui/screens/OxyAuthScreen.d.ts +1 -1
  283. package/lib/typescript/ui/screens/OxyAuthScreen.d.ts.map +1 -1
  284. package/lib/typescript/ui/screens/PrivacySettingsScreen.d.ts.map +1 -1
  285. package/lib/typescript/ui/stores/accountStore.d.ts.map +1 -1
  286. package/lib/typescript/ui/stores/authStore.d.ts +8 -7
  287. package/lib/typescript/ui/stores/authStore.d.ts.map +1 -1
  288. package/lib/typescript/ui/styles/spacing.d.ts +5 -0
  289. package/lib/typescript/ui/styles/spacing.d.ts.map +1 -1
  290. package/lib/typescript/ui/types/navigation.d.ts +2 -1
  291. package/lib/typescript/ui/types/navigation.d.ts.map +1 -1
  292. package/lib/typescript/ui/utils/avatarUtils.d.ts +2 -13
  293. package/lib/typescript/ui/utils/avatarUtils.d.ts.map +1 -1
  294. package/lib/typescript/ui/utils/storageHelpers.d.ts +0 -3
  295. package/lib/typescript/ui/utils/storageHelpers.d.ts.map +1 -1
  296. package/lib/typescript/utils/errorUtils.d.ts +6 -0
  297. package/lib/typescript/utils/errorUtils.d.ts.map +1 -1
  298. package/lib/typescript/utils/validationUtils.d.ts +8 -0
  299. package/lib/typescript/utils/validationUtils.d.ts.map +1 -1
  300. package/package.json +8 -7
  301. package/src/core/CrossDomainAuth.ts +307 -0
  302. package/src/core/HttpService.ts +99 -16
  303. package/src/core/OxyServices.base.ts +20 -3
  304. package/src/core/OxyServices.ts +7 -3
  305. package/src/core/index.ts +9 -1
  306. package/src/core/mixins/OxyServices.assets.ts +14 -3
  307. package/src/core/mixins/OxyServices.auth.ts +105 -36
  308. package/src/core/mixins/OxyServices.fedcm.ts +315 -0
  309. package/src/core/mixins/OxyServices.popup.ts +402 -0
  310. package/src/core/mixins/OxyServices.redirect.ts +397 -0
  311. package/src/core/mixins/OxyServices.user.ts +39 -24
  312. package/src/core/mixins/index.ts +19 -3
  313. package/src/crypto/index.ts +16 -5
  314. package/src/crypto/keyManager.ts +966 -0
  315. package/src/crypto/polyfill.ts +6 -5
  316. package/src/crypto/recoveryPhrase.ts +166 -0
  317. package/src/crypto/signatureService.ts +323 -0
  318. package/src/i18n/locales/en-US.json +1 -1
  319. package/src/index.ts +19 -15
  320. package/src/models/interfaces.ts +4 -16
  321. package/src/models/session.ts +2 -11
  322. package/src/types/bip39.d.ts +32 -0
  323. package/src/ui/components/BottomSheetRouter.tsx +6 -1
  324. package/src/ui/components/Icon.tsx +1 -1
  325. package/src/ui/components/IconButton/utils.ts +1 -1
  326. package/src/ui/components/OxyProvider.tsx +44 -12
  327. package/src/ui/components/TextField/Addons/Outline.tsx +2 -2
  328. package/src/ui/components/TextField/Adornment/utils.ts +2 -2
  329. package/src/ui/components/TextField/helpers.tsx +10 -10
  330. package/src/ui/components/TextField/types.tsx +1 -1
  331. package/src/ui/components/TouchableRipple/utils.ts +2 -2
  332. package/src/ui/components/Typography/AnimatedText.tsx +2 -2
  333. package/src/ui/components/types.tsx +6 -0
  334. package/src/ui/context/OxyContext.tsx +173 -195
  335. package/src/ui/context/hooks/useAuthOperations.ts +177 -36
  336. package/src/ui/context/hooks/useSessionManagement.ts +399 -0
  337. package/src/ui/hooks/mutations/useAccountMutations.ts +83 -76
  338. package/src/ui/hooks/queries/useAccountQueries.ts +29 -35
  339. package/src/ui/hooks/queries/useSecurityQueries.ts +1 -1
  340. package/src/ui/hooks/queries/useServicesQueries.ts +14 -6
  341. package/src/ui/hooks/useProfileEditing.ts +3 -3
  342. package/src/ui/hooks/useSessionManagement.ts +5 -10
  343. package/src/ui/hooks/useSessionSocket.ts +46 -175
  344. package/src/ui/hooks/useStorage.ts +24 -76
  345. package/src/ui/index.ts +22 -13
  346. package/src/ui/navigation/routes.ts +6 -2
  347. package/src/ui/screens/AccountCenterScreen.tsx +2 -2
  348. package/src/ui/screens/AccountOverviewScreen.tsx +1 -1
  349. package/src/ui/screens/AccountSettingsScreen.tsx +34 -37
  350. package/src/ui/screens/AccountSwitcherScreen.tsx +4 -4
  351. package/src/ui/screens/OxyAuthScreen.tsx +138 -64
  352. package/src/ui/screens/PrivacySettingsScreen.tsx +6 -12
  353. package/src/ui/stores/accountStore.ts +1 -11
  354. package/src/ui/stores/authStore.ts +43 -44
  355. package/src/ui/styles/spacing.ts +15 -2
  356. package/src/ui/types/navigation.ts +2 -2
  357. package/src/ui/utils/avatarUtils.ts +39 -46
  358. package/src/ui/utils/storageHelpers.ts +0 -4
  359. package/src/utils/__tests__/validationUtils.test.ts +16 -1
  360. package/src/utils/errorUtils.ts +8 -1
  361. package/src/utils/validationUtils.ts +12 -0
  362. package/lib/commonjs/core/services/SessionService.js +0 -163
  363. package/lib/commonjs/core/services/SessionService.js.map +0 -1
  364. package/lib/commonjs/core/services/TokenService.js +0 -220
  365. package/lib/commonjs/core/services/TokenService.js.map +0 -1
  366. package/lib/commonjs/crypto/types.js +0 -2
  367. package/lib/commonjs/crypto/types.js.map +0 -1
  368. package/lib/commonjs/ui/context/OxyContextBase.js +0 -21
  369. package/lib/commonjs/ui/context/OxyContextBase.js.map +0 -1
  370. package/lib/commonjs/ui/context/hooks/useStorage.js +0 -79
  371. package/lib/commonjs/ui/context/hooks/useStorage.js.map +0 -1
  372. package/lib/commonjs/ui/hooks/useAvatarPicker.js +0 -56
  373. package/lib/commonjs/ui/hooks/useAvatarPicker.js.map +0 -1
  374. package/lib/module/core/services/SessionService.js +0 -159
  375. package/lib/module/core/services/SessionService.js.map +0 -1
  376. package/lib/module/core/services/TokenService.js +0 -217
  377. package/lib/module/core/services/TokenService.js.map +0 -1
  378. package/lib/module/crypto/types.js +0 -2
  379. package/lib/module/crypto/types.js.map +0 -1
  380. package/lib/module/ui/context/OxyContextBase.js +0 -16
  381. package/lib/module/ui/context/OxyContextBase.js.map +0 -1
  382. package/lib/module/ui/context/hooks/useStorage.js +0 -74
  383. package/lib/module/ui/context/hooks/useStorage.js.map +0 -1
  384. package/lib/module/ui/hooks/useAvatarPicker.js +0 -50
  385. package/lib/module/ui/hooks/useAvatarPicker.js.map +0 -1
  386. package/lib/typescript/core/services/SessionService.d.ts +0 -78
  387. package/lib/typescript/core/services/SessionService.d.ts.map +0 -1
  388. package/lib/typescript/core/services/TokenService.d.ts +0 -72
  389. package/lib/typescript/core/services/TokenService.d.ts.map +0 -1
  390. package/lib/typescript/crypto/types.d.ts +0 -22
  391. package/lib/typescript/crypto/types.d.ts.map +0 -1
  392. package/lib/typescript/ui/context/OxyContextBase.d.ts +0 -63
  393. package/lib/typescript/ui/context/OxyContextBase.d.ts.map +0 -1
  394. package/lib/typescript/ui/context/hooks/useStorage.d.ts +0 -22
  395. package/lib/typescript/ui/context/hooks/useStorage.d.ts.map +0 -1
  396. package/lib/typescript/ui/hooks/useAvatarPicker.d.ts +0 -19
  397. package/lib/typescript/ui/hooks/useAvatarPicker.d.ts.map +0 -1
  398. package/src/core/services/SessionService.ts +0 -173
  399. package/src/core/services/TokenService.ts +0 -237
  400. package/src/crypto/types.ts +0 -23
  401. package/src/ui/context/OxyContextBase.tsx +0 -78
  402. package/src/ui/context/hooks/useStorage.ts +0 -104
  403. package/src/ui/hooks/useAvatarPicker.ts +0 -61
@@ -2,10 +2,12 @@ import { useCallback } from 'react';
2
2
  import type { ApiError, User } from '../../../models/interfaces';
3
3
  import type { AuthState } from '../../stores/authStore';
4
4
  import type { ClientSession, SessionLoginResponse } from '../../../models/session';
5
- import { fetchSessionsWithFallback } from '../../utils/sessionHelpers';
5
+ import { DeviceManager } from '../../../utils/deviceManager';
6
+ import { fetchSessionsWithFallback, mapSessionsToClient } from '../../utils/sessionHelpers';
6
7
  import { handleAuthError, isInvalidSessionError } from '../../utils/errorHandlers';
7
8
  import type { StorageInterface } from '../../utils/storageHelpers';
8
9
  import type { OxyServices } from '../../../core';
10
+ import { SignatureService } from '../../../crypto';
9
11
 
10
12
  export interface UseAuthOperationsOptions {
11
13
  oxyServices: OxyServices;
@@ -20,7 +22,7 @@ export interface UseAuthOperationsOptions {
20
22
  applyLanguagePreference: (user: User) => Promise<void>;
21
23
  onAuthStateChange?: (user: User | null) => void;
22
24
  onError?: (error: ApiError) => void;
23
- loginSuccess: () => void;
25
+ loginSuccess: (user: User) => void;
24
26
  loginFailure: (message: string) => void;
25
27
  logoutStore: () => void;
26
28
  setAuthState: (state: Partial<AuthState>) => void;
@@ -28,15 +30,22 @@ export interface UseAuthOperationsOptions {
28
30
  }
29
31
 
30
32
  export interface UseAuthOperationsResult {
31
- completeSignIn: (sessionResponse: SessionLoginResponse) => Promise<User>;
33
+ /** Sign in with existing public key */
34
+ signIn: (publicKey: string, deviceName?: string) => Promise<User>;
35
+ /** Logout from current session */
32
36
  logout: (targetSessionId?: string) => Promise<void>;
37
+ /** Logout from all sessions */
33
38
  logoutAll: () => Promise<void>;
34
39
  }
35
40
 
41
+ const LOGIN_ERROR_CODE = 'LOGIN_ERROR';
36
42
  const LOGOUT_ERROR_CODE = 'LOGOUT_ERROR';
37
43
  const LOGOUT_ALL_ERROR_CODE = 'LOGOUT_ALL_ERROR';
38
44
 
39
-
45
+ /**
46
+ * Authentication operations using public key cryptography.
47
+ * Accepts public key as parameter - identity management is handled by the app layer.
48
+ */
40
49
  export const useAuthOperations = ({
41
50
  oxyServices,
42
51
  storage,
@@ -57,17 +66,136 @@ export const useAuthOperations = ({
57
66
  logger,
58
67
  }: UseAuthOperationsOptions): UseAuthOperationsResult => {
59
68
 
60
- const completeSignIn = useCallback(
61
- async (sessionResponse: SessionLoginResponse): Promise<User> => {
62
- if (!storage) throw new Error('Storage not initialized');
69
+ /**
70
+ * Internal function to perform challenge-response sign in (works offline)
71
+ */
72
+ const performSignIn = useCallback(
73
+ async (publicKey: string): Promise<User> => {
74
+ const deviceFingerprintObj = DeviceManager.getDeviceFingerprint();
75
+ const deviceFingerprint = JSON.stringify(deviceFingerprintObj);
76
+ const deviceInfo = await DeviceManager.getDeviceInfo();
77
+ const deviceName = deviceInfo.deviceName || DeviceManager.getDefaultDeviceName();
63
78
 
64
- setAuthState({ isLoading: true, error: null });
79
+ let challenge: string;
80
+ let isOffline = false;
65
81
 
82
+ // Try to request challenge from server (online)
66
83
  try {
67
- oxyServices.setTokens(sessionResponse.accessToken, sessionResponse.refreshToken);
84
+ const challengeResponse = await oxyServices.requestChallenge(publicKey);
85
+ challenge = challengeResponse.challenge;
86
+ } catch (error) {
87
+ // Network error - generate challenge locally for offline sign-in
88
+ const errorMessage = error instanceof Error ? error.message : String(error);
89
+ const isNetworkError =
90
+ errorMessage.includes('Network') ||
91
+ errorMessage.includes('network') ||
92
+ errorMessage.includes('Failed to fetch') ||
93
+ errorMessage.includes('fetch failed') ||
94
+ (error as any)?.code === 'NETWORK_ERROR' ||
95
+ (error as any)?.status === 0;
96
+
97
+ if (isNetworkError) {
98
+ if (__DEV__ && logger) {
99
+ logger('Network unavailable, performing offline sign-in');
100
+ }
101
+ // Generate challenge locally
102
+ challenge = await SignatureService.generateChallenge();
103
+ isOffline = true;
104
+ } else {
105
+ // Re-throw non-network errors
106
+ throw error;
107
+ }
108
+ }
109
+
110
+ // Note: Biometric authentication check should be handled by the app layer
111
+ // (e.g., accounts app) before calling signIn. The biometric preference is stored
112
+ // in local storage as 'oxy_biometric_enabled' and can be checked there.
113
+
114
+ // Sign the challenge
115
+ const { challenge: signature, timestamp } = await SignatureService.signChallenge(challenge);
116
+
117
+ let fullUser: User;
118
+ let sessionResponse: SessionLoginResponse;
119
+
120
+ if (isOffline) {
121
+ // Offline sign-in: create local session and minimal user object
122
+ if (__DEV__ && logger) {
123
+ logger('Creating offline session');
124
+ }
125
+
126
+ // Generate a local session ID
127
+ const localSessionId = `offline_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
128
+ const localDeviceId = `device_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
129
+ const expiresAt = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(); // 7 days
130
+
131
+ // Create minimal user object with publicKey as id
132
+ fullUser = {
133
+ id: publicKey, // Use publicKey as id (per migration document)
134
+ publicKey,
135
+ username: '',
136
+ privacySettings: {},
137
+ } as User;
68
138
 
69
- const fullUser = await oxyServices.getUserBySession(sessionResponse.sessionId);
139
+ sessionResponse = {
140
+ sessionId: localSessionId,
141
+ deviceId: localDeviceId,
142
+ expiresAt,
143
+ user: {
144
+ id: publicKey,
145
+ username: '',
146
+ },
147
+ };
70
148
 
149
+ // Store offline session locally
150
+ const offlineSession: ClientSession = {
151
+ sessionId: localSessionId,
152
+ deviceId: localDeviceId,
153
+ expiresAt,
154
+ lastActive: new Date().toISOString(),
155
+ userId: publicKey,
156
+ isCurrent: true,
157
+ };
158
+
159
+ setActiveSessionId(localSessionId);
160
+ await saveActiveSessionId(localSessionId);
161
+ updateSessions([offlineSession], { merge: true });
162
+
163
+ // Mark session as offline for later sync
164
+ if (storage) {
165
+ await storage.setItem(`oxy_session_${localSessionId}_offline`, 'true');
166
+ }
167
+
168
+ if (__DEV__ && logger) {
169
+ logger('Offline sign-in successful');
170
+ }
171
+ } else {
172
+ // Online sign-in: use normal flow
173
+ // Verify and create session
174
+ sessionResponse = await oxyServices.verifyChallenge(
175
+ publicKey,
176
+ challenge,
177
+ signature,
178
+ timestamp,
179
+ deviceName,
180
+ deviceFingerprint,
181
+ );
182
+
183
+ // Get token for the session
184
+ try {
185
+ await oxyServices.getTokenBySession(sessionResponse.sessionId);
186
+ } catch (tokenError: unknown) {
187
+ const errorMessage = tokenError instanceof Error ? tokenError.message : String(tokenError);
188
+ const status = (tokenError as any)?.status;
189
+ if (status === 404 || errorMessage.includes('404')) {
190
+ throw new Error(`Session was created but token could not be retrieved. Session ID: ${sessionResponse.sessionId.substring(0, 8)}...`);
191
+ }
192
+ throw tokenError;
193
+ }
194
+
195
+ // Get full user data
196
+ fullUser = await oxyServices.getUserBySession(sessionResponse.sessionId);
197
+
198
+ // Fetch device sessions
71
199
  let allDeviceSessions: ClientSession[] = [];
72
200
  try {
73
201
  allDeviceSessions = await fetchSessionsWithFallback(oxyServices, sessionResponse.sessionId, {
@@ -76,11 +204,12 @@ export const useAuthOperations = ({
76
204
  logger,
77
205
  });
78
206
  } catch (error) {
79
- if (__DEV__) {
80
- console.warn('Failed to fetch device sessions after login:', error);
207
+ if (__DEV__ && logger) {
208
+ logger('Failed to fetch device sessions after login', error);
81
209
  }
82
210
  }
83
211
 
212
+ // Check for existing session for same user and switch to it to avoid duplicates
84
213
  const existingSession = allDeviceSessions.find(
85
214
  (session) =>
86
215
  session.userId?.toString() === fullUser.id?.toString() &&
@@ -88,11 +217,13 @@ export const useAuthOperations = ({
88
217
  );
89
218
 
90
219
  if (existingSession) {
220
+ // Switch to existing session instead of creating duplicate
91
221
  try {
92
222
  await oxyServices.logoutSession(sessionResponse.sessionId, sessionResponse.sessionId);
93
223
  } catch (logoutError) {
94
- if (__DEV__) {
95
- console.warn('Failed to logout duplicate session:', logoutError);
224
+ // Non-critical - continue to switch session even if logout fails
225
+ if (__DEV__ && logger) {
226
+ logger('Failed to logout duplicate session, continuing with switch', logoutError);
96
227
  }
97
228
  }
98
229
  await switchSession(existingSession.sessionId);
@@ -107,16 +238,41 @@ export const useAuthOperations = ({
107
238
  setActiveSessionId(sessionResponse.sessionId);
108
239
  await saveActiveSessionId(sessionResponse.sessionId);
109
240
  updateSessions(allDeviceSessions, { merge: true });
241
+ }
110
242
 
111
- await applyLanguagePreference(fullUser);
112
- loginSuccess();
113
- onAuthStateChange?.(fullUser);
243
+ await applyLanguagePreference(fullUser);
244
+ loginSuccess(fullUser);
245
+ onAuthStateChange?.(fullUser);
246
+
247
+ return fullUser;
248
+ },
249
+ [
250
+ applyLanguagePreference,
251
+ logger,
252
+ loginSuccess,
253
+ onAuthStateChange,
254
+ oxyServices,
255
+ saveActiveSessionId,
256
+ setActiveSessionId,
257
+ switchSession,
258
+ updateSessions,
259
+ storage,
260
+ ],
261
+ );
262
+
263
+ /**
264
+ * Sign in with existing public key
265
+ */
266
+ const signIn = useCallback(
267
+ async (publicKey: string, deviceName?: string): Promise<User> => {
268
+ setAuthState({ isLoading: true, error: null });
114
269
 
115
- return fullUser;
270
+ try {
271
+ return await performSignIn(publicKey);
116
272
  } catch (error) {
117
273
  const message = handleAuthError(error, {
118
274
  defaultMessage: 'Sign in failed',
119
- code: 'COMPLETE_SIGNIN_ERROR',
275
+ code: LOGIN_ERROR_CODE,
120
276
  onError,
121
277
  setAuthError: (msg: string) => setAuthState({ error: msg }),
122
278
  logger,
@@ -127,24 +283,9 @@ export const useAuthOperations = ({
127
283
  setAuthState({ isLoading: false });
128
284
  }
129
285
  },
130
- [
131
- storage,
132
- setAuthState,
133
- oxyServices,
134
- logger,
135
- saveActiveSessionId,
136
- setActiveSessionId,
137
- switchSession,
138
- updateSessions,
139
- applyLanguagePreference,
140
- loginSuccess,
141
- onAuthStateChange,
142
- onError,
143
- loginFailure,
144
- ],
286
+ [setAuthState, performSignIn, loginFailure, onError, logger],
145
287
  );
146
288
 
147
-
148
289
  /**
149
290
  * Logout from session
150
291
  */
@@ -225,7 +366,7 @@ export const useAuthOperations = ({
225
366
  }, [activeSessionId, clearSessionState, logger, onError, oxyServices, setAuthState]);
226
367
 
227
368
  return {
228
- completeSignIn,
369
+ signIn,
229
370
  logout,
230
371
  logoutAll,
231
372
  };
@@ -0,0 +1,399 @@
1
+ import { useCallback, useMemo, useRef, useState } from 'react';
2
+ import type { ApiError, User } from '../../../models/interfaces';
3
+ import type { ClientSession } from '../../../models/session';
4
+ import { mergeSessions, normalizeAndSortSessions, sessionsArraysEqual } from '../../../utils/sessionUtils';
5
+ import { fetchSessionsWithFallback, mapSessionsToClient, validateSessionBatch } from '../../utils/sessionHelpers';
6
+ import { getStorageKeys, type StorageInterface } from '../../utils/storageHelpers';
7
+ import { handleAuthError, isInvalidSessionError } from '../../utils/errorHandlers';
8
+ import type { OxyServices } from '../../../core';
9
+ import type { QueryClient } from '@tanstack/react-query';
10
+ import { clearQueryCache } from '../../hooks/queryClient';
11
+
12
+ export interface UseSessionManagementOptions {
13
+ oxyServices: OxyServices;
14
+ storage: StorageInterface | null;
15
+ storageKeyPrefix?: string;
16
+ loginSuccess: (user: User) => void;
17
+ logoutStore: () => void;
18
+ applyLanguagePreference: (user: User) => Promise<void>;
19
+ onAuthStateChange?: (user: User | null) => void;
20
+ onError?: (error: ApiError) => void;
21
+ setAuthError?: (message: string | null) => void;
22
+ logger?: (message: string, error?: unknown) => void;
23
+ setTokenReady?: (ready: boolean) => void;
24
+ queryClient?: QueryClient | null;
25
+ }
26
+
27
+ export interface UseSessionManagementResult {
28
+ sessions: ClientSession[];
29
+ activeSessionId: string | null;
30
+ setActiveSessionId: (sessionId: string | null) => void;
31
+ updateSessions: (incoming: ClientSession[], options?: { merge?: boolean }) => void;
32
+ switchSession: (sessionId: string) => Promise<User>;
33
+ refreshSessions: (activeUserId?: string) => Promise<void>;
34
+ clearSessionState: () => Promise<void>;
35
+ saveActiveSessionId: (sessionId: string) => Promise<void>;
36
+ trackRemovedSession: (sessionId: string) => void;
37
+ storageKeys: ReturnType<typeof getStorageKeys>;
38
+ isRefreshInFlight: boolean;
39
+ }
40
+
41
+ const DEFAULT_SAVE_ERROR_MESSAGE = 'Failed to save session data';
42
+ const CLEAR_STORAGE_ERROR = 'Failed to clear storage';
43
+
44
+ /**
45
+ * Manage session state, persistence, and high-level multi-session operations.
46
+ *
47
+ * @param options - Session management configuration
48
+ */
49
+ export const useSessionManagement = ({
50
+ oxyServices,
51
+ storage,
52
+ storageKeyPrefix,
53
+ loginSuccess,
54
+ logoutStore,
55
+ applyLanguagePreference,
56
+ onAuthStateChange,
57
+ onError,
58
+ setAuthError,
59
+ logger,
60
+ setTokenReady,
61
+ queryClient,
62
+ }: UseSessionManagementOptions): UseSessionManagementResult => {
63
+ const [sessions, setSessions] = useState<ClientSession[]>([]);
64
+ const [activeSessionId, setActiveSessionId] = useState<string | null>(null);
65
+
66
+ const refreshInFlightRef = useRef<Promise<void> | null>(null);
67
+ const removedSessionsRef = useRef<Set<string>>(new Set());
68
+ const lastRefreshRef = useRef<number>(0);
69
+
70
+ const storageKeys = useMemo(() => getStorageKeys(storageKeyPrefix), [storageKeyPrefix]);
71
+
72
+ const saveSessionIds = useCallback(
73
+ async (sessionIds: string[]): Promise<void> => {
74
+ if (!storage) return;
75
+ try {
76
+ const uniqueIds = Array.from(new Set(sessionIds));
77
+ await storage.setItem(storageKeys.sessionIds, JSON.stringify(uniqueIds));
78
+ } catch (error) {
79
+ if (logger) {
80
+ logger(DEFAULT_SAVE_ERROR_MESSAGE, error);
81
+ } else if (__DEV__) {
82
+ console.warn('Failed to save session IDs:', error);
83
+ }
84
+ }
85
+ },
86
+ [logger, storage, storageKeys.sessionIds],
87
+ );
88
+
89
+ const updateSessions = useCallback(
90
+ (incoming: ClientSession[], options: { merge?: boolean } = {}): void => {
91
+ setSessions((prevSessions) => {
92
+ const processed = options.merge
93
+ ? mergeSessions(prevSessions, incoming, activeSessionId, false)
94
+ : normalizeAndSortSessions(incoming, activeSessionId, false);
95
+
96
+ if (storage) {
97
+ void saveSessionIds(processed.map((session) => session.sessionId));
98
+ }
99
+
100
+ if (sessionsArraysEqual(prevSessions, processed)) {
101
+ return prevSessions;
102
+ }
103
+ return processed;
104
+ });
105
+ },
106
+ [activeSessionId, saveSessionIds, storage],
107
+ );
108
+
109
+ const saveActiveSessionId = useCallback(
110
+ async (sessionId: string): Promise<void> => {
111
+ if (!storage) return;
112
+ try {
113
+ await storage.setItem(storageKeys.activeSessionId, sessionId);
114
+ } catch (error) {
115
+ handleAuthError(error, {
116
+ defaultMessage: DEFAULT_SAVE_ERROR_MESSAGE,
117
+ code: 'SESSION_PERSISTENCE_ERROR',
118
+ onError,
119
+ setAuthError,
120
+ logger,
121
+ });
122
+ }
123
+ },
124
+ [logger, onError, setAuthError, storage, storageKeys.activeSessionId],
125
+ );
126
+
127
+ const removeActiveSessionId = useCallback(async (): Promise<void> => {
128
+ if (!storage) return;
129
+ try {
130
+ await storage.removeItem(storageKeys.activeSessionId);
131
+ } catch (error) {
132
+ handleAuthError(error, {
133
+ defaultMessage: DEFAULT_SAVE_ERROR_MESSAGE,
134
+ code: 'SESSION_PERSISTENCE_ERROR',
135
+ onError,
136
+ setAuthError,
137
+ logger,
138
+ });
139
+ }
140
+ }, [logger, onError, setAuthError, storage, storageKeys.activeSessionId]);
141
+
142
+ const clearSessionStorage = useCallback(async (): Promise<void> => {
143
+ if (!storage) return;
144
+ try {
145
+ await storage.removeItem(storageKeys.activeSessionId);
146
+ await storage.removeItem(storageKeys.sessionIds);
147
+ } catch (error) {
148
+ handleAuthError(error, {
149
+ defaultMessage: CLEAR_STORAGE_ERROR,
150
+ code: 'STORAGE_ERROR',
151
+ onError,
152
+ setAuthError,
153
+ logger,
154
+ });
155
+ }
156
+ }, [logger, onError, setAuthError, storage, storageKeys.activeSessionId, storageKeys.sessionIds]);
157
+
158
+ const clearSessionState = useCallback(async (): Promise<void> => {
159
+ setSessions([]);
160
+ setActiveSessionId(null);
161
+ logoutStore();
162
+
163
+ // Clear TanStack Query cache (in-memory)
164
+ if (queryClient) {
165
+ queryClient.clear();
166
+ }
167
+
168
+ // Clear persisted query cache
169
+ if (storage) {
170
+ try {
171
+ await clearQueryCache(storage);
172
+ } catch (error) {
173
+ if (logger) {
174
+ logger('Failed to clear persisted query cache', error);
175
+ }
176
+ }
177
+ }
178
+
179
+ await clearSessionStorage();
180
+ onAuthStateChange?.(null);
181
+ }, [clearSessionStorage, logoutStore, onAuthStateChange, queryClient, storage, logger]);
182
+
183
+ const activateSession = useCallback(
184
+ async (sessionId: string, user: User): Promise<void> => {
185
+ await oxyServices.getTokenBySession(sessionId);
186
+ setTokenReady?.(true);
187
+ setActiveSessionId(sessionId);
188
+ loginSuccess(user);
189
+ await saveActiveSessionId(sessionId);
190
+ await applyLanguagePreference(user);
191
+ onAuthStateChange?.(user);
192
+ },
193
+ [
194
+ applyLanguagePreference,
195
+ loginSuccess,
196
+ onAuthStateChange,
197
+ oxyServices,
198
+ saveActiveSessionId,
199
+ setTokenReady,
200
+ ],
201
+ );
202
+
203
+ const trackRemovedSession = useCallback((sessionId: string) => {
204
+ removedSessionsRef.current.add(sessionId);
205
+ setTimeout(() => {
206
+ removedSessionsRef.current.delete(sessionId);
207
+ }, 5000);
208
+ }, []);
209
+
210
+ const findReplacementSession = useCallback(
211
+ async (sessionIds: string[]): Promise<User | null> => {
212
+ if (!sessionIds.length) {
213
+ return null;
214
+ }
215
+
216
+ const validationResults = await validateSessionBatch(oxyServices, sessionIds, {
217
+ maxConcurrency: 3,
218
+ });
219
+
220
+ const validSession = validationResults.find((result) => result.valid);
221
+ if (!validSession) {
222
+ return null;
223
+ }
224
+
225
+ const validation = await oxyServices.validateSession(validSession.sessionId, {
226
+ useHeaderValidation: true,
227
+ });
228
+
229
+ if (!validation?.valid || !validation.user) {
230
+ return null;
231
+ }
232
+
233
+ const user = validation.user as User;
234
+ await activateSession(validSession.sessionId, user);
235
+ return user;
236
+ },
237
+ [activateSession, oxyServices],
238
+ );
239
+
240
+ const switchSession = useCallback(
241
+ async (sessionId: string): Promise<User> => {
242
+ try {
243
+ const validation = await oxyServices.validateSession(sessionId, { useHeaderValidation: true });
244
+ if (!validation?.valid) {
245
+ throw new Error('Session is invalid or expired');
246
+ }
247
+
248
+ if (!validation.user) {
249
+ throw new Error('User data not available from session validation');
250
+ }
251
+
252
+ const user = validation.user as User;
253
+ await activateSession(sessionId, user);
254
+
255
+ try {
256
+ const deviceSessions = await fetchSessionsWithFallback(oxyServices, sessionId, {
257
+ fallbackUserId: user.id,
258
+ logger,
259
+ });
260
+ updateSessions(deviceSessions, { merge: true });
261
+ } catch (error) {
262
+ if (__DEV__) {
263
+ console.warn('Failed to synchronize sessions after switch:', error);
264
+ }
265
+ }
266
+
267
+ return user;
268
+ } catch (error) {
269
+ const invalidSession = isInvalidSessionError(error);
270
+
271
+ if (invalidSession) {
272
+ updateSessions(sessions.filter((session) => session.sessionId !== sessionId), {
273
+ merge: false,
274
+ });
275
+ if (sessionId === activeSessionId) {
276
+ const otherSessionIds = sessions
277
+ .filter(
278
+ (session) =>
279
+ session.sessionId !== sessionId && !removedSessionsRef.current.has(session.sessionId),
280
+ )
281
+ .map((session) => session.sessionId);
282
+
283
+ const replacementUser = await findReplacementSession(otherSessionIds);
284
+ if (replacementUser) {
285
+ return replacementUser;
286
+ }
287
+ }
288
+ }
289
+
290
+ handleAuthError(error, {
291
+ defaultMessage: 'Failed to switch session',
292
+ code: invalidSession ? 'INVALID_SESSION' : 'SESSION_SWITCH_ERROR',
293
+ onError,
294
+ setAuthError,
295
+ logger,
296
+ });
297
+ throw error instanceof Error ? error : new Error('Failed to switch session');
298
+ }
299
+ },
300
+ [
301
+ activateSession,
302
+ activeSessionId,
303
+ findReplacementSession,
304
+ logger,
305
+ loginSuccess,
306
+ onError,
307
+ oxyServices,
308
+ sessions,
309
+ setAuthError,
310
+ updateSessions,
311
+ ],
312
+ );
313
+
314
+ const refreshSessions = useCallback(
315
+ async (activeUserId?: string): Promise<void> => {
316
+ if (!activeSessionId) return;
317
+
318
+ if (refreshInFlightRef.current) {
319
+ await refreshInFlightRef.current;
320
+ return;
321
+ }
322
+
323
+ const now = Date.now();
324
+ if (now - lastRefreshRef.current < 500) {
325
+ return;
326
+ }
327
+ lastRefreshRef.current = now;
328
+
329
+ const refreshPromise = (async () => {
330
+ try {
331
+ const deviceSessions = await fetchSessionsWithFallback(oxyServices, activeSessionId, {
332
+ fallbackUserId: activeUserId,
333
+ logger,
334
+ });
335
+ updateSessions(deviceSessions, { merge: true });
336
+ } catch (error) {
337
+ if (isInvalidSessionError(error)) {
338
+ const otherSessions = sessions
339
+ .filter(
340
+ (session) =>
341
+ session.sessionId !== activeSessionId &&
342
+ !removedSessionsRef.current.has(session.sessionId),
343
+ )
344
+ .map((session) => session.sessionId);
345
+
346
+ const replacementUser = await findReplacementSession(otherSessions);
347
+ if (!replacementUser) {
348
+ await clearSessionState();
349
+ }
350
+ return;
351
+ }
352
+
353
+ handleAuthError(error, {
354
+ defaultMessage: 'Failed to refresh sessions',
355
+ code: 'SESSION_REFRESH_ERROR',
356
+ onError,
357
+ setAuthError,
358
+ logger,
359
+ });
360
+ } finally {
361
+ refreshInFlightRef.current = null;
362
+ lastRefreshRef.current = Date.now();
363
+ }
364
+ })();
365
+
366
+ refreshInFlightRef.current = refreshPromise;
367
+ await refreshPromise;
368
+ },
369
+ [
370
+ activeSessionId,
371
+ clearSessionState,
372
+ findReplacementSession,
373
+ logger,
374
+ onError,
375
+ oxyServices,
376
+ sessions,
377
+ setAuthError,
378
+ updateSessions,
379
+ ],
380
+ );
381
+
382
+ const isRefreshInFlight = Boolean(refreshInFlightRef.current);
383
+
384
+ return {
385
+ sessions,
386
+ activeSessionId,
387
+ setActiveSessionId,
388
+ updateSessions,
389
+ switchSession,
390
+ refreshSessions,
391
+ clearSessionState,
392
+ saveActiveSessionId,
393
+ trackRemovedSession,
394
+ storageKeys,
395
+ isRefreshInFlight,
396
+ };
397
+ };
398
+
399
+