@oxyhq/services 5.16.27 → 5.16.29

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 (28) hide show
  1. package/lib/commonjs/crypto/keyManager.js +3 -0
  2. package/lib/commonjs/crypto/keyManager.js.map +1 -1
  3. package/lib/commonjs/ui/context/OxyContext.js +70 -16
  4. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  5. package/lib/commonjs/ui/hooks/useTransferQueries.js +6 -58
  6. package/lib/commonjs/ui/hooks/useTransferQueries.js.map +1 -1
  7. package/lib/commonjs/ui/stores/transferStore.js +1 -9
  8. package/lib/commonjs/ui/stores/transferStore.js.map +1 -1
  9. package/lib/module/crypto/keyManager.js +3 -0
  10. package/lib/module/crypto/keyManager.js.map +1 -1
  11. package/lib/module/ui/context/OxyContext.js +70 -16
  12. package/lib/module/ui/context/OxyContext.js.map +1 -1
  13. package/lib/module/ui/hooks/useTransferQueries.js +5 -57
  14. package/lib/module/ui/hooks/useTransferQueries.js.map +1 -1
  15. package/lib/module/ui/stores/transferStore.js +0 -7
  16. package/lib/module/ui/stores/transferStore.js.map +1 -1
  17. package/lib/typescript/crypto/keyManager.d.ts +2 -1
  18. package/lib/typescript/crypto/keyManager.d.ts.map +1 -1
  19. package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
  20. package/lib/typescript/ui/hooks/useTransferQueries.d.ts +5 -15
  21. package/lib/typescript/ui/hooks/useTransferQueries.d.ts.map +1 -1
  22. package/lib/typescript/ui/stores/transferStore.d.ts +0 -4
  23. package/lib/typescript/ui/stores/transferStore.d.ts.map +1 -1
  24. package/package.json +1 -1
  25. package/src/crypto/keyManager.ts +5 -1
  26. package/src/ui/context/OxyContext.tsx +67 -12
  27. package/src/ui/hooks/useTransferQueries.ts +10 -62
  28. package/src/ui/stores/transferStore.ts +0 -6
@@ -1,28 +1,18 @@
1
+ import type { OxyServices } from '../../core';
1
2
  /**
2
3
  * Query keys for transfer-related queries
3
4
  */
4
5
  export declare const transferQueryKeys: {
5
- all: readonly ["transfers"];
6
- completion: (transferId: string) => readonly ["transfers", "completion", string];
7
6
  pending: () => readonly ["transfers", "pending"];
8
7
  };
9
- /**
10
- * Hook to check if a transfer was completed
11
- * Only runs when authenticated and transferId is provided
12
- */
13
- export declare const useCheckTransferCompletion: (transferId: string | null, enabled?: boolean) => import("@tanstack/react-query").UseQueryResult<{
14
- completed: boolean;
15
- transferId?: string;
16
- sourceDeviceId?: string;
17
- publicKey?: string;
18
- transferCode?: string;
19
- completedAt?: string;
20
- } | null, any>;
21
8
  /**
22
9
  * Hook to check all pending transfers for completion
23
10
  * Used when app comes back online
11
+ *
12
+ * This version accepts oxyServices and isAuthenticated as parameters to avoid
13
+ * circular dependency when used inside OxyContext
24
14
  */
