@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.
- package/lib/commonjs/crypto/keyManager.js +3 -0
- package/lib/commonjs/crypto/keyManager.js.map +1 -1
- package/lib/commonjs/ui/context/OxyContext.js +70 -16
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/hooks/useTransferQueries.js +6 -58
- package/lib/commonjs/ui/hooks/useTransferQueries.js.map +1 -1
- package/lib/commonjs/ui/stores/transferStore.js +1 -9
- package/lib/commonjs/ui/stores/transferStore.js.map +1 -1
- package/lib/module/crypto/keyManager.js +3 -0
- package/lib/module/crypto/keyManager.js.map +1 -1
- package/lib/module/ui/context/OxyContext.js +70 -16
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/hooks/useTransferQueries.js +5 -57
- package/lib/module/ui/hooks/useTransferQueries.js.map +1 -1
- package/lib/module/ui/stores/transferStore.js +0 -7
- package/lib/module/ui/stores/transferStore.js.map +1 -1
- package/lib/typescript/crypto/keyManager.d.ts +2 -1
- package/lib/typescript/crypto/keyManager.d.ts.map +1 -1
- package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/useTransferQueries.d.ts +5 -15
- package/lib/typescript/ui/hooks/useTransferQueries.d.ts.map +1 -1
- package/lib/typescript/ui/stores/transferStore.d.ts +0 -4
- package/lib/typescript/ui/stores/transferStore.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/crypto/keyManager.ts +5 -1
- package/src/ui/context/OxyContext.tsx +67 -12
- package/src/ui/hooks/useTransferQueries.ts +10 -62
- 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":"
|
|
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
|
|
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.
|
|
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",
|
package/src/crypto/keyManager.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
1147
|
+
computedIsAuthenticated,
|
|
1093
1148
|
isLoading,
|
|
1094
1149
|
logout,
|
|
1095
1150
|
logoutAll,
|
|
@@ -1,77 +1,25 @@
|
|
|
1
|
-
import { useQuery
|
|
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
|
-
|
|
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
|
|