@oxyhq/auth 1.0.0
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/README.md +56 -0
- package/dist/cjs/WebOxyProvider.js +287 -0
- package/dist/cjs/hooks/mutations/index.js +23 -0
- package/dist/cjs/hooks/mutations/mutationFactory.js +126 -0
- package/dist/cjs/hooks/mutations/useAccountMutations.js +275 -0
- package/dist/cjs/hooks/mutations/useServicesMutations.js +149 -0
- package/dist/cjs/hooks/queries/index.js +35 -0
- package/dist/cjs/hooks/queries/queryKeys.js +82 -0
- package/dist/cjs/hooks/queries/useAccountQueries.js +141 -0
- package/dist/cjs/hooks/queries/useSecurityQueries.js +45 -0
- package/dist/cjs/hooks/queries/useServicesQueries.js +113 -0
- package/dist/cjs/hooks/queryClient.js +110 -0
- package/dist/cjs/hooks/useAssets.js +225 -0
- package/dist/cjs/hooks/useFileDownloadUrl.js +91 -0
- package/dist/cjs/hooks/useFileFiltering.js +81 -0
- package/dist/cjs/hooks/useFollow.js +159 -0
- package/dist/cjs/hooks/useFollow.types.js +4 -0
- package/dist/cjs/hooks/useQueryClient.js +16 -0
- package/dist/cjs/hooks/useSessionSocket.js +215 -0
- package/dist/cjs/hooks/useWebSSO.js +146 -0
- package/dist/cjs/index.js +115 -0
- package/dist/cjs/stores/accountStore.js +226 -0
- package/dist/cjs/stores/assetStore.js +192 -0
- package/dist/cjs/stores/authStore.js +47 -0
- package/dist/cjs/stores/followStore.js +154 -0
- package/dist/cjs/utils/authHelpers.js +154 -0
- package/dist/cjs/utils/avatarUtils.js +77 -0
- package/dist/cjs/utils/errorHandlers.js +128 -0
- package/dist/cjs/utils/sessionHelpers.js +90 -0
- package/dist/cjs/utils/storageHelpers.js +147 -0
- package/dist/esm/WebOxyProvider.js +282 -0
- package/dist/esm/hooks/mutations/index.js +10 -0
- package/dist/esm/hooks/mutations/mutationFactory.js +122 -0
- package/dist/esm/hooks/mutations/useAccountMutations.js +267 -0
- package/dist/esm/hooks/mutations/useServicesMutations.js +141 -0
- package/dist/esm/hooks/queries/index.js +14 -0
- package/dist/esm/hooks/queries/queryKeys.js +76 -0
- package/dist/esm/hooks/queries/useAccountQueries.js +131 -0
- package/dist/esm/hooks/queries/useSecurityQueries.js +40 -0
- package/dist/esm/hooks/queries/useServicesQueries.js +105 -0
- package/dist/esm/hooks/queryClient.js +104 -0
- package/dist/esm/hooks/useAssets.js +220 -0
- package/dist/esm/hooks/useFileDownloadUrl.js +86 -0
- package/dist/esm/hooks/useFileFiltering.js +78 -0
- package/dist/esm/hooks/useFollow.js +154 -0
- package/dist/esm/hooks/useFollow.types.js +3 -0
- package/dist/esm/hooks/useQueryClient.js +12 -0
- package/dist/esm/hooks/useSessionSocket.js +209 -0
- package/dist/esm/hooks/useWebSSO.js +143 -0
- package/dist/esm/index.js +48 -0
- package/dist/esm/stores/accountStore.js +219 -0
- package/dist/esm/stores/assetStore.js +180 -0
- package/dist/esm/stores/authStore.js +44 -0
- package/dist/esm/stores/followStore.js +151 -0
- package/dist/esm/utils/authHelpers.js +145 -0
- package/dist/esm/utils/avatarUtils.js +72 -0
- package/dist/esm/utils/errorHandlers.js +121 -0
- package/dist/esm/utils/sessionHelpers.js +84 -0
- package/dist/esm/utils/storageHelpers.js +108 -0
- package/dist/types/WebOxyProvider.d.ts +97 -0
- package/dist/types/hooks/mutations/index.d.ts +8 -0
- package/dist/types/hooks/mutations/mutationFactory.d.ts +75 -0
- package/dist/types/hooks/mutations/useAccountMutations.d.ts +68 -0
- package/dist/types/hooks/mutations/useServicesMutations.d.ts +22 -0
- package/dist/types/hooks/queries/index.d.ts +10 -0
- package/dist/types/hooks/queries/queryKeys.d.ts +64 -0
- package/dist/types/hooks/queries/useAccountQueries.d.ts +42 -0
- package/dist/types/hooks/queries/useSecurityQueries.d.ts +14 -0
- package/dist/types/hooks/queries/useServicesQueries.d.ts +31 -0
- package/dist/types/hooks/queryClient.d.ts +18 -0
- package/dist/types/hooks/useAssets.d.ts +34 -0
- package/dist/types/hooks/useFileDownloadUrl.d.ts +18 -0
- package/dist/types/hooks/useFileFiltering.d.ts +28 -0
- package/dist/types/hooks/useFollow.d.ts +61 -0
- package/dist/types/hooks/useFollow.types.d.ts +32 -0
- package/dist/types/hooks/useQueryClient.d.ts +6 -0
- package/dist/types/hooks/useSessionSocket.d.ts +13 -0
- package/dist/types/hooks/useWebSSO.d.ts +57 -0
- package/dist/types/index.d.ts +46 -0
- package/dist/types/stores/accountStore.d.ts +33 -0
- package/dist/types/stores/assetStore.d.ts +53 -0
- package/dist/types/stores/authStore.d.ts +16 -0
- package/dist/types/stores/followStore.d.ts +24 -0
- package/dist/types/utils/authHelpers.d.ts +98 -0
- package/dist/types/utils/avatarUtils.d.ts +33 -0
- package/dist/types/utils/errorHandlers.d.ts +34 -0
- package/dist/types/utils/sessionHelpers.d.ts +63 -0
- package/dist/types/utils/storageHelpers.d.ts +27 -0
- package/package.json +71 -0
- package/src/WebOxyProvider.tsx +372 -0
- package/src/global.d.ts +1 -0
- package/src/hooks/mutations/index.ts +25 -0
- package/src/hooks/mutations/mutationFactory.ts +215 -0
- package/src/hooks/mutations/useAccountMutations.ts +344 -0
- package/src/hooks/mutations/useServicesMutations.ts +164 -0
- package/src/hooks/queries/index.ts +36 -0
- package/src/hooks/queries/queryKeys.ts +88 -0
- package/src/hooks/queries/useAccountQueries.ts +152 -0
- package/src/hooks/queries/useSecurityQueries.ts +64 -0
- package/src/hooks/queries/useServicesQueries.ts +126 -0
- package/src/hooks/queryClient.ts +112 -0
- package/src/hooks/useAssets.ts +291 -0
- package/src/hooks/useFileDownloadUrl.ts +118 -0
- package/src/hooks/useFileFiltering.ts +115 -0
- package/src/hooks/useFollow.ts +175 -0
- package/src/hooks/useFollow.types.ts +33 -0
- package/src/hooks/useQueryClient.ts +17 -0
- package/src/hooks/useSessionSocket.ts +233 -0
- package/src/hooks/useWebSSO.ts +187 -0
- package/src/index.ts +144 -0
- package/src/stores/accountStore.ts +296 -0
- package/src/stores/assetStore.ts +281 -0
- package/src/stores/authStore.ts +63 -0
- package/src/stores/followStore.ts +181 -0
- package/src/utils/authHelpers.ts +183 -0
- package/src/utils/avatarUtils.ts +103 -0
- package/src/utils/errorHandlers.ts +194 -0
- package/src/utils/sessionHelpers.ts +151 -0
- package/src/utils/storageHelpers.ts +130 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.usePrivacySettings = exports.useUsersBySessions = exports.useUserByUsername = exports.useUserById = exports.useCurrentUser = exports.useUserProfiles = exports.useUserProfile = void 0;
|
|
4
|
+
const react_query_1 = require("@tanstack/react-query");
|
|
5
|
+
const queryKeys_1 = require("./queryKeys");
|
|
6
|
+
const WebOxyProvider_1 = require("../../WebOxyProvider");
|
|
7
|
+
const authHelpers_1 = require("../../utils/authHelpers");
|
|
8
|
+
/**
|
|
9
|
+
* Get user profile by session ID
|
|
10
|
+
*/
|
|
11
|
+
const useUserProfile = (sessionId, options) => {
|
|
12
|
+
const { oxyServices } = (0, WebOxyProvider_1.useWebOxy)();
|
|
13
|
+
return (0, react_query_1.useQuery)({
|
|
14
|
+
queryKey: queryKeys_1.queryKeys.users.profile(sessionId || ''),
|
|
15
|
+
queryFn: async () => {
|
|
16
|
+
if (!sessionId) {
|
|
17
|
+
throw new Error('Session ID is required');
|
|
18
|
+
}
|
|
19
|
+
return await oxyServices.getUserBySession(sessionId);
|
|
20
|
+
},
|
|
21
|
+
enabled: (options?.enabled !== false) && !!sessionId,
|
|
22
|
+
staleTime: 5 * 60 * 1000, // 5 minutes
|
|
23
|
+
gcTime: 30 * 60 * 1000, // 30 minutes
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
exports.useUserProfile = useUserProfile;
|
|
27
|
+
/**
|
|
28
|
+
* Get multiple user profiles by session IDs (batch query)
|
|
29
|
+
*/
|
|
30
|
+
const useUserProfiles = (sessionIds, options) => {
|
|
31
|
+
const { oxyServices } = (0, WebOxyProvider_1.useWebOxy)();
|
|
32
|
+
return (0, react_query_1.useQueries)({
|
|
33
|
+
queries: sessionIds.map((sessionId) => ({
|
|
34
|
+
queryKey: queryKeys_1.queryKeys.users.profile(sessionId),
|
|
35
|
+
queryFn: async () => {
|
|
36
|
+
const results = await oxyServices.getUsersBySessions([sessionId]);
|
|
37
|
+
return results[0]?.user || null;
|
|
38
|
+
},
|
|
39
|
+
enabled: (options?.enabled !== false) && !!sessionId,
|
|
40
|
+
staleTime: 5 * 60 * 1000,
|
|
41
|
+
gcTime: 30 * 60 * 1000,
|
|
42
|
+
})),
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
exports.useUserProfiles = useUserProfiles;
|
|
46
|
+
/**
|
|
47
|
+
* Get current authenticated user
|
|
48
|
+
*/
|
|
49
|
+
const useCurrentUser = (options) => {
|
|
50
|
+
const { oxyServices, activeSessionId, isAuthenticated } = (0, WebOxyProvider_1.useWebOxy)();
|
|
51
|
+
return (0, react_query_1.useQuery)({
|
|
52
|
+
queryKey: queryKeys_1.queryKeys.accounts.current(),
|
|
53
|
+
queryFn: async () => {
|
|
54
|
+
if (!activeSessionId) {
|
|
55
|
+
throw new Error('No active session');
|
|
56
|
+
}
|
|
57
|
+
return await oxyServices.getUserBySession(activeSessionId);
|
|
58
|
+
},
|
|
59
|
+
enabled: (options?.enabled !== false) && isAuthenticated && !!activeSessionId,
|
|
60
|
+
staleTime: 1 * 60 * 1000, // 1 minute for current user
|
|
61
|
+
gcTime: 30 * 60 * 1000,
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
exports.useCurrentUser = useCurrentUser;
|
|
65
|
+
/**
|
|
66
|
+
* Get user by ID
|
|
67
|
+
*/
|
|
68
|
+
const useUserById = (userId, options) => {
|
|
69
|
+
const { oxyServices } = (0, WebOxyProvider_1.useWebOxy)();
|
|
70
|
+
return (0, react_query_1.useQuery)({
|
|
71
|
+
queryKey: queryKeys_1.queryKeys.users.detail(userId || ''),
|
|
72
|
+
queryFn: async () => {
|
|
73
|
+
if (!userId) {
|
|
74
|
+
throw new Error('User ID is required');
|
|
75
|
+
}
|
|
76
|
+
return await oxyServices.getUserById(userId);
|
|
77
|
+
},
|
|
78
|
+
enabled: (options?.enabled !== false) && !!userId,
|
|
79
|
+
staleTime: 5 * 60 * 1000,
|
|
80
|
+
gcTime: 30 * 60 * 1000,
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
exports.useUserById = useUserById;
|
|
84
|
+
/**
|
|
85
|
+
* Get user profile by username
|
|
86
|
+
*/
|
|
87
|
+
const useUserByUsername = (username, options) => {
|
|
88
|
+
const { oxyServices } = (0, WebOxyProvider_1.useWebOxy)();
|
|
89
|
+
return (0, react_query_1.useQuery)({
|
|
90
|
+
queryKey: [...queryKeys_1.queryKeys.users.details(), 'username', username || ''],
|
|
91
|
+
queryFn: async () => {
|
|
92
|
+
if (!username) {
|
|
93
|
+
throw new Error('Username is required');
|
|
94
|
+
}
|
|
95
|
+
return await oxyServices.getProfileByUsername(username);
|
|
96
|
+
},
|
|
97
|
+
enabled: (options?.enabled !== false) && !!username,
|
|
98
|
+
staleTime: 5 * 60 * 1000,
|
|
99
|
+
gcTime: 30 * 60 * 1000,
|
|
100
|
+
});
|
|
101
|
+
};
|
|
102
|
+
exports.useUserByUsername = useUserByUsername;
|
|
103
|
+
/**
|
|
104
|
+
* Batch get users by session IDs (optimized single API call)
|
|
105
|
+
*/
|
|
106
|
+
const useUsersBySessions = (sessionIds, options) => {
|
|
107
|
+
const { oxyServices } = (0, WebOxyProvider_1.useWebOxy)();
|
|
108
|
+
return (0, react_query_1.useQuery)({
|
|
109
|
+
queryKey: queryKeys_1.queryKeys.accounts.list(sessionIds),
|
|
110
|
+
queryFn: async () => {
|
|
111
|
+
if (sessionIds.length === 0) {
|
|
112
|
+
return [];
|
|
113
|
+
}
|
|
114
|
+
return await oxyServices.getUsersBySessions(sessionIds);
|
|
115
|
+
},
|
|
116
|
+
enabled: (options?.enabled !== false) && sessionIds.length > 0,
|
|
117
|
+
staleTime: 5 * 60 * 1000,
|
|
118
|
+
gcTime: 30 * 60 * 1000,
|
|
119
|
+
});
|
|
120
|
+
};
|
|
121
|
+
exports.useUsersBySessions = useUsersBySessions;
|
|
122
|
+
/**
|
|
123
|
+
* Get privacy settings for a user
|
|
124
|
+
*/
|
|
125
|
+
const usePrivacySettings = (userId, options) => {
|
|
126
|
+
const { oxyServices, activeSessionId, user } = (0, WebOxyProvider_1.useWebOxy)();
|
|
127
|
+
const targetUserId = userId || user?.id;
|
|
128
|
+
return (0, react_query_1.useQuery)({
|
|
129
|
+
queryKey: queryKeys_1.queryKeys.privacy.settings(targetUserId),
|
|
130
|
+
queryFn: async () => {
|
|
131
|
+
if (!targetUserId) {
|
|
132
|
+
throw new Error('User ID is required');
|
|
133
|
+
}
|
|
134
|
+
return (0, authHelpers_1.authenticatedApiCall)(oxyServices, activeSessionId, () => oxyServices.getPrivacySettings(targetUserId));
|
|
135
|
+
},
|
|
136
|
+
enabled: (options?.enabled !== false) && !!targetUserId,
|
|
137
|
+
staleTime: 2 * 60 * 1000, // 2 minutes
|
|
138
|
+
gcTime: 10 * 60 * 1000, // 10 minutes
|
|
139
|
+
});
|
|
140
|
+
};
|
|
141
|
+
exports.usePrivacySettings = usePrivacySettings;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useRecentSecurityActivity = exports.useSecurityActivity = void 0;
|
|
4
|
+
const react_query_1 = require("@tanstack/react-query");
|
|
5
|
+
const queryKeys_1 = require("./queryKeys");
|
|
6
|
+
const WebOxyProvider_1 = require("../../WebOxyProvider");
|
|
7
|
+
/**
|
|
8
|
+
* Get user's security activity with pagination
|
|
9
|
+
*/
|
|
10
|
+
const useSecurityActivity = (options) => {
|
|
11
|
+
const { oxyServices, activeSessionId } = (0, WebOxyProvider_1.useWebOxy)();
|
|
12
|
+
return (0, react_query_1.useQuery)({
|
|
13
|
+
queryKey: queryKeys_1.queryKeys.security.activity(options?.limit, options?.offset, options?.eventType),
|
|
14
|
+
queryFn: async () => {
|
|
15
|
+
if (!activeSessionId) {
|
|
16
|
+
throw new Error('No active session');
|
|
17
|
+
}
|
|
18
|
+
const response = await oxyServices.getSecurityActivity(options?.limit, options?.offset, options?.eventType);
|
|
19
|
+
return response;
|
|
20
|
+
},
|
|
21
|
+
enabled: (options?.enabled !== false) && !!activeSessionId,
|
|
22
|
+
staleTime: 5 * 60 * 1000, // 5 minutes
|
|
23
|
+
gcTime: 10 * 60 * 1000, // 10 minutes
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
exports.useSecurityActivity = useSecurityActivity;
|
|
27
|
+
/**
|
|
28
|
+
* Get recent security activity (convenience hook)
|
|
29
|
+
*/
|
|
30
|
+
const useRecentSecurityActivity = (limit = 10) => {
|
|
31
|
+
const { oxyServices, activeSessionId } = (0, WebOxyProvider_1.useWebOxy)();
|
|
32
|
+
return (0, react_query_1.useQuery)({
|
|
33
|
+
queryKey: queryKeys_1.queryKeys.security.recent(limit),
|
|
34
|
+
queryFn: async () => {
|
|
35
|
+
if (!activeSessionId) {
|
|
36
|
+
throw new Error('No active session');
|
|
37
|
+
}
|
|
38
|
+
return await oxyServices.getRecentSecurityActivity(limit);
|
|
39
|
+
},
|
|
40
|
+
enabled: !!activeSessionId,
|
|
41
|
+
staleTime: 5 * 60 * 1000, // 5 minutes
|
|
42
|
+
gcTime: 10 * 60 * 1000, // 10 minutes
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
exports.useRecentSecurityActivity = useRecentSecurityActivity;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useSecurityInfo = exports.useUserDevices = exports.useDeviceSessions = exports.useSession = exports.useSessions = void 0;
|
|
4
|
+
const react_query_1 = require("@tanstack/react-query");
|
|
5
|
+
const queryKeys_1 = require("./queryKeys");
|
|
6
|
+
const WebOxyProvider_1 = require("../../WebOxyProvider");
|
|
7
|
+
const sessionHelpers_1 = require("../../utils/sessionHelpers");
|
|
8
|
+
const authHelpers_1 = require("../../utils/authHelpers");
|
|
9
|
+
/**
|
|
10
|
+
* Get all active sessions for the current user
|
|
11
|
+
*/
|
|
12
|
+
const useSessions = (userId, options) => {
|
|
13
|
+
const { oxyServices, activeSessionId } = (0, WebOxyProvider_1.useWebOxy)();
|
|
14
|
+
return (0, react_query_1.useQuery)({
|
|
15
|
+
queryKey: queryKeys_1.queryKeys.sessions.list(userId),
|
|
16
|
+
queryFn: async () => {
|
|
17
|
+
if (!activeSessionId) {
|
|
18
|
+
throw new Error('No active session');
|
|
19
|
+
}
|
|
20
|
+
const sessions = await (0, sessionHelpers_1.fetchSessionsWithFallback)(oxyServices, activeSessionId, {
|
|
21
|
+
fallbackDeviceId: undefined,
|
|
22
|
+
fallbackUserId: userId,
|
|
23
|
+
});
|
|
24
|
+
return (0, sessionHelpers_1.mapSessionsToClient)(sessions, activeSessionId);
|
|
25
|
+
},
|
|
26
|
+
enabled: (options?.enabled !== false) && !!activeSessionId,
|
|
27
|
+
staleTime: 2 * 60 * 1000, // 2 minutes (sessions change frequently)
|
|
28
|
+
gcTime: 10 * 60 * 1000, // 10 minutes
|
|
29
|
+
});
|
|
30
|
+
};
|
|
31
|
+
exports.useSessions = useSessions;
|
|
32
|
+
/**
|
|
33
|
+
* Get specific session by ID
|
|
34
|
+
*/
|
|
35
|
+
const useSession = (sessionId, options) => {
|
|
36
|
+
const { oxyServices } = (0, WebOxyProvider_1.useWebOxy)();
|
|
37
|
+
return (0, react_query_1.useQuery)({
|
|
38
|
+
queryKey: queryKeys_1.queryKeys.sessions.detail(sessionId || ''),
|
|
39
|
+
queryFn: async () => {
|
|
40
|
+
if (!sessionId) {
|
|
41
|
+
throw new Error('Session ID is required');
|
|
42
|
+
}
|
|
43
|
+
const validation = await oxyServices.validateSession(sessionId, { useHeaderValidation: true });
|
|
44
|
+
if (!validation?.valid || !validation.user) {
|
|
45
|
+
throw new Error('Session not found or invalid');
|
|
46
|
+
}
|
|
47
|
+
const now = new Date();
|
|
48
|
+
return {
|
|
49
|
+
sessionId,
|
|
50
|
+
deviceId: '', // Device ID not available from validation response
|
|
51
|
+
expiresAt: validation.expiresAt || new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000).toISOString(),
|
|
52
|
+
lastActive: validation.lastActivity || now.toISOString(),
|
|
53
|
+
userId: validation.user.id?.toString() ?? '',
|
|
54
|
+
isCurrent: false,
|
|
55
|
+
};
|
|
56
|
+
},
|
|
57
|
+
enabled: (options?.enabled !== false) && !!sessionId,
|
|
58
|
+
staleTime: 2 * 60 * 1000,
|
|
59
|
+
gcTime: 10 * 60 * 1000,
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
exports.useSession = useSession;
|
|
63
|
+
/**
|
|
64
|
+
* Get device sessions for the current active session
|
|
65
|
+
*/
|
|
66
|
+
const useDeviceSessions = (options) => {
|
|
67
|
+
const { oxyServices, activeSessionId } = (0, WebOxyProvider_1.useWebOxy)();
|
|
68
|
+
return (0, react_query_1.useQuery)({
|
|
69
|
+
queryKey: queryKeys_1.queryKeys.sessions.active(),
|
|
70
|
+
queryFn: async () => {
|
|
71
|
+
if (!activeSessionId) {
|
|
72
|
+
throw new Error('No active session');
|
|
73
|
+
}
|
|
74
|
+
return await oxyServices.getDeviceSessions(activeSessionId);
|
|
75
|
+
},
|
|
76
|
+
enabled: (options?.enabled !== false) && !!activeSessionId,
|
|
77
|
+
staleTime: 2 * 60 * 1000,
|
|
78
|
+
gcTime: 10 * 60 * 1000,
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
exports.useDeviceSessions = useDeviceSessions;
|
|
82
|
+
/**
|
|
83
|
+
* Get user devices
|
|
84
|
+
*/
|
|
85
|
+
const useUserDevices = (options) => {
|
|
86
|
+
const { oxyServices, isAuthenticated, activeSessionId } = (0, WebOxyProvider_1.useWebOxy)();
|
|
87
|
+
return (0, react_query_1.useQuery)({
|
|
88
|
+
queryKey: queryKeys_1.queryKeys.devices.list(),
|
|
89
|
+
queryFn: async () => {
|
|
90
|
+
return (0, authHelpers_1.authenticatedApiCall)(oxyServices, activeSessionId, () => oxyServices.getUserDevices());
|
|
91
|
+
},
|
|
92
|
+
enabled: (options?.enabled !== false) && isAuthenticated,
|
|
93
|
+
staleTime: 5 * 60 * 1000,
|
|
94
|
+
gcTime: 30 * 60 * 1000,
|
|
95
|
+
});
|
|
96
|
+
};
|
|
97
|
+
exports.useUserDevices = useUserDevices;
|
|
98
|
+
/**
|
|
99
|
+
* Get security information
|
|
100
|
+
*/
|
|
101
|
+
const useSecurityInfo = (options) => {
|
|
102
|
+
const { oxyServices, isAuthenticated } = (0, WebOxyProvider_1.useWebOxy)();
|
|
103
|
+
return (0, react_query_1.useQuery)({
|
|
104
|
+
queryKey: [...queryKeys_1.queryKeys.devices.all, 'security'],
|
|
105
|
+
queryFn: async () => {
|
|
106
|
+
return await oxyServices.getSecurityInfo();
|
|
107
|
+
},
|
|
108
|
+
enabled: (options?.enabled !== false) && isAuthenticated,
|
|
109
|
+
staleTime: 5 * 60 * 1000,
|
|
110
|
+
gcTime: 30 * 60 * 1000,
|
|
111
|
+
});
|
|
112
|
+
};
|
|
113
|
+
exports.useSecurityInfo = useSecurityInfo;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.clearQueryCache = exports.createQueryClient = exports.createPersistenceAdapter = void 0;
|
|
4
|
+
const react_query_1 = require("@tanstack/react-query");
|
|
5
|
+
const QUERY_CACHE_KEY = 'oxy_query_cache';
|
|
6
|
+
const QUERY_CACHE_VERSION = '1';
|
|
7
|
+
/**
|
|
8
|
+
* Custom persistence adapter for TanStack Query using our StorageInterface
|
|
9
|
+
*/
|
|
10
|
+
const createPersistenceAdapter = (storage) => {
|
|
11
|
+
return {
|
|
12
|
+
persistClient: async (client) => {
|
|
13
|
+
try {
|
|
14
|
+
const serialized = JSON.stringify({
|
|
15
|
+
clientState: client,
|
|
16
|
+
timestamp: Date.now(),
|
|
17
|
+
version: QUERY_CACHE_VERSION,
|
|
18
|
+
});
|
|
19
|
+
await storage.setItem(QUERY_CACHE_KEY, serialized);
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
if (__DEV__) {
|
|
23
|
+
console.warn('[QueryClient] Failed to persist cache:', error);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
restoreClient: async () => {
|
|
28
|
+
try {
|
|
29
|
+
const cached = await storage.getItem(QUERY_CACHE_KEY);
|
|
30
|
+
if (!cached)
|
|
31
|
+
return undefined;
|
|
32
|
+
const parsed = JSON.parse(cached);
|
|
33
|
+
// Check version compatibility
|
|
34
|
+
if (parsed.version !== QUERY_CACHE_VERSION) {
|
|
35
|
+
// Clear old cache on version mismatch
|
|
36
|
+
await storage.removeItem(QUERY_CACHE_KEY);
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
// Check if cache is too old (30 days)
|
|
40
|
+
const maxAge = 30 * 24 * 60 * 60 * 1000;
|
|
41
|
+
if (parsed.timestamp && Date.now() - parsed.timestamp > maxAge) {
|
|
42
|
+
await storage.removeItem(QUERY_CACHE_KEY);
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
return parsed.clientState;
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
if (__DEV__) {
|
|
49
|
+
console.warn('[QueryClient] Failed to restore cache:', error);
|
|
50
|
+
}
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
removeClient: async () => {
|
|
55
|
+
try {
|
|
56
|
+
await storage.removeItem(QUERY_CACHE_KEY);
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
if (__DEV__) {
|
|
60
|
+
console.warn('[QueryClient] Failed to remove cache:', error);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
exports.createPersistenceAdapter = createPersistenceAdapter;
|
|
67
|
+
/**
|
|
68
|
+
* Create a QueryClient with offline-first configuration
|
|
69
|
+
*/
|
|
70
|
+
const createQueryClient = (storage) => {
|
|
71
|
+
const client = new react_query_1.QueryClient({
|
|
72
|
+
defaultOptions: {
|
|
73
|
+
queries: {
|
|
74
|
+
// Data is fresh for 5 minutes
|
|
75
|
+
staleTime: 5 * 60 * 1000,
|
|
76
|
+
// Keep unused data in cache for 30 minutes
|
|
77
|
+
gcTime: 30 * 60 * 1000,
|
|
78
|
+
// Retry 3 times with exponential backoff
|
|
79
|
+
retry: 3,
|
|
80
|
+
retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000),
|
|
81
|
+
// Refetch on reconnect
|
|
82
|
+
refetchOnReconnect: true,
|
|
83
|
+
// Don't refetch on window focus (better for mobile)
|
|
84
|
+
refetchOnWindowFocus: false,
|
|
85
|
+
// Offline-first: use cache when offline
|
|
86
|
+
networkMode: 'offlineFirst',
|
|
87
|
+
},
|
|
88
|
+
mutations: {
|
|
89
|
+
// Retry once for mutations
|
|
90
|
+
retry: 1,
|
|
91
|
+
// Offline-first: queue mutations when offline
|
|
92
|
+
networkMode: 'offlineFirst',
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
// Note: Persistence is handled by TanStack Query's built-in persistence
|
|
97
|
+
// For now, we rely on the query client's default behavior with networkMode: 'offlineFirst'
|
|
98
|
+
// The cache will be available in memory and queries will use cached data when offline
|
|
99
|
+
// Full persistence to AsyncStorage can be added later with @tanstack/react-query-persist-client if needed
|
|
100
|
+
return client;
|
|
101
|
+
};
|
|
102
|
+
exports.createQueryClient = createQueryClient;
|
|
103
|
+
/**
|
|
104
|
+
* Clear persisted query cache
|
|
105
|
+
*/
|
|
106
|
+
const clearQueryCache = async (storage) => {
|
|
107
|
+
const adapter = (0, exports.createPersistenceAdapter)(storage);
|
|
108
|
+
await adapter.removeClient();
|
|
109
|
+
};
|
|
110
|
+
exports.clearQueryCache = clearQueryCache;
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useAssets = exports.setOxyAssetInstance = void 0;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
const assetStore_1 = require("../stores/assetStore");
|
|
6
|
+
// Create a singleton instance for the hook
|
|
7
|
+
let oxyInstance = null;
|
|
8
|
+
const setOxyAssetInstance = (instance) => {
|
|
9
|
+
oxyInstance = instance;
|
|
10
|
+
};
|
|
11
|
+
exports.setOxyAssetInstance = setOxyAssetInstance;
|
|
12
|
+
/**
|
|
13
|
+
* Hook for managing assets with Zustand store integration
|
|
14
|
+
*/
|
|
15
|
+
const useAssets = () => {
|
|
16
|
+
const { assets, uploadProgress, loading, errors, setAsset, setAssets, removeAsset, setUploadProgress, removeUploadProgress, addLink, removeLink, setUploading, setLinking, setDeleting, setUploadError, setLinkError, setDeleteError, clearErrors, getAssetsByApp, getAssetsByEntity, getAssetUsageCount, isAssetLinked, reset } = (0, assetStore_1.useAssetStore)();
|
|
17
|
+
// Upload asset with progress tracking
|
|
18
|
+
const upload = (0, react_1.useCallback)(async (file, metadata) => {
|
|
19
|
+
if (!oxyInstance) {
|
|
20
|
+
throw new Error('OxyServices instance not configured. Call setOxyAssetInstance first.');
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
clearErrors();
|
|
24
|
+
setUploading(true);
|
|
25
|
+
// Upload file (progress tracking simplified for now)
|
|
26
|
+
const result = await oxyInstance.assetUpload(file, undefined, metadata);
|
|
27
|
+
// Update progress with final status
|
|
28
|
+
if (result?.file) {
|
|
29
|
+
const fileId = result.file.id;
|
|
30
|
+
setUploadProgress(fileId, {
|
|
31
|
+
fileId,
|
|
32
|
+
uploaded: file.size,
|
|
33
|
+
total: file.size,
|
|
34
|
+
percentage: 100,
|
|
35
|
+
status: 'complete'
|
|
36
|
+
});
|
|
37
|
+
// Remove progress after a short delay
|
|
38
|
+
setTimeout(() => {
|
|
39
|
+
removeUploadProgress(fileId);
|
|
40
|
+
}, 2000);
|
|
41
|
+
}
|
|
42
|
+
// Add asset to store
|
|
43
|
+
if (result.file) {
|
|
44
|
+
setAsset(result.file);
|
|
45
|
+
return result.file;
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
setUploadError(error.message || 'Upload failed');
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
finally {
|
|
54
|
+
setUploading(false);
|
|
55
|
+
}
|
|
56
|
+
}, [
|
|
57
|
+
clearErrors,
|
|
58
|
+
setUploading,
|
|
59
|
+
setUploadProgress,
|
|
60
|
+
removeUploadProgress,
|
|
61
|
+
setAsset,
|
|
62
|
+
setUploadError
|
|
63
|
+
]);
|
|
64
|
+
// Link asset to entity
|
|
65
|
+
const link = (0, react_1.useCallback)(async (assetId, app, entityType, entityId) => {
|
|
66
|
+
if (!oxyInstance) {
|
|
67
|
+
throw new Error('OxyServices instance not configured. Call setOxyAssetInstance first.');
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
clearErrors();
|
|
71
|
+
setLinking(true);
|
|
72
|
+
// Auto-detect visibility for avatars and profile banners
|
|
73
|
+
const visibility = (entityType === 'avatar' || entityType === 'profile-banner')
|
|
74
|
+
? 'public'
|
|
75
|
+
: undefined;
|
|
76
|
+
const result = await oxyInstance.assetLink(assetId, app, entityType, entityId, visibility);
|
|
77
|
+
if (result.file) {
|
|
78
|
+
setAsset(result.file);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
// If API doesn't return full file, update store optimistically
|
|
82
|
+
addLink(assetId, {
|
|
83
|
+
app,
|
|
84
|
+
entityType,
|
|
85
|
+
entityId,
|
|
86
|
+
createdBy: '', // Will be filled by server
|
|
87
|
+
createdAt: new Date().toISOString()
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
setLinkError(error.message || 'Link failed');
|
|
93
|
+
throw error;
|
|
94
|
+
}
|
|
95
|
+
finally {
|
|
96
|
+
setLinking(false);
|
|
97
|
+
}
|
|
98
|
+
}, [clearErrors, setLinking, setAsset, addLink, setLinkError]);
|
|
99
|
+
// Unlink asset from entity
|
|
100
|
+
const unlink = (0, react_1.useCallback)(async (assetId, app, entityType, entityId) => {
|
|
101
|
+
if (!oxyInstance) {
|
|
102
|
+
throw new Error('OxyServices instance not configured. Call setOxyAssetInstance first.');
|
|
103
|
+
}
|
|
104
|
+
try {
|
|
105
|
+
clearErrors();
|
|
106
|
+
setLinking(true);
|
|
107
|
+
const result = await oxyInstance.assetUnlink(assetId, app, entityType, entityId);
|
|
108
|
+
if (result.file) {
|
|
109
|
+
setAsset(result.file);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
// Update store optimistically
|
|
113
|
+
removeLink(assetId, app, entityType, entityId);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
setLinkError(error.message || 'Unlink failed');
|
|
118
|
+
throw error;
|
|
119
|
+
}
|
|
120
|
+
finally {
|
|
121
|
+
setLinking(false);
|
|
122
|
+
}
|
|
123
|
+
}, [clearErrors, setLinking, setAsset, removeLink, setLinkError]);
|
|
124
|
+
// Get asset URL
|
|
125
|
+
const getUrl = (0, react_1.useCallback)(async (assetId, variant, expiresIn) => {
|
|
126
|
+
if (!oxyInstance) {
|
|
127
|
+
throw new Error('OxyServices instance not configured. Call setOxyAssetInstance first.');
|
|
128
|
+
}
|
|
129
|
+
try {
|
|
130
|
+
const result = await oxyInstance.assetGetUrl(assetId, variant, expiresIn);
|
|
131
|
+
return result.url;
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
throw error;
|
|
135
|
+
}
|
|
136
|
+
}, []);
|
|
137
|
+
// Get asset metadata
|
|
138
|
+
const getAsset = (0, react_1.useCallback)(async (assetId) => {
|
|
139
|
+
if (!oxyInstance) {
|
|
140
|
+
throw new Error('OxyServices instance not configured. Call setOxyAssetInstance first.');
|
|
141
|
+
}
|
|
142
|
+
try {
|
|
143
|
+
const result = await oxyInstance.assetGet(assetId);
|
|
144
|
+
if (result.file) {
|
|
145
|
+
setAsset(result.file);
|
|
146
|
+
return result.file;
|
|
147
|
+
}
|
|
148
|
+
throw new Error('Asset not found');
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
throw error;
|
|
152
|
+
}
|
|
153
|
+
}, [setAsset]);
|
|
154
|
+
// Delete asset
|
|
155
|
+
const deleteAsset = (0, react_1.useCallback)(async (assetId, force = false) => {
|
|
156
|
+
if (!oxyInstance) {
|
|
157
|
+
throw new Error('OxyServices instance not configured. Call setOxyAssetInstance first.');
|
|
158
|
+
}
|
|
159
|
+
try {
|
|
160
|
+
clearErrors();
|
|
161
|
+
setDeleting(true);
|
|
162
|
+
await oxyInstance.assetDelete(assetId, force);
|
|
163
|
+
removeAsset(assetId);
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
setDeleteError(error.message || 'Delete failed');
|
|
167
|
+
throw error;
|
|
168
|
+
}
|
|
169
|
+
finally {
|
|
170
|
+
setDeleting(false);
|
|
171
|
+
}
|
|
172
|
+
}, [clearErrors, setDeleting, removeAsset, setDeleteError]);
|
|
173
|
+
// Restore asset from trash
|
|
174
|
+
const restore = (0, react_1.useCallback)(async (assetId) => {
|
|
175
|
+
if (!oxyInstance) {
|
|
176
|
+
throw new Error('OxyServices instance not configured. Call setOxyAssetInstance first.');
|
|
177
|
+
}
|
|
178
|
+
try {
|
|
179
|
+
const result = await oxyInstance.assetRestore(assetId);
|
|
180
|
+
if (result.file) {
|
|
181
|
+
setAsset(result.file);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
throw error;
|
|
186
|
+
}
|
|
187
|
+
}, [setAsset]);
|
|
188
|
+
// Get variants
|
|
189
|
+
const getVariants = (0, react_1.useCallback)(async (assetId) => {
|
|
190
|
+
if (!oxyInstance) {
|
|
191
|
+
throw new Error('OxyServices instance not configured. Call setOxyAssetInstance first.');
|
|
192
|
+
}
|
|
193
|
+
try {
|
|
194
|
+
return await oxyInstance.assetGetVariants(assetId);
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
throw error;
|
|
198
|
+
}
|
|
199
|
+
}, []);
|
|
200
|
+
return {
|
|
201
|
+
// State
|
|
202
|
+
assets: Object.values(assets),
|
|
203
|
+
uploadProgress,
|
|
204
|
+
loading,
|
|
205
|
+
errors,
|
|
206
|
+
// Actions
|
|
207
|
+
upload,
|
|
208
|
+
link,
|
|
209
|
+
unlink,
|
|
210
|
+
getUrl,
|
|
211
|
+
getAsset,
|
|
212
|
+
deleteAsset,
|
|
213
|
+
restore,
|
|
214
|
+
getVariants,
|
|
215
|
+
// Utility methods
|
|
216
|
+
getAssetsByApp,
|
|
217
|
+
getAssetsByEntity,
|
|
218
|
+
getAssetUsageCount,
|
|
219
|
+
isAssetLinked,
|
|
220
|
+
// Store management
|
|
221
|
+
clearErrors,
|
|
222
|
+
reset
|
|
223
|
+
};
|
|
224
|
+
};
|
|
225
|
+
exports.useAssets = useAssets;
|