25
- export declare const useCheckPendingTransfers: () => import("@tanstack/react-query").UseQueryResult<{
15
+ export declare const useCheckPendingTransfers: (oxyServices?: OxyServices | null, isAuthenticated?: boolean) => import("@tanstack/react-query").UseQueryResult<{
26
16
  transferId: string;
27
17
  completed: boolean;
28
18
  data?: {
@@ -1 +1 @@
1
- {"version":3,"file":"useTransferQueries.d.ts","sourceRoot":"","sources":["../../../../src/ui/hooks/useTransferQueries.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,eAAO,MAAM,iBAAiB;;6BAEH,MAAM;;CAEhC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,0BAA0B,GAAI,YAAY,MAAM,GAAG,IAAI,EAAE,UAAS,OAAc;eAYxE,OAAO;iBACL,MAAM;qBACF,MAAM;gBACX,MAAM;mBACH,MAAM;kBACP,MAAM;cAgC7B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,wBAAwB;gBAajB,MAAM;eACP,OAAO;WACX;QACL,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB;WA2DR,CAAC"}
1
+ {"version":3,"file":"useTransferQueries.d.ts","sourceRoot":"","sources":["../../../../src/ui/hooks/useTransferQueries.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;GAEG;AACH,eAAO,MAAM,iBAAiB;;CAE7B,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,wBAAwB,GACnC,cAAc,WAAW,GAAG,IAAI,EAChC,kBAAkB,OAAO;gBAaP,MAAM;eACP,OAAO;WACX;QACL,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB;WA2DR,CAAC"}
@@ -32,8 +32,4 @@ export declare const useTransferCodesForPersistence: () => {
32
32
  transferCodes: Record<string, TransferCodeData>;
33
33
  activeTransferId: string | null;
34
34
  };
35
- /**
36
- * Hook to check if store has been restored
37
- */
38
- export declare const useTransferStoreRestored: () => boolean;
39
35
  //# sourceMappingURL=transferStore.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"transferStore.d.ts","sourceRoot":"","sources":["../../../../src/ui/stores/transferStore.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAC;CAC3C;AAED,MAAM,WAAW,aAAa;IAE5B,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAGhD,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAGhC,UAAU,EAAE,OAAO,CAAC;IAGpB,iBAAiB,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAChH,eAAe,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,gBAAgB,GAAG,IAAI,CAAC;IACjE,iBAAiB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,mBAAmB,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,WAAW,GAAG,QAAQ,KAAK,IAAI,CAAC;IAC7F,sBAAsB,EAAE,MAAM,KAAK,CAAC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,gBAAgB,CAAA;KAAE,CAAC,CAAC;IACpF,mBAAmB,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IACzC,mBAAmB,EAAE,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACzD,kBAAkB,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,EAAE,gBAAgB,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACvG,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAUD,eAAO,MAAM,gBAAgB,4EAyI1B,CAAC;AAEJ;;GAEG;AACH,eAAO,MAAM,8BAA8B;;;CAO1C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,wBAAwB,eAEpC,CAAC"}
1
+ {"version":3,"file":"transferStore.d.ts","sourceRoot":"","sources":["../../../../src/ui/stores/transferStore.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAC;CAC3C;AAED,MAAM,WAAW,aAAa;IAE5B,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAGhD,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAGhC,UAAU,EAAE,OAAO,CAAC;IAGpB,iBAAiB,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAChH,eAAe,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,gBAAgB,GAAG,IAAI,CAAC;IACjE,iBAAiB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,mBAAmB,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,WAAW,GAAG,QAAQ,KAAK,IAAI,CAAC;IAC7F,sBAAsB,EAAE,MAAM,KAAK,CAAC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,gBAAgB,CAAA;KAAE,CAAC,CAAC;IACpF,mBAAmB,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IACzC,mBAAmB,EAAE,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACzD,kBAAkB,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,EAAE,gBAAgB,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACvG,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAUD,eAAO,MAAM,gBAAgB,4EAyI1B,CAAC;AAEJ;;GAEG;AACH,eAAO,MAAM,8BAA8B;;;CAO1C,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxyhq/services",
3
- "version": "5.16.27",
3
+ "version": "5.16.29",
4
4
  "description": "Reusable OxyHQ module to handle authentication, user management, karma system, device-based session management and more 🚀",
5
5
  "main": "lib/commonjs/index.js",
6
6
  "module": "lib/module/index.js",
@@ -124,8 +124,9 @@ export class KeyManager {
124
124
  /**
125
125
  * Invalidate cached identity state
126
126
  * Called internally when identity is created/deleted/imported
127
+ * Can also be called externally to force a fresh state check (e.g., on app startup)
127
128
  */
128
- private static invalidateCache(): void {
129
+ static invalidateCache(): void {
129
130
  KeyManager.cachedPublicKey = null;
130
131
  KeyManager.cachedHasIdentity = null;
131
132
  }
@@ -434,6 +435,9 @@ export class KeyManager {
434
435
  return false; // Identity storage is only available on native platforms
435
436
  }
436
437
  try {
438
+ // Invalidate cache before restoring to ensure fresh state
439
+ KeyManager.invalidateCache();
440
+
437
441
  const store = await initSecureStore();
438
442
 
439
443
  // Check if backup exists
@@ -165,7 +165,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
165
165
 
166
166
  const {
167
167
  user,
168
- isAuthenticated,
168
+ isAuthenticated: isAuthenticatedFromStore,
169
169
  isLoading,
170
170
  error,
171
171
  loginSuccess,
@@ -219,12 +219,16 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
219
219
 
220
220
  const checkAndRestoreIdentity = async () => {
221
221
  try {
222
+ // CRITICAL: Invalidate cache on app startup to ensure fresh state check
223
+ // This prevents stale cache from previous session from showing incorrect state
224
+ KeyManager.invalidateCache();
225
+
222
226
  // Check if identity exists and verify integrity
223
227
  const hasIdentity = await KeyManager.hasIdentity();
224
228
  if (hasIdentity) {
225
229
  const isValid = await KeyManager.verifyIdentityIntegrity();
226
230
  if (!isValid) {
227
- // Try to restore from backup
231
+ // Try to restore from backup (cache will be invalidated inside restoreIdentityFromBackup)
228
232
  const restored = await KeyManager.restoreIdentityFromBackup();
229
233
  if (__DEV__) {
230
234
  logger(restored
@@ -237,7 +241,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
237
241
  await KeyManager.backupIdentity();
238
242
  }
239
243
  } else {
240
- // No identity - try to restore from backup
244
+ // No identity - try to restore from backup (cache will be invalidated inside restoreIdentityFromBackup)
241
245
  const restored = await KeyManager.restoreIdentityFromBackup();
242
246
  if (restored && __DEV__) {
243
247
  logger('Identity restored from backup on startup');
@@ -254,9 +258,6 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
254
258
  checkAndRestoreIdentity();
255
259
  }, [storage, isStorageReady, logger]);
256
260
 
257
- // Offline queuing is now handled by TanStack Query mutations
258
- // No need for custom offline queue
259
-
260
261
  const {
261
262
  currentLanguage,
262
263
  metadata: currentLanguageMetadata,
@@ -276,7 +277,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
276
277
  const {
277
278
  sessions,
278
279
  activeSessionId,
279
- setActiveSessionId,
280
+ setActiveSessionId: setActiveSessionIdFromHook,
280
281
  updateSessions,
281
282
  switchSession,
282
283
  refreshSessions,
@@ -313,7 +314,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
313
314
  storage,
314
315
  sessions,
315
316
  activeSessionId,
316
- setActiveSessionId,
317
+ setActiveSessionId: setActiveSessionIdFromHook,
317
318
  updateSessions,
318
319
  saveActiveSessionId,
319
320
  clearSessionState,
@@ -559,7 +560,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
559
560
  clearTimeout(checkTimeout);
560
561
  }
561
562
  };
562
- }, [oxyServices, storage, syncIdentity, logger, hasIdentity, isAuthenticated]);
563
+ }, [oxyServices, storage, syncIdentity, logger, hasIdentity]);
563
564
 
564
565
  const { getDeviceSessions, logoutAllDeviceSessions, updateDeviceName } = useDeviceManagement({
565
566
  oxyServices,
@@ -631,6 +632,24 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
631
632
  // Don't log expected session errors during restoration
632
633
  } else if (isTimeoutOrNetworkError(switchError)) {
633
634
  // Timeout/network error - non-critical, don't block
635
+ // However, if we have valid sessions, we should still set activeSessionId
636
+ // so that isAuthenticated can be computed correctly
637
+ if (validSessions.length > 0) {
638
+ const matchingSession = validSessions.find(s => s.sessionId === storedActiveSessionId);
639
+ if (matchingSession) {
640
+ // Set active session even if validation timed out (offline scenario)
641
+ setActiveSessionIdFromHook(storedActiveSessionId);
642
+ // Try to get user from session if possible (might fail offline, but that's OK)
643
+ try {
644
+ const validation = await oxyServices.validateSession(storedActiveSessionId, { useHeaderValidation: false });
645
+ if (validation?.valid && validation.user) {
646
+ loginSuccess(validation.user);
647
+ }
648
+ } catch {
649
+ // Ignore - we're offline, will sync when online
650
+ }
651
+ }
652
+ }
634
653
  if (__DEV__) {
635
654
  loggerUtil.debug('Active session validation timeout (expected when offline)', { component: 'OxyContext', method: 'restoreSessionsFromStorage' }, switchError as unknown);
636
655
  }
@@ -639,6 +658,26 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
639
658
  logger('Active session validation error', switchError);
640
659
  }
641
660
  }
661
+ } else if (validSessions.length > 0) {
662
+ // No stored active session, but we have valid sessions - activate the first one
663
+ const firstSession = validSessions[0];
664
+ try {
665
+ await switchSession(firstSession.sessionId);
666
+ } catch (switchError) {
667
+ // If switch fails, at least set the activeSessionId so UI can show sessions
668
+ if (isTimeoutOrNetworkError(switchError)) {
669
+ setActiveSessionIdFromHook(firstSession.sessionId);
670
+ // Try to get user from session
671
+ try {
672
+ const validation = await oxyServices.validateSession(firstSession.sessionId, { useHeaderValidation: false });
673
+ if (validation?.valid && validation.user) {
674
+ loginSuccess(validation.user);
675
+ }
676
+ } catch {
677
+ // Ignore - offline scenario
678
+ }
679
+ }
680
+ }
642
681
  }
643
682
  } catch (error) {
644
683
  if (__DEV__) {
@@ -657,6 +696,8 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
657
696
  storageKeys.sessionIds,
658
697
  switchSession,
659
698
  updateSessions,
699
+ setActiveSessionIdFromHook,
700
+ loginSuccess,
660
701
  ]);
661
702
 
662
703
  useEffect(() => {
@@ -673,6 +714,18 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
673
714
  : undefined;
674
715
  const currentDeviceId = activeSession?.deviceId ?? null;
675
716
 
717
+ // Compute isAuthenticated from actual session state, not just auth store
718
+ // This ensures UI shows correct state even if loginSuccess wasn't called during restoration
719
+ const isAuthenticatedFromSessions = useMemo(() => {
720
+ return !!(activeSessionId && sessions.length > 0 && user);
721
+ }, [activeSessionId, sessions.length, user]);
722
+
723
+ // Use session-based authentication state if auth store says not authenticated but we have sessions
724
+ // This handles the case where sessions were restored but loginSuccess wasn't called
725
+ const computedIsAuthenticated = useMemo(() => {
726
+ return isAuthenticatedFromStore || isAuthenticatedFromSessions;
727
+ }, [isAuthenticatedFromStore, isAuthenticatedFromSessions]);
728
+
676
729
  // Get userId from JWT token (MongoDB ObjectId) for socket room matching
677
730
  // user.id is set to publicKey for compatibility, but socket rooms use MongoDB ObjectId
678
731
  // The JWT token's userId field contains the MongoDB ObjectId
@@ -801,7 +854,9 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
801
854
  }, [logger, logout]);
802
855
 
803
856
  // Check pending transfers when authenticated and online using TanStack Query
804
- const { data: pendingTransferResults } = useCheckPendingTransfers();
857
+ // Check for pending transfers that may have completed while offline
858
+ // Results are processed via socket events (onIdentityTransferComplete), so we don't need to process query results here
859
+ useCheckPendingTransfers(oxyServices, computedIsAuthenticated);
805
860
 
806
861
  const handleIdentityTransferComplete = useCallback(
807
862
  async (data: { transferId: string; sourceDeviceId: string; publicKey: string; transferCode?: string; completedAt: string }) => {
@@ -1022,7 +1077,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
1022
1077
  sessions,
1023
1078
  activeSessionId,
1024
1079
  currentDeviceId,
1025
- isAuthenticated,
1080
+ isAuthenticated: computedIsAuthenticated,
1026
1081
  isLoading,
1027
1082
  isTokenReady: tokenReady,
1028
1083
  isStorageReady,
@@ -1089,7 +1144,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
1089
1144
  currentNativeLanguageName,
1090
1145
  error,
1091
1146
  getDeviceSessions,
1092
- isAuthenticated,
1147
+ computedIsAuthenticated,
1093
1148
  isLoading,
1094
1149
  logout,
1095
1150
  logoutAll,
@@ -1,77 +1,25 @@
1
- import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
2
- import { useOxy } from '../context/OxyContext';
1
+ import { useQuery } from '@tanstack/react-query';
3
2
  import { useTransferStore } from '../stores/transferStore';
3
+ import type { OxyServices } from '../../core';
4
4
 
5
5
  /**
6
6
  * Query keys for transfer-related queries
7
7
  */
8
8
  export const transferQueryKeys = {
9
- all: ['transfers'] as const,
10
- completion: (transferId: string) => ['transfers', 'completion', transferId] as const,
11
9
  pending: () => ['transfers', 'pending'] as const,
12
10
  };
13
11
 
14
- /**
15
- * Hook to check if a transfer was completed
16
- * Only runs when authenticated and transferId is provided
17
- */
18
- export const useCheckTransferCompletion = (transferId: string | null, enabled: boolean = true) => {
19
- const { oxyServices, isAuthenticated } = useOxy();
20
-
21
- return useQuery({
22
- queryKey: transferId ? transferQueryKeys.completion(transferId) : ['transfers', 'completion', 'null'],
23
- queryFn: async () => {
24
- if (!transferId || !oxyServices) {
25
- return null;
26
- }
27
-
28
- try {
29
- const response = await oxyServices.makeRequest<{
30
- completed: boolean;
31
- transferId?: string;
32
- sourceDeviceId?: string;
33
- publicKey?: string;
34
- transferCode?: string;
35
- completedAt?: string;
36
- }>(
37
- 'GET',
38
- `/api/identity/check-transfer/${transferId}`,
39
- undefined,
40
- { cache: false }
41
- );
42
-
43
- return response;
44
- } catch (error: any) {
45
- // Handle 401 errors gracefully - don't throw, just return null
46
- if (error?.status === 401 || error?.message?.includes('401') || error?.message?.includes('authentication')) {
47
- if (__DEV__) {
48
- console.warn('[useCheckTransferCompletion] Authentication required, skipping check');
49
- }
50
- return null;
51
- }
52
- throw error;
53
- }
54
- },
55
- enabled: enabled && !!transferId && isAuthenticated && !!oxyServices,
56
- staleTime: 30 * 1000, // 30 seconds - completion status doesn't change frequently
57
- gcTime: 5 * 60 * 1000, // 5 minutes
58
- retry: (failureCount, error: any) => {
59
- // Don't retry on 401 errors
60
- if (error?.status === 401 || error?.message?.includes('401')) {
61
- return false;
62
- }
63
- return failureCount < 2;
64
- },
65
- retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 5000),
66
- });
67
- };
68
-
69
12
  /**
70
13
  * Hook to check all pending transfers for completion
71
14
  * Used when app comes back online
15
+ *
16
+ * This version accepts oxyServices and isAuthenticated as parameters to avoid
17
+ * circular dependency when used inside OxyContext
72
18
  */
73
- export const useCheckPendingTransfers = () => {
74
- const { oxyServices, isAuthenticated } = useOxy();
19
+ export const useCheckPendingTransfers = (
20
+ oxyServices?: OxyServices | null,
21
+ isAuthenticated?: boolean
22
+ ) => {
75
23
  const getAllPendingTransfers = useTransferStore((state) => state.getAllPendingTransfers);
76
24
  const pendingTransfers = getAllPendingTransfers();
77
25
 
@@ -145,7 +93,7 @@ export const useCheckPendingTransfers = () => {
145
93
 
146
94
  return results;
147
95
  },
148
- enabled: isAuthenticated && !!oxyServices && pendingTransfers.length > 0,
96
+ enabled: (isAuthenticated ?? false) && !!oxyServices && pendingTransfers.length > 0,
149
97
  staleTime: 30 * 1000, // 30 seconds
150
98
  gcTime: 5 * 60 * 1000, // 5 minutes
151
99
  retry: false, // Don't retry - we'll check again on next reconnect
@@ -192,10 +192,4 @@ export const useTransferCodesForPersistence = () => {
192
192
  );
193
193
  };
194
194
 
195
- /**
196
- * Hook to check if store has been restored
197
- */
198
- export const useTransferStoreRestored = () => {
199
- return useTransferStore((state) => state.isRestored);
200
- };
201
195