@oxyhq/services 5.13.0 → 5.13.2

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 (353) hide show
  1. package/README.md +71 -0
  2. package/lib/commonjs/core/HttpClient.js +238 -0
  3. package/lib/commonjs/core/HttpClient.js.map +1 -0
  4. package/lib/commonjs/core/OxyServices.js +530 -332
  5. package/lib/commonjs/core/OxyServices.js.map +1 -1
  6. package/lib/commonjs/core/RequestManager.js +199 -0
  7. package/lib/commonjs/core/RequestManager.js.map +1 -0
  8. package/lib/commonjs/core/index.js +38 -1
  9. package/lib/commonjs/core/index.js.map +1 -1
  10. package/lib/commonjs/i18n/index.js +37 -1
  11. package/lib/commonjs/i18n/index.js.map +1 -1
  12. package/lib/commonjs/i18n/locales/ar-SA.json +128 -0
  13. package/lib/commonjs/i18n/locales/ca-ES.json +128 -0
  14. package/lib/commonjs/i18n/locales/de-DE.json +128 -0
  15. package/lib/commonjs/i18n/locales/en-US.json +85 -12
  16. package/lib/commonjs/i18n/locales/es-ES.json +58 -6
  17. package/lib/commonjs/i18n/locales/fr-FR.json +128 -0
  18. package/lib/commonjs/i18n/locales/it-IT.json +128 -0
  19. package/lib/commonjs/i18n/locales/ja-JP.json +127 -0
  20. package/lib/commonjs/i18n/locales/ko-KR.json +128 -0
  21. package/lib/commonjs/i18n/locales/pt-PT.json +128 -0
  22. package/lib/commonjs/i18n/locales/zh-CN.json +128 -0
  23. package/lib/commonjs/index.js +36 -0
  24. package/lib/commonjs/index.js.map +1 -1
  25. package/lib/commonjs/ui/components/Avatar.js +94 -27
  26. package/lib/commonjs/ui/components/Avatar.js.map +1 -1
  27. package/lib/commonjs/ui/components/FollowButton.js +1 -0
  28. package/lib/commonjs/ui/components/FollowButton.js.map +1 -1
  29. package/lib/commonjs/ui/components/FontLoader.js +22 -42
  30. package/lib/commonjs/ui/components/FontLoader.js.map +1 -1
  31. package/lib/commonjs/ui/components/OxyProvider.js +5 -8
  32. package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
  33. package/lib/commonjs/ui/components/StepBasedScreen.js +64 -44
  34. package/lib/commonjs/ui/components/StepBasedScreen.js.map +1 -1
  35. package/lib/commonjs/ui/components/internal/GroupedPillButtons.js +14 -35
  36. package/lib/commonjs/ui/components/internal/GroupedPillButtons.js.map +1 -1
  37. package/lib/commonjs/ui/components/internal/PinInput.js +2 -2
  38. package/lib/commonjs/ui/components/internal/PinInput.js.map +1 -1
  39. package/lib/commonjs/ui/components/internal/TextField.js +13 -8
  40. package/lib/commonjs/ui/components/internal/TextField.js.map +1 -1
  41. package/lib/commonjs/ui/context/OxyContext.js +443 -371
  42. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  43. package/lib/commonjs/ui/hooks/useSessionSocket.js +80 -22
  44. package/lib/commonjs/ui/hooks/useSessionSocket.js.map +1 -1
  45. package/lib/commonjs/ui/index.js +4 -1
  46. package/lib/commonjs/ui/index.js.map +1 -1
  47. package/lib/commonjs/ui/screens/AccountSettingsScreen.js +32 -2
  48. package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
  49. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +101 -59
  50. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -1
  51. package/lib/commonjs/ui/screens/FileManagementScreen.js +3 -2
  52. package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
  53. package/lib/commonjs/ui/screens/LanguageSelectorScreen.js +75 -117
  54. package/lib/commonjs/ui/screens/LanguageSelectorScreen.js.map +1 -1
  55. package/lib/commonjs/ui/screens/SignInScreen.js +43 -50
  56. package/lib/commonjs/ui/screens/SignInScreen.js.map +1 -1
  57. package/lib/commonjs/ui/screens/SignUpScreen.js +14 -16
  58. package/lib/commonjs/ui/screens/SignUpScreen.js.map +1 -1
  59. package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js +188 -142
  60. package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js.map +1 -1
  61. package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js +10 -10
  62. package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js.map +1 -1
  63. package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js +2 -4
  64. package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js.map +1 -1
  65. package/lib/commonjs/ui/screens/steps/RecoverRequestStep.js +45 -25
  66. package/lib/commonjs/ui/screens/steps/RecoverRequestStep.js.map +1 -1
  67. package/lib/commonjs/ui/screens/steps/RecoverResetPasswordStep.js +88 -53
  68. package/lib/commonjs/ui/screens/steps/RecoverResetPasswordStep.js.map +1 -1
  69. package/lib/commonjs/ui/screens/steps/RecoverSuccessStep.js +79 -58
  70. package/lib/commonjs/ui/screens/steps/RecoverSuccessStep.js.map +1 -1
  71. package/lib/commonjs/ui/screens/steps/RecoverVerifyStep.js +61 -52
  72. package/lib/commonjs/ui/screens/steps/RecoverVerifyStep.js.map +1 -1
  73. package/lib/commonjs/ui/screens/steps/SignInPasswordStep.js +218 -39
  74. package/lib/commonjs/ui/screens/steps/SignInPasswordStep.js.map +1 -1
  75. package/lib/commonjs/ui/screens/steps/SignInTotpStep.js +77 -50
  76. package/lib/commonjs/ui/screens/steps/SignInTotpStep.js.map +1 -1
  77. package/lib/commonjs/ui/screens/steps/SignInUsernameStep.js +424 -71
  78. package/lib/commonjs/ui/screens/steps/SignInUsernameStep.js.map +1 -1
  79. package/lib/commonjs/ui/screens/steps/SignUpIdentityStep.js +55 -30
  80. package/lib/commonjs/ui/screens/steps/SignUpIdentityStep.js.map +1 -1
  81. package/lib/commonjs/ui/screens/steps/SignUpSecurityStep.js +64 -46
  82. package/lib/commonjs/ui/screens/steps/SignUpSecurityStep.js.map +1 -1
  83. package/lib/commonjs/ui/screens/steps/SignUpSummaryStep.js +84 -146
  84. package/lib/commonjs/ui/screens/steps/SignUpSummaryStep.js.map +1 -1
  85. package/lib/commonjs/ui/screens/steps/SignUpWelcomeStep.js +113 -34
  86. package/lib/commonjs/ui/screens/steps/SignUpWelcomeStep.js.map +1 -1
  87. package/lib/commonjs/ui/stores/accountStore.js +237 -0
  88. package/lib/commonjs/ui/stores/accountStore.js.map +1 -0
  89. package/lib/commonjs/ui/stores/authStore.js +17 -20
  90. package/lib/commonjs/ui/stores/authStore.js.map +1 -1
  91. package/lib/commonjs/ui/styles/authStyles.js +16 -8
  92. package/lib/commonjs/ui/styles/authStyles.js.map +1 -1
  93. package/lib/commonjs/ui/styles/index.js +11 -0
  94. package/lib/commonjs/ui/styles/index.js.map +1 -1
  95. package/lib/commonjs/ui/styles/spacing.js +51 -0
  96. package/lib/commonjs/ui/styles/spacing.js.map +1 -0
  97. package/lib/commonjs/utils/asyncUtils.js +9 -22
  98. package/lib/commonjs/utils/asyncUtils.js.map +1 -1
  99. package/lib/commonjs/utils/cache.js +259 -0
  100. package/lib/commonjs/utils/cache.js.map +1 -0
  101. package/lib/commonjs/utils/index.js +99 -0
  102. package/lib/commonjs/utils/index.js.map +1 -1
  103. package/lib/commonjs/utils/languageUtils.js +159 -0
  104. package/lib/commonjs/utils/languageUtils.js.map +1 -0
  105. package/lib/commonjs/utils/requestUtils.js +217 -0
  106. package/lib/commonjs/utils/requestUtils.js.map +1 -0
  107. package/lib/commonjs/utils/sessionUtils.js +191 -0
  108. package/lib/commonjs/utils/sessionUtils.js.map +1 -0
  109. package/lib/commonjs/utils/validationUtils.js +1 -1
  110. package/lib/module/core/HttpClient.js +232 -0
  111. package/lib/module/core/HttpClient.js.map +1 -0
  112. package/lib/module/core/OxyServices.js +528 -326
  113. package/lib/module/core/OxyServices.js.map +1 -1
  114. package/lib/module/core/RequestManager.js +194 -0
  115. package/lib/module/core/RequestManager.js.map +1 -0
  116. package/lib/module/core/index.js +2 -0
  117. package/lib/module/core/index.js.map +1 -1
  118. package/lib/module/i18n/index.js +37 -1
  119. package/lib/module/i18n/index.js.map +1 -1
  120. package/lib/module/i18n/locales/ar-SA.json +128 -0
  121. package/lib/module/i18n/locales/ca-ES.json +128 -0
  122. package/lib/module/i18n/locales/de-DE.json +128 -0
  123. package/lib/module/i18n/locales/en-US.json +85 -12
  124. package/lib/module/i18n/locales/es-ES.json +58 -6
  125. package/lib/module/i18n/locales/fr-FR.json +128 -0
  126. package/lib/module/i18n/locales/it-IT.json +128 -0
  127. package/lib/module/i18n/locales/ja-JP.json +127 -0
  128. package/lib/module/i18n/locales/ko-KR.json +128 -0
  129. package/lib/module/i18n/locales/pt-PT.json +128 -0
  130. package/lib/module/i18n/locales/zh-CN.json +128 -0
  131. package/lib/module/index.js +2 -0
  132. package/lib/module/index.js.map +1 -1
  133. package/lib/module/ui/components/Avatar.js +94 -27
  134. package/lib/module/ui/components/Avatar.js.map +1 -1
  135. package/lib/module/ui/components/FollowButton.js +1 -0
  136. package/lib/module/ui/components/FollowButton.js.map +1 -1
  137. package/lib/module/ui/components/FontLoader.js +23 -43
  138. package/lib/module/ui/components/FontLoader.js.map +1 -1
  139. package/lib/module/ui/components/OxyProvider.js +6 -8
  140. package/lib/module/ui/components/OxyProvider.js.map +1 -1
  141. package/lib/module/ui/components/StepBasedScreen.js +65 -45
  142. package/lib/module/ui/components/StepBasedScreen.js.map +1 -1
  143. package/lib/module/ui/components/internal/GroupedPillButtons.js +14 -35
  144. package/lib/module/ui/components/internal/GroupedPillButtons.js.map +1 -1
  145. package/lib/module/ui/components/internal/PinInput.js +2 -2
  146. package/lib/module/ui/components/internal/PinInput.js.map +1 -1
  147. package/lib/module/ui/components/internal/TextField.js +13 -8
  148. package/lib/module/ui/components/internal/TextField.js.map +1 -1
  149. package/lib/module/ui/context/OxyContext.js +442 -370
  150. package/lib/module/ui/context/OxyContext.js.map +1 -1
  151. package/lib/module/ui/hooks/useSessionSocket.js +80 -22
  152. package/lib/module/ui/hooks/useSessionSocket.js.map +1 -1
  153. package/lib/module/ui/index.js +4 -2
  154. package/lib/module/ui/index.js.map +1 -1
  155. package/lib/module/ui/screens/AccountSettingsScreen.js +33 -2
  156. package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
  157. package/lib/module/ui/screens/AccountSwitcherScreen.js +102 -60
  158. package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
  159. package/lib/module/ui/screens/FileManagementScreen.js +3 -2
  160. package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
  161. package/lib/module/ui/screens/LanguageSelectorScreen.js +73 -117
  162. package/lib/module/ui/screens/LanguageSelectorScreen.js.map +1 -1
  163. package/lib/module/ui/screens/SignInScreen.js +44 -51
  164. package/lib/module/ui/screens/SignInScreen.js.map +1 -1
  165. package/lib/module/ui/screens/SignUpScreen.js +14 -16
  166. package/lib/module/ui/screens/SignUpScreen.js.map +1 -1
  167. package/lib/module/ui/screens/WelcomeNewUserScreen.js +187 -143
  168. package/lib/module/ui/screens/WelcomeNewUserScreen.js.map +1 -1
  169. package/lib/module/ui/screens/internal/SignInPasswordStep.js +10 -10
  170. package/lib/module/ui/screens/internal/SignInPasswordStep.js.map +1 -1
  171. package/lib/module/ui/screens/internal/SignInUsernameStep.js +2 -4
  172. package/lib/module/ui/screens/internal/SignInUsernameStep.js.map +1 -1
  173. package/lib/module/ui/screens/steps/RecoverRequestStep.js +45 -25
  174. package/lib/module/ui/screens/steps/RecoverRequestStep.js.map +1 -1
  175. package/lib/module/ui/screens/steps/RecoverResetPasswordStep.js +89 -54
  176. package/lib/module/ui/screens/steps/RecoverResetPasswordStep.js.map +1 -1
  177. package/lib/module/ui/screens/steps/RecoverSuccessStep.js +80 -59
  178. package/lib/module/ui/screens/steps/RecoverSuccessStep.js.map +1 -1
  179. package/lib/module/ui/screens/steps/RecoverVerifyStep.js +62 -53
  180. package/lib/module/ui/screens/steps/RecoverVerifyStep.js.map +1 -1
  181. package/lib/module/ui/screens/steps/SignInPasswordStep.js +219 -40
  182. package/lib/module/ui/screens/steps/SignInPasswordStep.js.map +1 -1
  183. package/lib/module/ui/screens/steps/SignInTotpStep.js +78 -51
  184. package/lib/module/ui/screens/steps/SignInTotpStep.js.map +1 -1
  185. package/lib/module/ui/screens/steps/SignInUsernameStep.js +426 -73
  186. package/lib/module/ui/screens/steps/SignInUsernameStep.js.map +1 -1
  187. package/lib/module/ui/screens/steps/SignUpIdentityStep.js +55 -30
  188. package/lib/module/ui/screens/steps/SignUpIdentityStep.js.map +1 -1
  189. package/lib/module/ui/screens/steps/SignUpSecurityStep.js +65 -47
  190. package/lib/module/ui/screens/steps/SignUpSecurityStep.js.map +1 -1
  191. package/lib/module/ui/screens/steps/SignUpSummaryStep.js +84 -146
  192. package/lib/module/ui/screens/steps/SignUpSummaryStep.js.map +1 -1
  193. package/lib/module/ui/screens/steps/SignUpWelcomeStep.js +114 -35
  194. package/lib/module/ui/screens/steps/SignUpWelcomeStep.js.map +1 -1
  195. package/lib/module/ui/stores/accountStore.js +229 -0
  196. package/lib/module/ui/stores/accountStore.js.map +1 -0
  197. package/lib/module/ui/stores/authStore.js +17 -20
  198. package/lib/module/ui/stores/authStore.js.map +1 -1
  199. package/lib/module/ui/styles/authStyles.js +16 -8
  200. package/lib/module/ui/styles/authStyles.js.map +1 -1
  201. package/lib/module/ui/styles/index.js +1 -0
  202. package/lib/module/ui/styles/index.js.map +1 -1
  203. package/lib/module/ui/styles/spacing.js +48 -0
  204. package/lib/module/ui/styles/spacing.js.map +1 -0
  205. package/lib/module/utils/asyncUtils.js +10 -22
  206. package/lib/module/utils/asyncUtils.js.map +1 -1
  207. package/lib/module/utils/cache.js +250 -0
  208. package/lib/module/utils/cache.js.map +1 -0
  209. package/lib/module/utils/index.js +7 -0
  210. package/lib/module/utils/index.js.map +1 -1
  211. package/lib/module/utils/languageUtils.js +151 -0
  212. package/lib/module/utils/languageUtils.js.map +1 -0
  213. package/lib/module/utils/requestUtils.js +210 -0
  214. package/lib/module/utils/requestUtils.js.map +1 -0
  215. package/lib/module/utils/sessionUtils.js +180 -0
  216. package/lib/module/utils/sessionUtils.js.map +1 -0
  217. package/lib/module/utils/validationUtils.js +1 -1
  218. package/lib/typescript/core/HttpClient.d.ts +64 -0
  219. package/lib/typescript/core/HttpClient.d.ts.map +1 -0
  220. package/lib/typescript/core/OxyServices.d.ts +86 -73
  221. package/lib/typescript/core/OxyServices.d.ts.map +1 -1
  222. package/lib/typescript/core/RequestManager.d.ts +67 -0
  223. package/lib/typescript/core/RequestManager.d.ts.map +1 -0
  224. package/lib/typescript/core/index.d.ts +2 -0
  225. package/lib/typescript/core/index.d.ts.map +1 -1
  226. package/lib/typescript/i18n/index.d.ts.map +1 -1
  227. package/lib/typescript/index.d.ts +2 -0
  228. package/lib/typescript/index.d.ts.map +1 -1
  229. package/lib/typescript/models/interfaces.d.ts +15 -0
  230. package/lib/typescript/models/interfaces.d.ts.map +1 -1
  231. package/lib/typescript/models/session.d.ts +1 -0
  232. package/lib/typescript/models/session.d.ts.map +1 -1
  233. package/lib/typescript/ui/components/Avatar.d.ts +6 -7
  234. package/lib/typescript/ui/components/Avatar.d.ts.map +1 -1
  235. package/lib/typescript/ui/components/FollowButton.d.ts.map +1 -1
  236. package/lib/typescript/ui/components/FontLoader.d.ts +3 -3
  237. package/lib/typescript/ui/components/FontLoader.d.ts.map +1 -1
  238. package/lib/typescript/ui/components/OxyProvider.d.ts +2 -2
  239. package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -1
  240. package/lib/typescript/ui/components/StepBasedScreen.d.ts.map +1 -1
  241. package/lib/typescript/ui/components/internal/GroupedPillButtons.d.ts.map +1 -1
  242. package/lib/typescript/ui/components/internal/TextField.d.ts.map +1 -1
  243. package/lib/typescript/ui/context/OxyContext.d.ts +5 -0
  244. package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
  245. package/lib/typescript/ui/hooks/useSessionSocket.d.ts.map +1 -1
  246. package/lib/typescript/ui/index.d.ts +2 -2
  247. package/lib/typescript/ui/index.d.ts.map +1 -1
  248. package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
  249. package/lib/typescript/ui/screens/AccountSwitcherScreen.d.ts.map +1 -1
  250. package/lib/typescript/ui/screens/LanguageSelectorScreen.d.ts +3 -3
  251. package/lib/typescript/ui/screens/LanguageSelectorScreen.d.ts.map +1 -1
  252. package/lib/typescript/ui/screens/SignInScreen.d.ts.map +1 -1
  253. package/lib/typescript/ui/screens/SignUpScreen.d.ts.map +1 -1
  254. package/lib/typescript/ui/screens/WelcomeNewUserScreen.d.ts.map +1 -1
  255. package/lib/typescript/ui/screens/internal/SignInPasswordStep.d.ts.map +1 -1
  256. package/lib/typescript/ui/screens/steps/RecoverRequestStep.d.ts.map +1 -1
  257. package/lib/typescript/ui/screens/steps/RecoverResetPasswordStep.d.ts.map +1 -1
  258. package/lib/typescript/ui/screens/steps/RecoverSuccessStep.d.ts.map +1 -1
  259. package/lib/typescript/ui/screens/steps/RecoverVerifyStep.d.ts.map +1 -1
  260. package/lib/typescript/ui/screens/steps/SignInPasswordStep.d.ts +2 -0
  261. package/lib/typescript/ui/screens/steps/SignInPasswordStep.d.ts.map +1 -1
  262. package/lib/typescript/ui/screens/steps/SignInTotpStep.d.ts.map +1 -1
  263. package/lib/typescript/ui/screens/steps/SignInUsernameStep.d.ts.map +1 -1
  264. package/lib/typescript/ui/screens/steps/SignUpIdentityStep.d.ts.map +1 -1
  265. package/lib/typescript/ui/screens/steps/SignUpSecurityStep.d.ts.map +1 -1
  266. package/lib/typescript/ui/screens/steps/SignUpSummaryStep.d.ts.map +1 -1
  267. package/lib/typescript/ui/screens/steps/SignUpWelcomeStep.d.ts.map +1 -1
  268. package/lib/typescript/ui/stores/accountStore.d.ts +34 -0
  269. package/lib/typescript/ui/stores/accountStore.d.ts.map +1 -0
  270. package/lib/typescript/ui/stores/authStore.d.ts +7 -3
  271. package/lib/typescript/ui/stores/authStore.d.ts.map +1 -1
  272. package/lib/typescript/ui/styles/authStyles.d.ts +19 -2
  273. package/lib/typescript/ui/styles/authStyles.d.ts.map +1 -1
  274. package/lib/typescript/ui/styles/index.d.ts +1 -0
  275. package/lib/typescript/ui/styles/index.d.ts.map +1 -1
  276. package/lib/typescript/ui/styles/spacing.d.ts +43 -0
  277. package/lib/typescript/ui/styles/spacing.d.ts.map +1 -0
  278. package/lib/typescript/utils/asyncUtils.d.ts +2 -0
  279. package/lib/typescript/utils/asyncUtils.d.ts.map +1 -1
  280. package/lib/typescript/utils/cache.d.ts +128 -0
  281. package/lib/typescript/utils/cache.d.ts.map +1 -0
  282. package/lib/typescript/utils/index.d.ts +4 -0
  283. package/lib/typescript/utils/index.d.ts.map +1 -1
  284. package/lib/typescript/utils/languageUtils.d.ts +38 -0
  285. package/lib/typescript/utils/languageUtils.d.ts.map +1 -0
  286. package/lib/typescript/utils/requestUtils.d.ts +122 -0
  287. package/lib/typescript/utils/requestUtils.d.ts.map +1 -0
  288. package/lib/typescript/utils/sessionUtils.d.ts +55 -0
  289. package/lib/typescript/utils/sessionUtils.d.ts.map +1 -0
  290. package/lib/typescript/utils/validationUtils.d.ts +1 -1
  291. package/package.json +1 -1
  292. package/src/core/HttpClient.ts +277 -0
  293. package/src/core/OxyServices.ts +461 -352
  294. package/src/core/RequestManager.ts +240 -0
  295. package/src/core/index.ts +10 -0
  296. package/src/i18n/index.ts +36 -0
  297. package/src/i18n/locales/ar-SA.json +128 -0
  298. package/src/i18n/locales/ca-ES.json +128 -0
  299. package/src/i18n/locales/de-DE.json +128 -0
  300. package/src/i18n/locales/en-US.json +85 -12
  301. package/src/i18n/locales/es-ES.json +58 -6
  302. package/src/i18n/locales/fr-FR.json +128 -0
  303. package/src/i18n/locales/it-IT.json +128 -0
  304. package/src/i18n/locales/ja-JP.json +127 -0
  305. package/src/i18n/locales/ko-KR.json +128 -0
  306. package/src/i18n/locales/pt-PT.json +128 -0
  307. package/src/i18n/locales/zh-CN.json +128 -0
  308. package/src/index.ts +10 -0
  309. package/src/models/interfaces.ts +19 -0
  310. package/src/models/session.ts +1 -1
  311. package/src/ui/components/Avatar.tsx +151 -35
  312. package/src/ui/components/FollowButton.tsx +1 -0
  313. package/src/ui/components/FontLoader.tsx +17 -37
  314. package/src/ui/components/OxyProvider.tsx +14 -13
  315. package/src/ui/components/StepBasedScreen.tsx +66 -43
  316. package/src/ui/components/internal/GroupedPillButtons.tsx +15 -31
  317. package/src/ui/components/internal/PinInput.tsx +2 -2
  318. package/src/ui/components/internal/TextField.tsx +7 -6
  319. package/src/ui/context/OxyContext.tsx +441 -326
  320. package/src/ui/hooks/useSessionSocket.ts +72 -18
  321. package/src/ui/index.ts +4 -1
  322. package/src/ui/screens/AccountSettingsScreen.tsx +34 -2
  323. package/src/ui/screens/AccountSwitcherScreen.tsx +102 -68
  324. package/src/ui/screens/FileManagementScreen.tsx +16 -16
  325. package/src/ui/screens/LanguageSelectorScreen.tsx +86 -143
  326. package/src/ui/screens/SignInScreen.tsx +59 -43
  327. package/src/ui/screens/SignUpScreen.tsx +14 -15
  328. package/src/ui/screens/WelcomeNewUserScreen.tsx +153 -105
  329. package/src/ui/screens/internal/SignInPasswordStep.tsx +4 -6
  330. package/src/ui/screens/internal/SignInUsernameStep.tsx +1 -1
  331. package/src/ui/screens/steps/RecoverRequestStep.tsx +34 -24
  332. package/src/ui/screens/steps/RecoverResetPasswordStep.tsx +65 -36
  333. package/src/ui/screens/steps/RecoverSuccessStep.tsx +71 -47
  334. package/src/ui/screens/steps/RecoverVerifyStep.tsx +60 -50
  335. package/src/ui/screens/steps/SignInPasswordStep.tsx +190 -32
  336. package/src/ui/screens/steps/SignInTotpStep.tsx +68 -34
  337. package/src/ui/screens/steps/SignInUsernameStep.tsx +446 -63
  338. package/src/ui/screens/steps/SignUpIdentityStep.tsx +49 -35
  339. package/src/ui/screens/steps/SignUpSecurityStep.tsx +56 -39
  340. package/src/ui/screens/steps/SignUpSummaryStep.tsx +99 -89
  341. package/src/ui/screens/steps/SignUpWelcomeStep.tsx +88 -20
  342. package/src/ui/stores/accountStore.ts +285 -0
  343. package/src/ui/stores/authStore.ts +16 -19
  344. package/src/ui/styles/authStyles.ts +16 -8
  345. package/src/ui/styles/index.ts +1 -0
  346. package/src/ui/styles/spacing.ts +46 -0
  347. package/src/utils/asyncUtils.ts +10 -24
  348. package/src/utils/cache.ts +264 -0
  349. package/src/utils/index.ts +19 -0
  350. package/src/utils/languageUtils.ts +174 -0
  351. package/src/utils/requestUtils.ts +234 -0
  352. package/src/utils/sessionUtils.ts +206 -0
  353. package/src/utils/validationUtils.ts +1 -1
