@oxyhq/services 5.6.10 → 5.7.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.
@@ -138,6 +138,18 @@ export const OxyContextProvider: React.FC<OxyContextProviderProps> = ({
138
138
  // Add a new state to track token restoration
139
139
  const [tokenReady, setTokenReady] = React.useState(false);
140
140
 
141
+ // Add refs to prevent duplicate API calls
142
+ const initAuthRef = React.useRef(false);
143
+ const tokenRestoreRef = React.useRef(false);
144
+
145
+ // Development warning about React StrictMode
146
+ React.useEffect(() => {
147
+ if (__DEV__) {
148
+ console.log('🔍 OxyContext: React StrictMode may cause effects to run twice in development');
149
+ console.log('🔍 This is normal and helps detect side effects. Production builds will not have this behavior.');
150
+ }
151
+ }, []);
152
+
141
153
  // Storage keys (memoized to prevent infinite loops)
142
154
  const keys = useMemo(() => getSecureStorageKeys(storageKeyPrefix), [storageKeyPrefix]);
143
155
 
@@ -159,8 +171,12 @@ export const OxyContextProvider: React.FC<OxyContextProviderProps> = ({
159
171
  // Effect to initialize authentication state
160
172
  useEffect(() => {
161
173
  const initAuth = async () => {
162
- if (!storage) return;
174
+ if (!storage || initAuthRef.current) return;
175
+
176
+ // Prevent multiple simultaneous initializations
177
+ if (isLoading) return;
163
178
 
179
+ initAuthRef.current = true;
164
180
  useAuthStore.setState({ isLoading: true });
165
181
  try {
166
182
  // Load stored sessions
@@ -254,15 +270,16 @@ export const OxyContextProvider: React.FC<OxyContextProviderProps> = ({
254
270
  }
255
271
  };
256
272
 
257
- if (storage) {
273
+ if (storage && !isLoading) {
258
274
  initAuth();
259
275
  }
260
- }, [storage, oxyServices, keys, onAuthStateChange]);
276
+ }, [storage, oxyServices, keys.sessions, keys.activeSessionId]); // Removed onAuthStateChange from deps
261
277
 
262
- // Effect to restore token on app load or session switch
278
+ // Effect to restore token on app load or session switch - with proper guards
263
279
  useEffect(() => {
264
280
  const restoreToken = async () => {
265
- if (activeSessionId && oxyServices) {
281
+ if (activeSessionId && oxyServices && !tokenReady && !tokenRestoreRef.current) {
282
+ tokenRestoreRef.current = true;
266
283
  try {
267
284
  await oxyServices.getTokenBySession(activeSessionId);
268
285
  setTokenReady(true);
@@ -271,13 +288,16 @@ export const OxyContextProvider: React.FC<OxyContextProviderProps> = ({
271
288
  await logout();
272
289
  setTokenReady(false);
273
290
  }
274
- } else {
291
+ } else if (!activeSessionId && !tokenReady) {
275
292
  setTokenReady(true); // No session, so token is not needed
276
293
  }
277
294
  };
278
- restoreToken();
279
- // Only run when activeSessionId or oxyServices changes
280
- }, [activeSessionId, oxyServices]);
295
+
296
+ // Only run if we haven't already set tokenReady
297
+ if (!tokenReady) {
298
+ restoreToken();
299
+ }
300
+ }, [activeSessionId, oxyServices, tokenReady]); // Added tokenReady to prevent re-runs
281
301
 
282
302
  // Remove invalid session
283
303
  const removeInvalidSession = useCallback(async (sessionId: string): Promise<void> => {
@@ -13,9 +13,10 @@ interface UseSessionSocketProps {
13
13
 
14
14
  export function useSessionSocket({ userId, activeSessionId, refreshSessions, logout, baseURL, onRemoteSignOut }: UseSessionSocketProps) {
15
15
  const socketRef = useRef<any>(null);
16
+ const connectedRef = useRef(false);
16
17
 
17
18
  useEffect(() => {
18
- if (!userId || !baseURL) return;
19
+ if (!userId || !baseURL || connectedRef.current) return;
19
20
 
20
21
  if (!socketRef.current) {
21
22
  socketRef.current = io(baseURL, {
@@ -26,6 +27,7 @@ export function useSessionSocket({ userId, activeSessionId, refreshSessions, log
26
27
 
27
28
  socket.on('connect', () => {
28
29
  console.log('Socket connected:', socket.id);
30
+ connectedRef.current = true;
29
31
  });
30
32
 
31
33
  socket.emit('join', { userId: `user:${userId}` });
@@ -43,6 +45,7 @@ export function useSessionSocket({ userId, activeSessionId, refreshSessions, log
43
45
  });
44
46
 
45
47
  return () => {
48
+ connectedRef.current = false;
46
49
  socket.emit('leave', { userId: `user:${userId}` });
47
50
  socket.off('session_update');
48
51
  };