@oxyhq/services 5.16.13 → 5.16.14
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/core/mixins/OxyServices.security.js +54 -0
- package/lib/commonjs/core/mixins/OxyServices.security.js.map +1 -0
- package/lib/commonjs/core/mixins/index.js +3 -2
- package/lib/commonjs/core/mixins/index.js.map +1 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js +16 -2
- package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js.map +1 -1
- package/lib/commonjs/ui/hooks/queries/index.js +13 -0
- package/lib/commonjs/ui/hooks/queries/index.js.map +1 -1
- package/lib/commonjs/ui/hooks/queries/queryKeys.js +6 -0
- package/lib/commonjs/ui/hooks/queries/queryKeys.js.map +1 -1
- package/lib/commonjs/ui/hooks/queries/useSecurityQueries.js +58 -0
- package/lib/commonjs/ui/hooks/queries/useSecurityQueries.js.map +1 -0
- package/lib/commonjs/ui/utils/avatarUtils.js +4 -0
- package/lib/commonjs/ui/utils/avatarUtils.js.map +1 -1
- package/lib/module/core/mixins/OxyServices.security.js +50 -0
- package/lib/module/core/mixins/OxyServices.security.js.map +1 -0
- package/lib/module/core/mixins/index.js +2 -1
- package/lib/module/core/mixins/index.js.map +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/ui/hooks/mutations/useAccountMutations.js +16 -2
- package/lib/module/ui/hooks/mutations/useAccountMutations.js.map +1 -1
- package/lib/module/ui/hooks/queries/index.js +3 -0
- package/lib/module/ui/hooks/queries/index.js.map +1 -1
- package/lib/module/ui/hooks/queries/queryKeys.js +6 -0
- package/lib/module/ui/hooks/queries/queryKeys.js.map +1 -1
- package/lib/module/ui/hooks/queries/useSecurityQueries.js +52 -0
- package/lib/module/ui/hooks/queries/useSecurityQueries.js.map +1 -0
- package/lib/module/ui/utils/avatarUtils.js +4 -0
- package/lib/module/ui/utils/avatarUtils.js.map +1 -1
- package/lib/typescript/core/mixins/OxyServices.security.d.ts +67 -0
- package/lib/typescript/core/mixins/OxyServices.security.d.ts.map +1 -0
- package/lib/typescript/core/mixins/index.d.ts +48 -0
- package/lib/typescript/core/mixins/index.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +1 -1
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/models/interfaces.d.ts +34 -0
- package/lib/typescript/models/interfaces.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/queries/index.d.ts +1 -0
- package/lib/typescript/ui/hooks/queries/index.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/queries/queryKeys.d.ts +5 -0
- package/lib/typescript/ui/hooks/queries/queryKeys.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/queries/useSecurityQueries.d.ts +15 -0
- package/lib/typescript/ui/hooks/queries/useSecurityQueries.d.ts.map +1 -0
- package/lib/typescript/ui/utils/avatarUtils.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/core/mixins/OxyServices.security.ts +59 -0
- package/src/core/mixins/index.ts +14 -11
- package/src/index.ts +6 -1
- package/src/models/interfaces.ts +47 -0
- package/src/ui/hooks/mutations/useAccountMutations.ts +17 -2
- package/src/ui/hooks/queries/index.ts +6 -0
- package/src/ui/hooks/queries/queryKeys.ts +9 -0
- package/src/ui/hooks/queries/useSecurityQueries.ts +64 -0
- package/src/ui/utils/avatarUtils.ts +4 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Security Methods Mixin
|
|
3
|
+
*/
|
|
4
|
+
import type { OxyServicesBase } from '../OxyServices.base';
|
|
5
|
+
import type { SecurityActivity, SecurityActivityResponse, SecurityEventType } from '../../models/interfaces';
|
|
6
|
+
|
|
7
|
+
export function OxyServicesSecurityMixin<T extends typeof OxyServicesBase>(Base: T) {
|
|
8
|
+
return class extends Base {
|
|
9
|
+
constructor(...args: any[]) {
|
|
10
|
+
super(...(args as [any]));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Get user's security activity with pagination
|
|
15
|
+
* @param limit - Number of results (default: 50, max: 100)
|
|
16
|
+
* @param offset - Pagination offset (default: 0)
|
|
17
|
+
* @param eventType - Optional filter by event type
|
|
18
|
+
* @returns Security activity response with pagination
|
|
19
|
+
*/
|
|
20
|
+
async getSecurityActivity(
|
|
21
|
+
limit?: number,
|
|
22
|
+
offset?: number,
|
|
23
|
+
eventType?: SecurityEventType
|
|
24
|
+
): Promise<SecurityActivityResponse> {
|
|
25
|
+
try {
|
|
26
|
+
const params: any = {};
|
|
27
|
+
if (limit !== undefined) params.limit = limit;
|
|
28
|
+
if (offset !== undefined) params.offset = offset;
|
|
29
|
+
if (eventType) params.eventType = eventType;
|
|
30
|
+
|
|
31
|
+
const response = await this.makeRequest<SecurityActivityResponse>(
|
|
32
|
+
'GET',
|
|
33
|
+
'/api/security/activity',
|
|
34
|
+
params,
|
|
35
|
+
{ cache: false }
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
return response;
|
|
39
|
+
} catch (error) {
|
|
40
|
+
throw this.handleError(error);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Get recent security activity (convenience method)
|
|
46
|
+
* @param limit - Number of recent events to fetch (default: 10)
|
|
47
|
+
* @returns Array of recent security activities
|
|
48
|
+
*/
|
|
49
|
+
async getRecentSecurityActivity(limit: number = 10): Promise<SecurityActivity[]> {
|
|
50
|
+
try {
|
|
51
|
+
const response = await this.getSecurityActivity(limit, 0);
|
|
52
|
+
return response.data || [];
|
|
53
|
+
} catch (error) {
|
|
54
|
+
throw this.handleError(error);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
package/src/core/mixins/index.ts
CHANGED
|
@@ -17,6 +17,7 @@ import { OxyServicesDeveloperMixin } from './OxyServices.developer';
|
|
|
17
17
|
import { OxyServicesLocationMixin } from './OxyServices.location';
|
|
18
18
|
import { OxyServicesAnalyticsMixin } from './OxyServices.analytics';
|
|
19
19
|
import { OxyServicesDevicesMixin } from './OxyServices.devices';
|
|
20
|
+
import { OxyServicesSecurityMixin } from './OxyServices.security';
|
|
20
21
|
import { OxyServicesUtilityMixin } from './OxyServices.utility';
|
|
21
22
|
|
|
22
23
|
/**
|
|
@@ -29,17 +30,19 @@ import { OxyServicesUtilityMixin } from './OxyServices.utility';
|
|
|
29
30
|
*/
|
|
30
31
|
export function composeOxyServices() {
|
|
31
32
|
return OxyServicesUtilityMixin(
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
33
|
+
OxyServicesSecurityMixin(
|
|
34
|
+
OxyServicesDevicesMixin(
|
|
35
|
+
OxyServicesAnalyticsMixin(
|
|
36
|
+
OxyServicesLocationMixin(
|
|
37
|
+
OxyServicesDeveloperMixin(
|
|
38
|
+
OxyServicesAssetsMixin(
|
|
39
|
+
OxyServicesKarmaMixin(
|
|
40
|
+
OxyServicesPaymentMixin(
|
|
41
|
+
OxyServicesLanguageMixin(
|
|
42
|
+
OxyServicesPrivacyMixin(
|
|
43
|
+
OxyServicesUserMixin(
|
|
44
|
+
OxyServicesAuthMixin(OxyServicesBase)
|
|
45
|
+
)
|
|
43
46
|
)
|
|
44
47
|
)
|
|
45
48
|
)
|
package/src/index.ts
CHANGED
|
@@ -103,7 +103,12 @@ export type {
|
|
|
103
103
|
AssetUpdateVisibilityResponse,
|
|
104
104
|
// Account storage usage
|
|
105
105
|
AccountStorageCategoryUsage,
|
|
106
|
-
AccountStorageUsageResponse
|
|
106
|
+
AccountStorageUsageResponse,
|
|
107
|
+
// Security activity
|
|
108
|
+
SecurityEventType,
|
|
109
|
+
SecurityEventSeverity,
|
|
110
|
+
SecurityActivity,
|
|
111
|
+
SecurityActivityResponse
|
|
107
112
|
} from './models/interfaces';
|
|
108
113
|
|
|
109
114
|
export type {
|
package/src/models/interfaces.ts
CHANGED
|
@@ -403,6 +403,53 @@ export interface AccountStorageUsageResponse {
|
|
|
403
403
|
updatedAt: string;
|
|
404
404
|
}
|
|
405
405
|
|
|
406
|
+
/**
|
|
407
|
+
* Security activity event types
|
|
408
|
+
*/
|
|
409
|
+
export type SecurityEventType =
|
|
410
|
+
| 'sign_in'
|
|
411
|
+
| 'sign_out'
|
|
412
|
+
| 'email_changed'
|
|
413
|
+
| 'profile_updated'
|
|
414
|
+
| 'device_added'
|
|
415
|
+
| 'device_removed'
|
|
416
|
+
| 'account_recovery'
|
|
417
|
+
| 'security_settings_changed'
|
|
418
|
+
| 'suspicious_activity';
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Security event severity levels
|
|
422
|
+
*/
|
|
423
|
+
export type SecurityEventSeverity = 'low' | 'medium' | 'high' | 'critical';
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Security activity event
|
|
427
|
+
*/
|
|
428
|
+
export interface SecurityActivity {
|
|
429
|
+
id: string;
|
|
430
|
+
userId: string;
|
|
431
|
+
eventType: SecurityEventType;
|
|
432
|
+
eventDescription: string;
|
|
433
|
+
metadata?: Record<string, any>;
|
|
434
|
+
ipAddress?: string;
|
|
435
|
+
userAgent?: string;
|
|
436
|
+
deviceId?: string;
|
|
437
|
+
timestamp: string;
|
|
438
|
+
severity: SecurityEventSeverity;
|
|
439
|
+
createdAt: string;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Security activity response with pagination
|
|
444
|
+
*/
|
|
445
|
+
export interface SecurityActivityResponse {
|
|
446
|
+
data: SecurityActivity[];
|
|
447
|
+
total: number;
|
|
448
|
+
limit: number;
|
|
449
|
+
offset: number;
|
|
450
|
+
hasMore: boolean;
|
|
451
|
+
}
|
|
452
|
+
|
|
406
453
|
export interface AssetUploadProgress {
|
|
407
454
|
fileId: string;
|
|
408
455
|
uploaded: number;
|
|
@@ -4,6 +4,7 @@ import { queryKeys, invalidateAccountQueries, invalidateUserQueries } from '../q
|
|
|
4
4
|
import { useOxy } from '../../context/OxyContext';
|
|
5
5
|
import { toast } from '../../../lib/sonner';
|
|
6
6
|
import { refreshAvatarInStore } from '../../utils/avatarUtils';
|
|
7
|
+
import { useAuthStore } from '../../stores/authStore';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Update user profile with optimistic updates and offline queue support
|
|
@@ -107,6 +108,9 @@ export const useUpdateProfile = () => {
|
|
|
107
108
|
queryClient.setQueryData(queryKeys.users.profile(activeSessionId), data);
|
|
108
109
|
}
|
|
109
110
|
|
|
111
|
+
// Update authStore so frontend components see the changes immediately
|
|
112
|
+
useAuthStore.getState().setUser(data);
|
|
113
|
+
|
|
110
114
|
// If avatar was updated, refresh accountStore with cache-busted URL
|
|
111
115
|
if (updates.avatar && activeSessionId && oxyServices) {
|
|
112
116
|
refreshAvatarInStore(activeSessionId, updates.avatar, oxyServices);
|
|
@@ -220,6 +224,9 @@ export const useUploadAvatar = () => {
|
|
|
220
224
|
queryClient.setQueryData(queryKeys.users.profile(activeSessionId), data);
|
|
221
225
|
}
|
|
222
226
|
|
|
227
|
+
// Update authStore so frontend components see the changes immediately
|
|
228
|
+
useAuthStore.getState().setUser(data);
|
|
229
|
+
|
|
223
230
|
// Refresh accountStore with cache-busted URL if avatar was updated
|
|
224
231
|
if (data?.avatar && activeSessionId && oxyServices) {
|
|
225
232
|
refreshAvatarInStore(activeSessionId, data.avatar, oxyServices);
|
|
@@ -268,6 +275,10 @@ export const useUpdateAccountSettings = () => {
|
|
|
268
275
|
},
|
|
269
276
|
onSuccess: (data) => {
|
|
270
277
|
queryClient.setQueryData(queryKeys.accounts.current(), data);
|
|
278
|
+
|
|
279
|
+
// Update authStore so frontend components see the changes immediately
|
|
280
|
+
useAuthStore.getState().setUser(data);
|
|
281
|
+
|
|
271
282
|
invalidateAccountQueries(queryClient);
|
|
272
283
|
toast.success('Settings updated successfully');
|
|
273
284
|
},
|
|
@@ -394,10 +405,14 @@ export const useUpdatePrivacySettings = () => {
|
|
|
394
405
|
// Also update account query if it contains privacy settings
|
|
395
406
|
const currentUser = queryClient.getQueryData<User>(queryKeys.accounts.current());
|
|
396
407
|
if (currentUser) {
|
|
397
|
-
|
|
408
|
+
const updatedUser = {
|
|
398
409
|
...currentUser,
|
|
399
410
|
privacySettings: data,
|
|
400
|
-
}
|
|
411
|
+
};
|
|
412
|
+
queryClient.setQueryData<User>(queryKeys.accounts.current(), updatedUser);
|
|
413
|
+
|
|
414
|
+
// Update authStore so frontend components see the changes immediately
|
|
415
|
+
useAuthStore.getState().setUser(updatedUser);
|
|
401
416
|
}
|
|
402
417
|
invalidateAccountQueries(queryClient);
|
|
403
418
|
},
|
|
@@ -25,6 +25,12 @@ export {
|
|
|
25
25
|
useSecurityInfo,
|
|
26
26
|
} from './useServicesQueries';
|
|
27
27
|
|
|
28
|
+
// Security activity query hooks
|
|
29
|
+
export {
|
|
30
|
+
useSecurityActivity,
|
|
31
|
+
useRecentSecurityActivity,
|
|
32
|
+
} from './useSecurityQueries';
|
|
33
|
+
|
|
28
34
|
// Query keys and invalidation helpers (for advanced usage)
|
|
29
35
|
export { queryKeys, invalidateAccountQueries, invalidateUserQueries, invalidateSessionQueries } from './queryKeys';
|
|
30
36
|
|
|
@@ -54,6 +54,15 @@ export const queryKeys = {
|
|
|
54
54
|
all: ['privacy'] as const,
|
|
55
55
|
settings: (userId?: string) => [...queryKeys.privacy.all, 'settings', userId || 'current'] as const,
|
|
56
56
|
},
|
|
57
|
+
|
|
58
|
+
// Security activity queries
|
|
59
|
+
security: {
|
|
60
|
+
all: ['security'] as const,
|
|
61
|
+
activity: (limit?: number, offset?: number, eventType?: string) =>
|
|
62
|
+
[...queryKeys.security.all, 'activity', limit, offset, eventType] as const,
|
|
63
|
+
recent: (limit: number) =>
|
|
64
|
+
[...queryKeys.security.all, 'recent', limit] as const,
|
|
65
|
+
},
|
|
57
66
|
} as const;
|
|
58
67
|
|
|
59
68
|
/**
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { useQuery } from '@tanstack/react-query';
|
|
2
|
+
import { queryKeys } from './queryKeys';
|
|
3
|
+
import { useOxy } from '../../context/OxyContext';
|
|
4
|
+
import type { SecurityActivity, SecurityEventType } from '../../../models/interfaces';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Get user's security activity with pagination
|
|
8
|
+
*/
|
|
9
|
+
export const useSecurityActivity = (
|
|
10
|
+
options?: {
|
|
11
|
+
limit?: number;
|
|
12
|
+
offset?: number;
|
|
13
|
+
eventType?: SecurityEventType;
|
|
14
|
+
enabled?: boolean;
|
|
15
|
+
}
|
|
16
|
+
) => {
|
|
17
|
+
const { oxyServices, activeSessionId } = useOxy();
|
|
18
|
+
|
|
19
|
+
return useQuery({
|
|
20
|
+
queryKey: queryKeys.security.activity(
|
|
21
|
+
options?.limit,
|
|
22
|
+
options?.offset,
|
|
23
|
+
options?.eventType
|
|
24
|
+
),
|
|
25
|
+
queryFn: async () => {
|
|
26
|
+
if (!activeSessionId) {
|
|
27
|
+
throw new Error('No active session');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const response = await oxyServices.getSecurityActivity(
|
|
31
|
+
options?.limit,
|
|
32
|
+
options?.offset,
|
|
33
|
+
options?.eventType
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
return response;
|
|
37
|
+
},
|
|
38
|
+
enabled: (options?.enabled !== false) && !!activeSessionId,
|
|
39
|
+
staleTime: 5 * 60 * 1000, // 5 minutes
|
|
40
|
+
gcTime: 10 * 60 * 1000, // 10 minutes
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Get recent security activity (convenience hook)
|
|
46
|
+
*/
|
|
47
|
+
export const useRecentSecurityActivity = (limit: number = 10) => {
|
|
48
|
+
const { oxyServices, activeSessionId } = useOxy();
|
|
49
|
+
|
|
50
|
+
return useQuery<SecurityActivity[]>({
|
|
51
|
+
queryKey: queryKeys.security.recent(limit),
|
|
52
|
+
queryFn: async () => {
|
|
53
|
+
if (!activeSessionId) {
|
|
54
|
+
throw new Error('No active session');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return await oxyServices.getRecentSecurityActivity(limit);
|
|
58
|
+
},
|
|
59
|
+
enabled: !!activeSessionId,
|
|
60
|
+
staleTime: 5 * 60 * 1000, // 5 minutes
|
|
61
|
+
gcTime: 10 * 60 * 1000, // 10 minutes
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { OxyServices } from '../../core';
|
|
2
2
|
import type { User } from '../../models/interfaces';
|
|
3
3
|
import { useAccountStore } from '../stores/accountStore';
|
|
4
|
+
import { useAuthStore } from '../stores/authStore';
|
|
4
5
|
import { QueryClient } from '@tanstack/react-query';
|
|
5
6
|
import { queryKeys, invalidateUserQueries, invalidateAccountQueries } from '../hooks/queries/queryKeys';
|
|
6
7
|
|
|
@@ -103,6 +104,9 @@ export async function updateProfileWithAvatar(
|
|
|
103
104
|
queryClient.setQueryData(queryKeys.users.profile(activeSessionId), data);
|
|
104
105
|
}
|
|
105
106
|
|
|
107
|
+
// Update authStore so frontend components see the changes immediately
|
|
108
|
+
useAuthStore.getState().setUser(data);
|
|
109
|
+
|
|
106
110
|
// If avatar was updated, refresh accountStore with cache-busted URL
|
|
107
111
|
if (updates.avatar && activeSessionId) {
|
|
108
112
|
refreshAvatarInStore(activeSessionId, updates.avatar, oxyServices);
|