@oxyhq/services 5.5.5 → 5.5.7

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 (32) hide show
  1. package/lib/commonjs/core/AuthManager.js +378 -0
  2. package/lib/commonjs/core/AuthManager.js.map +1 -0
  3. package/lib/commonjs/core/index.js +13 -2
  4. package/lib/commonjs/core/index.js.map +1 -1
  5. package/lib/commonjs/ui/context/OxyContext.js +87 -456
  6. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  7. package/lib/commonjs/ui/hooks/useAuthFetch.js +36 -58
  8. package/lib/commonjs/ui/hooks/useAuthFetch.js.map +1 -1
  9. package/lib/commonjs/ui/screens/SessionManagementScreen.js.map +1 -1
  10. package/lib/module/core/AuthManager.js +373 -0
  11. package/lib/module/core/AuthManager.js.map +1 -0
  12. package/lib/module/core/index.js +6 -2
  13. package/lib/module/core/index.js.map +1 -1
  14. package/lib/module/ui/context/OxyContext.js +87 -456
  15. package/lib/module/ui/context/OxyContext.js.map +1 -1
  16. package/lib/module/ui/hooks/useAuthFetch.js +36 -58
  17. package/lib/module/ui/hooks/useAuthFetch.js.map +1 -1
  18. package/lib/module/ui/screens/SessionManagementScreen.js.map +1 -1
  19. package/lib/typescript/core/AuthManager.d.ts +100 -0
  20. package/lib/typescript/core/AuthManager.d.ts.map +1 -0
  21. package/lib/typescript/core/index.d.ts +6 -2
  22. package/lib/typescript/core/index.d.ts.map +1 -1
  23. package/lib/typescript/ui/context/OxyContext.d.ts +7 -10
  24. package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
  25. package/lib/typescript/ui/hooks/useAuthFetch.d.ts +4 -9
  26. package/lib/typescript/ui/hooks/useAuthFetch.d.ts.map +1 -1
  27. package/package.json +1 -1
  28. package/src/core/AuthManager.ts +389 -0
  29. package/src/core/index.ts +7 -2
  30. package/src/ui/context/OxyContext.tsx +99 -508
  31. package/src/ui/hooks/useAuthFetch.ts +37 -55
  32. package/src/ui/screens/SessionManagementScreen.tsx +9 -9
@@ -1,33 +1,23 @@
1
1
  /**
2
- * Zero Config Authenticated Fetch Hook
2
+ * Simplified Authenticated Fetch Hook
3
3
  *
4
- * Simple hook that provides fetch-like API with automatic authentication
5
- * Leverages the existing useOxy hook and OxyProvider infrastructure
6
- *
7
- * Usage:
8
- * const authFetch = useAuthFetch();
9
- * const response = await authFetch('/api/protected');
10
- * const data = await authFetch.get('/api/users');
4
+ * Clean, professional hook that uses the centralized AuthManager
5
+ * No more duplicate authentication logic or race conditions
11
6
  */
12
7
 
13
8
  import { useCallback } from 'react';
14
9
  import { useOxy } from '../context/OxyContext';
15
10
 
16
11
  export interface AuthFetchOptions extends Omit<RequestInit, 'body'> {
17
- body?: any; // Allow any type for body, we'll JSON.stringify if needed
12
+ body?: any;
18
13
  }
19
14
 