@@ -56,7 +56,6 @@
56
56
  *
57
57
  * See method JSDoc for more details and options.
58
58
  */
59
- import axios, { type AxiosInstance, type InternalAxiosRequestConfig } from 'axios';
60
59
  import { jwtDecode } from 'jwt-decode';
61
60
  import type {
62
61
  OxyConfig as OxyConfigBase,
@@ -67,6 +66,8 @@ import type {
67
66
  AssetUrlResponse,
68
67
  AssetVariant
69
68
  } from '../models/interfaces';
69
+ import { normalizeLanguageCode, getLanguageMetadata, getLanguageName, getNativeLanguageName } from '../utils/languageUtils';
70
+ import type { LanguageMetadata } from '../utils/languageUtils';
70
71
  /**
71
72
  * OxyConfig - Configuration for OxyServices
72
73
  * @property baseURL - The Oxy API base URL (e.g., https://api.oxy.so)
@@ -78,6 +79,8 @@ export interface OxyConfig extends OxyConfigBase {
78
79
  import type { SessionLoginResponse } from '../models/session';
79
80
  import { handleHttpError } from '../utils/errorUtils';
80
81
  import { buildSearchParams, buildPaginationParams, type PaginationParams } from '../utils/apiUtils';
82
+ import { HttpClient } from './HttpClient';
83
+ import { RequestManager, type RequestOptions } from './RequestManager';
81
84
 
82
85
  interface JwtPayload {
83
86
  exp?: number;
@@ -117,55 +120,18 @@ export class OxyAuthenticationTimeoutError extends OxyAuthenticationError {
117
120
  * OxyServices - Unified client library for interacting with the Oxy API
118
121
  *
119
122
  * This class provides all API functionality in one simple, easy-to-use interface.
120
- * No need to manage multiple service instances - everything is available directly.
123
+ * Architecture:
124
+ * - HttpClient: Handles HTTP communication and authentication
125
+ * - RequestManager: Handles caching, deduplication, queuing, and retry
126
+ * - OxyServices: Provides high-level API methods
121
127
  */
122
- // Centralized token store
123
- class TokenStore {
124
- private static instance: TokenStore;
125
- private accessToken: string | null = null;
126
- private refreshToken: string | null = null;
127
-
128
- private constructor() {}
129
-
130
- static getInstance(): TokenStore {
131
- if (!TokenStore.instance) {
132
- TokenStore.instance = new TokenStore();
133
- }
134
- return TokenStore.instance;
135
- }
136
-
137
- setTokens(accessToken: string, refreshToken = ''): void {
138
- this.accessToken = accessToken;
139
- this.refreshToken = refreshToken;
140
- }
141
-
142
- getAccessToken(): string | null {
143
- return this.accessToken;
144
- }
145
-
146
- getRefreshToken(): string | null {
147
- return this.refreshToken;
148
- }
149
-
150
- clearTokens(): void {
151
- this.accessToken = null;
152
- this.refreshToken = null;
153
- }
154
-
155
- hasAccessToken(): boolean {
156
- return !!this.accessToken;
157
- }
158
- }
159
-
160
128
  export class OxyServices {
161
- protected client: AxiosInstance;
162
- private tokenStore: TokenStore;
129
+ private httpClient: HttpClient;
130
+ private requestManager: RequestManager;
163
131
  private cloudURL: string;
132
+ private config: OxyConfig;
133
+
164
134
 
165
- /**
166
- * Creates a new instance of the OxyServices client
167
- * @param config - Configuration for the client
168
- */
169
135
  /**
170
136
  * Creates a new instance of the OxyServices client
171
137
  * @param config - Configuration for the client
@@ -173,99 +139,33 @@ export class OxyServices {
173
139
  * config.cloudURL: Oxy Cloud URL (e.g., https://cloud.oxy.so)
174
140
  */
175
141
  constructor(config: OxyConfig) {
176
- this.client = axios.create({
177
- baseURL: config.baseURL,
178
- timeout: 5000 // 5 second timeout
179
- });
142
+ this.config = config;
180
143
  this.cloudURL = config.cloudURL || OXY_CLOUD_URL;
181
- this.tokenStore = TokenStore.getInstance();
182
- this.setupInterceptors();
144
+
145
+ // Initialize HTTP client (handles authentication and interceptors)
146
+ this.httpClient = new HttpClient(config);
147
+
148
+ // Initialize request manager (handles caching, deduplication, queuing, retry)
149
+ this.requestManager = new RequestManager(this.httpClient, config);
183
150
  }
184
151
 
185
152
  // Test-only utility to reset global tokens between jest tests
186
153
  static __resetTokensForTests(): void {
187
- try {
188
- TokenStore.getInstance().clearTokens();
189
- } catch {}
154
+ HttpClient.__resetTokensForTests();
190
155
  }
191
156
 
157
+
192
158
  /**
193
- * Setup axios interceptors for authentication and error handling
159
+ * Make a request with all performance optimizations
160
+ * This is the main method for all API calls - ensures authentication and performance features
194
161
  */
195
- private setupInterceptors(): void {
196
- // Request interceptor for adding auth header and handling token refresh
197
- this.client.interceptors.request.use(
198
- async (req: InternalAxiosRequestConfig) => {
199
- console.log('🔍 Interceptor - URL:', req.url);
200
- console.log('🔍 Interceptor - Has token:', this.tokenStore.hasAccessToken());
201
-
202
- const accessToken = this.tokenStore.getAccessToken();
203
- if (!accessToken) {
204
- console.log('❌ Interceptor - No token available');
205
- return req;
206
- }
207
-
208
- try {
209
- console.log('✅ Interceptor - Adding Authorization header');
210
-
211
- const decoded = jwtDecode<JwtPayload>(accessToken);
212
- const currentTime = Math.floor(Date.now() / 1000);
213
-
214
- // If token expires in less than 60 seconds, refresh it
215
- if (decoded.exp && decoded.exp - currentTime < 60) {
216
- // For session-based tokens, get a new token from the session
217
- if (decoded.sessionId) {
218
- try {
219
- // Create a new axios instance to avoid interceptor recursion
220
- const refreshClient = axios.create({
221
- baseURL: this.client.defaults.baseURL,
222
- timeout: this.client.defaults.timeout
223
- });
224
- const res = await refreshClient.get(`/api/session/token/${decoded.sessionId}`);
225
- this.tokenStore.setTokens(res.data.accessToken);
226
- req.headers.Authorization = `Bearer ${res.data.accessToken}`;
227
- console.log('✅ Interceptor - Token refreshed and Authorization header set');
228
- } catch (refreshError) {
229
- // If refresh fails, use current token anyway
230
- req.headers.Authorization = `Bearer ${accessToken}`;
231
- console.log('❌ Interceptor - Token refresh failed, using current token');
232
- }
233
- } else {
234
- // No session ID, use current token
235
- req.headers.Authorization = `Bearer ${accessToken}`;
236
- console.log('✅ Interceptor - No session ID, using current token');
237
- }
238
- } else {
239
- // Add authorization header with current token
240
- req.headers.Authorization = `Bearer ${accessToken}`;
241
- console.log('✅ Interceptor - Authorization header set with current token');
242
- }
243
- } catch (error) {
244
- console.log('❌ Interceptor - Error processing token:', error);
245
- // Even if there's an error, still try to use the token
246
- req.headers.Authorization = `Bearer ${accessToken}`;
247
- console.log('⚠️ Interceptor - Using token despite error');
248
- }
249
-
250
- return req;
251
- },
252
- (error) => {
253
- console.log('❌ Interceptor - Request error:', error);
254
- return Promise.reject(error);
255
- }
256
- );
257
-
258
- // Response interceptor for handling auth errors
259
- this.client.interceptors.response.use(
260
- (response) => response,
261
- (error) => {
262
- if (error.response?.status === 401) {
263
- console.log('❌ Response interceptor - 401 Unauthorized, clearing tokens');
264
- this.clearTokens();
265
- }
266
- return Promise.reject(error);
267
- }
268
- );
162
+ private async makeRequest<T>(
163
+ method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE',
164
+ url: string,
165
+ data?: any,
166
+ options: RequestOptions = {}
167
+ ): Promise<T> {
168
+ return this.requestManager.request<T>(method, url, data, options);
269
169
  }
270
170
 
271
171
  // ============================================================================
@@ -276,7 +176,35 @@ export class OxyServices {
276
176
  * Get the configured Oxy API base URL
277
177
  */
278
178
  public getBaseURL(): string {
279
- return this.client.defaults.baseURL || '';
179
+ return this.httpClient.getBaseURL();
180
+ }
181
+
182
+ /**
183
+ * Get performance metrics
184
+ */
185
+ public getMetrics() {
186
+ return this.requestManager.getMetrics();
187
+ }
188
+
189
+ /**
190
+ * Clear request cache
191
+ */
192
+ public clearCache(): void {
193
+ this.requestManager.clearCache();
194
+ }
195
+
196
+ /**
197
+ * Clear specific cache entry
198
+ */
199
+ public clearCacheEntry(key: string): void {
200
+ this.requestManager.clearCacheEntry(key);
201
+ }
202
+
203
+ /**
204
+ * Get cache statistics
205
+ */
206
+ public getCacheStats() {
207
+ return this.requestManager.getCacheStats();
280
208
  }
281
209
 
282
210
  /**
@@ -290,21 +218,21 @@ export class OxyServices {
290
218
  * Set authentication tokens
291
219
  */
292
220
  public setTokens(accessToken: string, refreshToken = ''): void {
293
- this.tokenStore.setTokens(accessToken, refreshToken);
221
+ this.httpClient.setTokens(accessToken, refreshToken);
294
222
  }
295
223
 
296
224
  /**
297
225
  * Clear stored authentication tokens
298
226
  */
299
227
  public clearTokens(): void {
300
- this.tokenStore.clearTokens();
228
+ this.httpClient.clearTokens();
301
229
  }
302
230
 
303
231
  /**
304
232
  * Get the current user ID from the access token
305
233
  */
306
234
  public getCurrentUserId(): string | null {
307
- const accessToken = this.tokenStore.getAccessToken();
235
+ const accessToken = this.httpClient.getAccessToken();
308
236
  if (!accessToken) {
309
237
  return null;
310
238
  }
@@ -321,21 +249,21 @@ export class OxyServices {
321
249
  * Check if the client has a valid access token
322
250
  */
323
251
  private hasAccessToken(): boolean {
324
- return this.tokenStore.hasAccessToken();
252
+ return this.httpClient.hasAccessToken();
325
253
  }
326
254
 
327
255
  /**
328
256
  * Check if the client has a valid access token (public method)
329
257
  */
330
258
  public hasValidToken(): boolean {
331
- return this.tokenStore.hasAccessToken();
259
+ return this.httpClient.hasAccessToken();
332
260
  }
333
261
 
334
262
  /**
335
263
  * Get the raw access token (for constructing anchor URLs when needed)
336
264
  */
337
265
  public getAccessToken(): string | null {
338
- return this.tokenStore.getAccessToken();
266
+ return this.httpClient.getAccessToken();
339
267
  }
340
268
 
341
269
  /**
@@ -354,7 +282,7 @@ export class OxyServices {
354
282
  const checkInterval = 100; // Check every 100ms
355
283
 
356
284
  while (Date.now() - startTime < timeoutMs) {
357
- if (this.tokenStore.hasAccessToken()) {
285
+ if (this.httpClient.hasAccessToken()) {
358
286
  return true;
359
287
  }
360
288
  await new Promise(resolve => setTimeout(resolve, checkInterval));
@@ -385,17 +313,14 @@ export class OxyServices {
385
313
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
386
314
  try {
387
315
  // First attempt: check if we have a token
388
- if (!this.tokenStore.hasAccessToken()) {
316
+ if (!this.httpClient.hasAccessToken()) {
389
317
  if (attempt === 0) {
390
318
  // On first attempt, wait briefly for authentication to complete
391
- console.log(`🔄 ${operationName} - Waiting for authentication...`);
392
319
  const authReady = await this.waitForAuthentication(authTimeoutMs);
393
320
 
394
321
  if (!authReady) {
395
322
  throw new OxyAuthenticationTimeoutError(operationName, authTimeoutMs);
396
323
  }
397
-
398
- console.log(`✅ ${operationName} - Authentication ready, proceeding...`);
399
324
  } else {
400
325
  // On retry attempts, fail immediately if no token
401
326
  throw new OxyAuthenticationError(
@@ -416,7 +341,6 @@ export class OxyServices {
416
341
  error instanceof OxyAuthenticationError;
417
342
 
418
343
  if (isAuthError && !isLastAttempt && !(error instanceof OxyAuthenticationTimeoutError)) {
419
- console.log(`🔄 ${operationName} - Auth error on attempt ${attempt + 1}, retrying in ${retryDelay}ms...`);
420
344
  await new Promise(resolve => setTimeout(resolve, retryDelay));
421
345
  continue;
422
346
  }
@@ -442,19 +366,16 @@ export class OxyServices {
442
366
  }
443
367
 
444
368
  try {
445
- const res = await this.client.get('/api/auth/validate');
446
- return res.data.valid === true;
369
+ const res = await this.makeRequest<{ valid: boolean }>('GET', '/api/auth/validate', undefined, {
370
+ cache: false,
371
+ retry: false,
372
+ });
373
+ return res.valid === true;
447
374
  } catch (error) {
448
375
  return false;
449
376
  }
450
377
  }
451
378
 
452
- /**
453
- * Get the HTTP client instance (public for external use)
454
- */
455
- public getClient(): AxiosInstance {
456
- return this.client;
457
- }
458
379
 
459
380
  /**
460
381
  * Centralized error handling
@@ -478,8 +399,7 @@ export class OxyServices {
478
399
  [key: string]: any
479
400
  }> {
480
401
  try {
481
- const res = await this.client.get('/health');
482
- return res.data;
402
+ return await this.makeRequest('GET', '/health', undefined, { cache: false });
483
403
  } catch (error) {
484
404
  throw this.handleError(error);
485
405
  }
@@ -494,15 +414,15 @@ export class OxyServices {
494
414
  */
495
415
  async signUp(username: string, email: string, password: string): Promise<{ message: string; token: string; user: User }> {
496
416
  try {
497
- const res = await this.client.post('/api/auth/signup', {
417
+ const res = await this.makeRequest<{ message: string; token: string; user: User }>('POST', '/api/auth/signup', {
498
418
  username,
499
419
  email,
500
420
  password
501
- });
502
- if (!res || !res.data || (typeof res.data === 'object' && Object.keys(res.data).length === 0)) {
421
+ }, { cache: false });
422
+ if (!res || (typeof res === 'object' && Object.keys(res).length === 0)) {
503
423
  throw new OxyAuthenticationError('Sign up failed', 'SIGNUP_FAILED', 400);
504
424
  }
505
- return res.data;
425
+ return res;
506
426
  } catch (error) {
507
427
  throw this.handleError(error);
508
428
  }
@@ -513,8 +433,7 @@ export class OxyServices {
513
433
  */
514
434
  async requestRecovery(identifier: string): Promise<{ delivery?: string; destination?: string }> {
515
435
  try {
516
- const res = await this.client.post('/api/auth/recover/request', { identifier });
517
- return res.data;
436
+ return await this.makeRequest('POST', '/api/auth/recover/request', { identifier }, { cache: false });
518
437
  } catch (error: any) {
519
438
  throw this.handleError(error);
520
439
  }
@@ -525,8 +444,7 @@ export class OxyServices {
525
444
  */
526
445
  async verifyRecoveryCode(identifier: string, code: string): Promise<{ verified: boolean }> {
527
446
  try {
528
- const res = await this.client.post('/api/auth/recover/verify', { identifier, code });
529
- return res.data;
447
+ return await this.makeRequest('POST', '/api/auth/recover/verify', { identifier, code }, { cache: false });
530
448
  } catch (error: any) {
531
449
  throw this.handleError(error);
532
450
  }
@@ -537,8 +455,7 @@ export class OxyServices {
537
455
  */
538
456
  async resetPassword(identifier: string, code: string, newPassword: string): Promise<{ success: boolean }> {
539
457
  try {
540
- const res = await this.client.post('/api/auth/recover/reset', { identifier, code, newPassword });
541
- return res.data;
458
+ return await this.makeRequest('POST', '/api/auth/recover/reset', { identifier, code, newPassword }, { cache: false });
542
459
  } catch (error: any) {
543
460
  throw this.handleError(error);
544
461
  }
@@ -549,8 +466,7 @@ export class OxyServices {
549
466
  */
550
467
  async resetPasswordWithTotp(identifier: string, code: string, newPassword: string): Promise<{ success: boolean }> {
551
468
  try {
552
- const res = await this.client.post('/api/auth/recover/totp/reset', { identifier, code, newPassword });
553
- return res.data;
469
+ return await this.makeRequest('POST', '/api/auth/recover/totp/reset', { identifier, code, newPassword }, { cache: false });
554
470
  } catch (error: any) {
555
471
  throw this.handleError(error);
556
472
  }
@@ -558,8 +474,7 @@ export class OxyServices {
558
474
 
559
475
  async resetPasswordWithBackupCode(identifier: string, backupCode: string, newPassword: string): Promise<{ success: boolean }> {
560
476
  try {
561
- const res = await this.client.post('/api/auth/recover/backup/reset', { identifier, backupCode, newPassword });
562
- return res.data;
477
+ return await this.makeRequest('POST', '/api/auth/recover/backup/reset', { identifier, backupCode, newPassword }, { cache: false });
563
478
  } catch (error: any) {
564
479
  throw this.handleError(error);
565
480
  }
@@ -567,8 +482,7 @@ export class OxyServices {
567
482
 
568
483
  async resetPasswordWithRecoveryKey(identifier: string, recoveryKey: string, newPassword: string): Promise<{ success: boolean; nextRecoveryKey?: string }> {
569
484
  try {
570
- const res = await this.client.post('/api/auth/recover/recovery-key/reset', { identifier, recoveryKey, newPassword });
571
- return res.data;
485
+ return await this.makeRequest('POST', '/api/auth/recover/recovery-key/reset', { identifier, recoveryKey, newPassword }, { cache: false });
572
486
  } catch (error: any) {
573
487
  throw this.handleError(error);
574
488
  }
@@ -584,13 +498,12 @@ export class OxyServices {
584
498
  deviceFingerprint?: any
585
499
  ): Promise<SessionLoginResponse | { mfaRequired: true; mfaToken: string; expiresAt: string }> {
586
500
  try {
587
- const res = await this.client.post('/api/auth/login', {
501
+ return await this.makeRequest<SessionLoginResponse | { mfaRequired: true; mfaToken: string; expiresAt: string }>('POST', '/api/auth/login', {
588
502
  username,
589
503
  password,
590
504
  deviceName,
591
505
  deviceFingerprint
592
- });
593
- return res.data;
506
+ }, { cache: false });
594
507
  } catch (error) {
595
508
  throw this.handleError(error);
596
509
  }
@@ -601,8 +514,7 @@ export class OxyServices {
601
514
  */
602
515
  async verifyTotpLogin(mfaToken: string, code: string): Promise<SessionLoginResponse> {
603
516
  try {
604
- const res = await this.client.post('/api/auth/totp/verify-login', { mfaToken, code });
605
- return res.data;
517
+ return await this.makeRequest<SessionLoginResponse>('POST', '/api/auth/totp/verify-login', { mfaToken, code }, { cache: false });
606
518
  } catch (error) {
607
519
  throw this.handleError(error);
608
520
  }
@@ -613,8 +525,38 @@ export class OxyServices {
613
525
  */
614
526
  async getUserBySession(sessionId: string): Promise<User> {
615
527
  try {
616
- const res = await this.client.get(`/api/session/user/${sessionId}`);
617
- return res.data;
528
+ return await this.makeRequest<User>('GET', `/api/session/user/${sessionId}`, undefined, {
529
+ cache: true,
530
+ cacheTTL: 2 * 60 * 1000, // 2 minutes cache for user data
531
+ });
532
+ } catch (error) {
533
+ throw this.handleError(error);
534
+ }
535
+ }
536
+
537
+ /**
538
+ * Batch get multiple user profiles by session IDs (optimized for account switching)
539
+ * Returns array of { sessionId, user } objects
540
+ */
541
+ async getUsersBySessions(sessionIds: string[]): Promise<Array<{ sessionId: string; user: User | null }>> {
542
+ try {
543
+ if (!Array.isArray(sessionIds) || sessionIds.length === 0) {
544
+ return [];
545
+ }
546
+
547
+ // Deduplicate and sort sessionIds for consistent cache keys
548
+ const uniqueSessionIds = Array.from(new Set(sessionIds)).sort();
549
+
550
+ return await this.makeRequest<Array<{ sessionId: string; user: User | null }>>(
551
+ 'POST',
552
+ '/api/session/users/batch',
553
+ { sessionIds: uniqueSessionIds },
554
+ {
555
+ cache: true,
556
+ cacheTTL: 2 * 60 * 1000, // 2 minutes cache
557
+ deduplicate: true, // Important for batch requests
558
+ }
559
+ );
618
560
  } catch (error) {
619
561
  throw this.handleError(error);
620
562
  }
@@ -625,19 +567,16 @@ export class OxyServices {
625
567
  */
626
568
  async getTokenBySession(sessionId: string): Promise<{ accessToken: string; expiresAt: string }> {
627
569
  try {
628
- console.log('🔑 getTokenBySession - Fetching token for session:', sessionId);
629
- const res = await this.client.get(`/api/session/token/${sessionId}`);
630
- const { accessToken } = res.data;
631
-
632
- console.log('🔑 getTokenBySession - Token received:', !!accessToken);
570
+ const res = await this.makeRequest<{ accessToken: string; expiresAt: string }>('GET', `/api/session/token/${sessionId}`, undefined, {
571
+ cache: false,
572
+ retry: false,
573
+ });
633
574
 
634
575
  // Set the token in the centralized token store
635
- this.setTokens(accessToken);
636
- console.log('🔑 getTokenBySession - Token set in store');
576
+ this.setTokens(res.accessToken);
637
577
 
638
- return res.data;
578
+ return res;
639
579
  } catch (error) {
640
- console.log('❌ getTokenBySession - Error:', error);
641
580
  throw this.handleError(error);
642
581
  }
643
582
  }
@@ -647,8 +586,9 @@ export class OxyServices {
647
586
  */
648
587
  async getSessionsBySessionId(sessionId: string): Promise<any[]> {
649
588
  try {
650
- const res = await this.client.get(`/api/session/sessions/${sessionId}`);
651
- return res.data;
589
+ return await this.makeRequest('GET', `/api/session/sessions/${sessionId}`, undefined, {
590
+ cache: false,
591
+ });
652
592
  } catch (error) {
653
593
  throw this.handleError(error);
654
594
  }
@@ -663,7 +603,7 @@ export class OxyServices {
663
603
  ? `/api/session/logout/${sessionId}/${targetSessionId}`
664
604
  : `/api/session/logout/${sessionId}`;
665
605
 
666
- await this.client.post(url);
606
+ await this.makeRequest('POST', url, undefined, { cache: false });
667
607
  } catch (error) {
668
608
  throw this.handleError(error);
669
609
  }
@@ -674,7 +614,7 @@ export class OxyServices {
674
614
  */
675
615
  async logoutAllSessions(sessionId: string): Promise<void> {
676
616
  try {
677
- await this.client.post(`/api/session/logout-all/${sessionId}`);
617
+ await this.makeRequest('POST', `/api/session/logout-all/${sessionId}`, undefined, { cache: false });
678
618
  } catch (error) {
679
619
  throw this.handleError(error);
680
620
  }
@@ -706,9 +646,11 @@ export class OxyServices {
706
646
  params.append('useHeaderValidation', 'true');
707
647
  }
708
648
 
709
- const url = `/api/session/validate/${sessionId}?${params.toString()}`;
710
- const res = await this.client.get(url);
711
- return res.data;
649
+ const url = `/api/session/validate/${sessionId}`;
650
+ const urlParams: any = {};
651
+ if (options.deviceFingerprint) urlParams.deviceFingerprint = options.deviceFingerprint;
652
+ if (options.useHeaderValidation) urlParams.useHeaderValidation = 'true';
653
+ return await this.makeRequest('GET', url, urlParams, { cache: false });
712
654
  } catch (error) {
713
655
  throw this.handleError(error);
714
656
  }
@@ -719,8 +661,7 @@ export class OxyServices {
719
661
  */
720
662
  async checkUsernameAvailability(username: string): Promise<{ available: boolean; message: string }> {
721
663
  try {
722
- const res = await this.client.get(`/api/auth/check-username/${username}`);
723
- return res.data;
664
+ return await this.makeRequest('GET', `/api/auth/check-username/${username}`, undefined, { cache: false });
724
665
  } catch (error) {
725
666
  throw this.handleError(error);
726
667
  }
@@ -731,8 +672,7 @@ export class OxyServices {
731
672
  */
732
673
  async checkEmailAvailability(email: string): Promise<{ available: boolean; message: string }> {
733
674
  try {
734
- const res = await this.client.get(`/api/auth/check-email/${email}`);
735
- return res.data;
675
+ return await this.makeRequest('GET', `/api/auth/check-email/${email}`, undefined, { cache: false });
736
676
  } catch (error) {
737
677
  throw this.handleError(error);
738
678
  }
@@ -747,8 +687,10 @@ export class OxyServices {
747
687
  */
748
688
  async getProfileByUsername(username: string): Promise<User> {
749
689
  try {
750
- const res = await this.client.get(`/api/profiles/username/${username}`);
751
- return res.data;
690
+ return await this.makeRequest<User>('GET', `/api/profiles/username/${username}`, undefined, {
691
+ cache: true,
692
+ cacheTTL: 5 * 60 * 1000, // 5 minutes cache for profiles
693
+ });
752
694
  } catch (error) {
753
695
  throw this.handleError(error);
754
696
  }
@@ -760,10 +702,8 @@ export class OxyServices {
760
702
 
761
703
  async startTotpEnrollment(sessionId: string): Promise<{ secret: string; otpauthUrl: string; issuer: string; label: string }> {
762
704
  try {
763
- const res = await this.client.post('/api/auth/totp/enroll/start', { sessionId }, {
764
- headers: { 'x-session-id': sessionId }
765
- });
766
- return res.data;
705
+ // Note: x-session-id header is handled by HttpClient interceptors if needed
706
+ return await this.makeRequest('POST', '/api/auth/totp/enroll/start', { sessionId }, { cache: false });
767
707
  } catch (error) {
768
708
  throw this.handleError(error);
769
709
  }
@@ -771,10 +711,7 @@ export class OxyServices {
771
711
 
772
712
  async verifyTotpEnrollment(sessionId: string, code: string): Promise<{ enabled: boolean; backupCodes?: string[]; recoveryKey?: string }> {
773
713
  try {
774
- const res = await this.client.post('/api/auth/totp/enroll/verify', { sessionId, code }, {
775
- headers: { 'x-session-id': sessionId }
776
- });
777
- return res.data;
714
+ return await this.makeRequest('POST', '/api/auth/totp/enroll/verify', { sessionId, code }, { cache: false });
778
715
  } catch (error) {
779
716
  throw this.handleError(error);
780
717
  }
@@ -782,10 +719,7 @@ export class OxyServices {
782
719
 
783
720
  async disableTotp(sessionId: string, code: string): Promise<{ disabled: boolean }> {
784
721
  try {
785
- const res = await this.client.post('/api/auth/totp/disable', { sessionId, code }, {
786
- headers: { 'x-session-id': sessionId }
787
- });
788
- return res.data;
722
+ return await this.makeRequest('POST', '/api/auth/totp/disable', { sessionId, code }, { cache: false });
789
723
  } catch (error) {
790
724
  throw this.handleError(error);
791
725
  }
@@ -798,9 +732,14 @@ export class OxyServices {
798
732
  try {
799
733
  const params = { query, ...pagination };
800
734
  const searchParams = buildSearchParams(params);
801
-
802
- const res = await this.client.get(`/api/profiles/search?${searchParams.toString()}`);
803
- return res.data;
735
+ const paramsObj: any = {};
736
+ searchParams.forEach((value, key) => {
737
+ paramsObj[key] = value;
738
+ });
739
+ return await this.makeRequest<User[]>('GET', '/api/profiles/search', paramsObj, {
740
+ cache: true,
741
+ cacheTTL: 2 * 60 * 1000, // 2 minutes cache
742
+ });
804
743
  } catch (error) {
805
744
  throw this.handleError(error);
806
745
  }
@@ -818,8 +757,7 @@ export class OxyServices {
818
757
  [key: string]: any;
819
758
  }>> {
820
759
  return this.withAuthRetry(async () => {
821
- const res = await this.client.get('/api/profiles/recommendations');
822
- return res.data;
760
+ return await this.makeRequest('GET', '/api/profiles/recommendations', undefined, { cache: true });
823
761
  }, 'getProfileRecommendations');
824
762
  }
825
763
 
@@ -828,8 +766,10 @@ export class OxyServices {
828
766
  */
829
767
  async getUserById(userId: string): Promise<User> {
830
768
  try {
831
- const res = await this.client.get(`/api/users/${userId}`);
832
- return res.data;
769
+ return await this.makeRequest<User>('GET', `/api/users/${userId}`, undefined, {
770
+ cache: true,
771
+ cacheTTL: 5 * 60 * 1000, // 5 minutes cache
772
+ });
833
773
  } catch (error) {
834
774
  throw this.handleError(error);
835
775
  }
@@ -840,8 +780,10 @@ export class OxyServices {
840
780
  */
841
781
  async getCurrentUser(): Promise<User> {
842
782
  return this.withAuthRetry(async () => {
843
- const res = await this.client.get('/api/users/me');
844
- return res.data;
783
+ return await this.makeRequest<User>('GET', '/api/users/me', undefined, {
784
+ cache: true,
785
+ cacheTTL: 1 * 60 * 1000, // 1 minute cache for current user
786
+ });
845
787
  }, 'getCurrentUser');
846
788
  }
847
789
 
@@ -850,20 +792,136 @@ export class OxyServices {
850
792
  */
851
793
  async updateProfile(updates: Record<string, any>): Promise<User> {
852
794
  try {
853
- const res = await this.client.put('/api/users/me', updates);
854
- return res.data;
795
+ return await this.makeRequest<User>('PUT', '/api/users/me', updates, { cache: false });
855
796
  } catch (error) {
856
797
  throw this.handleError(error);
857
798
  }
858
799
  }
859
800
 
801
+ // ============================================================================
802
+ // LANGUAGE METHODS
803
+ // ============================================================================
804
+
805
+ /**
806
+ * Get the current language from storage or user profile
807
+ * @param storageKeyPrefix - Optional prefix for storage key (default: 'oxy_session')
808
+ * @returns The current language code (e.g., 'en-US') or null if not set
809
+ */
810
+ async getCurrentLanguage(storageKeyPrefix: string = 'oxy_session'): Promise<string | null> {
811
+ try {
812
+ // First try to get from user profile if authenticated
813
+ try {
814
+ const user = await this.getCurrentUser();
815
+ const userLanguage = (user as Record<string, unknown>)?.language as string | undefined;
816
+ if (userLanguage) {
817
+ return normalizeLanguageCode(userLanguage) || userLanguage;
818
+ }
819
+ } catch (e) {
820
+ // User not authenticated or error, continue to storage
821
+ }
822
+
823
+ // Fall back to storage
824
+ const storage = await this.getStorage();
825
+ const storageKey = `${storageKeyPrefix}_language`;
826
+ const storedLanguage = await storage.getItem(storageKey);
827
+ if (storedLanguage) {
828
+ return normalizeLanguageCode(storedLanguage) || storedLanguage;
829
+ }
830
+
831
+ return null;
832
+ } catch (error) {
833
+ if (__DEV__) {
834
+ console.warn('Failed to get current language:', error);
835
+ }
836
+ return null;
837
+ }
838
+ }
839
+
840
+ /**
841
+ * Get the current language with metadata (name, nativeName, etc.)
842
+ * @param storageKeyPrefix - Optional prefix for storage key (default: 'oxy_session')
843
+ * @returns Language metadata object or null if not set
844
+ */
845
+ async getCurrentLanguageMetadata(storageKeyPrefix: string = 'oxy_session'): Promise<LanguageMetadata | null> {
846
+ const languageCode = await this.getCurrentLanguage(storageKeyPrefix);
847
+ return getLanguageMetadata(languageCode);
848
+ }
849
+
850
+ /**
851
+ * Get the current language name (e.g., 'English')
852
+ * @param storageKeyPrefix - Optional prefix for storage key (default: 'oxy_session')
853
+ * @returns Language name or null if not set
854
+ */
855
+ async getCurrentLanguageName(storageKeyPrefix: string = 'oxy_session'): Promise<string | null> {
856
+ const languageCode = await this.getCurrentLanguage(storageKeyPrefix);
857
+ if (!languageCode) return null;
858
+ return getLanguageName(languageCode);
859
+ }
860
+
861
+ /**
862
+ * Get the current native language name (e.g., 'Español')
863
+ * @param storageKeyPrefix - Optional prefix for storage key (default: 'oxy_session')
864
+ * @returns Native language name or null if not set
865
+ */
866
+ async getCurrentNativeLanguageName(storageKeyPrefix: string = 'oxy_session'): Promise<string | null> {
867
+ const languageCode = await this.getCurrentLanguage(storageKeyPrefix);
868
+ if (!languageCode) return null;
869
+ return getNativeLanguageName(languageCode);
870
+ }
871
+
872
+ /**
873
+ * Get appropriate storage for the platform (similar to DeviceManager)
874
+ * @private
875
+ */
876
+ private async getStorage(): Promise<{
877
+ getItem: (key: string) => Promise<string | null>;
878
+ setItem: (key: string, value: string) => Promise<void>;
879
+ removeItem: (key: string) => Promise<void>;
880
+ }> {
881
+ const isReactNative = typeof navigator !== 'undefined' && navigator.product === 'ReactNative';
882
+
883
+ if (isReactNative) {
884
+ try {
885
+ const asyncStorageModule = await import('@react-native-async-storage/async-storage');
886
+ const storage = (asyncStorageModule.default as unknown) as import('@react-native-async-storage/async-storage').AsyncStorageStatic;
887
+ return {
888
+ getItem: storage.getItem.bind(storage),
889
+ setItem: storage.setItem.bind(storage),
890
+ removeItem: storage.removeItem.bind(storage),
891
+ };
892
+ } catch (error) {
893
+ console.error('AsyncStorage not available in React Native:', error);
894
+ throw new Error('AsyncStorage is required in React Native environment');
895
+ }
896
+ } else {
897
+ // Use localStorage for web
898
+ return {
899
+ getItem: async (key: string) => {
900
+ if (typeof window !== 'undefined' && window.localStorage) {
901
+ return localStorage.getItem(key);
902
+ }
903
+ return null;
904
+ },
905
+ setItem: async (key: string, value: string) => {
906
+ if (typeof window !== 'undefined' && window.localStorage) {
907
+ localStorage.setItem(key, value);
908
+ }
909
+ },
910
+ removeItem: async (key: string) => {
911
+ if (typeof window !== 'undefined' && window.localStorage) {
912
+ localStorage.removeItem(key);
913
+ }
914
+ }
915
+ };
916
+ }
917
+ }
918
+
860
919
  /**
861
920
  * Update user by ID (admin function)
862
921
  */
863
922
  async updateUser(userId: string, updates: Record<string, any>): Promise<User> {
864
923
  try {
865
- const res = await this.client.put(`/api/users/${userId}`, updates);
866
- return res.data;
924
+ return await this.makeRequest<User>('PUT', `/api/users/${userId}`, updates, { cache: false });
867
925
  } catch (error) {
868
926
  throw this.handleError(error);
869
927
  }
@@ -874,8 +932,7 @@ export class OxyServices {
874
932
  */
875
933
  async followUser(userId: string): Promise<{ success: boolean; message: string }> {
876
934
  try {
877
- const res = await this.client.post(`/api/users/${userId}/follow`);
878
- return res.data;
935
+ return await this.makeRequest('POST', `/api/users/${userId}/follow`, undefined, { cache: false });
879
936
  } catch (error) {
880
937
  throw this.handleError(error);
881
938
  }
@@ -886,8 +943,7 @@ export class OxyServices {
886
943
  */
887
944
  async unfollowUser(userId: string): Promise<{ success: boolean; message: string }> {
888
945
  try {
889
- const res = await this.client.delete(`/api/users/${userId}/follow`);
890
- return res.data;
946
+ return await this.makeRequest('DELETE', `/api/users/${userId}/follow`, undefined, { cache: false });
891
947
  } catch (error) {
892
948
  throw this.handleError(error);
893
949
  }
@@ -898,8 +954,10 @@ export class OxyServices {
898
954
  */
899
955
  async getFollowStatus(userId: string): Promise<{ isFollowing: boolean }> {
900
956
  try {
901
- const res = await this.client.get(`/api/users/${userId}/follow-status`);
902
- return res.data;
957
+ return await this.makeRequest('GET', `/api/users/${userId}/follow-status`, undefined, {
958
+ cache: true,
959
+ cacheTTL: 1 * 60 * 1000, // 1 minute cache
960
+ });
903
961
  } catch (error) {
904
962
  throw this.handleError(error);
905
963
  }
@@ -914,8 +972,15 @@ export class OxyServices {
914
972
  ): Promise<{ followers: User[]; total: number; hasMore: boolean }> {
915
973
  try {
916
974
  const params = buildPaginationParams(pagination || {});
917
- const res = await this.client.get(`/api/users/${userId}/followers?${params.toString()}`);
918
- return res.data;
975
+ const response = await this.makeRequest<{ data: User[]; pagination: { total: number; hasMore: boolean } }>('GET', `/api/users/${userId}/followers`, params, {
976
+ cache: true,
977
+ cacheTTL: 2 * 60 * 1000, // 2 minutes cache
978
+ });
979
+ return {
980
+ followers: response.data || [],
981
+ total: response.pagination.total,
982
+ hasMore: response.pagination.hasMore,
983
+ };
919
984
  } catch (error) {
920
985
  throw this.handleError(error);
921
986
  }
@@ -930,8 +995,15 @@ export class OxyServices {
930
995
  ): Promise<{ following: User[]; total: number; hasMore: boolean }> {
931
996
  try {
932
997
  const params = buildPaginationParams(pagination || {});
933
- const res = await this.client.get(`/api/users/${userId}/following?${params.toString()}`);
934
- return res.data;
998
+ const response = await this.makeRequest<{ data: User[]; pagination: { total: number; hasMore: boolean } }>('GET', `/api/users/${userId}/following`, params, {
999
+ cache: true,
1000
+ cacheTTL: 2 * 60 * 1000, // 2 minutes cache
1001
+ });
1002
+ return {
1003
+ following: response.data || [],
1004
+ total: response.pagination.total,
1005
+ hasMore: response.pagination.hasMore,
1006
+ };
935
1007
  } catch (error) {
936
1008
  throw this.handleError(error);
937
1009
  }
@@ -942,8 +1014,9 @@ export class OxyServices {
942
1014
  */
943
1015
  async getNotifications(): Promise<Notification[]> {
944
1016
  return this.withAuthRetry(async () => {
945
- const res = await this.client.get('/api/notifications');
946
- return res.data;
1017
+ return await this.makeRequest<Notification[]>('GET', '/api/notifications', undefined, {
1018
+ cache: false, // Don't cache notifications - always get fresh data
1019
+ });
947
1020
  }, 'getNotifications');
948
1021
  }
949
1022
 
@@ -952,8 +1025,10 @@ export class OxyServices {
952
1025
  */
953
1026
  async getUnreadCount(): Promise<number> {
954
1027
  try {
955
- const res = await this.client.get('/api/notifications/unread-count');
956
- return res.data.count;
1028
+ const res = await this.makeRequest<{ count: number }>('GET', '/api/notifications/unread-count', undefined, {
1029
+ cache: false, // Don't cache unread count - always get fresh data
1030
+ });
1031
+ return res.count;
957
1032
  } catch (error) {
958
1033
  throw this.handleError(error);
959
1034
  }
@@ -964,8 +1039,7 @@ export class OxyServices {
964
1039
  */
965
1040
  async createNotification(data: Partial<Notification>): Promise<Notification> {
966
1041
  try {
967
- const res = await this.client.post('/api/notifications', data);
968
- return res.data;
1042
+ return await this.makeRequest<Notification>('POST', '/api/notifications', data, { cache: false });
969
1043
  } catch (error) {
970
1044
  throw this.handleError(error);
971
1045
  }
@@ -976,7 +1050,7 @@ export class OxyServices {
976
1050
  */
977
1051
  async markNotificationAsRead(notificationId: string): Promise<void> {
978
1052
  try {
979
- await this.client.put(`/api/notifications/${notificationId}/read`);
1053
+ await this.makeRequest('PUT', `/api/notifications/${notificationId}/read`, undefined, { cache: false });
980
1054
  } catch (error) {
981
1055
  throw this.handleError(error);
982
1056
  }
@@ -987,7 +1061,7 @@ export class OxyServices {
987
1061
  */
988
1062
  async markAllNotificationsAsRead(): Promise<void> {
989
1063
  try {
990
- await this.client.put('/api/notifications/read-all');
1064
+ await this.makeRequest('PUT', '/api/notifications/read-all', undefined, { cache: false });
991
1065
  } catch (error) {
992
1066
  throw this.handleError(error);
993
1067
  }
@@ -998,7 +1072,7 @@ export class OxyServices {
998
1072
  */
999
1073
  async deleteNotification(notificationId: string): Promise<void> {
1000
1074
  try {
1001
- await this.client.delete(`/api/notifications/${notificationId}`);
1075
+ await this.makeRequest('DELETE', `/api/notifications/${notificationId}`, undefined, { cache: false });
1002
1076
  } catch (error) {
1003
1077
  throw this.handleError(error);
1004
1078
  }
@@ -1013,8 +1087,7 @@ export class OxyServices {
1013
1087
  */
1014
1088
  async createPayment(data: any): Promise<any> {
1015
1089
  try {
1016
- const res = await this.client.post('/api/payments', data);
1017
- return res.data;
1090
+ return await this.makeRequest('POST', '/api/payments', data, { cache: false });
1018
1091
  } catch (error) {
1019
1092
  throw this.handleError(error);
1020
1093
  }
@@ -1025,8 +1098,10 @@ export class OxyServices {
1025
1098
  */
1026
1099
  async getPayment(paymentId: string): Promise<any> {
1027
1100
  try {
1028
- const res = await this.client.get(`/api/payments/${paymentId}`);
1029
- return res.data;
1101
+ return await this.makeRequest('GET', `/api/payments/${paymentId}`, undefined, {
1102
+ cache: true,
1103
+ cacheTTL: 5 * 60 * 1000, // 5 minutes cache
1104
+ });
1030
1105
  } catch (error) {
1031
1106
  throw this.handleError(error);
1032
1107
  }
@@ -1037,8 +1112,9 @@ export class OxyServices {
1037
1112
  */
1038
1113
  async getUserPayments(): Promise<any[]> {
1039
1114
  try {
1040
- const res = await this.client.get('/api/payments/user');
1041
- return res.data;
1115
+ return await this.makeRequest('GET', '/api/payments/user', undefined, {
1116
+ cache: false, // Don't cache user payments - always get fresh data
1117
+ });
1042
1118
  } catch (error) {
1043
1119
  throw this.handleError(error);
1044
1120
  }
@@ -1053,8 +1129,10 @@ export class OxyServices {
1053
1129
  */
1054
1130
  async getUserKarma(userId: string): Promise<any> {
1055
1131
  try {
1056
- const res = await this.client.get(`/api/karma/${userId}`);
1057
- return res.data;
1132
+ return await this.makeRequest('GET', `/api/karma/${userId}`, undefined, {
1133
+ cache: true,
1134
+ cacheTTL: 2 * 60 * 1000, // 2 minutes cache
1135
+ });
1058
1136
  } catch (error) {
1059
1137
  throw this.handleError(error);
1060
1138
  }
@@ -1065,11 +1143,10 @@ export class OxyServices {
1065
1143
  */
1066
1144
  async giveKarma(userId: string, amount: number, reason?: string): Promise<any> {
1067
1145
  try {
1068
- const res = await this.client.post(`/api/karma/${userId}/give`, {
1146
+ return await this.makeRequest('POST', `/api/karma/${userId}/give`, {
1069
1147
  amount,
1070
1148
  reason
1071
- });
1072
- return res.data;
1149
+ }, { cache: false });
1073
1150
  } catch (error) {
1074
1151
  throw this.handleError(error);
1075
1152
  }
@@ -1080,8 +1157,10 @@ export class OxyServices {
1080
1157
  */
1081
1158
  async getUserKarmaTotal(userId: string): Promise<any> {
1082
1159
  try {
1083
- const res = await this.client.get(`/api/karma/${userId}/total`);
1084
- return res.data;
1160
+ return await this.makeRequest('GET', `/api/karma/${userId}/total`, undefined, {
1161
+ cache: true,
1162
+ cacheTTL: 2 * 60 * 1000, // 2 minutes cache
1163
+ });
1085
1164
  } catch (error) {
1086
1165
  throw this.handleError(error);
1087
1166
  }
@@ -1092,12 +1171,14 @@ export class OxyServices {
1092
1171
  */
1093
1172
  async getUserKarmaHistory(userId: string, limit?: number, offset?: number): Promise<any> {
1094
1173
  try {
1095
- const params = new URLSearchParams();
1096
- if (limit) params.append('limit', limit.toString());
1097
- if (offset) params.append('offset', offset.toString());
1174
+ const params: any = {};
1175
+ if (limit) params.limit = limit;
1176
+ if (offset) params.offset = offset;
1098
1177
 
1099
- const res = await this.client.get(`/api/karma/${userId}/history?${params.toString()}`);
1100
- return res.data;
1178
+ return await this.makeRequest('GET', `/api/karma/${userId}/history`, params, {
1179
+ cache: true,
1180
+ cacheTTL: 2 * 60 * 1000, // 2 minutes cache
1181
+ });
1101
1182
  } catch (error) {
1102
1183
  throw this.handleError(error);
1103
1184
  }
@@ -1108,8 +1189,10 @@ export class OxyServices {
1108
1189
  */
1109
1190
  async getKarmaLeaderboard(): Promise<any> {
1110
1191
  try {
1111
- const res = await this.client.get('/api/karma/leaderboard');
1112
- return res.data;
1192
+ return await this.makeRequest('GET', '/api/karma/leaderboard', undefined, {
1193
+ cache: true,
1194
+ cacheTTL: 5 * 60 * 1000, // 5 minutes cache
1195
+ });
1113
1196
  } catch (error) {
1114
1197
  throw this.handleError(error);
1115
1198
  }
@@ -1120,8 +1203,10 @@ export class OxyServices {
1120
1203
  */
1121
1204
  async getKarmaRules(): Promise<any> {
1122
1205
  try {
1123
- const res = await this.client.get('/api/karma/rules');
1124
- return res.data;
1206
+ return await this.makeRequest('GET', '/api/karma/rules', undefined, {
1207
+ cache: true,
1208
+ cacheTTL: 30 * 60 * 1000, // 30 minutes cache (rules don't change often)
1209
+ });
1125
1210
  } catch (error) {
1126
1211
  throw this.handleError(error);
1127
1212
  }
@@ -1137,8 +1222,7 @@ export class OxyServices {
1137
1222
  async deleteFile(fileId: string): Promise<any> {
1138
1223
  try {
1139
1224
  // Central Asset Service delete with force=true behavior controlled by caller via assetDelete
1140
- const res = await this.client.delete(`/api/assets/${encodeURIComponent(fileId)}`);
1141
- return res.data;
1225
+ return await this.makeRequest('DELETE', `/api/assets/${encodeURIComponent(fileId)}`, undefined, { cache: false });
1142
1226
  } catch (error) {
1143
1227
  throw this.handleError(error);
1144
1228
  }
@@ -1153,7 +1237,7 @@ export class OxyServices {
1153
1237
  if (variant) params.set('variant', variant);
1154
1238
  if (expiresIn) params.set('expiresIn', String(expiresIn));
1155
1239
  params.set('fallback', 'placeholderVisible');
1156
- const token = this.tokenStore.getAccessToken();
1240
+ const token = this.httpClient.getAccessToken();
1157
1241
  if (token) params.set('token', token);
1158
1242
 
1159
1243
  // Use params.toString() to detect whether there are query params.
@@ -1179,12 +1263,12 @@ export class OxyServices {
1179
1263
  */
1180
1264
  async listUserFiles(limit?: number, offset?: number): Promise<{ files: any[]; total: number; hasMore: boolean }> {
1181
1265
  try {
1182
- const params = new URLSearchParams();
1183
- if (limit) params.append('limit', String(limit));
1184
- if (offset) params.append('offset', String(offset));
1185
- const qs = params.toString();
1186
- const res = await this.client.get(`/api/assets${qs ? `?${qs}` : ''}`);
1187
- return res.data;
1266
+ const paramsObj: any = {};
1267
+ if (limit) paramsObj.limit = limit;
1268
+ if (offset) paramsObj.offset = offset;
1269
+ return await this.makeRequest('GET', '/api/assets', paramsObj, {
1270
+ cache: false, // Don't cache file lists - always get fresh data
1271
+ });
1188
1272
  } catch (error) {
1189
1273
  throw this.handleError(error);
1190
1274
  }
@@ -1197,8 +1281,12 @@ export class OxyServices {
1197
1281
  */
1198
1282
  async getFileContentAsText(fileId: string, variant?: string): Promise<string> {
1199
1283
  try {
1200
- const urlRes = await this.client.get(`/api/assets/${encodeURIComponent(fileId)}/url${variant ? `?variant=${encodeURIComponent(variant)}` : ''}`);
1201
- const downloadUrl = urlRes.data?.url;
1284
+ const params: any = variant ? { variant } : undefined;
1285
+ const urlRes = await this.makeRequest<{ url: string }>('GET', `/api/assets/${encodeURIComponent(fileId)}/url`, params, {
1286
+ cache: true,
1287
+ cacheTTL: 10 * 60 * 1000, // 10 minutes cache for URLs
1288
+ });
1289
+ const downloadUrl = urlRes?.url;
1202
1290
  const response = await fetch(downloadUrl);
1203
1291
  return await response.text();
1204
1292
  } catch (error) {
@@ -1211,8 +1299,12 @@ export class OxyServices {
1211
1299
  */
1212
1300
  async getFileContentAsBlob(fileId: string, variant?: string): Promise<Blob> {
1213
1301
  try {
1214
- const urlRes = await this.client.get(`/api/assets/${encodeURIComponent(fileId)}/url${variant ? `?variant=${encodeURIComponent(variant)}` : ''}`);
1215
- const downloadUrl = urlRes.data?.url;
1302
+ const params: any = variant ? { variant } : undefined;
1303
+ const urlRes = await this.makeRequest<{ url: string }>('GET', `/api/assets/${encodeURIComponent(fileId)}/url`, params, {
1304
+ cache: true,
1305
+ cacheTTL: 10 * 60 * 1000, // 10 minutes cache for URLs
1306
+ });
1307
+ const downloadUrl = urlRes?.url;
1216
1308
  const response = await fetch(downloadUrl);
1217
1309
  return await response.blob();
1218
1310
  } catch (error) {
@@ -1247,12 +1339,11 @@ export class OxyServices {
1247
1339
  */
1248
1340
  async assetInit(sha256: string, size: number, mime: string): Promise<AssetInitResponse> {
1249
1341
  try {
1250
- const res = await this.client.post('/api/assets/init', {
1342
+ return await this.makeRequest<AssetInitResponse>('POST', '/api/assets/init', {
1251
1343
  sha256,
1252
1344
  size,
1253
1345
  mime
1254
- });
1255
- return res.data;
1346
+ }, { cache: false });
1256
1347
  } catch (error) {
1257
1348
  throw this.handleError(error);
1258
1349
  }
@@ -1263,15 +1354,14 @@ export class OxyServices {
1263
1354
  */
1264
1355
  async assetComplete(fileId: string, originalName: string, size: number, mime: string, visibility?: 'private' | 'public' | 'unlisted', metadata?: Record<string, any>): Promise<any> {
1265
1356
  try {
1266
- const res = await this.client.post('/api/assets/complete', {
1357
+ return await this.makeRequest('POST', '/api/assets/complete', {
1267
1358
  fileId,
1268
1359
  originalName,
1269
1360
  size,
1270
1361
  mime,
1271
1362
  visibility,
1272
1363
  metadata
1273
- });
1274
- return res.data;
1364
+ }, { cache: false });
1275
1365
  } catch (error) {
1276
1366
  throw this.handleError(error);
1277
1367
  }
@@ -1295,8 +1385,11 @@ export class OxyServices {
1295
1385
  // Fallback: direct upload via API to avoid CORS issues
1296
1386
  const fd = new FormData();
1297
1387
  fd.append('file', file);
1298
- await this.client.post(`/api/assets/${encodeURIComponent(initResponse.fileId)}/upload-direct`, fd, {
1299
- headers: { 'Content-Type': 'multipart/form-data' }
1388
+ // Use httpClient directly for FormData uploads (bypasses RequestManager for special handling)
1389
+ await this.httpClient.request({
1390
+ method: 'POST',
1391
+ url: `/api/assets/${encodeURIComponent(initResponse.fileId)}/upload-direct`,
1392
+ data: fd,
1300
1393
  });
1301
1394
  }
1302
1395
 
@@ -1354,8 +1447,7 @@ export class OxyServices {
1354
1447
  const body: any = { app, entityType, entityId };
1355
1448
  if (visibility) body.visibility = visibility;
1356
1449
  if (webhookUrl) body.webhookUrl = webhookUrl;
1357
- const res = await this.client.post(`/api/assets/${fileId}/links`, body);
1358
- return res.data;
1450
+ return await this.makeRequest('POST', `/api/assets/${fileId}/links`, body, { cache: false });
1359
1451
  } catch (error) {
1360
1452
  throw this.handleError(error);
1361
1453
  }
@@ -1366,14 +1458,11 @@ export class OxyServices {
1366
1458
  */
1367
1459
  async assetUnlink(fileId: string, app: string, entityType: string, entityId: string): Promise<any> {
1368
1460
  try {
1369
- const res = await this.client.delete(`/api/assets/${fileId}/links`, {
1370
- data: {
1371
- app,
1372
- entityType,
1373
- entityId
1374
- }
1375
- });
1376
- return res.data;
1461
+ return await this.makeRequest('DELETE', `/api/assets/${fileId}/links`, {
1462
+ app,
1463
+ entityType,
1464
+ entityId
1465
+ }, { cache: false });
1377
1466
  } catch (error) {
1378
1467
  throw this.handleError(error);
1379
1468
  }
@@ -1384,8 +1473,10 @@ export class OxyServices {
1384
1473
  */
1385
1474
  async assetGet(fileId: string): Promise<any> {
1386
1475
  try {
1387
- const res = await this.client.get(`/api/assets/${fileId}`);
1388
- return res.data;
1476
+ return await this.makeRequest('GET', `/api/assets/${fileId}`, undefined, {
1477
+ cache: true,
1478
+ cacheTTL: 5 * 60 * 1000, // 5 minutes cache
1479
+ });
1389
1480
  } catch (error) {
1390
1481
  throw this.handleError(error);
1391
1482
  }
@@ -1396,15 +1487,14 @@ export class OxyServices {
1396
1487
  */
1397
1488
  async assetGetUrl(fileId: string, variant?: string, expiresIn?: number): Promise<AssetUrlResponse> {
1398
1489
  try {
1399
- const params = new URLSearchParams();
1400
- if (variant) params.set('variant', variant);
1401
- if (expiresIn) params.set('expiresIn', expiresIn.toString());
1402
-
1403
- const queryString = params.toString();
1404
- const url = `/api/assets/${fileId}/url${queryString ? `?${queryString}` : ''}`;
1490
+ const params: any = {};
1491
+ if (variant) params.variant = variant;
1492
+ if (expiresIn) params.expiresIn = expiresIn;
1405
1493
 
1406
- const res = await this.client.get(url);
1407
- return res.data;
1494
+ return await this.makeRequest<AssetUrlResponse>('GET', `/api/assets/${fileId}/url`, params, {
1495
+ cache: true,
1496
+ cacheTTL: 10 * 60 * 1000, // 10 minutes cache for URLs
1497
+ });
1408
1498
  } catch (error) {
1409
1499
  throw this.handleError(error);
1410
1500
  }
@@ -1415,8 +1505,7 @@ export class OxyServices {
1415
1505
  */
1416
1506
  async assetRestore(fileId: string): Promise<any> {
1417
1507
  try {
1418
- const res = await this.client.post(`/api/assets/${fileId}/restore`);
1419
- return res.data;
1508
+ return await this.makeRequest('POST', `/api/assets/${fileId}/restore`, undefined, { cache: false });
1420
1509
  } catch (error) {
1421
1510
  throw this.handleError(error);
1422
1511
  }
@@ -1427,9 +1516,8 @@ export class OxyServices {
1427
1516
  */
1428
1517
  async assetDelete(fileId: string, force: boolean = false): Promise<any> {
1429
1518
  try {
1430
- const params = force ? '?force=true' : '';
1431
- const res = await this.client.delete(`/api/assets/${fileId}${params}`);
1432
- return res.data;
1519
+ const params: any = force ? { force: 'true' } : undefined;
1520
+ return await this.makeRequest('DELETE', `/api/assets/${fileId}`, params, { cache: false });
1433
1521
  } catch (error) {
1434
1522
  throw this.handleError(error);
1435
1523
  }
@@ -1455,10 +1543,9 @@ export class OxyServices {
1455
1543
  */
1456
1544
  async assetUpdateVisibility(fileId: string, visibility: 'private' | 'public' | 'unlisted'): Promise<any> {
1457
1545
  try {
1458
- const res = await this.client.patch(`/api/assets/${fileId}/visibility`, {
1546
+ return await this.makeRequest('PATCH', `/api/assets/${fileId}/visibility`, {
1459
1547
  visibility
1460
- });
1461
- return res.data;
1548
+ }, { cache: false });
1462
1549
  } catch (error) {
1463
1550
  throw this.handleError(error);
1464
1551
  }
@@ -1515,8 +1602,11 @@ export class OxyServices {
1515
1602
  */
1516
1603
  async getDeveloperApps(): Promise<any[]> {
1517
1604
  try {
1518
- const res = await this.client.get('/api/developer/apps');
1519
- return res.data;
1605
+ const res = await this.makeRequest<{ apps?: any[] }>('GET', '/api/developer/apps', undefined, {
1606
+ cache: true,
1607
+ cacheTTL: 2 * 60 * 1000, // 2 minutes cache
1608
+ });
1609
+ return res.apps || [];
1520
1610
  } catch (error) {
1521
1611
  throw this.handleError(error);
1522
1612
  }
@@ -1528,12 +1618,13 @@ export class OxyServices {
1528
1618
  async createDeveloperApp(data: {
1529
1619
  name: string;
1530
1620
  description?: string;
1531
- webhookUrl?: string;
1621
+ webhookUrl: string;
1622
+ devWebhookUrl?: string;
1532
1623
  scopes?: string[];
1533
1624
  }): Promise<any> {
1534
1625
  try {
1535
- const res = await this.client.post('/api/developer/apps', data);
1536
- return res.data;
1626
+ const res = await this.makeRequest<{ app: any }>('POST', '/api/developer/apps', data, { cache: false });
1627
+ return res.app;
1537
1628
  } catch (error) {
1538
1629
  throw this.handleError(error);
1539
1630
  }
@@ -1544,8 +1635,11 @@ export class OxyServices {
1544
1635
  */
1545
1636
  async getDeveloperApp(appId: string): Promise<any> {
1546
1637
  try {
1547
- const res = await this.client.get(`/api/developer/apps/${appId}`);
1548
- return res.data;
1638
+ const res = await this.makeRequest<{ app: any }>('GET', `/api/developer/apps/${appId}`, undefined, {
1639
+ cache: true,
1640
+ cacheTTL: 5 * 60 * 1000, // 5 minutes cache
1641
+ });
1642
+ return res.app;
1549
1643
  } catch (error) {
1550
1644
  throw this.handleError(error);
1551
1645
  }
@@ -1558,11 +1652,12 @@ export class OxyServices {
1558
1652
  name?: string;
1559
1653
  description?: string;
1560
1654
  webhookUrl?: string;
1655
+ devWebhookUrl?: string;
1561
1656
  scopes?: string[];
1562
1657
  }): Promise<any> {
1563
1658
  try {
1564
- const res = await this.client.patch(`/api/developer/apps/${appId}`, data);
1565
- return res.data;
1659
+ const res = await this.makeRequest<{ app: any }>('PATCH', `/api/developer/apps/${appId}`, data, { cache: false });
1660
+ return res.app;
1566
1661
  } catch (error) {
1567
1662
  throw this.handleError(error);
1568
1663
  }
@@ -1573,8 +1668,7 @@ export class OxyServices {
1573
1668
  */
1574
1669
  async regenerateDeveloperAppSecret(appId: string): Promise<any> {
1575
1670
  try {
1576
- const res = await this.client.post(`/api/developer/apps/${appId}/regenerate-secret`);
1577
- return res.data;
1671
+ return await this.makeRequest('POST', `/api/developer/apps/${appId}/regenerate-secret`, undefined, { cache: false });
1578
1672
  } catch (error) {
1579
1673
  throw this.handleError(error);
1580
1674
  }
@@ -1585,8 +1679,7 @@ export class OxyServices {
1585
1679
  */
1586
1680
  async deleteDeveloperApp(appId: string): Promise<any> {
1587
1681
  try {
1588
- const res = await this.client.delete(`/api/developer/apps/${appId}`);
1589
- return res.data;
1682
+ return await this.makeRequest('DELETE', `/api/developer/apps/${appId}`, undefined, { cache: false });
1590
1683
  } catch (error) {
1591
1684
  throw this.handleError(error);
1592
1685
  }
@@ -1601,11 +1694,10 @@ export class OxyServices {
1601
1694
  */
1602
1695
  async updateLocation(latitude: number, longitude: number): Promise<any> {
1603
1696
  try {
1604
- const res = await this.client.post('/api/location', {
1697
+ return await this.makeRequest('POST', '/api/location', {
1605
1698
  latitude,
1606
1699
  longitude
1607
- });
1608
- return res.data;
1700
+ }, { cache: false });
1609
1701
  } catch (error) {
1610
1702
  throw this.handleError(error);
1611
1703
  }
@@ -1616,9 +1708,10 @@ export class OxyServices {
1616
1708
  */
1617
1709
  async getNearbyUsers(radius?: number): Promise<any[]> {
1618
1710
  try {
1619
- const params = radius ? `?radius=${radius}` : '';
1620
- const res = await this.client.get(`/api/location/nearby${params}`);
1621
- return res.data;
1711
+ const params: any = radius ? { radius } : undefined;
1712
+ return await this.makeRequest('GET', '/api/location/nearby', params, {
1713
+ cache: false, // Don't cache location data - always get fresh data
1714
+ });
1622
1715
  } catch (error) {
1623
1716
  throw this.handleError(error);
1624
1717
  }
@@ -1633,10 +1726,10 @@ export class OxyServices {
1633
1726
  */
1634
1727
  async trackEvent(eventName: string, properties?: Record<string, any>): Promise<void> {
1635
1728
  try {
1636
- await this.client.post('/api/analytics/events', {
1729
+ await this.makeRequest('POST', '/api/analytics/events', {
1637
1730
  event: eventName,
1638
1731
  properties
1639
- });
1732
+ }, { cache: false, retry: false }); // Don't retry analytics events
1640
1733
  } catch (error) {
1641
1734
  throw this.handleError(error);
1642
1735
  }
@@ -1647,12 +1740,14 @@ export class OxyServices {
1647
1740
  */
1648
1741
  async getAnalytics(startDate?: string, endDate?: string): Promise<any> {
1649
1742
  try {
1650
- const params = new URLSearchParams();
1651
- if (startDate) params.append('startDate', startDate);
1652
- if (endDate) params.append('endDate', endDate);
1743
+ const params: any = {};
1744
+ if (startDate) params.startDate = startDate;
1745
+ if (endDate) params.endDate = endDate;
1653
1746
 
1654
- const res = await this.client.get(`/api/analytics?${params.toString()}`);
1655
- return res.data;
1747
+ return await this.makeRequest('GET', '/api/analytics', params, {
1748
+ cache: true,
1749
+ cacheTTL: 5 * 60 * 1000, // 5 minutes cache
1750
+ });
1656
1751
  } catch (error) {
1657
1752
  throw this.handleError(error);
1658
1753
  }
@@ -1667,8 +1762,7 @@ export class OxyServices {
1667
1762
  */
1668
1763
  async registerDevice(deviceData: any): Promise<any> {
1669
1764
  try {
1670
- const res = await this.client.post('/api/devices', deviceData);
1671
- return res.data;
1765
+ return await this.makeRequest('POST', '/api/devices', deviceData, { cache: false });
1672
1766
  } catch (error) {
1673
1767
  throw this.handleError(error);
1674
1768
  }
@@ -1679,8 +1773,9 @@ export class OxyServices {
1679
1773
  */
1680
1774
  async getUserDevices(): Promise<any[]> {
1681
1775
  try {
1682
- const res = await this.client.get('/api/devices');
1683
- return res.data;
1776
+ return await this.makeRequest('GET', '/api/devices', undefined, {
1777
+ cache: false, // Don't cache device list - always get fresh data
1778
+ });
1684
1779
  } catch (error) {
1685
1780
  throw this.handleError(error);
1686
1781
  }
@@ -1691,7 +1786,7 @@ export class OxyServices {
1691
1786
  */
1692
1787
  async removeDevice(deviceId: string): Promise<void> {
1693
1788
  try {
1694
- await this.client.delete(`/api/devices/${deviceId}`);
1789
+ await this.makeRequest('DELETE', `/api/devices/${deviceId}`, undefined, { cache: false });
1695
1790
  } catch (error) {
1696
1791
  throw this.handleError(error);
1697
1792
  }
@@ -1699,11 +1794,16 @@ export class OxyServices {
1699
1794
 
1700
1795
  /**
1701
1796
  * Get device sessions
1797
+ * Note: Not cached by default to ensure fresh data, but can be cached via makeRequest if needed
1702
1798
  */
1703
1799
  async getDeviceSessions(sessionId: string): Promise<any[]> {
1704
1800
  try {
1705
- const res = await this.client.get(`/api/devices/sessions/${sessionId}`);
1706
- return res.data;
1801
+ // Use makeRequest for consistent error handling and optional caching
1802
+ // Cache disabled by default to ensure fresh session data
1803
+ return await this.makeRequest<any[]>('GET', `/api/session/device/sessions/${sessionId}`, undefined, {
1804
+ cache: false, // Don't cache sessions - always get fresh data
1805
+ deduplicate: true, // Deduplicate concurrent requests for same sessionId
1806
+ });
1707
1807
  } catch (error) {
1708
1808
  throw this.handleError(error);
1709
1809
  }
@@ -1718,8 +1818,11 @@ export class OxyServices {
1718
1818
  if (deviceId) params.append('deviceId', deviceId);
1719
1819
  if (excludeCurrent) params.append('excludeCurrent', 'true');
1720
1820
 
1721
- const res = await this.client.post(`/api/devices/logout-all/${sessionId}?${params.toString()}`);
1722
- return res.data;
1821
+ const urlParams: any = {};
1822
+ params.forEach((value, key) => {
1823
+ urlParams[key] = value;
1824
+ });
1825
+ return await this.makeRequest('POST', `/api/session/device/logout-all/${sessionId}`, urlParams, { cache: false });
1723
1826
  } catch (error) {
1724
1827
  throw this.handleError(error);
1725
1828
  }
@@ -1730,8 +1833,7 @@ export class OxyServices {
1730
1833
  */
1731
1834
  async updateDeviceName(sessionId: string, deviceName: string): Promise<any> {
1732
1835
  try {
1733
- const res = await this.client.put(`/api/devices/name/${sessionId}`, { deviceName });
1734
- return res.data;
1836
+ return await this.makeRequest('PUT', `/api/session/device/name/${sessionId}`, { deviceName }, { cache: false });
1735
1837
  } catch (error) {
1736
1838
  throw this.handleError(error);
1737
1839
  }
@@ -1751,8 +1853,15 @@ export class OxyServices {
1751
1853
  image?: string;
1752
1854
  }> {
1753
1855
  try {
1754
- const res = await this.client.get(`/api/link-metadata?url=${encodeURIComponent(url)}`);
1755
- return res.data;
1856
+ return await this.makeRequest<{
1857
+ url: string;
1858
+ title: string;
1859
+ description: string;
1860
+ image?: string;
1861
+ }>('GET', '/api/link-metadata', { url }, {
1862
+ cache: true,
1863
+ cacheTTL: 30 * 60 * 1000, // 30 minutes cache for link metadata
1864
+ });
1756
1865
  } catch (error) {
1757
1866
  throw this.handleError(error);
1758
1867
  }