@oxyhq/services 5.7.5 → 5.8.1

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 (239) 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 +88 -29
  5. package/lib/commonjs/index.js.map +1 -1
  6. package/lib/commonjs/node/createAuth.js +585 -7
  7. package/lib/commonjs/node/createAuth.js.map +1 -1
  8. package/lib/commonjs/node/index.js +38 -1
  9. package/lib/commonjs/node/index.js.map +1 -1
  10. package/lib/commonjs/ui/components/Avatar.js +15 -6
  11. package/lib/commonjs/ui/components/Avatar.js.map +1 -1
  12. package/lib/commonjs/ui/components/GroupedItem.js +58 -13
  13. package/lib/commonjs/ui/components/GroupedItem.js.map +1 -1
  14. package/lib/commonjs/ui/components/GroupedSection.js +7 -1
  15. package/lib/commonjs/ui/components/GroupedSection.js.map +1 -1
  16. package/lib/commonjs/ui/components/Header.js +322 -0
  17. package/lib/commonjs/ui/components/Header.js.map +1 -0
  18. package/lib/commonjs/ui/components/OxyProvider.js +23 -7
  19. package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
  20. package/lib/commonjs/ui/components/index.js +7 -0
  21. package/lib/commonjs/ui/components/index.js.map +1 -1
  22. package/lib/commonjs/ui/components/internal/GroupedPillButtons.js +1 -1
  23. package/lib/commonjs/ui/components/internal/GroupedPillButtons.js.map +1 -1
  24. package/lib/commonjs/ui/components/internal/TextField.js +606 -546
  25. package/lib/commonjs/ui/components/internal/TextField.js.map +1 -1
  26. package/lib/commonjs/ui/components/internal/TextField.md +436 -0
  27. package/lib/commonjs/ui/context/OxyContext.js +122 -78
  28. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  29. package/lib/commonjs/ui/hooks/useSessionSocket.js +5 -2
  30. package/lib/commonjs/ui/hooks/useSessionSocket.js.map +1 -1
  31. package/lib/commonjs/ui/navigation/OxyRouter.js +1 -1
  32. package/lib/commonjs/ui/navigation/OxyRouter.js.map +1 -1
  33. package/lib/commonjs/ui/screens/AccountCenterScreen.js +6 -6
  34. package/lib/commonjs/ui/screens/AccountCenterScreen.js.map +1 -1
  35. package/lib/commonjs/ui/screens/AccountManagementDemo.js +3 -3
  36. package/lib/commonjs/ui/screens/AccountManagementDemo.js.map +1 -1
  37. package/lib/commonjs/ui/screens/AccountOverviewScreen.js +241 -598
  38. package/lib/commonjs/ui/screens/AccountOverviewScreen.js.map +1 -1
  39. package/lib/commonjs/ui/screens/AccountSettingsScreen.js +1151 -406
  40. package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
  41. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +135 -237
  42. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -1
  43. package/lib/commonjs/ui/screens/AppInfoScreen.js +246 -463
  44. package/lib/commonjs/ui/screens/AppInfoScreen.js.map +1 -1
  45. package/lib/commonjs/ui/screens/FeedbackScreen.js +3 -3
  46. package/lib/commonjs/ui/screens/FeedbackScreen.js.map +1 -1
  47. package/lib/commonjs/ui/screens/PaymentGatewayScreen.js +808 -650
  48. package/lib/commonjs/ui/screens/PaymentGatewayScreen.js.map +1 -1
  49. package/lib/commonjs/ui/screens/RecoverAccountScreen.js +51 -72
  50. package/lib/commonjs/ui/screens/RecoverAccountScreen.js.map +1 -1
  51. package/lib/commonjs/ui/screens/SessionManagementScreen.js +11 -29
  52. package/lib/commonjs/ui/screens/SessionManagementScreen.js.map +1 -1
  53. package/lib/commonjs/ui/screens/SignInScreen.js +30 -303
  54. package/lib/commonjs/ui/screens/SignInScreen.js.map +1 -1
  55. package/lib/commonjs/ui/screens/SignUpScreen.js +4 -4
  56. package/lib/commonjs/ui/screens/SignUpScreen.js.map +1 -1
  57. package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js +19 -31
  58. package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js.map +1 -1
  59. package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js +7 -10
  60. package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js.map +1 -1
  61. package/lib/commonjs/ui/screens/internal/SignUpIdentityStep.js +11 -5
  62. package/lib/commonjs/ui/screens/internal/SignUpIdentityStep.js.map +1 -1
  63. package/lib/commonjs/ui/screens/internal/SignUpSecurityStep.js +11 -4
  64. package/lib/commonjs/ui/screens/internal/SignUpSecurityStep.js.map +1 -1
  65. package/lib/commonjs/ui/stores/authStore.js +12 -0
  66. package/lib/commonjs/ui/stores/authStore.js.map +1 -1
  67. package/lib/commonjs/ui/styles/authStyles.js +337 -0
  68. package/lib/commonjs/ui/styles/authStyles.js.map +1 -0
  69. package/lib/commonjs/ui/styles/index.js +11 -0
  70. package/lib/commonjs/ui/styles/index.js.map +1 -1
  71. package/lib/module/core/index.js +177 -41
  72. package/lib/module/core/index.js.map +1 -1
  73. package/lib/module/index.js +26 -4
  74. package/lib/module/index.js.map +1 -1
  75. package/lib/module/node/createAuth.js +584 -7
  76. package/lib/module/node/createAuth.js.map +1 -1
  77. package/lib/module/node/index.js +7 -1
  78. package/lib/module/node/index.js.map +1 -1
  79. package/lib/module/ui/components/Avatar.js +15 -6
  80. package/lib/module/ui/components/Avatar.js.map +1 -1
  81. package/lib/module/ui/components/GroupedItem.js +59 -14
  82. package/lib/module/ui/components/GroupedItem.js.map +1 -1
  83. package/lib/module/ui/components/GroupedSection.js +7 -1
  84. package/lib/module/ui/components/GroupedSection.js.map +1 -1
  85. package/lib/module/ui/components/Header.js +317 -0
  86. package/lib/module/ui/components/Header.js.map +1 -0
  87. package/lib/module/ui/components/OxyProvider.js +25 -9
  88. package/lib/module/ui/components/OxyProvider.js.map +1 -1
  89. package/lib/module/ui/components/index.js +1 -0
  90. package/lib/module/ui/components/index.js.map +1 -1
  91. package/lib/module/ui/components/internal/GroupedPillButtons.js +1 -1
  92. package/lib/module/ui/components/internal/GroupedPillButtons.js.map +1 -1
  93. package/lib/module/ui/components/internal/TextField.js +607 -547
  94. package/lib/module/ui/components/internal/TextField.js.map +1 -1
  95. package/lib/module/ui/components/internal/TextField.md +436 -0
  96. package/lib/module/ui/context/OxyContext.js +121 -77
  97. package/lib/module/ui/context/OxyContext.js.map +1 -1
  98. package/lib/module/ui/hooks/useSessionSocket.js +5 -2
  99. package/lib/module/ui/hooks/useSessionSocket.js.map +1 -1
  100. package/lib/module/ui/navigation/OxyRouter.js +1 -1
  101. package/lib/module/ui/navigation/OxyRouter.js.map +1 -1
  102. package/lib/module/ui/screens/AccountCenterScreen.js +6 -6
  103. package/lib/module/ui/screens/AccountCenterScreen.js.map +1 -1
  104. package/lib/module/ui/screens/AccountManagementDemo.js +3 -3
  105. package/lib/module/ui/screens/AccountManagementDemo.js.map +1 -1
  106. package/lib/module/ui/screens/AccountOverviewScreen.js +242 -597
  107. package/lib/module/ui/screens/AccountOverviewScreen.js.map +1 -1
  108. package/lib/module/ui/screens/AccountSettingsScreen.js +1152 -407
  109. package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
  110. package/lib/module/ui/screens/AccountSwitcherScreen.js +135 -237
  111. package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
  112. package/lib/module/ui/screens/AppInfoScreen.js +248 -465
  113. package/lib/module/ui/screens/AppInfoScreen.js.map +1 -1
  114. package/lib/module/ui/screens/FeedbackScreen.js +3 -3
  115. package/lib/module/ui/screens/FeedbackScreen.js.map +1 -1
  116. package/lib/module/ui/screens/PaymentGatewayScreen.js +809 -651
  117. package/lib/module/ui/screens/PaymentGatewayScreen.js.map +1 -1
  118. package/lib/module/ui/screens/RecoverAccountScreen.js +53 -74
  119. package/lib/module/ui/screens/RecoverAccountScreen.js.map +1 -1
  120. package/lib/module/ui/screens/SessionManagementScreen.js +11 -29
  121. package/lib/module/ui/screens/SessionManagementScreen.js.map +1 -1
  122. package/lib/module/ui/screens/SignInScreen.js +32 -305
  123. package/lib/module/ui/screens/SignInScreen.js.map +1 -1
  124. package/lib/module/ui/screens/SignUpScreen.js +5 -5
  125. package/lib/module/ui/screens/SignUpScreen.js.map +1 -1
  126. package/lib/module/ui/screens/internal/SignInPasswordStep.js +19 -31
  127. package/lib/module/ui/screens/internal/SignInPasswordStep.js.map +1 -1
  128. package/lib/module/ui/screens/internal/SignInUsernameStep.js +7 -10
  129. package/lib/module/ui/screens/internal/SignInUsernameStep.js.map +1 -1
  130. package/lib/module/ui/screens/internal/SignUpIdentityStep.js +11 -5
  131. package/lib/module/ui/screens/internal/SignUpIdentityStep.js.map +1 -1
  132. package/lib/module/ui/screens/internal/SignUpSecurityStep.js +11 -4
  133. package/lib/module/ui/screens/internal/SignUpSecurityStep.js.map +1 -1
  134. package/lib/module/ui/stores/authStore.js +12 -0
  135. package/lib/module/ui/stores/authStore.js.map +1 -1
  136. package/lib/module/ui/styles/authStyles.js +332 -0
  137. package/lib/module/ui/styles/authStyles.js.map +1 -0
  138. package/lib/module/ui/styles/index.js +1 -0
  139. package/lib/module/ui/styles/index.js.map +1 -1
  140. package/lib/typescript/core/index.d.ts +68 -24
  141. package/lib/typescript/core/index.d.ts.map +1 -1
  142. package/lib/typescript/index.d.ts +13 -3
  143. package/lib/typescript/index.d.ts.map +1 -1
  144. package/lib/typescript/node/createAuth.d.ts +112 -0
  145. package/lib/typescript/node/createAuth.d.ts.map +1 -1
  146. package/lib/typescript/node/index.d.ts +2 -0
  147. package/lib/typescript/node/index.d.ts.map +1 -1
  148. package/lib/typescript/ui/components/Avatar.d.ts.map +1 -1
  149. package/lib/typescript/ui/components/GroupedItem.d.ts +6 -0
  150. package/lib/typescript/ui/components/GroupedItem.d.ts.map +1 -1
  151. package/lib/typescript/ui/components/GroupedSection.d.ts +6 -0
  152. package/lib/typescript/ui/components/GroupedSection.d.ts.map +1 -1
  153. package/lib/typescript/ui/components/Header.d.ts +22 -0
  154. package/lib/typescript/ui/components/Header.d.ts.map +1 -0
  155. package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -1
  156. package/lib/typescript/ui/components/index.d.ts +1 -0
  157. package/lib/typescript/ui/components/index.d.ts.map +1 -1
  158. package/lib/typescript/ui/components/internal/TextField.d.ts +31 -16
  159. package/lib/typescript/ui/components/internal/TextField.d.ts.map +1 -1
  160. package/lib/typescript/ui/context/OxyContext.d.ts +5 -2
  161. package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
  162. package/lib/typescript/ui/hooks/useSessionSocket.d.ts.map +1 -1
  163. package/lib/typescript/ui/navigation/types.d.ts +9 -2
  164. package/lib/typescript/ui/navigation/types.d.ts.map +1 -1
  165. package/lib/typescript/ui/screens/AccountOverviewScreen.d.ts.map +1 -1
  166. package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
  167. package/lib/typescript/ui/screens/AccountSwitcherScreen.d.ts.map +1 -1
  168. package/lib/typescript/ui/screens/AppInfoScreen.d.ts.map +1 -1
  169. package/lib/typescript/ui/screens/PaymentGatewayScreen.d.ts.map +1 -1
  170. package/lib/typescript/ui/screens/RecoverAccountScreen.d.ts +5 -1
  171. package/lib/typescript/ui/screens/RecoverAccountScreen.d.ts.map +1 -1
  172. package/lib/typescript/ui/screens/SessionManagementScreen.d.ts.map +1 -1
  173. package/lib/typescript/ui/screens/SignInScreen.d.ts.map +1 -1
  174. package/lib/typescript/ui/screens/internal/SignInPasswordStep.d.ts +1 -1
  175. package/lib/typescript/ui/screens/internal/SignInPasswordStep.d.ts.map +1 -1
  176. package/lib/typescript/ui/screens/internal/SignInUsernameStep.d.ts +0 -1
  177. package/lib/typescript/ui/screens/internal/SignInUsernameStep.d.ts.map +1 -1
  178. package/lib/typescript/ui/screens/internal/SignUpIdentityStep.d.ts.map +1 -1
  179. package/lib/typescript/ui/screens/internal/SignUpSecurityStep.d.ts.map +1 -1
  180. package/lib/typescript/ui/stores/authStore.d.ts.map +1 -1
  181. package/lib/typescript/ui/styles/authStyles.d.ts +326 -0
  182. package/lib/typescript/ui/styles/authStyles.d.ts.map +1 -0
  183. package/lib/typescript/ui/styles/index.d.ts +1 -0
  184. package/lib/typescript/ui/styles/index.d.ts.map +1 -1
  185. package/package.json +1 -4
  186. package/src/core/index.ts +195 -41
  187. package/src/index.ts +72 -4
  188. package/src/node/createAuth.ts +623 -7
  189. package/src/node/index.ts +19 -1
  190. package/src/ui/components/Avatar.tsx +11 -5
  191. package/src/ui/components/GroupedItem.tsx +57 -9
  192. package/src/ui/components/GroupedSection.tsx +12 -0
  193. package/src/ui/components/Header.tsx +364 -0
  194. package/src/ui/components/OxyProvider.tsx +31 -15
  195. package/src/ui/components/index.ts +1 -0
  196. package/src/ui/components/internal/GroupedPillButtons.tsx +1 -1
  197. package/src/ui/components/internal/TextField.md +436 -0
  198. package/src/ui/components/internal/TextField.tsx +720 -620
  199. package/src/ui/context/OxyContext.tsx +150 -63
  200. package/src/ui/hooks/useSessionSocket.ts +5 -2
  201. package/src/ui/navigation/OxyRouter.tsx +1 -1
  202. package/src/ui/navigation/types.ts +10 -2
  203. package/src/ui/screens/AccountCenterScreen.tsx +5 -5
  204. package/src/ui/screens/AccountManagementDemo.tsx +9 -9
  205. package/src/ui/screens/AccountOverviewScreen.tsx +265 -414
  206. package/src/ui/screens/AccountSettingsScreen.tsx +1165 -403
  207. package/src/ui/screens/AccountSwitcherScreen.tsx +158 -202
  208. package/src/ui/screens/AppInfoScreen.tsx +270 -497
  209. package/src/ui/screens/FeedbackScreen.tsx +3 -3
  210. package/src/ui/screens/PaymentGatewayScreen.tsx +668 -365
  211. package/src/ui/screens/ProfileScreen.tsx +5 -5
  212. package/src/ui/screens/RecoverAccountScreen.tsx +46 -74
  213. package/src/ui/screens/SessionManagementScreen.tsx +14 -22
  214. package/src/ui/screens/SignInScreen.tsx +27 -294
  215. package/src/ui/screens/SignUpScreen.tsx +5 -5
  216. package/src/ui/screens/internal/SignInPasswordStep.tsx +11 -22
  217. package/src/ui/screens/internal/SignInUsernameStep.tsx +3 -10
  218. package/src/ui/screens/internal/SignUpIdentityStep.tsx +2 -5
  219. package/src/ui/screens/internal/SignUpSecurityStep.tsx +3 -4
  220. package/src/ui/stores/authStore.ts +12 -0
  221. package/src/ui/styles/authStyles.ts +352 -0
  222. package/src/ui/styles/index.ts +1 -0
  223. package/lib/commonjs/core/auth-manager.js +0 -440
  224. package/lib/commonjs/core/auth-manager.js.map +0 -1
  225. package/lib/commonjs/core/use-auth.js +0 -244
  226. package/lib/commonjs/core/use-auth.js.map +0 -1
  227. package/lib/module/core/auth-manager.js +0 -432
  228. package/lib/module/core/auth-manager.js.map +0 -1
  229. package/lib/module/core/use-auth.js +0 -235
  230. package/lib/module/core/use-auth.js.map +0 -1
  231. package/lib/typescript/core/auth-manager.d.ts +0 -136
  232. package/lib/typescript/core/auth-manager.d.ts.map +0 -1
  233. package/lib/typescript/core/use-auth.d.ts +0 -79
  234. package/lib/typescript/core/use-auth.d.ts.map +0 -1
  235. package/src/__tests__/middleware.test.ts +0 -105
  236. package/src/__tests__/setup.ts +0 -10
  237. package/src/__tests__/zero-config-auth.test.ts +0 -607
  238. package/src/core/auth-manager.ts +0 -500
  239. package/src/core/use-auth.tsx +0 -245