20
15
  export interface AuthFetchAPI {
21
- // Main fetch function (drop-in replacement)
22
16
  (input: RequestInfo | URL, init?: AuthFetchOptions): Promise<Response>;
23
-
24
- // Convenience methods for JSON APIs
25
17
  get: (endpoint: string, options?: AuthFetchOptions) => Promise<any>;
26
18
  post: (endpoint: string, data?: any, options?: AuthFetchOptions) => Promise<any>;
27
19
  put: (endpoint: string, data?: any, options?: AuthFetchOptions) => Promise<any>;
28
20
  delete: (endpoint: string, options?: AuthFetchOptions) => Promise<any>;
29
-
30
- // Access to auth state and methods
31
21
  isAuthenticated: boolean;
32
22
  user: any;
33
23
  login: (username: string, password: string) => Promise<any>;
@@ -37,39 +27,41 @@ export interface AuthFetchAPI {
37
27
 
38
28
  /**
39
29
  * Hook that provides authenticated fetch functionality
40
- * Uses the existing OxyServices instance from useOxy context
30
+ * Uses the centralized AuthManager for all authentication operations
41
31
  */
42
32
  export function useAuthFetch(): AuthFetchAPI {
43
- const { oxyServices, isAuthenticated, user, login, logout, signUp, activeSessionId } = useOxy();
33
+ const { authManager, isAuthenticated, user, login, logout, signUp } = useOxy();
34
+
35
+ console.log('[useAuthFetch] Hook initialized');
36
+ console.log('[useAuthFetch] authManager:', !!authManager);
37
+ console.log('[useAuthFetch] isAuthenticated:', isAuthenticated);
38
+ console.log('[useAuthFetch] user:', !!user);
44
39
 
45
- // Main fetch function with automatic auth headers
46
40
  const authFetch = useCallback(async (input: RequestInfo | URL, init?: AuthFetchOptions): Promise<Response> => {
47
- const url = resolveURL(input, oxyServices.getBaseURL());
48
- const options = await addAuthHeaders(init, oxyServices, activeSessionId || undefined, isAuthenticated);
41
+ const url = resolveURL(input, authManager.getBaseURL());
42
+ const options = await addAuthHeaders(init, authManager);
49
43
 
50
44
  try {
51
45
  let response = await fetch(url, options);
52
46
 
53
47
  // Handle token expiry and automatic refresh
54
48
  if (response.status === 401 && isAuthenticated) {
55
- // Try to refresh token and retry
56
49
  try {
57
- await oxyServices.refreshTokens();
58
- const retryOptions = await addAuthHeaders(init, oxyServices, activeSessionId || undefined, isAuthenticated);
50
+ await authManager.refreshToken();
51
+ const retryOptions = await addAuthHeaders(init, authManager);
59
52
  response = await fetch(url, retryOptions);
60
53
  } catch (refreshError) {
61
- // Refresh failed, user needs to login again
62
- console.warn('Token refresh failed, user needs to re-authenticate');
54
+ console.warn('[AuthFetch] Token refresh failed:', refreshError);
63
55
  throw new Error('Authentication expired. Please login again.');
64
56
  }
65
57
  }
66
58
 
67
59
  return response;
68
60
  } catch (error) {
69
- console.error('AuthFetch error:', error);
61
+ console.error('[AuthFetch] Request failed:', error);
70
62
  throw error;
71
63
  }
72
- }, [oxyServices, activeSessionId, isAuthenticated]);
64
+ }, [authManager, isAuthenticated]);
73
65
 
74
66
  // JSON convenience methods
75
67
  const get = useCallback(async (endpoint: string, options?: AuthFetchOptions) => {
@@ -108,7 +100,7 @@ export function useAuthFetch(): AuthFetchAPI {
108
100
  return handleJsonResponse(response);
109
101
  }, [authFetch]);
110
102
 
111
- // Attach convenience methods and auth state to the main function
103
+ // Attach convenience methods and auth state
112
104
  const fetchWithMethods = authFetch as AuthFetchAPI;
113
105
  fetchWithMethods.get = get;
114
106
  fetchWithMethods.post = post;
@@ -124,62 +116,53 @@ export function useAuthFetch(): AuthFetchAPI {
124
116
  }
125
117
 
126
118
  /**
127
- * Helper functions
119
+ * Helper functions - much simpler now
128
120
  */
129
121
 
130
122
  function resolveURL(input: RequestInfo | URL, baseURL: string): string {
131
123
  const url = input.toString();
132
124
 
133
- // If it's already a full URL, return as is
134
125
  if (url.startsWith('http://') || url.startsWith('https://')) {
135
126
  return url;
136
127
  }
137
128
 
138
- // If it starts with /, it's relative to base URL
139
129
  if (url.startsWith('/')) {
140
130
  return `${baseURL}${url}`;
141
131
  }
142
132
 
143
- // Otherwise, append to base URL with /
144
133
  return `${baseURL}/${url}`;
145
134
  }
146
135
 
147
- async function addAuthHeaders(init?: AuthFetchOptions, oxyServices?: any, activeSessionId?: string, isAuthenticated?: boolean): Promise<RequestInit> {
136
+ async function addAuthHeaders(init?: AuthFetchOptions, authManager?: any): Promise<RequestInit> {
148
137
  const headers = new Headers(init?.headers);
149
138
 
150
- // Debug logging
151
- console.log('[Auth API Debug] isAuthenticated:', isAuthenticated, 'activeSessionId:', activeSessionId, 'oxyServices:', !!oxyServices);
139
+ console.log('[AuthFetch] addAuthHeaders called');
140
+ console.log('[AuthFetch] Has authManager:', !!authManager);
141
+ console.log('[AuthFetch] AuthManager type:', typeof authManager);
142
+ console.log('[AuthFetch] Has Authorization header already:', headers.has('Authorization'));
152
143
 
153
- // Add auth header if user is authenticated (use context state instead of getCurrentUserId)
154
- if (isAuthenticated && oxyServices && !headers.has('Authorization')) {
144
+ if (authManager && !headers.has('Authorization')) {
155
145
  try {
156
- // First try to get regular JWT access token
157
- let accessToken = oxyServices.getAccessToken?.();
158
- console.log('[Auth API Debug] JWT accessToken from getAccessToken():', !!accessToken);
146
+ console.log('[AuthFetch] AuthManager.isAuthenticated():', authManager.isAuthenticated());
159
147
 
160
- // If no JWT token but we have a secure session, try to get token from session
161
- if (!accessToken && activeSessionId) {
162
- console.log('[Auth API] No JWT token, trying to get token from secure session:', activeSessionId);
163
- try {
164
- const tokenData = await oxyServices.getTokenBySession(activeSessionId);
165
- accessToken = tokenData.accessToken;
166
- console.log('[Auth API] Got token from session successfully');
167
- } catch (error) {
168
- console.warn('[Auth API] Failed to get token from session:', error);
169
- }
170
- }
148
+ const accessToken = await authManager.getAccessToken();
149
+ console.log('[AuthFetch] Got access token:', !!accessToken);
171
150
 
172
151
  if (accessToken) {
173
152
  headers.set('Authorization', `Bearer ${accessToken}`);
174
- console.log('[Auth API] Added Authorization header successfully');
153
+ console.log('[AuthFetch] Added Authorization header successfully');
154
+ } else if (authManager.isAuthenticated()) {
155
+ console.error('[AuthFetch] User is authenticated but no token available');
156
+ throw new Error('Authentication state inconsistent. Please login again.');
175
157
  } else {
176
- console.warn('[Auth API] No authentication token available - JWT token:', !!oxyServices.getAccessToken?.(), 'activeSessionId:', activeSessionId);
158
+ console.log('[AuthFetch] User not authenticated, skipping auth header');
177
159
  }
178
160
  } catch (error) {
179
- console.error('[Auth API] Error getting access token:', error);
161
+ console.error('[AuthFetch] Failed to get access token:', error);
162
+ throw error;
180
163
  }
181
164
  } else {
182
- console.warn('[Auth API] Cannot authenticate - isAuthenticated:', isAuthenticated, 'oxyServices:', !!oxyServices, 'hasAuthHeader:', headers.has('Authorization'));
165
+ console.log('[AuthFetch] Skipping auth header - authManager:', !!authManager, 'hasAuthHeader:', headers.has('Authorization'));
183
166
  }
184
167
 
185
168
  const body = init?.body;
@@ -214,7 +197,6 @@ async function handleJsonResponse(response: Response): Promise<any> {
214
197
  try {
215
198
  return await response.json();
216
199
  } catch {
217
- // If response isn't JSON, return the response itself
218
200
  return response;
219
201
  }
220
202
  }
@@ -82,10 +82,10 @@ const SessionManagementScreen: React.FC<BaseScreenProps> = ({
82
82
  try {
83
83
  setActionLoading(sessionId);
84
84
  await logout(sessionId);
85
-
85
+
86
86
  // Refresh sessions to update the list
87
87
  await refreshSessions();
88
-
88
+
89
89
  toast.success('Session logged out successfully');
90
90
  } catch (error) {
91
91
  console.error('Logout session failed:', error);
@@ -100,8 +100,8 @@ const SessionManagementScreen: React.FC<BaseScreenProps> = ({
100
100
  };
101
101
 
102
102
  const handleLogoutOtherSessions = async () => {
103
- const otherSessionsCount = userSessions.filter(s => s.sessionId !== activeSessionId).length;
104
-
103
+ const otherSessionsCount = userSessions.filter((s: any) => s.sessionId !== activeSessionId).length;
104
+
105
105
  if (otherSessionsCount === 0) {
106
106
  toast.info('No other sessions to logout.');
107
107
  return;
@@ -124,10 +124,10 @@ const SessionManagementScreen: React.FC<BaseScreenProps> = ({
124
124
  await logout(session.sessionId);
125
125
  }
126
126
  }
127
-
127
+
128
128
  // Refresh sessions to update the list
129
129
  await refreshSessions();
130
-
130
+
131
131
  toast.success('Other sessions logged out successfully');
132
132
  } catch (error) {
133
133
  console.error('Logout other sessions failed:', error);
@@ -175,7 +175,7 @@ const SessionManagementScreen: React.FC<BaseScreenProps> = ({
175
175
  if (diffInMinutes < 60) return `${diffInMinutes}m ago`;
176
176
  if (diffInMinutes < 1440) return `${Math.floor(diffInMinutes / 60)}h ago`;
177
177
  if (diffInMinutes < 10080) return `${Math.floor(diffInMinutes / 1440)}d ago`;
178
-
178
+
179
179
  return date.toLocaleDateString();
180
180
  };
181
181
 
@@ -230,7 +230,7 @@ const SessionManagementScreen: React.FC<BaseScreenProps> = ({
230
230
  >
231
231
  {userSessions.length > 0 ? (
232
232
  <>
233
- {userSessions.map((session) => (
233
+ {userSessions.map((session: any) => (
234
234
  <View
235
235
  key={session.sessionId}
236
236
  style={[
@@ -294,7 +294,7 @@ const SessionManagementScreen: React.FC<BaseScreenProps> = ({
294
294
  <TouchableOpacity
295
295
  style={[styles.bulkActionButton, { backgroundColor: isDarkTheme ? '#1A1A1A' : '#F0F0F0', borderColor }]}
296
296
  onPress={handleLogoutOtherSessions}
297
- disabled={actionLoading === 'others' || userSessions.filter(s => s.sessionId !== activeSessionId).length === 0}
297
+ disabled={actionLoading === 'others' || userSessions.filter((s: any) => s.sessionId !== activeSessionId).length === 0}
298
298
  >
299
299
  {actionLoading === 'others' ? (
300
300
  <ActivityIndicator size="small" color={primaryColor} />