@oxyhq/services 5.17.0 → 5.17.3
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/ui/components/OxyProvider.js +6 -24
- package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
- package/lib/commonjs/ui/context/OxyContext.js +34 -15
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/context/OxyContextBase.js +21 -0
- package/lib/commonjs/ui/context/OxyContextBase.js.map +1 -0
- package/lib/commonjs/ui/hooks/queries/useAccountQueries.js +8 -8
- package/lib/commonjs/ui/hooks/queries/useAccountQueries.js.map +1 -1
- package/lib/commonjs/ui/hooks/queries/useSecurityQueries.js +3 -3
- package/lib/commonjs/ui/hooks/queries/useSecurityQueries.js.map +1 -1
- package/lib/commonjs/ui/hooks/queries/useServicesQueries.js +6 -6
- package/lib/commonjs/ui/hooks/queries/useServicesQueries.js.map +1 -1
- package/lib/module/ui/components/OxyProvider.js +6 -24
- package/lib/module/ui/components/OxyProvider.js.map +1 -1
- package/lib/module/ui/context/OxyContext.js +23 -13
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/context/OxyContextBase.js +16 -0
- package/lib/module/ui/context/OxyContextBase.js.map +1 -0
- package/lib/module/ui/hooks/queries/useAccountQueries.js +1 -1
- package/lib/module/ui/hooks/queries/useAccountQueries.js.map +1 -1
- package/lib/module/ui/hooks/queries/useSecurityQueries.js +1 -1
- package/lib/module/ui/hooks/queries/useSecurityQueries.js.map +1 -1
- package/lib/module/ui/hooks/queries/useServicesQueries.js +1 -1
- package/lib/module/ui/hooks/queries/useServicesQueries.js.map +1 -1
- package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -1
- package/lib/typescript/ui/context/OxyContext.d.ts +2 -94
- package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/ui/context/OxyContextBase.d.ts +99 -0
- package/lib/typescript/ui/context/OxyContextBase.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/ui/components/OxyProvider.tsx +8 -21
- package/src/ui/context/OxyContext.tsx +27 -88
- package/src/ui/context/OxyContextBase.tsx +95 -0
- package/src/ui/hooks/queries/useAccountQueries.ts +1 -1
- package/src/ui/hooks/queries/useSecurityQueries.ts +1 -1
- package/src/ui/hooks/queries/useServicesQueries.ts +1 -1
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { OxyServices } from '../../core';
|
|
3
|
+
import type { User, ApiError } from '../../models/interfaces';
|
|
4
|
+
import type { ClientSession } from '../../models/session';
|
|
5
|
+
import type { UseFollowHook } from '../hooks/useFollow.types';
|
|
6
|
+
import type { useLanguageManagement } from '../hooks/useLanguageManagement';
|
|
7
|
+
import type { RouteName } from '../navigation/routes';
|
|
8
|
+
import type { BackupData } from '../../crypto';
|
|
9
|
+
export interface OxyContextState {
|
|
10
|
+
user: User | null;
|
|
11
|
+
sessions: ClientSession[];
|
|
12
|
+
activeSessionId: string | null;
|
|
13
|
+
currentDeviceId: string | null;
|
|
14
|
+
isAuthenticated: boolean;
|
|
15
|
+
isLoading: boolean;
|
|
16
|
+
isTokenReady: boolean;
|
|
17
|
+
isStorageReady: boolean;
|
|
18
|
+
error: string | null;
|
|
19
|
+
currentLanguage: string;
|
|
20
|
+
currentLanguageMetadata: ReturnType<typeof useLanguageManagement>['metadata'];
|
|
21
|
+
currentLanguageName: string;
|
|
22
|
+
currentNativeLanguageName: string;
|
|
23
|
+
createIdentity: () => Promise<{
|
|
24
|
+
synced: boolean;
|
|
25
|
+
}>;
|
|
26
|
+
importIdentity: (backupData: BackupData, password: string) => Promise<{
|
|
27
|
+
synced: boolean;
|
|
28
|
+
}>;
|
|
29
|
+
signIn: (deviceName?: string) => Promise<User>;
|
|
30
|
+
hasIdentity: () => Promise<boolean>;
|
|
31
|
+
getPublicKey: () => Promise<string | null>;
|
|
32
|
+
isIdentitySynced: () => Promise<boolean>;
|
|
33
|
+
syncIdentity: () => Promise<User>;
|
|
34
|
+
deleteIdentityAndClearAccount: (skipBackup?: boolean, force?: boolean, userConfirmed?: boolean) => Promise<void>;
|
|
35
|
+
storeTransferCode: (transferId: string, code: string, sourceDeviceId: string | null, publicKey: string) => Promise<void>;
|
|
36
|
+
getTransferCode: (transferId: string) => {
|
|
37
|
+
code: string;
|
|
38
|
+
sourceDeviceId: string | null;
|
|
39
|
+
publicKey: string;
|
|
40
|
+
timestamp: number;
|
|
41
|
+
state: 'pending' | 'completed' | 'failed';
|
|
42
|
+
} | null;
|
|
43
|
+
clearTransferCode: (transferId: string) => Promise<void>;
|
|
44
|
+
getAllPendingTransfers: () => Array<{
|
|
45
|
+
transferId: string;
|
|
46
|
+
data: {
|
|
47
|
+
code: string;
|
|
48
|
+
sourceDeviceId: string | null;
|
|
49
|
+
publicKey: string;
|
|
50
|
+
timestamp: number;
|
|
51
|
+
state: 'pending' | 'completed' | 'failed';
|
|
52
|
+
};
|
|
53
|
+
}>;
|
|
54
|
+
getActiveTransferId: () => string | null;
|
|
55
|
+
updateTransferState: (transferId: string, state: 'pending' | 'completed' | 'failed') => Promise<void>;
|
|
56
|
+
identitySyncState: {
|
|
57
|
+
isSynced: boolean;
|
|
58
|
+
isSyncing: boolean;
|
|
59
|
+
};
|
|
60
|
+
logout: (targetSessionId?: string) => Promise<void>;
|
|
61
|
+
logoutAll: () => Promise<void>;
|
|
62
|
+
switchSession: (sessionId: string) => Promise<void>;
|
|
63
|
+
removeSession: (sessionId: string) => Promise<void>;
|
|
64
|
+
refreshSessions: () => Promise<void>;
|
|
65
|
+
setLanguage: (languageId: string) => Promise<void>;
|
|
66
|
+
getDeviceSessions: () => Promise<Array<{
|
|
67
|
+
sessionId: string;
|
|
68
|
+
deviceId: string;
|
|
69
|
+
deviceName?: string;
|
|
70
|
+
lastActive?: string;
|
|
71
|
+
expiresAt?: string;
|
|
72
|
+
}>>;
|
|
73
|
+
logoutAllDeviceSessions: () => Promise<void>;
|
|
74
|
+
updateDeviceName: (deviceName: string) => Promise<void>;
|
|
75
|
+
clearSessionState: () => Promise<void>;
|
|
76
|
+
clearAllAccountData: () => Promise<void>;
|
|
77
|
+
oxyServices: OxyServices;
|
|
78
|
+
useFollow?: UseFollowHook;
|
|
79
|
+
showBottomSheet?: (screenOrConfig: RouteName | {
|
|
80
|
+
screen: RouteName;
|
|
81
|
+
props?: Record<string, unknown>;
|
|
82
|
+
}) => void;
|
|
83
|
+
openAvatarPicker: () => void;
|
|
84
|
+
}
|
|
85
|
+
export declare const OxyContext: import("react").Context<OxyContextState | null>;
|
|
86
|
+
export interface OxyContextProviderProps {
|
|
87
|
+
children: ReactNode;
|
|
88
|
+
oxyServices?: OxyServices;
|
|
89
|
+
baseURL?: string;
|
|
90
|
+
storageKeyPrefix?: string;
|
|
91
|
+
onAuthStateChange?: (user: User | null) => void;
|
|
92
|
+
onError?: (error: ApiError) => void;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Hook to access the Oxy context.
|
|
96
|
+
* Must be used within an OxyContextProvider.
|
|
97
|
+
*/
|
|
98
|
+
export declare const useOxy: () => OxyContextState;
|
|
99
|
+
//# sourceMappingURL=OxyContextBase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OxyContextBase.d.ts","sourceRoot":"","sources":["../../../../src/ui/context/OxyContextBase.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oxyhq/services",
|
|
3
|
-
"version": "5.17.
|
|
3
|
+
"version": "5.17.3",
|
|
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",
|
|
@@ -10,7 +10,6 @@ import { setupFonts } from './FontLoader';
|
|
|
10
10
|
import BottomSheetRouter from './BottomSheetRouter';
|
|
11
11
|
import { Toaster } from '../../lib/sonner';
|
|
12
12
|
import { createQueryClient } from '../hooks/queryClient';
|
|
13
|
-
import { useStorage } from '../hooks/useStorage';
|
|
14
13
|
|
|
15
14
|
// Initialize fonts automatically
|
|
16
15
|
setupFonts();
|
|
@@ -34,26 +33,20 @@ const OxyProvider: FC<OxyProviderProps> = ({
|
|
|
34
33
|
// bottom sheet experience is removed. At the moment both modes behave the same.
|
|
35
34
|
void contextOnly;
|
|
36
35
|
|
|
37
|
-
//
|
|
38
|
-
const { storage, isReady: isStorageReady } = useStorage();
|
|
39
|
-
|
|
40
|
-
// Initialize React Query Client with persistence
|
|
36
|
+
// Initialize React Query Client (in-memory; persistence handled separately if needed)
|
|
41
37
|
const queryClientRef = useRef<ReturnType<typeof createQueryClient> | null>(null);
|
|
42
|
-
const [queryClient, setQueryClient] = useState<ReturnType<typeof createQueryClient
|
|
38
|
+
const [queryClient, setQueryClient] = useState<ReturnType<typeof createQueryClient>>(
|
|
39
|
+
() => providedQueryClient ?? createQueryClient(),
|
|
40
|
+
);
|
|
43
41
|
|
|
44
42
|
useEffect(() => {
|
|
45
|
-
if (providedQueryClient) {
|
|
43
|
+
if (providedQueryClient && queryClientRef.current !== providedQueryClient) {
|
|
46
44
|
queryClientRef.current = providedQueryClient;
|
|
47
45
|
setQueryClient(providedQueryClient);
|
|
48
|
-
} else if (
|
|
49
|
-
|
|
50
|
-
if (!queryClientRef.current) {
|
|
51
|
-
const client = createQueryClient(storage);
|
|
52
|
-
queryClientRef.current = client;
|
|
53
|
-
setQueryClient(client);
|
|
54
|
-
}
|
|
46
|
+
} else if (!queryClientRef.current) {
|
|
47
|
+
queryClientRef.current = queryClient;
|
|
55
48
|
}
|
|
56
|
-
}, [providedQueryClient,
|
|
49
|
+
}, [providedQueryClient, queryClient]);
|
|
57
50
|
|
|
58
51
|
// Hook React Query focus manager into React Native AppState
|
|
59
52
|
useEffect(() => {
|
|
@@ -114,12 +107,6 @@ const OxyProvider: FC<OxyProviderProps> = ({
|
|
|
114
107
|
};
|
|
115
108
|
}, []);
|
|
116
109
|
|
|
117
|
-
// Ensure we have a valid QueryClient
|
|
118
|
-
if (!queryClient) {
|
|
119
|
-
// Return loading state or fallback
|
|
120
|
-
return null;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
110
|
return (
|
|
124
111
|
<SafeAreaProvider>
|
|
125
112
|
<GestureHandlerRootView style={{ flex: 1 }}>
|
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
2
|
import {
|
|
3
|
-
createContext,
|
|
4
3
|
useCallback,
|
|
5
|
-
useContext,
|
|
6
4
|
useEffect,
|
|
7
5
|
useMemo,
|
|
8
6
|
useRef,
|
|
9
7
|
useState,
|
|
10
|
-
type ReactNode,
|
|
11
8
|
} from 'react';
|
|
12
9
|
import { Platform } from 'react-native';
|
|
13
10
|
import { OxyServices } from '../../core';
|
|
14
|
-
import type { User
|
|
11
|
+
import type { User } from '../../models/interfaces';
|
|
15
12
|
import type { ClientSession } from '../../models/session';
|
|
16
13
|
import { toast } from '../../lib/sonner';
|
|
17
14
|
import { useAuthStore, type AuthState } from '../stores/authStore';
|
|
@@ -27,88 +24,25 @@ import { getStorageKeys } from '../utils/storageHelpers';
|
|
|
27
24
|
import { isInvalidSessionError, isTimeoutOrNetworkError } from '../utils/errorHandlers';
|
|
28
25
|
import type { RouteName } from '../navigation/routes';
|
|
29
26
|
import { showBottomSheet as globalShowBottomSheet } from '../navigation/bottomSheetManager';
|
|
30
|
-
import { useQueryClient } from '@tanstack/react-query';
|
|
31
|
-
import { useCurrentUser } from '../hooks/queries';
|
|
27
|
+
import { useQueryClient, useQuery } from '@tanstack/react-query';
|
|
32
28
|
import { clearQueryCache } from '../hooks/queryClient';
|
|
29
|
+
import { queryKeys } from '../hooks/queries/queryKeys';
|
|
33
30
|
import { KeyManager, type BackupData } from '../../crypto';
|
|
34
31
|
import { translate } from '../../i18n';
|
|
35
32
|
import { updateAvatarVisibility, updateProfileWithAvatar } from '../utils/avatarUtils';
|
|
36
33
|
import { useAccountStore } from '../stores/accountStore';
|
|
37
34
|
import { logger as loggerUtil } from '../../utils/loggerUtils';
|
|
38
35
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
currentLanguage: string;
|
|
50
|
-
currentLanguageMetadata: ReturnType<typeof useLanguageManagement>['metadata'];
|
|
51
|
-
currentLanguageName: string;
|
|
52
|
-
currentNativeLanguageName: string;
|
|
53
|
-
|
|
54
|
-
// Identity management (public key authentication - offline-first)
|
|
55
|
-
createIdentity: () => Promise<{ synced: boolean }>;
|
|
56
|
-
importIdentity: (backupData: BackupData, password: string) => Promise<{ synced: boolean }>;
|
|
57
|
-
signIn: (deviceName?: string) => Promise<User>;
|
|
58
|
-
hasIdentity: () => Promise<boolean>;
|
|
59
|
-
getPublicKey: () => Promise<string | null>;
|
|
60
|
-
isIdentitySynced: () => Promise<boolean>;
|
|
61
|
-
syncIdentity: () => Promise<User>;
|
|
62
|
-
deleteIdentityAndClearAccount: (skipBackup?: boolean, force?: boolean, userConfirmed?: boolean) => Promise<void>;
|
|
63
|
-
storeTransferCode: (transferId: string, code: string, sourceDeviceId: string | null, publicKey: string) => Promise<void>;
|
|
64
|
-
getTransferCode: (transferId: string) => { code: string; sourceDeviceId: string | null; publicKey: string; timestamp: number; state: 'pending' | 'completed' | 'failed' } | null;
|
|
65
|
-
clearTransferCode: (transferId: string) => Promise<void>;
|
|
66
|
-
getAllPendingTransfers: () => Array<{ transferId: string; data: { code: string; sourceDeviceId: string | null; publicKey: string; timestamp: number; state: 'pending' | 'completed' | 'failed' } }>;
|
|
67
|
-
getActiveTransferId: () => string | null;
|
|
68
|
-
updateTransferState: (transferId: string, state: 'pending' | 'completed' | 'failed') => Promise<void>;
|
|
69
|
-
|
|
70
|
-
// Identity sync state (reactive, from Zustand store)
|
|
71
|
-
identitySyncState: {
|
|
72
|
-
isSynced: boolean;
|
|
73
|
-
isSyncing: boolean;
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
// Session management
|
|
77
|
-
logout: (targetSessionId?: string) => Promise<void>;
|
|
78
|
-
logoutAll: () => Promise<void>;
|
|
79
|
-
switchSession: (sessionId: string) => Promise<void>;
|
|
80
|
-
removeSession: (sessionId: string) => Promise<void>;
|
|
81
|
-
refreshSessions: () => Promise<void>;
|
|
82
|
-
setLanguage: (languageId: string) => Promise<void>;
|
|
83
|
-
getDeviceSessions: () => Promise<
|
|
84
|
-
Array<{
|
|
85
|
-
sessionId: string;
|
|
86
|
-
deviceId: string;
|
|
87
|
-
deviceName?: string;
|
|
88
|
-
lastActive?: string;
|
|
89
|
-
expiresAt?: string;
|
|
90
|
-
}>
|
|
91
|
-
>;
|
|
92
|
-
logoutAllDeviceSessions: () => Promise<void>;
|
|
93
|
-
updateDeviceName: (deviceName: string) => Promise<void>;
|
|
94
|
-
clearSessionState: () => Promise<void>;
|
|
95
|
-
clearAllAccountData: () => Promise<void>;
|
|
96
|
-
oxyServices: OxyServices;
|
|
97
|
-
useFollow?: UseFollowHook;
|
|
98
|
-
showBottomSheet?: (screenOrConfig: RouteName | { screen: RouteName; props?: Record<string, unknown> }) => void;
|
|
99
|
-
openAvatarPicker: () => void;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const OxyContext = createContext<OxyContextState | null>(null);
|
|
103
|
-
|
|
104
|
-
export interface OxyContextProviderProps {
|
|
105
|
-
children: ReactNode;
|
|
106
|
-
oxyServices?: OxyServices;
|
|
107
|
-
baseURL?: string;
|
|
108
|
-
storageKeyPrefix?: string;
|
|
109
|
-
onAuthStateChange?: (user: User | null) => void;
|
|
110
|
-
onError?: (error: ApiError) => void;
|
|
111
|
-
}
|
|
36
|
+
// Import context, types and useOxy from base file to avoid circular dependencies
|
|
37
|
+
import {
|
|
38
|
+
OxyContext,
|
|
39
|
+
useOxy,
|
|
40
|
+
type OxyContextState,
|
|
41
|
+
type OxyContextProviderProps,
|
|
42
|
+
} from './OxyContextBase';
|
|
43
|
+
|
|
44
|
+
// Re-export for backwards compatibility
|
|
45
|
+
export { OxyContext, useOxy, type OxyContextState, type OxyContextProviderProps };
|
|
112
46
|
|
|
113
47
|
let cachedUseFollowHook: UseFollowHook | null = null;
|
|
114
48
|
|
|
@@ -297,7 +231,20 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
297
231
|
|
|
298
232
|
// Get current user from query (no persistent cache - always fetch fresh)
|
|
299
233
|
// Services never caches profile - always fetch from backend
|
|
300
|
-
|
|
234
|
+
// Note: We use useQuery directly here instead of useCurrentUser to avoid
|
|
235
|
+
// circular dependency (useCurrentUser calls useOxy, but we're inside the provider)
|
|
236
|
+
const { data: userData } = useQuery({
|
|
237
|
+
queryKey: queryKeys.accounts.current(),
|
|
238
|
+
queryFn: async () => {
|
|
239
|
+
if (!activeSessionId) {
|
|
240
|
+
throw new Error('No active session');
|
|
241
|
+
}
|
|
242
|
+
return await oxyServices.getUserBySession(activeSessionId);
|
|
243
|
+
},
|
|
244
|
+
enabled: isAuthenticated && !!activeSessionId,
|
|
245
|
+
staleTime: 0, // Always fetch fresh - Services never caches profile
|
|
246
|
+
gcTime: 0, // No garbage collection time - always fetch fresh
|
|
247
|
+
});
|
|
301
248
|
const user = userData ?? null;
|
|
302
249
|
|
|
303
250
|
const {
|
|
@@ -1206,12 +1153,4 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
1206
1153
|
|
|
1207
1154
|
export const OxyContextProvider = OxyProvider;
|
|
1208
1155
|
|
|
1209
|
-
export const useOxy = (): OxyContextState => {
|
|
1210
|
-
const context = useContext(OxyContext);
|
|
1211
|
-
if (!context) {
|
|
1212
|
-
throw new Error('useOxy must be used within an OxyContextProvider');
|
|
1213
|
-
}
|
|
1214
|
-
return context;
|
|
1215
|
-
};
|
|
1216
|
-
|
|
1217
1156
|
export default OxyContext;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { createContext, useContext } from 'react';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
import type { OxyServices } from '../../core';
|
|
4
|
+
import type { User, ApiError } from '../../models/interfaces';
|
|
5
|
+
import type { ClientSession } from '../../models/session';
|
|
6
|
+
import type { UseFollowHook } from '../hooks/useFollow.types';
|
|
7
|
+
import type { useLanguageManagement } from '../hooks/useLanguageManagement';
|
|
8
|
+
import type { RouteName } from '../navigation/routes';
|
|
9
|
+
import type { BackupData } from '../../crypto';
|
|
10
|
+
|
|
11
|
+
export interface OxyContextState {
|
|
12
|
+
user: User | null;
|
|
13
|
+
sessions: ClientSession[];
|
|
14
|
+
activeSessionId: string | null;
|
|
15
|
+
currentDeviceId: string | null;
|
|
16
|
+
isAuthenticated: boolean;
|
|
17
|
+
isLoading: boolean;
|
|
18
|
+
isTokenReady: boolean;
|
|
19
|
+
isStorageReady: boolean;
|
|
20
|
+
error: string | null;
|
|
21
|
+
currentLanguage: string;
|
|
22
|
+
currentLanguageMetadata: ReturnType<typeof useLanguageManagement>['metadata'];
|
|
23
|
+
currentLanguageName: string;
|
|
24
|
+
currentNativeLanguageName: string;
|
|
25
|
+
|
|
26
|
+
// Identity management (public key authentication - offline-first)
|
|
27
|
+
createIdentity: () => Promise<{ synced: boolean }>;
|
|
28
|
+
importIdentity: (backupData: BackupData, password: string) => Promise<{ synced: boolean }>;
|
|
29
|
+
signIn: (deviceName?: string) => Promise<User>;
|
|
30
|
+
hasIdentity: () => Promise<boolean>;
|
|
31
|
+
getPublicKey: () => Promise<string | null>;
|
|
32
|
+
isIdentitySynced: () => Promise<boolean>;
|
|
33
|
+
syncIdentity: () => Promise<User>;
|
|
34
|
+
deleteIdentityAndClearAccount: (skipBackup?: boolean, force?: boolean, userConfirmed?: boolean) => Promise<void>;
|
|
35
|
+
storeTransferCode: (transferId: string, code: string, sourceDeviceId: string | null, publicKey: string) => Promise<void>;
|
|
36
|
+
getTransferCode: (transferId: string) => { code: string; sourceDeviceId: string | null; publicKey: string; timestamp: number; state: 'pending' | 'completed' | 'failed' } | null;
|
|
37
|
+
clearTransferCode: (transferId: string) => Promise<void>;
|
|
38
|
+
getAllPendingTransfers: () => Array<{ transferId: string; data: { code: string; sourceDeviceId: string | null; publicKey: string; timestamp: number; state: 'pending' | 'completed' | 'failed' } }>;
|
|
39
|
+
getActiveTransferId: () => string | null;
|
|
40
|
+
updateTransferState: (transferId: string, state: 'pending' | 'completed' | 'failed') => Promise<void>;
|
|
41
|
+
|
|
42
|
+
// Identity sync state (reactive, from Zustand store)
|
|
43
|
+
identitySyncState: {
|
|
44
|
+
isSynced: boolean;
|
|
45
|
+
isSyncing: boolean;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// Session management
|
|
49
|
+
logout: (targetSessionId?: string) => Promise<void>;
|
|
50
|
+
logoutAll: () => Promise<void>;
|
|
51
|
+
switchSession: (sessionId: string) => Promise<void>;
|
|
52
|
+
removeSession: (sessionId: string) => Promise<void>;
|
|
53
|
+
refreshSessions: () => Promise<void>;
|
|
54
|
+
setLanguage: (languageId: string) => Promise<void>;
|
|
55
|
+
getDeviceSessions: () => Promise<
|
|
56
|
+
Array<{
|
|
57
|
+
sessionId: string;
|
|
58
|
+
deviceId: string;
|
|
59
|
+
deviceName?: string;
|
|
60
|
+
lastActive?: string;
|
|
61
|
+
expiresAt?: string;
|
|
62
|
+
}>
|
|
63
|
+
>;
|
|
64
|
+
logoutAllDeviceSessions: () => Promise<void>;
|
|
65
|
+
updateDeviceName: (deviceName: string) => Promise<void>;
|
|
66
|
+
clearSessionState: () => Promise<void>;
|
|
67
|
+
clearAllAccountData: () => Promise<void>;
|
|
68
|
+
oxyServices: OxyServices;
|
|
69
|
+
useFollow?: UseFollowHook;
|
|
70
|
+
showBottomSheet?: (screenOrConfig: RouteName | { screen: RouteName; props?: Record<string, unknown> }) => void;
|
|
71
|
+
openAvatarPicker: () => void;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export const OxyContext = createContext<OxyContextState | null>(null);
|
|
75
|
+
|
|
76
|
+
export interface OxyContextProviderProps {
|
|
77
|
+
children: ReactNode;
|
|
78
|
+
oxyServices?: OxyServices;
|
|
79
|
+
baseURL?: string;
|
|
80
|
+
storageKeyPrefix?: string;
|
|
81
|
+
onAuthStateChange?: (user: User | null) => void;
|
|
82
|
+
onError?: (error: ApiError) => void;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Hook to access the Oxy context.
|
|
87
|
+
* Must be used within an OxyContextProvider.
|
|
88
|
+
*/
|
|
89
|
+
export const useOxy = (): OxyContextState => {
|
|
90
|
+
const context = useContext(OxyContext);
|
|
91
|
+
if (!context) {
|
|
92
|
+
throw new Error('useOxy must be used within an OxyContextProvider');
|
|
93
|
+
}
|
|
94
|
+
return context;
|
|
95
|
+
};
|
|
@@ -2,7 +2,7 @@ import { useQuery, useQueries } from '@tanstack/react-query';
|
|
|
2
2
|
import type { User } from '../../../models/interfaces';
|
|
3
3
|
import type { OxyServices } from '../../../core';
|
|
4
4
|
import { queryKeys } from './queryKeys';
|
|
5
|
-
import { useOxy } from '../../context/
|
|
5
|
+
import { useOxy } from '../../context/OxyContextBase';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Get user profile by session ID
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useQuery } from '@tanstack/react-query';
|
|
2
2
|
import { queryKeys } from './queryKeys';
|
|
3
|
-
import { useOxy } from '../../context/
|
|
3
|
+
import { useOxy } from '../../context/OxyContextBase';
|
|
4
4
|
import type { SecurityActivity, SecurityEventType } from '../../../models/interfaces';
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useQuery } from '@tanstack/react-query';
|
|
2
2
|
import type { ClientSession } from '../../../models/session';
|
|
3
3
|
import { queryKeys } from './queryKeys';
|
|
4
|
-
import { useOxy } from '../../context/
|
|
4
|
+
import { useOxy } from '../../context/OxyContextBase';
|
|
5
5
|
import { fetchSessionsWithFallback, mapSessionsToClient } from '../../utils/sessionHelpers';
|
|
6
6
|
|
|
7
7
|
/**
|