@@ -1,6 +1,6 @@
1
- import React, { createContext, useContext, useEffect, useCallback, ReactNode, useMemo } from 'react';
1
+ import React, { createContext, useContext, useEffect, useCallback, ReactNode, useMemo, useRef, useState } from 'react';
2
2
  import { OxyServices } from '../../core';
3
- import { User } from '../../models/interfaces';
3
+ import { User, ApiError } from '../../models/interfaces';
4
4
  import { SecureLoginResponse, SecureClientSession, MinimalUserData } from '../../models/secureSession';
5
5
  import { DeviceManager } from '../../utils/deviceManager';
6
6
  import { useSessionSocket } from '../hooks/useSessionSocket';
@@ -49,9 +49,11 @@ const OxyContext = createContext<OxyContextState | null>(null);
49
49
  // Props for the OxyContextProvider
50
50
  export interface OxyContextProviderProps {
51
51
  children: ReactNode;
52
- oxyServices: OxyServices;
52
+ oxyServices?: OxyServices; // Now optional - will be created automatically if not provided
53
+ baseURL?: string; // New: API base URL for automatic service creation
53
54
  storageKeyPrefix?: string;
54
55
  onAuthStateChange?: (user: User | null) => void;
56
+ onError?: (error: ApiError) => void; // New: Error callback
55
57
  bottomSheetRef?: React.RefObject<any>;
56
58
  }
