@oxyhq/services 5.7.5 → 5.8.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 (303) hide show
  1. package/README.md +76 -76
  2. package/lib/commonjs/core/index.js +177 -102
  3. package/lib/commonjs/core/index.js.map +1 -1
  4. package/lib/commonjs/index.js +69 -28
  5. package/lib/commonjs/index.js.map +1 -1
  6. package/lib/commonjs/ui/components/Avatar.js +15 -6
  7. package/lib/commonjs/ui/components/Avatar.js.map +1 -1
  8. package/lib/commonjs/ui/components/FollowButton.js +100 -12
  9. package/lib/commonjs/ui/components/FollowButton.js.map +1 -1
  10. package/lib/commonjs/ui/components/GroupedItem.js +58 -13
  11. package/lib/commonjs/ui/components/GroupedItem.js.map +1 -1
  12. package/lib/commonjs/ui/components/GroupedSection.js +7 -1
  13. package/lib/commonjs/ui/components/GroupedSection.js.map +1 -1
  14. package/lib/commonjs/ui/components/Header.js +356 -0
  15. package/lib/commonjs/ui/components/Header.js.map +1 -0
  16. package/lib/commonjs/ui/components/OxyProvider.js +28 -7
  17. package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
  18. package/lib/commonjs/ui/components/index.js +7 -0
  19. package/lib/commonjs/ui/components/index.js.map +1 -1
  20. package/lib/commonjs/ui/components/internal/GroupedPillButtons.js +1 -1
  21. package/lib/commonjs/ui/components/internal/GroupedPillButtons.js.map +1 -1
  22. package/lib/commonjs/ui/components/internal/TextField.js +606 -546
  23. package/lib/commonjs/ui/components/internal/TextField.js.map +1 -1
  24. package/lib/commonjs/ui/components/internal/TextField.md +436 -0
  25. package/lib/commonjs/ui/context/OxyContext.js +181 -199
  26. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  27. package/lib/commonjs/ui/hooks/index.js +6 -0
  28. package/lib/commonjs/ui/hooks/index.js.map +1 -1
  29. package/lib/commonjs/ui/hooks/useFollow.js +59 -2
  30. package/lib/commonjs/ui/hooks/useFollow.js.map +1 -1
  31. package/lib/commonjs/ui/hooks/useSessionSocket.js +5 -2
  32. package/lib/commonjs/ui/hooks/useSessionSocket.js.map +1 -1
  33. package/lib/commonjs/ui/navigation/OxyRouter.js +11 -1
  34. package/lib/commonjs/ui/navigation/OxyRouter.js.map +1 -1
  35. package/lib/commonjs/ui/screens/AccountCenterScreen.js +6 -6
  36. package/lib/commonjs/ui/screens/AccountCenterScreen.js.map +1 -1
  37. package/lib/commonjs/ui/screens/AccountManagementDemo.js +3 -3
  38. package/lib/commonjs/ui/screens/AccountManagementDemo.js.map +1 -1
  39. package/lib/commonjs/ui/screens/AccountOverviewScreen.js +241 -598
  40. package/lib/commonjs/ui/screens/AccountOverviewScreen.js.map +1 -1
  41. package/lib/commonjs/ui/screens/AccountSettingsScreen.js +1160 -406
  42. package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
  43. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +135 -237
  44. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -1
  45. package/lib/commonjs/ui/screens/AppInfoScreen.js +246 -463
  46. package/lib/commonjs/ui/screens/AppInfoScreen.js.map +1 -1
  47. package/lib/commonjs/ui/screens/FeedbackScreen.js +3 -3
  48. package/lib/commonjs/ui/screens/FeedbackScreen.js.map +1 -1
  49. package/lib/commonjs/ui/screens/PaymentGatewayScreen.js +808 -650
  50. package/lib/commonjs/ui/screens/PaymentGatewayScreen.js.map +1 -1
  51. package/lib/commonjs/ui/screens/ProfileScreen.js +214 -37
  52. package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
  53. package/lib/commonjs/ui/screens/RecoverAccountScreen.js +51 -72
  54. package/lib/commonjs/ui/screens/RecoverAccountScreen.js.map +1 -1
  55. package/lib/commonjs/ui/screens/SessionManagementScreen.js +11 -29
  56. package/lib/commonjs/ui/screens/SessionManagementScreen.js.map +1 -1
  57. package/lib/commonjs/ui/screens/SignInScreen.js +30 -303
  58. package/lib/commonjs/ui/screens/SignInScreen.js.map +1 -1
  59. package/lib/commonjs/ui/screens/SignUpScreen.js +4 -4
  60. package/lib/commonjs/ui/screens/SignUpScreen.js.map +1 -1
  61. package/lib/commonjs/ui/screens/UserLinksScreen.js +90 -0
  62. package/lib/commonjs/ui/screens/UserLinksScreen.js.map +1 -0
  63. package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js +19 -31
  64. package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js.map +1 -1
  65. package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js +7 -10
  66. package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js.map +1 -1
  67. package/lib/commonjs/ui/screens/internal/SignUpIdentityStep.js +11 -5
  68. package/lib/commonjs/ui/screens/internal/SignUpIdentityStep.js.map +1 -1
  69. package/lib/commonjs/ui/screens/internal/SignUpSecurityStep.js +11 -4
  70. package/lib/commonjs/ui/screens/internal/SignUpSecurityStep.js.map +1 -1
  71. package/lib/commonjs/ui/screens/karma/KarmaAboutScreen.js +9 -6
  72. package/lib/commonjs/ui/screens/karma/KarmaAboutScreen.js.map +1 -1
  73. package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js +3 -30
  74. package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
  75. package/lib/commonjs/ui/screens/karma/KarmaFAQScreen.js +37 -46
  76. package/lib/commonjs/ui/screens/karma/KarmaFAQScreen.js.map +1 -1
  77. package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js +9 -12
  78. package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js.map +1 -1
  79. package/lib/commonjs/ui/screens/karma/KarmaRewardsScreen.js +9 -12
  80. package/lib/commonjs/ui/screens/karma/KarmaRewardsScreen.js.map +1 -1
  81. package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js +9 -12
  82. package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js.map +1 -1
  83. package/lib/commonjs/ui/stores/authStore.js +36 -6
  84. package/lib/commonjs/ui/stores/authStore.js.map +1 -1
  85. package/lib/commonjs/ui/stores/followStore.js +106 -1
  86. package/lib/commonjs/ui/stores/followStore.js.map +1 -1
  87. package/lib/commonjs/ui/styles/authStyles.js +337 -0
  88. package/lib/commonjs/ui/styles/authStyles.js.map +1 -0
  89. package/lib/commonjs/ui/styles/index.js +11 -0
  90. package/lib/commonjs/ui/styles/index.js.map +1 -1
  91. package/lib/module/core/index.js +177 -41
  92. package/lib/module/core/index.js.map +1 -1
  93. package/lib/module/index.js +24 -4
  94. package/lib/module/index.js.map +1 -1
  95. package/lib/module/ui/components/Avatar.js +15 -6
  96. package/lib/module/ui/components/Avatar.js.map +1 -1
  97. package/lib/module/ui/components/FollowButton.js +101 -13
  98. package/lib/module/ui/components/FollowButton.js.map +1 -1
  99. package/lib/module/ui/components/GroupedItem.js +59 -14
  100. package/lib/module/ui/components/GroupedItem.js.map +1 -1
  101. package/lib/module/ui/components/GroupedSection.js +7 -1
  102. package/lib/module/ui/components/GroupedSection.js.map +1 -1
  103. package/lib/module/ui/components/Header.js +351 -0
  104. package/lib/module/ui/components/Header.js.map +1 -0
  105. package/lib/module/ui/components/OxyProvider.js +30 -9
  106. package/lib/module/ui/components/OxyProvider.js.map +1 -1
  107. package/lib/module/ui/components/index.js +1 -0
  108. package/lib/module/ui/components/index.js.map +1 -1
  109. package/lib/module/ui/components/internal/GroupedPillButtons.js +1 -1
  110. package/lib/module/ui/components/internal/GroupedPillButtons.js.map +1 -1
  111. package/lib/module/ui/components/internal/TextField.js +607 -547
  112. package/lib/module/ui/components/internal/TextField.js.map +1 -1
  113. package/lib/module/ui/components/internal/TextField.md +436 -0
  114. package/lib/module/ui/context/OxyContext.js +180 -198
  115. package/lib/module/ui/context/OxyContext.js.map +1 -1
  116. package/lib/module/ui/hooks/index.js +1 -1
  117. package/lib/module/ui/hooks/index.js.map +1 -1
  118. package/lib/module/ui/hooks/useFollow.js +57 -1
  119. package/lib/module/ui/hooks/useFollow.js.map +1 -1
  120. package/lib/module/ui/hooks/useSessionSocket.js +5 -2
  121. package/lib/module/ui/hooks/useSessionSocket.js.map +1 -1
  122. package/lib/module/ui/navigation/OxyRouter.js +11 -1
  123. package/lib/module/ui/navigation/OxyRouter.js.map +1 -1
  124. package/lib/module/ui/screens/AccountCenterScreen.js +6 -6
  125. package/lib/module/ui/screens/AccountCenterScreen.js.map +1 -1
  126. package/lib/module/ui/screens/AccountManagementDemo.js +3 -3
  127. package/lib/module/ui/screens/AccountManagementDemo.js.map +1 -1
  128. package/lib/module/ui/screens/AccountOverviewScreen.js +242 -597
  129. package/lib/module/ui/screens/AccountOverviewScreen.js.map +1 -1
  130. package/lib/module/ui/screens/AccountSettingsScreen.js +1161 -407
  131. package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
  132. package/lib/module/ui/screens/AccountSwitcherScreen.js +135 -237
  133. package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
  134. package/lib/module/ui/screens/AppInfoScreen.js +248 -465
  135. package/lib/module/ui/screens/AppInfoScreen.js.map +1 -1
  136. package/lib/module/ui/screens/FeedbackScreen.js +3 -3
  137. package/lib/module/ui/screens/FeedbackScreen.js.map +1 -1
  138. package/lib/module/ui/screens/PaymentGatewayScreen.js +809 -651
  139. package/lib/module/ui/screens/PaymentGatewayScreen.js.map +1 -1
  140. package/lib/module/ui/screens/ProfileScreen.js +214 -37
  141. package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
  142. package/lib/module/ui/screens/RecoverAccountScreen.js +53 -74
  143. package/lib/module/ui/screens/RecoverAccountScreen.js.map +1 -1
  144. package/lib/module/ui/screens/SessionManagementScreen.js +11 -29
  145. package/lib/module/ui/screens/SessionManagementScreen.js.map +1 -1
  146. package/lib/module/ui/screens/SignInScreen.js +32 -305
  147. package/lib/module/ui/screens/SignInScreen.js.map +1 -1
  148. package/lib/module/ui/screens/SignUpScreen.js +5 -5
  149. package/lib/module/ui/screens/SignUpScreen.js.map +1 -1
  150. package/lib/module/ui/screens/UserLinksScreen.js +85 -0
  151. package/lib/module/ui/screens/UserLinksScreen.js.map +1 -0
  152. package/lib/module/ui/screens/internal/SignInPasswordStep.js +19 -31
  153. package/lib/module/ui/screens/internal/SignInPasswordStep.js.map +1 -1
  154. package/lib/module/ui/screens/internal/SignInUsernameStep.js +7 -10
  155. package/lib/module/ui/screens/internal/SignInUsernameStep.js.map +1 -1
  156. package/lib/module/ui/screens/internal/SignUpIdentityStep.js +11 -5
  157. package/lib/module/ui/screens/internal/SignUpIdentityStep.js.map +1 -1
  158. package/lib/module/ui/screens/internal/SignUpSecurityStep.js +11 -4
  159. package/lib/module/ui/screens/internal/SignUpSecurityStep.js.map +1 -1
  160. package/lib/module/ui/screens/karma/KarmaAboutScreen.js +9 -6
  161. package/lib/module/ui/screens/karma/KarmaAboutScreen.js.map +1 -1
  162. package/lib/module/ui/screens/karma/KarmaCenterScreen.js +3 -30
  163. package/lib/module/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
  164. package/lib/module/ui/screens/karma/KarmaFAQScreen.js +37 -46
  165. package/lib/module/ui/screens/karma/KarmaFAQScreen.js.map +1 -1
  166. package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js +9 -12
  167. package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js.map +1 -1
  168. package/lib/module/ui/screens/karma/KarmaRewardsScreen.js +9 -12
  169. package/lib/module/ui/screens/karma/KarmaRewardsScreen.js.map +1 -1
  170. package/lib/module/ui/screens/karma/KarmaRulesScreen.js +9 -12
  171. package/lib/module/ui/screens/karma/KarmaRulesScreen.js.map +1 -1
  172. package/lib/module/ui/stores/authStore.js +36 -6
  173. package/lib/module/ui/stores/authStore.js.map +1 -1
  174. package/lib/module/ui/stores/followStore.js +106 -1
  175. package/lib/module/ui/stores/followStore.js.map +1 -1
  176. package/lib/module/ui/styles/authStyles.js +332 -0
  177. package/lib/module/ui/styles/authStyles.js.map +1 -0
  178. package/lib/module/ui/styles/index.js +1 -0
  179. package/lib/module/ui/styles/index.js.map +1 -1
  180. package/lib/typescript/core/index.d.ts +68 -24
  181. package/lib/typescript/core/index.d.ts.map +1 -1
  182. package/lib/typescript/index.d.ts +13 -3
  183. package/lib/typescript/index.d.ts.map +1 -1
  184. package/lib/typescript/ui/components/Avatar.d.ts.map +1 -1
  185. package/lib/typescript/ui/components/FollowButton.d.ts +1 -0
  186. package/lib/typescript/ui/components/FollowButton.d.ts.map +1 -1
  187. package/lib/typescript/ui/components/GroupedItem.d.ts +6 -0
  188. package/lib/typescript/ui/components/GroupedItem.d.ts.map +1 -1
  189. package/lib/typescript/ui/components/GroupedSection.d.ts +6 -0
  190. package/lib/typescript/ui/components/GroupedSection.d.ts.map +1 -1
  191. package/lib/typescript/ui/components/Header.d.ts +24 -0
  192. package/lib/typescript/ui/components/Header.d.ts.map +1 -0
  193. package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -1
  194. package/lib/typescript/ui/components/index.d.ts +1 -0
  195. package/lib/typescript/ui/components/index.d.ts.map +1 -1
  196. package/lib/typescript/ui/components/internal/TextField.d.ts +31 -16
  197. package/lib/typescript/ui/components/internal/TextField.d.ts.map +1 -1
  198. package/lib/typescript/ui/context/OxyContext.d.ts +5 -2
  199. package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
  200. package/lib/typescript/ui/hooks/index.d.ts +1 -1
  201. package/lib/typescript/ui/hooks/index.d.ts.map +1 -1
  202. package/lib/typescript/ui/hooks/useFollow.d.ts +20 -0
  203. package/lib/typescript/ui/hooks/useFollow.d.ts.map +1 -1
  204. package/lib/typescript/ui/hooks/useSessionSocket.d.ts.map +1 -1
  205. package/lib/typescript/ui/navigation/OxyRouter.d.ts.map +1 -1
  206. package/lib/typescript/ui/navigation/types.d.ts +9 -2
  207. package/lib/typescript/ui/navigation/types.d.ts.map +1 -1
  208. package/lib/typescript/ui/screens/AccountOverviewScreen.d.ts.map +1 -1
  209. package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
  210. package/lib/typescript/ui/screens/AccountSwitcherScreen.d.ts.map +1 -1
  211. package/lib/typescript/ui/screens/AppInfoScreen.d.ts.map +1 -1
  212. package/lib/typescript/ui/screens/PaymentGatewayScreen.d.ts.map +1 -1
  213. package/lib/typescript/ui/screens/ProfileScreen.d.ts.map +1 -1
  214. package/lib/typescript/ui/screens/RecoverAccountScreen.d.ts +5 -1
  215. package/lib/typescript/ui/screens/RecoverAccountScreen.d.ts.map +1 -1
  216. package/lib/typescript/ui/screens/SessionManagementScreen.d.ts.map +1 -1
  217. package/lib/typescript/ui/screens/SignInScreen.d.ts.map +1 -1
  218. package/lib/typescript/ui/screens/UserLinksScreen.d.ts +15 -0
  219. package/lib/typescript/ui/screens/UserLinksScreen.d.ts.map +1 -0
  220. package/lib/typescript/ui/screens/internal/SignInPasswordStep.d.ts +1 -1
  221. package/lib/typescript/ui/screens/internal/SignInPasswordStep.d.ts.map +1 -1
  222. package/lib/typescript/ui/screens/internal/SignInUsernameStep.d.ts +0 -1
  223. package/lib/typescript/ui/screens/internal/SignInUsernameStep.d.ts.map +1 -1
  224. package/lib/typescript/ui/screens/internal/SignUpIdentityStep.d.ts.map +1 -1
  225. package/lib/typescript/ui/screens/internal/SignUpSecurityStep.d.ts.map +1 -1
  226. package/lib/typescript/ui/screens/karma/KarmaAboutScreen.d.ts.map +1 -1
  227. package/lib/typescript/ui/screens/karma/KarmaCenterScreen.d.ts.map +1 -1
  228. package/lib/typescript/ui/screens/karma/KarmaFAQScreen.d.ts.map +1 -1
  229. package/lib/typescript/ui/screens/karma/KarmaLeaderboardScreen.d.ts.map +1 -1
  230. package/lib/typescript/ui/screens/karma/KarmaRewardsScreen.d.ts.map +1 -1
  231. package/lib/typescript/ui/screens/karma/KarmaRulesScreen.d.ts.map +1 -1
  232. package/lib/typescript/ui/stores/authStore.d.ts +3 -1
  233. package/lib/typescript/ui/stores/authStore.d.ts.map +1 -1
  234. package/lib/typescript/ui/stores/followStore.d.ts +10 -0
  235. package/lib/typescript/ui/stores/followStore.d.ts.map +1 -1
  236. package/lib/typescript/ui/styles/authStyles.d.ts +326 -0
  237. package/lib/typescript/ui/styles/authStyles.d.ts.map +1 -0
  238. package/lib/typescript/ui/styles/index.d.ts +1 -0
  239. package/lib/typescript/ui/styles/index.d.ts.map +1 -1
  240. package/package.json +1 -4
  241. package/src/core/index.ts +195 -41
  242. package/src/index.ts +64 -4
  243. package/src/ui/components/Avatar.tsx +11 -5
  244. package/src/ui/components/FollowButton.tsx +95 -11
  245. package/src/ui/components/GroupedItem.tsx +57 -9
  246. package/src/ui/components/GroupedSection.tsx +12 -0
  247. package/src/ui/components/Header.tsx +405 -0
  248. package/src/ui/components/OxyProvider.tsx +37 -15
  249. package/src/ui/components/index.ts +1 -0
  250. package/src/ui/components/internal/GroupedPillButtons.tsx +1 -1
  251. package/src/ui/components/internal/TextField.md +436 -0
  252. package/src/ui/components/internal/TextField.tsx +720 -620
  253. package/src/ui/context/OxyContext.tsx +211 -195
  254. package/src/ui/hooks/index.ts +1 -1
  255. package/src/ui/hooks/useFollow.ts +63 -0
  256. package/src/ui/hooks/useSessionSocket.ts +5 -2
  257. package/src/ui/navigation/OxyRouter.tsx +11 -1
  258. package/src/ui/navigation/types.ts +10 -2
  259. package/src/ui/screens/AccountCenterScreen.tsx +5 -5
  260. package/src/ui/screens/AccountManagementDemo.tsx +9 -9
  261. package/src/ui/screens/AccountOverviewScreen.tsx +265 -414
  262. package/src/ui/screens/AccountSettingsScreen.tsx +1173 -403
  263. package/src/ui/screens/AccountSwitcherScreen.tsx +158 -202
  264. package/src/ui/screens/AppInfoScreen.tsx +270 -497
  265. package/src/ui/screens/FeedbackScreen.tsx +3 -3
  266. package/src/ui/screens/PaymentGatewayScreen.tsx +668 -365
  267. package/src/ui/screens/ProfileScreen.tsx +196 -33
  268. package/src/ui/screens/RecoverAccountScreen.tsx +46 -74
  269. package/src/ui/screens/SessionManagementScreen.tsx +14 -22
  270. package/src/ui/screens/SignInScreen.tsx +27 -294
  271. package/src/ui/screens/SignUpScreen.tsx +5 -5
  272. package/src/ui/screens/UserLinksScreen.tsx +96 -0
  273. package/src/ui/screens/internal/SignInPasswordStep.tsx +11 -22
  274. package/src/ui/screens/internal/SignInUsernameStep.tsx +3 -10
  275. package/src/ui/screens/internal/SignUpIdentityStep.tsx +2 -5
  276. package/src/ui/screens/internal/SignUpSecurityStep.tsx +3 -4
  277. package/src/ui/screens/karma/KarmaAboutScreen.tsx +9 -2
  278. package/src/ui/screens/karma/KarmaCenterScreen.tsx +1 -20
  279. package/src/ui/screens/karma/KarmaFAQScreen.tsx +40 -24
  280. package/src/ui/screens/karma/KarmaLeaderboardScreen.tsx +9 -3
  281. package/src/ui/screens/karma/KarmaRewardsScreen.tsx +9 -3
  282. package/src/ui/screens/karma/KarmaRulesScreen.tsx +9 -3
  283. package/src/ui/stores/authStore.ts +34 -7
  284. package/src/ui/stores/followStore.ts +102 -1
  285. package/src/ui/styles/authStyles.ts +352 -0
  286. package/src/ui/styles/index.ts +1 -0
  287. package/lib/commonjs/core/auth-manager.js +0 -440
  288. package/lib/commonjs/core/auth-manager.js.map +0 -1
  289. package/lib/commonjs/core/use-auth.js +0 -244
  290. package/lib/commonjs/core/use-auth.js.map +0 -1
  291. package/lib/module/core/auth-manager.js +0 -432
  292. package/lib/module/core/auth-manager.js.map +0 -1
  293. package/lib/module/core/use-auth.js +0 -235
  294. package/lib/module/core/use-auth.js.map +0 -1
  295. package/lib/typescript/core/auth-manager.d.ts +0 -136
  296. package/lib/typescript/core/auth-manager.d.ts.map +0 -1
  297. package/lib/typescript/core/use-auth.d.ts +0 -79
  298. package/lib/typescript/core/use-auth.d.ts.map +0 -1
  299. package/src/__tests__/middleware.test.ts +0 -105
  300. package/src/__tests__/setup.ts +0 -10
  301. package/src/__tests__/zero-config-auth.test.ts +0 -607
  302. package/src/core/auth-manager.ts +0 -500
  303. package/src/core/use-auth.tsx +0 -245