57
59
 
@@ -114,13 +116,30 @@ const getSecureStorageKeys = (prefix = 'oxy_secure') => ({
114
116
  activeSessionId: `${prefix}_active_session_id`, // ID of currently active session
115
117
  });
116
118
 
117
- export const OxyContextProvider: React.FC<OxyContextProviderProps> = ({
119
+ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
118
120
  children,
119
- oxyServices,
121
+ oxyServices: providedOxyServices,
122
+ baseURL,
120
123
  storageKeyPrefix = 'oxy_secure',
121
124
  onAuthStateChange,
125
+ onError,
122
126
  bottomSheetRef,
123
127
  }) => {
128
+ // Create oxyServices automatically if not provided
129
+ const oxyServicesRef = useRef<OxyServices | null>(null);
130
+
131
+ if (!oxyServicesRef.current) {
132
+ if (providedOxyServices) {
133
+ oxyServicesRef.current = providedOxyServices;
134
+ } else if (baseURL) {
135
+ oxyServicesRef.current = new OxyServices({ baseURL });
136
+ } else {
137
+ throw new Error('Either oxyServices or baseURL must be provided to OxyContextProvider');
138
+ }
139
+ }
140
+
141
+ const oxyServices = oxyServicesRef.current;
142
+
124
143
  // Zustand state
125
144
  const user = useAuthStore((state) => state.user);
126
145
  const isAuthenticated = useAuthStore((state) => state.isAuthenticated);
@@ -259,25 +278,7 @@ export const OxyContextProvider: React.FC<OxyContextProviderProps> = ({
259
278
  }
260
279
  }, [storage, oxyServices, keys, onAuthStateChange]);
261
280
 
262
- // Effect to restore token on app load or session switch
263
- useEffect(() => {
264
- const restoreToken = async () => {
265
- if (activeSessionId && oxyServices) {
266
- try {
267
- await oxyServices.getTokenBySession(activeSessionId);
268
- setTokenReady(true);
269
- } catch (err) {
270
- // If token restoration fails, force logout
271
- await logout();
272
- setTokenReady(false);
273
- }
274
- } else {
275
- setTokenReady(true); // No session, so token is not needed
276
- }
277
- };
278
- restoreToken();
279
- // Only run when activeSessionId or oxyServices changes
280
- }, [activeSessionId, oxyServices]);
281
+
281
282
 
282
283
  // Remove invalid session
283
284
  const removeInvalidSession = useCallback(async (sessionId: string): Promise<void> => {
@@ -357,7 +358,7 @@ export const OxyContextProvider: React.FC<OxyContextProviderProps> = ({
357
358
  }, [oxyServices, onAuthStateChange, loginSuccess, saveActiveSessionId]);
358
359
 
359
360
  // Secure login method
360
- const login = async (username: string, password: string, deviceName?: string): Promise<User> => {
361
+ const login = useCallback(async (username: string, password: string, deviceName?: string): Promise<User> => {
361
362
  if (!storage) throw new Error('Storage not initialized');
362
363
  useAuthStore.setState({ isLoading: true, error: null });
363
364
 
@@ -439,10 +440,10 @@ export const OxyContextProvider: React.FC<OxyContextProviderProps> = ({
439
440
  } finally {
440
441
  useAuthStore.setState({ isLoading: false });
441
442
  }
442
- };
443
+ }, [storage, oxyServices, sessions, activeSessionId, saveSessionsToStorage, saveActiveSessionId, loginSuccess, setMinimalUser, onAuthStateChange, loginFailure]);
443
444
 
444
445
  // Logout method
445
- const logout = async (targetSessionId?: string): Promise<void> => {
446
+ const logout = useCallback(async (targetSessionId?: string): Promise<void> => {
446
447
  if (!activeSessionId) return;
447
448
 
448
449
  try {
@@ -475,10 +476,10 @@ export const OxyContextProvider: React.FC<OxyContextProviderProps> = ({
475
476
  console.error('Logout error:', error);
476
477
  useAuthStore.setState({ error: 'Logout failed' });
477
478
  }
478
- };
479
+ }, [activeSessionId, oxyServices, sessions, saveSessionsToStorage, switchToSession, logoutStore, setMinimalUser, storage, keys.activeSessionId, onAuthStateChange]);
479
480
 
480
481
  // Logout all sessions
481
- const logoutAll = async (): Promise<void> => {
482
+ const logoutAll = useCallback(async (): Promise<void> => {
482
483
  console.log('logoutAll called with activeSessionId:', activeSessionId);
483
484
 
484
485
  if (!activeSessionId) {
@@ -515,10 +516,30 @@ export const OxyContextProvider: React.FC<OxyContextProviderProps> = ({
515
516
  useAuthStore.setState({ error: `Logout all failed: ${error instanceof Error ? error.message : 'Unknown error'}` });
516
517
  throw error;
517
518
  }
518
- };
519
+ }, [activeSessionId, oxyServices, logoutStore, setMinimalUser, clearAllStorage, onAuthStateChange]);
520
+
521
+ // Effect to restore token on app load or session switch
522
+ useEffect(() => {
523
+ const restoreToken = async () => {
524
+ if (activeSessionId && oxyServices) {
525
+ try {
526
+ await oxyServices.getTokenBySession(activeSessionId);
527
+ setTokenReady(true);
528
+ } catch (err) {
529
+ // If token restoration fails, force logout
530
+ await logout();
531
+ setTokenReady(false);
532
+ }
533
+ } else {
534
+ setTokenReady(true); // No session, so token is not needed
535
+ }
536
+ };
537
+ restoreToken();
538
+ // Only run when activeSessionId or oxyServices changes
539
+ }, [activeSessionId, oxyServices, logout]);
519
540
 
520
541
  // Sign up method
521
- const signUp = async (username: string, email: string, password: string): Promise<User> => {
542
+ const signUp = useCallback(async (username: string, email: string, password: string): Promise<User> => {
522
543
  if (!storage) throw new Error('Storage not initialized');
523
544
 
524
545
  useAuthStore.setState({ isLoading: true, error: null });
@@ -540,42 +561,83 @@ export const OxyContextProvider: React.FC<OxyContextProviderProps> = ({
540
561
  } finally {
541
562
  useAuthStore.setState({ isLoading: false });
542
563
  }
543
- };
564
+ }, [storage, oxyServices, login, loginFailure]);
544
565
 
545
566
  // Switch session method
546
- const switchSession = async (sessionId: string): Promise<void> => {
567
+ const switchSession = useCallback(async (sessionId: string): Promise<void> => {
547
568
  await switchToSession(sessionId);
548
- };
569
+ }, [switchToSession]);
549
570
 
550
571
  // Remove session method
551
- const removeSession = async (sessionId: string): Promise<void> => {
572
+ const removeSession = useCallback(async (sessionId: string): Promise<void> => {
552
573
  await logout(sessionId);
553
- };
574
+ }, [logout]);
554
575
 
555
576
  // Refresh sessions method
556
- const refreshSessions = async (): Promise<void> => {
557
- if (!activeSessionId) return;
577
+ const refreshSessions = useCallback(async (): Promise<void> => {
578
+ console.log('refreshSessions called with activeSessionId:', activeSessionId);
579
+
580
+ if (!activeSessionId) {
581
+ console.log('refreshSessions: No activeSessionId, returning');
582
+ return;
583
+ }
558
584
 
559
585
  try {
586
+ console.log('refreshSessions: Calling getSessionsBySessionId...');
560
587
  const serverSessions = await oxyServices.getSessionsBySessionId(activeSessionId);
588
+ console.log('refreshSessions: Server sessions received:', serverSessions);
561
589
 
562
590
  // Update local sessions with server data
563
591
  const updatedSessions: SecureClientSession[] = serverSessions.map(serverSession => ({
564
592
  sessionId: serverSession.sessionId,
565
593
  deviceId: serverSession.deviceId,
566
- expiresAt: new Date().toISOString(), // You might want to get this from server
567
- lastActive: new Date().toISOString()
594
+ expiresAt: serverSession.expiresAt || new Date().toISOString(),
595
+ lastActive: serverSession.lastActive || new Date().toISOString(),
596
+ userId: serverSession.userId || user?.id
568
597
  }));
569
598
 
599
+ console.log('refreshSessions: Updated sessions:', updatedSessions);
570
600
  setSessions(updatedSessions);
571
601
  await saveSessionsToStorage(updatedSessions);
602
+ console.log('refreshSessions: Sessions saved to storage');
572
603
  } catch (error) {
573
604
  console.error('Refresh sessions error:', error);
605
+
606
+ // If the current session is invalid, try to find another valid session
607
+ if (sessions.length > 1) {
608
+ console.log('Current session invalid, trying to switch to another session...');
609
+ const otherSessions = sessions.filter(s => s.sessionId !== activeSessionId);
610
+
611
+ for (const session of otherSessions) {
612
+ try {
613
+ // Try to validate this session
614
+ await oxyServices.validateSession(session.sessionId);
615
+ console.log('Found valid session, switching to:', session.sessionId);
616
+ await switchToSession(session.sessionId);
617
+ return; // Successfully switched to another session
618
+ } catch (sessionError) {
619
+ console.log('Session validation failed for:', session.sessionId, sessionError);
620
+ continue; // Try next session
621
+ }
622
+ }
623
+ }
624
+
625
+ // If no valid sessions found, clear all sessions
626
+ console.log('No valid sessions found, clearing all sessions');
627
+ setSessions([]);
628
+ setActiveSessionId(null);
629
+ logoutStore();
630
+ setMinimalUser(null);
631
+ await clearAllStorage();
632
+
633
+ if (onAuthStateChange) {
634
+ onAuthStateChange(null);
635
+ }
574
636
  }
575
- };
637
+ }, [activeSessionId, oxyServices, user?.id, sessions, saveSessionsToStorage, switchToSession, logoutStore, setMinimalUser, clearAllStorage, onAuthStateChange]);
576
638
 
577
639
  // Device management methods
578
- const getDeviceSessions = async (): Promise<any[]> => {
640
+ const getDeviceSessions = useCallback(async (): Promise<any[]> => {
579
641
  if (!activeSessionId) throw new Error('No active session');
580
642
 
581
643
  try {
@@ -584,9 +646,9 @@ export const OxyContextProvider: React.FC<OxyContextProviderProps> = ({
584
646
  console.error('Get device sessions error:', error);
585
647
  throw error;
586
648
  }
587
- };
649
+ }, [activeSessionId, oxyServices]);
588
650
 
589
- const logoutAllDeviceSessions = async (): Promise<void> => {
651
+ const logoutAllDeviceSessions = useCallback(async (): Promise<void> => {
590
652
  if (!activeSessionId) throw new Error('No active session');
591
653
 
592
654
  try {
@@ -606,9 +668,9 @@ export const OxyContextProvider: React.FC<OxyContextProviderProps> = ({
606
668
  console.error('Logout all device sessions error:', error);
607
669
  throw error;
608
670
  }
609
- };
671
+ }, [activeSessionId, oxyServices, logoutStore, setMinimalUser, clearAllStorage, onAuthStateChange]);
610
672
 
611
- const updateDeviceName = async (deviceName: string): Promise<void> => {
673
+ const updateDeviceName = useCallback(async (deviceName: string): Promise<void> => {
612
674
  if (!activeSessionId) throw new Error('No active session');
613
675
 
614
676
  try {
@@ -620,7 +682,7 @@ export const OxyContextProvider: React.FC<OxyContextProviderProps> = ({
620
682
  console.error('Update device name error:', error);
621
683
  throw error;
622
684
  }
623
- };
685
+ }, [activeSessionId, oxyServices]);
624
686
 
625
687
  // Bottom sheet control methods
626
688
  const showBottomSheet = useCallback((screenOrConfig?: string | { screen: string; props?: Record<string, any> }) => {
@@ -638,6 +700,7 @@ export const OxyContextProvider: React.FC<OxyContextProviderProps> = ({
638
700
  bottomSheetRef.current.present();
639
701
  } else {
640
702
  console.warn('No expand or present method available on bottomSheetRef');
703
+ console.log('Available methods on bottomSheetRef.current:', Object.keys(bottomSheetRef.current));
641
704
  }
642
705
 
643
706
  // Then navigate to the specified screen if provided
@@ -657,6 +720,8 @@ export const OxyContextProvider: React.FC<OxyContextProviderProps> = ({
657
720
  }
658
721
  } else {
659
722
  console.warn('bottomSheetRef is not available');
723
+ console.warn('To fix this, ensure you pass a bottomSheetRef to OxyProvider:');
724
+ console.warn('<OxyProvider baseURL="..." bottomSheetRef={yourBottomSheetRef}>');
660
725
  }
661
726
  }, [bottomSheetRef]);
662
727
 
@@ -672,16 +737,38 @@ export const OxyContextProvider: React.FC<OxyContextProviderProps> = ({
672
737
  userId: user?.id,
673
738
  activeSessionId,
674
739
  refreshSessions,
675
- logout: () => logout(),
740
+ logout,
676
741
  baseURL: oxyServices.getBaseURL(),
677
- onRemoteSignOut: () => {
742
+ onRemoteSignOut: useCallback(() => {
678
743
  toast.info('You have been signed out remotely.');
679
744
  logout();
680
- },
745
+ }, [logout]),
681
746
  });
682
747
 
683
748
  // Context value
684
- const contextValue: OxyContextState = {
749
+ const contextValue: OxyContextState = useMemo(() => ({
750
+ user,
751
+ minimalUser,
752
+ sessions,
753
+ activeSessionId,
754
+ isAuthenticated,
755
+ isLoading,
756
+ error,
757
+ login,
758
+ logout,
759
+ logoutAll,
760
+ signUp,
761
+ switchSession,
762
+ removeSession,
763
+ refreshSessions,
764
+ getDeviceSessions,
765
+ logoutAllDeviceSessions,
766
+ updateDeviceName,
767
+ oxyServices,
768
+ bottomSheetRef,
769
+ showBottomSheet,
770
+ hideBottomSheet,
771
+ }), [
685
772
  user,
686
773
  minimalUser,
687
774
  sessions,
@@ -691,22 +778,19 @@ export const OxyContextProvider: React.FC<OxyContextProviderProps> = ({
691
778
  error,
692
779
  login,
693
780
  logout,
694
- logoutAll: async () => { await logout(); },
695
- signUp: async (username, email, password) => {
696
- await signUp(username, email, password);
697
- return user as User; // Return the latest user from Zustand
698
- },
699
- switchSession: async (sessionId) => { await switchToSession(sessionId); },
700
- removeSession: async (sessionId) => { await removeSession(sessionId); },
701
- refreshSessions: async () => { await refreshSessions(); },
702
- getDeviceSessions: async () => { return await getDeviceSessions(); },
703
- logoutAllDeviceSessions: async () => { await logoutAllDeviceSessions(); },
704
- updateDeviceName: async (deviceName) => { await updateDeviceName(deviceName); },
781
+ logoutAll,
782
+ signUp,
783
+ switchSession,
784
+ removeSession,
785
+ refreshSessions,
786
+ getDeviceSessions,
787
+ logoutAllDeviceSessions,
788
+ updateDeviceName,
705
789
  oxyServices,
706
790
  bottomSheetRef,
707
791
  showBottomSheet,
708
792
  hideBottomSheet,
709
- };
793
+ ]);
710
794
 
711
795
  // Wrap children rendering to block until token is ready
712
796
  if (!tokenReady) {
@@ -720,6 +804,9 @@ export const OxyContextProvider: React.FC<OxyContextProviderProps> = ({
720
804
  );
721
805
  };
722
806
 
807
+ // Alias for backward compatibility
808
+ export const OxyContextProvider = OxyProvider;
809
+
723
810
  // Hook to use the context
724
811
  export const useOxy = (): OxyContextState => {
725
812
  const context = useContext(OxyContext);
@@ -33,12 +33,15 @@ export function useSessionSocket({ userId, activeSessionId, refreshSessions, log
33
33
 
34
34
  socket.on('session_update', (data: { type: string; sessionId: string }) => {
35
35
  console.log('Received session_update:', data);
36
+
37
+ // Always refresh sessions to get the latest state
38
+ refreshSessions();
39
+
40
+ // If the current session was logged out, handle it specially
36
41
  if (data.sessionId === activeSessionId) {
37
42
  if (onRemoteSignOut) onRemoteSignOut();
38
43
  else toast.info('You have been signed out remotely.');
39
44
  logout();
40
- } else {
41
- refreshSessions();
42
45
  }
43
46
  });
44
47
 
@@ -57,7 +57,7 @@ const routes: Record<string, RouteConfig> = {
57
57
  component: AccountOverviewScreen,
58
58
  snapPoints: ['60%', '85%'],
59
59
  },
60
- AccountSettings: {
60
+ EditProfile: {
61
61
  component: AccountSettingsScreen,
62
62
  snapPoints: ['60%', '100%'],
63
63
  },
@@ -13,6 +13,9 @@ export interface BaseScreenProps {
13
13
  onAuthenticated?: (user: User) => void;
14
14
  theme: 'light' | 'dark';
15
15
  containerWidth?: number;
16
+ initialStep?: number;
17
+ username?: string;
18
+ userProfile?: any;
16
19
  }
17
20
 
18
21
  /**
@@ -42,9 +45,14 @@ export interface OxyRouterProps {
42
45
  */
43
46
  export interface OxyProviderProps {
44
47
  /**
45
- * Instance of OxyServices
48
+ * Instance of OxyServices (optional if baseURL is provided)
46
49
  */
47
- oxyServices: OxyServices;
50
+ oxyServices?: OxyServices;
51
+
52
+ /**
53
+ * API base URL for automatic service creation (optional if oxyServices is provided)
54
+ */
55
+ baseURL?: string;
48
56
 
49
57
  /**
50
58
  * Initial screen to display
@@ -81,7 +81,7 @@ const AccountCenterScreen: React.FC<BaseScreenProps> = ({
81
81
  <ProfileCard
82
82
  user={user}
83
83
  theme={theme}
84
- onEditPress={() => navigate('AccountSettings', { activeTab: 'profile' })}
84
+ onEditPress={() => navigate('EditProfile', { activeTab: 'profile' })}
85
85
  onClosePress={onClose}
86
86
  showCloseButton={!!onClose}
87
87
  />
@@ -93,7 +93,7 @@ const AccountCenterScreen: React.FC<BaseScreenProps> = ({
93
93
  <QuickActions
94
94
  actions={[
95
95
  { id: 'overview', icon: 'person-circle', iconColor: '#007AFF', title: 'Overview', onPress: () => navigate('AccountOverview') },
96
- { id: 'settings', icon: 'settings', iconColor: '#5856D6', title: 'Settings', onPress: () => navigate('AccountSettings') },
96
+ { id: 'settings', icon: 'settings', iconColor: '#5856D6', title: 'Edit Profile', onPress: () => navigate('EditProfile') },
97
97
  { id: 'sessions', icon: 'shield-checkmark', iconColor: '#30D158', title: 'Sessions', onPress: () => navigate('SessionManagement') },
98
98
  { id: 'premium', icon: 'star', iconColor: '#FFD700', title: 'Premium', onPress: () => navigate('PremiumSubscription') },
99
99
  ...(user?.isPremium ? [{ id: 'billing', icon: 'card', iconColor: '#34C759', title: 'Billing', onPress: () => navigate('') }] : []),
@@ -119,9 +119,9 @@ const AccountCenterScreen: React.FC<BaseScreenProps> = ({
119
119
  id: 'settings',
120
120
  icon: 'settings',
121
121
  iconColor: '#5856D6',
122
- title: 'Account Settings',
123
- subtitle: 'Manage your preferences',
124
- onPress: () => navigate('AccountSettings'),
122
+ title: 'Edit Profile',
123
+ subtitle: 'Manage your profile and preferences',
124
+ onPress: () => navigate('EditProfile'),
125
125
  },
126
126
  {
127
127
  id: 'sessions',
@@ -30,7 +30,7 @@ const AccountManagementDemo: React.FC = () => {
30
30
  'Multi-account switching',
31
31
  'Session management access'
32
32
  ]}
33
- navigatesTo={['AccountOverview', 'AccountSwitcher', 'AccountSettings', 'SessionManagement']}
33
+ navigatesTo={['AccountOverview', 'AccountSwitcher', 'EditProfile', 'SessionManagement']}
34
34
  />
35
35
 
36
36
  <ScreenCard
@@ -42,11 +42,11 @@ const AccountManagementDemo: React.FC = () => {
42
42
  'Subscription management',
43
43
  'Privacy and security overview'
44
44
  ]}
45
- navigatesTo={['AccountSettings', 'SessionManagement']}
45
+ navigatesTo={['EditProfile', 'SessionManagement']}
46
46
  />
47
47
 
48
48
  <ScreenCard
49
- title="AccountSettingsScreen"
49
+ title="EditProfileScreen"
50
50
  description="Complete account configuration and preferences"
51
51
  features={[
52
52
  'Profile editing (username, email, name)',
@@ -90,22 +90,22 @@ const AccountManagementDemo: React.FC = () => {
90
90
  <Text style={styles.flowDescription}>
91
91
  The screens are designed with intuitive navigation patterns:
92
92
  </Text>
93
-
93
+
94
94
  <View style={styles.flowItem}>
95
95
  <Text style={styles.flowStep}>1. Entry Point</Text>
96
96
  <Text style={styles.flowText}>Users typically start at AccountCenterScreen</Text>
97
97
  </View>
98
-
98
+
99
99
  <View style={styles.flowItem}>
100
100
  <Text style={styles.flowStep}>2. Explore</Text>
101
101
  <Text style={styles.flowText}>Navigate to specific screens based on needs</Text>
102
102
  </View>
103
-
103
+
104
104
  <View style={styles.flowItem}>
105
105
  <Text style={styles.flowStep}>3. Manage</Text>
106
106
  <Text style={styles.flowText}>Perform account actions in specialized screens</Text>
107
107
  </View>
108
-
108
+
109
109
  <View style={styles.flowItem}>
110
110
  <Text style={styles.flowStep}>4. Return</Text>
111
111
  <Text style={styles.flowText}>Navigate back or to related screens seamlessly</Text>
@@ -142,12 +142,12 @@ const ScreenCard: React.FC<{
142
142
  <View style={styles.screenCard}>
143
143
  <Text style={styles.screenTitle}>{title}</Text>
144
144
  <Text style={styles.screenDescription}>{description}</Text>
145
-
145
+
146
146
  <Text style={styles.featuresTitle}>Features:</Text>
147
147
  {features.map((feature, index) => (
148
148
  <Text key={index} style={styles.feature}>• {feature}</Text>
149
149
  ))}
150
-
150
+
151
151
  <Text style={styles.navigationTitle}>Navigates to:</Text>
152
152
  {navigatesTo.map((nav, index) => (
153
153
  <Text key={index} style={styles.navigationItem}>→ {nav}</Text>