@@ -1,500 +0,0 @@
1
- /**
2
- * Zero-Config Authentication Manager
3
- *
4
- * This module provides automatic token management, session handling,
5
- * and seamless authentication for Oxy services.
6
- */
7
-
8
- import axios, { AxiosInstance, AxiosError, InternalAxiosRequestConfig } from 'axios';
9
- import { jwtDecode } from 'jwt-decode';
10
- import AsyncStorage from '@react-native-async-storage/async-storage';
11
-
12
- interface AuthTokens {
13
- accessToken: string;
14
- refreshToken: string;
15
- }
16
-
17
- interface JwtPayload {
18
- exp: number;
19
- userId: string;
20
- username: string;
21
- [key: string]: any;
22
- }
23
-
24
- interface AuthState {
25
- isAuthenticated: boolean;
26
- user: any | null;
27
- tokens: AuthTokens | null;
28
- }
29
-
30
- interface LoginCredentials {
31
- username: string;
32
- password: string;
33
- }
34
-
35
- interface LoginResponse {
36
- success: boolean;
37
- accessToken: string;
38
- refreshToken: string;
39
- user: any;
40
- message?: string; // Make message optional
41
- }
42
-
43
- export class AuthenticationManager {
44
- private client: AxiosInstance;
45
- private tokens: AuthTokens | null = null;
46
- private user: any | null = null;
47
- private refreshPromise: Promise<AuthTokens> | null = null;
48
- private listeners: ((state: AuthState) => void)[] = [];
49
- private storageKey = '@oxy/auth-tokens';
50
-
51
- constructor(baseURL: string) {
52
- this.client = axios.create({
53
- baseURL,
54
- timeout: 15000,
55
- withCredentials: true, // Enable cookies for session management
56
- });
57
-
58
- this.setupInterceptors();
59
- this.initializeFromStorage();
60
- }
61
-
62
- /**
63
- * Setup axios interceptors for automatic token management
64
- */
65
- private setupInterceptors(): void {
66
- // Request interceptor - automatically add auth headers
67
- this.client.interceptors.request.use(
68
- async (config: InternalAxiosRequestConfig) => {
69
- // Skip auth for login/signup endpoints
70
- if (this.isPublicEndpoint(config.url || '')) {
71
- return config;
72
- }
73
-
74
- // Ensure we have a valid token
75
- await this.ensureValidToken();
76
-
77
- // Add authorization header if we have a token
78
- if (this.tokens?.accessToken) {
79
- config.headers = config.headers || {};
80
- config.headers.Authorization = `Bearer ${this.tokens.accessToken}`;
81
- }
82
-
83
- return config;
84
- },
85
- (error) => Promise.reject(error)
86
- );
87
-
88
- // Response interceptor - handle token expiration and auto-retry
89
- this.client.interceptors.response.use(
90
- (response) => response,
91
- async (error: AxiosError) => {
92
- const originalRequest = error.config as InternalAxiosRequestConfig & { _retry?: boolean };
93
-
94
- // If it's a 401 and we haven't already retried, attempt token refresh
95
- if (
96
- error.response?.status === 401 &&
97
- !originalRequest._retry &&
98
- this.tokens?.refreshToken &&
99
- !this.isPublicEndpoint(originalRequest?.url || '')
100
- ) {
101
- originalRequest._retry = true;
102
-
103
- try {
104
- await this.refreshTokens();
105
-
106
- // Retry original request with new token
107
- if (originalRequest && this.tokens?.accessToken) {
108
- originalRequest.headers = originalRequest.headers || {};
109
- originalRequest.headers.Authorization = `Bearer ${this.tokens.accessToken}`;
110
- return this.client(originalRequest);
111
- }
112
- } catch (refreshError) {
113
- // Refresh failed, clear tokens and notify listeners
114
- await this.logout();
115
- return Promise.reject(error);
116
- }
117
- }
118
-
119
- // For non-auth errors or failed retries, reject with formatted error
120
- return Promise.reject(this.formatError(error));
121
- }
122
- );
123
- }
124
-
125
- /**
126
- * Check if endpoint is public (doesn't require authentication)
127
- */
128
- private isPublicEndpoint(url: string): boolean {
129
- const publicPaths = [
130
- '/auth/login',
131
- '/auth/signup',
132
- '/auth/register',
133
- '/auth/check-username',
134
- '/auth/check-email',
135
- '/health',
136
- '/'
137
- ];
138
-
139
- return publicPaths.some(path => url.includes(path));
140
- }
141
-
142
- /**
143
- * Initialize authentication state from persistent storage
144
- */
145
- private async initializeFromStorage(): Promise<void> {
146
- try {
147
- const storedData = await AsyncStorage.getItem(this.storageKey);
148
- if (storedData) {
149
- const tokens = JSON.parse(storedData) as AuthTokens;
150
-
151
- // Validate that tokens haven't expired
152
- if (await this.validateStoredTokens(tokens)) {
153
- this.tokens = tokens;
154
- await this.fetchCurrentUser();
155
- this.notifyStateChange();
156
- } else {
157
- // Tokens expired, clear storage
158
- await AsyncStorage.removeItem(this.storageKey);
159
- }
160
- }
161
- } catch (error) {
162
- console.warn('[OxyAuth] Failed to initialize from storage:', error);
163
- await AsyncStorage.removeItem(this.storageKey);
164
- }
165
- }
166
-
167
- /**
168
- * Validate stored tokens without making network calls if possible
169
- */
170
- private async validateStoredTokens(tokens: AuthTokens): Promise<boolean> {
171
- try {
172
- // First check if access token is expired
173
- const decoded = jwtDecode<JwtPayload>(tokens.accessToken);
174
- const now = Math.floor(Date.now() / 1000);
175
-
176
- // If access token is still valid, we're good
177
- if (decoded.exp > now + 60) { // 60 second buffer
178
- return true;
179
- }
180
-
181
- // Access token expired, try refresh token
182
- const refreshDecoded = jwtDecode<JwtPayload>(tokens.refreshToken);
183
- return refreshDecoded.exp > now;
184
- } catch {
185
- return false;
186
- }
187
- }
188
-
189
- /**
190
- * Ensure we have a valid access token
191
- */
192
- private async ensureValidToken(): Promise<void> {
193
- if (!this.tokens?.accessToken) {
194
- return;
195
- }
196
-
197
- try {
198
- const decoded = jwtDecode<JwtPayload>(this.tokens.accessToken);
199
- const now = Math.floor(Date.now() / 1000);
200
-
201
- // Refresh if token expires within 5 minutes
202
- if (decoded.exp - now < 300) {
203
- await this.refreshTokens();
204
- }
205
- } catch (error) {
206
- console.warn('[OxyAuth] Token validation error:', error);
207
- // If token is malformed, try refresh
208
- if (this.tokens?.refreshToken) {
209
- await this.refreshTokens();
210
- }
211
- }
212
- }
213
-
214
- /**
215
- * Login with credentials
216
- */
217
- async login(credentials: LoginCredentials): Promise<LoginResponse> {
218
- try {
219
- const response = await this.client.post('/auth/login', credentials);
220
- const loginData = response.data as LoginResponse;
221
-
222
- if (loginData.success && loginData.accessToken && loginData.refreshToken) {
223
- await this.setTokens({
224
- accessToken: loginData.accessToken,
225
- refreshToken: loginData.refreshToken,
226
- });
227
-
228
- this.user = loginData.user;
229
- this.notifyStateChange();
230
-
231
- return loginData;
232
- } else {
233
- throw new Error(loginData.message || 'Login failed');
234
- }
235
- } catch (error) {
236
- throw this.formatError(error);
237
- }
238
- }
239
-
240
- /**
241
- * Register new user
242
- */
243
- async register(userData: { username: string; email: string; password: string }): Promise<LoginResponse> {
244
- try {
245
- const response = await this.client.post('/auth/register', userData);
246
- const registerData = response.data as LoginResponse;
247
-
248
- if (registerData.success && registerData.accessToken && registerData.refreshToken) {
249
- await this.setTokens({
250
- accessToken: registerData.accessToken,
251
- refreshToken: registerData.refreshToken,
252
- });
253
-
254
- this.user = registerData.user;
255
- this.notifyStateChange();
256
-
257
- return registerData;
258
- } else {
259
- throw new Error(registerData.message || 'Registration failed');
260
- }
261
- } catch (error) {
262
- throw this.formatError(error);
263
- }
264
- }
265
-
266
- /**
267
- * Logout user and clear all tokens
268
- */
269
- async logout(): Promise<void> {
270
- // Attempt server-side logout if we have tokens
271
- if (this.tokens?.refreshToken) {
272
- try {
273
- await this.client.post('/auth/logout', {
274
- refreshToken: this.tokens.refreshToken,
275
- });
276
- } catch (error) {
277
- console.warn('[OxyAuth] Server logout failed:', error);
278
- }
279
- }
280
-
281
- // Clear local state
282
- this.tokens = null;
283
- this.user = null;
284
-
285
- // Clear storage
286
- try {
287
- await AsyncStorage.removeItem(this.storageKey);
288
- } catch (error) {
289
- console.warn('[OxyAuth] Failed to clear storage:', error);
290
- }
291
-
292
- this.notifyStateChange();
293
- }
294
-
295
- /**
296
- * Refresh access token using refresh token
297
- */
298
- private async refreshTokens(): Promise<AuthTokens> {
299
- if (!this.tokens?.refreshToken) {
300
- throw new Error('No refresh token available');
301
- }
302
-
303
- // If refresh is already in progress, return that promise
304
- if (this.refreshPromise) {
305
- return this.refreshPromise;
306
- }
307
-
308
- this.refreshPromise = this.performTokenRefresh();
309
-
310
- try {
311
- const newTokens = await this.refreshPromise;
312
- this.refreshPromise = null;
313
- return newTokens;
314
- } catch (error) {
315
- this.refreshPromise = null;
316
- throw error;
317
- }
318
- }
319
-
320
- /**
321
- * Perform the actual token refresh
322
- */
323
- private async performTokenRefresh(): Promise<AuthTokens> {
324
- try {
325
- const response = await this.client.post('/auth/refresh', {
326
- refreshToken: this.tokens!.refreshToken,
327
- });
328
-
329
- const newTokens: AuthTokens = {
330
- accessToken: response.data.accessToken,
331
- refreshToken: response.data.refreshToken,
332
- };
333
-
334
- await this.setTokens(newTokens);
335
- return newTokens;
336
- } catch (error) {
337
- // Refresh failed, clear all tokens
338
- await this.logout();
339
- throw this.formatError(error);
340
- }
341
- }
342
-
343
- /**
344
- * Set tokens and persist to storage
345
- */
346
- private async setTokens(newTokens: AuthTokens): Promise<void> {
347
- this.tokens = newTokens;
348
-
349
- try {
350
- await AsyncStorage.setItem(this.storageKey, JSON.stringify(newTokens));
351
- } catch (error) {
352
- console.warn('[OxyAuth] Failed to persist tokens:', error);
353
- }
354
- }
355
-
356
- /**
357
- * Fetch current user profile
358
- */
359
- private async fetchCurrentUser(): Promise<void> {
360
- try {
361
- const response = await this.client.get('/auth/me');
362
- this.user = response.data.data || response.data;
363
- } catch (error) {
364
- console.warn('[OxyAuth] Failed to fetch current user:', error);
365
- // Don't throw here, we can still function without user profile
366
- }
367
- }
368
-
369
- /**
370
- * Get current authentication state
371
- */
372
- getAuthState(): AuthState {
373
- return {
374
- isAuthenticated: !!(this.tokens?.accessToken),
375
- user: this.user,
376
- tokens: this.tokens,
377
- };
378
- }
379
-
380
- /**
381
- * Get current user (loads if not cached)
382
- */
383
- async getCurrentUser(): Promise<any> {
384
- if (!this.tokens?.accessToken) {
385
- throw new Error('Not authenticated');
386
- }
387
-
388
- if (!this.user) {
389
- await this.fetchCurrentUser();
390
- }
391
-
392
- return this.user;
393
- }
394
-
395
- /**
396
- * Subscribe to authentication state changes
397
- */
398
- onAuthStateChange(callback: (state: AuthState) => void): () => void {
399
- this.listeners.push(callback);
400
-
401
- // Immediately call with current state
402
- callback(this.getAuthState());
403
-
404
- // Return unsubscribe function
405
- return () => {
406
- this.listeners = this.listeners.filter(listener => listener !== callback);
407
- };
408
- }
409
-
410
- /**
411
- * Notify all listeners of state changes
412
- */
413
- private notifyStateChange(): void {
414
- const state = this.getAuthState();
415
- this.listeners.forEach(listener => {
416
- try {
417
- listener(state);
418
- } catch (error) {
419
- console.error('[OxyAuth] Listener error:', error);
420
- }
421
- });
422
- }
423
-
424
- /**
425
- * Format error responses consistently
426
- */
427
- private formatError(error: any): Error {
428
- if (error?.response?.data?.message) {
429
- return new Error(error.response.data.message);
430
- }
431
-
432
- if (error?.message) {
433
- return new Error(error.message);
434
- }
435
-
436
- return new Error('An unexpected error occurred');
437
- }
438
-
439
- /**
440
- * Get authenticated HTTP client for making API calls
441
- */
442
- getClient(): AxiosInstance {
443
- return this.client;
444
- }
445
-
446
- /**
447
- * Check username availability
448
- */
449
- async checkUsernameAvailability(username: string): Promise<{ available: boolean; message: string }> {
450
- try {
451
- const response = await this.client.get(`/auth/check-username/${encodeURIComponent(username)}`);
452
- return response.data;
453
- } catch (error) {
454
- const axiosError = error as AxiosError;
455
- if (axiosError?.response?.status === 400) {
456
- return (axiosError.response as any).data;
457
- }
458
- throw this.formatError(error);
459
- }
460
- }
461
-
462
- /**
463
- * Check email availability
464
- */
465
- async checkEmailAvailability(email: string): Promise<{ available: boolean; message: string }> {
466
- try {
467
- const response = await this.client.post('/auth/check-email', { email });
468
- return response.data;
469
- } catch (error) {
470
- const axiosError = error as AxiosError;
471
- if (axiosError?.response?.status === 400) {
472
- return (axiosError.response as any).data;
473
- }
474
- throw this.formatError(error);
475
- }
476
- }
477
- }
478
-
479
- // Global auth manager instance
480
- let globalAuthManager: AuthenticationManager | null = null;
481
-
482
- /**
483
- * Initialize global authentication manager
484
- */
485
- export function initializeAuth(baseURL: string): AuthenticationManager {
486
- if (!globalAuthManager) {
487
- globalAuthManager = new AuthenticationManager(baseURL);
488
- }
489
- return globalAuthManager;
490
- }
491
-
492
- /**
493
- * Get global authentication manager instance
494
- */
495
- export function getAuthManager(): AuthenticationManager {
496
- if (!globalAuthManager) {
497
- throw new Error('Authentication manager not initialized. Call initializeAuth() first.');
498
- }
499
- return globalAuthManager;
500
- }