@oxyhq/services 5.17.7 → 5.17.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/lib/commonjs/crypto/keyManager.js +6 -161
  2. package/lib/commonjs/crypto/keyManager.js.map +1 -1
  3. package/lib/commonjs/ui/context/OxyContext.js +22 -582
  4. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  5. package/lib/commonjs/ui/context/OxyContextBase.js.map +1 -1
  6. package/lib/commonjs/ui/context/hooks/useAuthOperations.js +14 -331
  7. package/lib/commonjs/ui/context/hooks/useAuthOperations.js.map +1 -1
  8. package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js +8 -112
  9. package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js.map +1 -1
  10. package/lib/commonjs/ui/hooks/queries/useAccountQueries.js +2 -27
  11. package/lib/commonjs/ui/hooks/queries/useAccountQueries.js.map +1 -1
  12. package/lib/commonjs/ui/hooks/queries/useServicesQueries.js +2 -27
  13. package/lib/commonjs/ui/hooks/queries/useServicesQueries.js.map +1 -1
  14. package/lib/commonjs/ui/hooks/useSessionSocket.js +2 -88
  15. package/lib/commonjs/ui/hooks/useSessionSocket.js.map +1 -1
  16. package/lib/module/crypto/keyManager.js +6 -161
  17. package/lib/module/crypto/keyManager.js.map +1 -1
  18. package/lib/module/ui/context/OxyContext.js +20 -581
  19. package/lib/module/ui/context/OxyContext.js.map +1 -1
  20. package/lib/module/ui/context/OxyContextBase.js.map +1 -1
  21. package/lib/module/ui/context/hooks/useAuthOperations.js +14 -330
  22. package/lib/module/ui/context/hooks/useAuthOperations.js.map +1 -1
  23. package/lib/module/ui/hooks/mutations/useAccountMutations.js +8 -112
  24. package/lib/module/ui/hooks/mutations/useAccountMutations.js.map +1 -1
  25. package/lib/module/ui/hooks/queries/useAccountQueries.js +2 -27
  26. package/lib/module/ui/hooks/queries/useAccountQueries.js.map +1 -1
  27. package/lib/module/ui/hooks/queries/useServicesQueries.js +2 -27
  28. package/lib/module/ui/hooks/queries/useServicesQueries.js.map +1 -1
  29. package/lib/module/ui/hooks/useSessionSocket.js +2 -88
  30. package/lib/module/ui/hooks/useSessionSocket.js.map +1 -1
  31. package/lib/typescript/crypto/keyManager.d.ts +3 -20
  32. package/lib/typescript/crypto/keyManager.d.ts.map +1 -1
  33. package/lib/typescript/crypto/types.d.ts +4 -0
  34. package/lib/typescript/crypto/types.d.ts.map +1 -1
  35. package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
  36. package/lib/typescript/ui/context/OxyContextBase.d.ts +0 -37
  37. package/lib/typescript/ui/context/OxyContextBase.d.ts.map +1 -1
  38. package/lib/typescript/ui/context/hooks/useAuthOperations.d.ts +1 -20
  39. package/lib/typescript/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
  40. package/lib/typescript/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
  41. package/lib/typescript/ui/hooks/queries/useAccountQueries.d.ts.map +1 -1
  42. package/lib/typescript/ui/hooks/queries/useServicesQueries.d.ts.map +1 -1
  43. package/lib/typescript/ui/hooks/useSessionSocket.d.ts +1 -14
  44. package/lib/typescript/ui/hooks/useSessionSocket.d.ts.map +1 -1
  45. package/package.json +1 -1
  46. package/src/crypto/keyManager.ts +4 -170
  47. package/src/crypto/types.ts +4 -0
  48. package/src/ui/context/OxyContext.tsx +17 -630
  49. package/src/ui/context/OxyContextBase.tsx +2 -20
  50. package/src/ui/context/hooks/useAuthOperations.ts +22 -347
  51. package/src/ui/hooks/mutations/useAccountMutations.ts +12 -110
  52. package/src/ui/hooks/queries/useAccountQueries.ts +3 -27
  53. package/src/ui/hooks/queries/useServicesQueries.ts +3 -27
  54. package/src/ui/hooks/useSessionSocket.ts +2 -106
@@ -13,7 +13,7 @@ const getDeviceIdForSession = (sessions: ClientSession[] = [], sessionId: string
13
13
  * Update user profile with optimistic updates and offline queue support
14
14
  */
15
15
  export const useUpdateProfile = () => {
16
- const { oxyServices, activeSessionId, user, syncIdentity, sessions } = useOxy();
16
+ const { oxyServices, activeSessionId, user, sessions } = useOxy();
17
17
  const queryClient = useQueryClient();
18
18
 
19
19
  return useMutation({
@@ -24,19 +24,7 @@ export const useUpdateProfile = () => {
24
24
  // Try to get token for the session
25
25
  await oxyServices.getTokenBySession(activeSessionId, getDeviceIdForSession(sessions, activeSessionId));
26
26
  } catch (tokenError) {
27
- // If getting token fails, might be an offline session - try syncing
28
- const errorMessage = tokenError instanceof Error ? tokenError.message : String(tokenError);
29
- if (errorMessage.includes('AUTH_REQUIRED_OFFLINE_SESSION') || errorMessage.includes('offline')) {
30
- try {
31
- await syncIdentity();
32
- // Retry getting token after sync
33
- await oxyServices.getTokenBySession(activeSessionId, getDeviceIdForSession(sessions, activeSessionId));
34
- } catch (syncError) {
35
- throw new Error('Session needs to be synced. Please try again.');
36
- }
37
- } else {
38
- throw tokenError;
39
- }
27
+ throw tokenError;
40
28
  }
41
29
  }
42
30
 
@@ -48,19 +36,7 @@ export const useUpdateProfile = () => {
48
36
 
49
37
  // Handle authentication errors
50
38
  if (status === 401 || errorMessage.includes('Authentication required') || errorMessage.includes('Invalid or missing authorization header')) {
51
- // Try to sync session and get token
52
- if (activeSessionId) {
53
- try {
54
- await syncIdentity();
55
- await oxyServices.getTokenBySession(activeSessionId, getDeviceIdForSession(sessions, activeSessionId));
56
- // Retry the update after getting token
57
- return await oxyServices.updateProfile(updates);
58
- } catch (retryError) {
59
- throw new Error('Authentication failed. Please sign in again.');
60
- }
61
- } else {
62
- throw new Error('No active session. Please sign in.');
63
- }
39
+ throw error;
64
40
  }
65
41
 
66
42
  // TanStack Query will automatically retry on network errors
@@ -127,7 +103,7 @@ export const useUpdateProfile = () => {
127
103
  * Upload avatar with progress tracking and offline queue support
128
104
  */
129
105
  export const useUploadAvatar = () => {
130
- const { oxyServices, activeSessionId, syncIdentity, sessions } = useOxy();
106
+ const { oxyServices, activeSessionId, sessions } = useOxy();
131
107
  const queryClient = useQueryClient();
132
108
 
133
109
  return useMutation({
@@ -137,17 +113,7 @@ export const useUploadAvatar = () => {
137
113
  try {
138
114
  await oxyServices.getTokenBySession(activeSessionId, getDeviceIdForSession(sessions, activeSessionId));
139
115
  } catch (tokenError) {
140
- const errorMessage = tokenError instanceof Error ? tokenError.message : String(tokenError);
141
- if (errorMessage.includes('AUTH_REQUIRED_OFFLINE_SESSION') || errorMessage.includes('offline')) {
142
- try {
143
- await syncIdentity();
144
- await oxyServices.getTokenBySession(activeSessionId, getDeviceIdForSession(sessions, activeSessionId));
145
- } catch (syncError) {
146
- throw new Error('Session needs to be synced. Please try again.');
147
- }
148
- } else {
149
- throw tokenError;
150
- }
116
+ throw tokenError;
151
117
  }
152
118
  }
153
119
 
@@ -168,23 +134,7 @@ export const useUploadAvatar = () => {
168
134
 
169
135
  // Handle authentication errors
170
136
  if (status === 401 || errorMessage.includes('Authentication required') || errorMessage.includes('Invalid or missing authorization header')) {
171
- if (activeSessionId) {
172
- try {
173
- await syncIdentity();
174
- await oxyServices.getTokenBySession(activeSessionId, getDeviceIdForSession(sessions, activeSessionId));
175
- // Retry upload
176
- const uploadResult = await oxyServices.assetUpload(file as any, 'public');
177
- const fileId = uploadResult?.file?.id || uploadResult?.id || uploadResult;
178
- if (!fileId || typeof fileId !== 'string') {
179
- throw new Error('Failed to get file ID from upload result');
180
- }
181
- return await oxyServices.updateProfile({ avatar: fileId });
182
- } catch (retryError) {
183
- throw new Error('Authentication failed. Please sign in again.');
184
- }
185
- } else {
186
- throw new Error('No active session. Please sign in.');
187
- }
137
+ throw error;
188
138
  }
189
139
 
190
140
  // TanStack Query will automatically retry on network errors
@@ -286,7 +236,7 @@ export const useUpdateAccountSettings = () => {
286
236
  * Update privacy settings with optimistic updates and authentication handling
287
237
  */
288
238
  export const useUpdatePrivacySettings = () => {
289
- const { oxyServices, activeSessionId, syncIdentity, sessions } = useOxy();
239
+ const { oxyServices, activeSessionId, sessions } = useOxy();
290
240
  const queryClient = useQueryClient();
291
241
 
292
242
  return useMutation({
@@ -304,19 +254,7 @@ export const useUpdatePrivacySettings = () => {
304
254
  // Try to get token for the session
305
255
  await oxyServices.getTokenBySession(activeSessionId, getDeviceIdForSession(sessions, activeSessionId));
306
256
  } catch (tokenError) {
307
- // If getting token fails, might be an offline session - try syncing
308
- const errorMessage = tokenError instanceof Error ? tokenError.message : String(tokenError);
309
- if (errorMessage.includes('AUTH_REQUIRED_OFFLINE_SESSION') || errorMessage.includes('offline')) {
310
- try {
311
- await syncIdentity();
312
- // Retry getting token after sync
313
- await oxyServices.getTokenBySession(activeSessionId, getDeviceIdForSession(sessions, activeSessionId));
314
- } catch (syncError) {
315
- throw new Error('Session needs to be synced. Please try again.');
316
- }
317
- } else {
318
- throw tokenError;
319
- }
257
+ throw tokenError;
320
258
  }
321
259
  }
322
260
 
@@ -328,19 +266,7 @@ export const useUpdatePrivacySettings = () => {
328
266
 
329
267
  // Handle authentication errors
330
268
  if (status === 401 || errorMessage.includes('Authentication required') || errorMessage.includes('Invalid or missing authorization header')) {
331
- // Try to sync session and get token
332
- if (activeSessionId) {
333
- try {
334
- await syncIdentity();
335
- await oxyServices.getTokenBySession(activeSessionId, getDeviceIdForSession(sessions, activeSessionId));
336
- // Retry the update after getting token
337
- return await oxyServices.updatePrivacySettings(settings, targetUserId);
338
- } catch (retryError) {
339
- throw new Error('Authentication failed. Please sign in again.');
340
- }
341
- } else {
342
- throw new Error('No active session. Please sign in.');
343
- }
269
+ throw error;
344
270
  }
345
271
 
346
272
  // TanStack Query will automatically retry on network errors
@@ -424,7 +350,7 @@ export const useUpdatePrivacySettings = () => {
424
350
  * Upload file with authentication handling and progress tracking
425
351
  */
426
352
  export const useUploadFile = () => {
427
- const { oxyServices, activeSessionId, syncIdentity, sessions } = useOxy();
353
+ const { oxyServices, activeSessionId, sessions } = useOxy();
428
354
 
429
355
  return useMutation({
430
356
  mutationFn: async ({
@@ -444,19 +370,7 @@ export const useUploadFile = () => {
444
370
  // Try to get token for the session
445
371
  await oxyServices.getTokenBySession(activeSessionId, getDeviceIdForSession(sessions, activeSessionId));
446
372
  } catch (tokenError) {
447
- // If getting token fails, might be an offline session - try syncing
448
- const errorMessage = tokenError instanceof Error ? tokenError.message : String(tokenError);
449
- if (errorMessage.includes('AUTH_REQUIRED_OFFLINE_SESSION') || errorMessage.includes('offline')) {
450
- try {
451
- await syncIdentity();
452
- // Retry getting token after sync
453
- await oxyServices.getTokenBySession(activeSessionId, getDeviceIdForSession(sessions, activeSessionId));
454
- } catch (syncError) {
455
- throw new Error('Session needs to be synced. Please try again.');
456
- }
457
- } else {
458
- throw tokenError;
459
- }
373
+ throw tokenError;
460
374
  }
461
375
  }
462
376
 
@@ -468,19 +382,7 @@ export const useUploadFile = () => {
468
382
 
469
383
  // Handle authentication errors
470
384
  if (status === 401 || errorMessage.includes('Authentication required') || errorMessage.includes('Invalid or missing authorization header')) {
471
- // Try to sync session and get token
472
- if (activeSessionId) {
473
- try {
474
- await syncIdentity();
475
- await oxyServices.getTokenBySession(activeSessionId, getDeviceIdForSession(sessions, activeSessionId));
476
- // Retry the upload after getting token
477
- return await oxyServices.assetUpload(file as any, visibility, metadata, onProgress);
478
- } catch (retryError) {
479
- throw new Error('Authentication failed. Please sign in again.');
480
- }
481
- } else {
482
- throw new Error('No active session. Please sign in.');
483
- }
385
+ throw error;
484
386
  }
485
387
 
486
388
  // TanStack Query will automatically retry on network errors
@@ -128,7 +128,7 @@ export const useUsersBySessions = (sessionIds: string[], options?: { enabled?: b
128
128
  * Get privacy settings for a user
129
129
  */
130
130
  export const usePrivacySettings = (userId?: string, options?: { enabled?: boolean }) => {
131
- const { oxyServices, activeSessionId, syncIdentity, sessions } = useOxy();
131
+ const { oxyServices, activeSessionId, sessions } = useOxy();
132
132
  // Use getCurrentUserId() which returns MongoDB ObjectId from JWT token
133
133
  // Never use user?.id as it may be set to publicKey
134
134
  const targetUserId = userId || oxyServices.getCurrentUserId() || undefined;
@@ -147,19 +147,7 @@ export const usePrivacySettings = (userId?: string, options?: { enabled?: boolea
147
147
  // Try to get token for the session
148
148
  await oxyServices.getTokenBySession(activeSessionId, deviceId);
149
149
  } catch (tokenError) {
150
- // If getting token fails, might be an offline session - try syncing
151
- const errorMessage = tokenError instanceof Error ? tokenError.message : String(tokenError);
152
- if (errorMessage.includes('AUTH_REQUIRED_OFFLINE_SESSION') || errorMessage.includes('offline')) {
153
- try {
154
- await syncIdentity();
155
- // Retry getting token after sync
156
- await oxyServices.getTokenBySession(activeSessionId, deviceId);
157
- } catch (syncError) {
158
- throw new Error('Session needs to be synced. Please try again.');
159
- }
160
- } else {
161
- throw tokenError;
162
- }
150
+ throw tokenError;
163
151
  }
164
152
  }
165
153
 
@@ -171,19 +159,7 @@ export const usePrivacySettings = (userId?: string, options?: { enabled?: boolea
171
159
 
172
160
  // Handle authentication errors
173
161
  if (status === 401 || errorMessage.includes('Authentication required') || errorMessage.includes('Invalid or missing authorization header')) {
174
- // Try to sync session and get token
175
- if (activeSessionId) {
176
- try {
177
- await syncIdentity();
178
- await oxyServices.getTokenBySession(activeSessionId, deviceId);
179
- // Retry the request after getting token
180
- return await oxyServices.getPrivacySettings(targetUserId);
181
- } catch (retryError) {
182
- throw new Error('Authentication failed. Please sign in again.');
183
- }
184
- } else {
185
- throw new Error('No active session. Please sign in.');
186
- }
162
+ throw error;
187
163
  }
188
164
 
189
165
  // TanStack Query will automatically retry on network errors
@@ -89,7 +89,7 @@ export const useDeviceSessions = (options?: { enabled?: boolean }) => {
89
89
  * Get user devices
90
90
  */
91
91
  export const useUserDevices = (options?: { enabled?: boolean }) => {
92
- const { oxyServices, isAuthenticated, activeSessionId, syncIdentity, sessions } = useOxy();
92
+ const { oxyServices, isAuthenticated, activeSessionId, sessions } = useOxy();
93
93
  const deviceId = activeSessionId ? sessions.find((s) => s.sessionId === activeSessionId)?.deviceId : undefined;
94
94
 
95
95
  return useQuery({
@@ -101,19 +101,7 @@ export const useUserDevices = (options?: { enabled?: boolean }) => {
101
101
  // Try to get token for the session
102
102
  await oxyServices.getTokenBySession(activeSessionId, deviceId);
103
103
  } catch (tokenError) {
104
- // If getting token fails, might be an offline session - try syncing
105
- const errorMessage = tokenError instanceof Error ? tokenError.message : String(tokenError);
106
- if (errorMessage.includes('AUTH_REQUIRED_OFFLINE_SESSION') || errorMessage.includes('offline')) {
107
- try {
108
- await syncIdentity();
109
- // Retry getting token after sync
110
- await oxyServices.getTokenBySession(activeSessionId, deviceId);
111
- } catch (syncError) {
112
- throw new Error('Session needs to be synced. Please try again.');
113
- }
114
- } else {
115
- throw tokenError;
116
- }
104
+ throw tokenError;
117
105
  }
118
106
  }
119
107
 
@@ -125,19 +113,7 @@ export const useUserDevices = (options?: { enabled?: boolean }) => {
125
113
 
126
114
  // Handle authentication errors
127
115
  if (status === 401 || errorMessage.includes('Authentication required') || errorMessage.includes('Invalid or missing authorization header')) {
128
- // Try to sync session and get token
129
- if (activeSessionId) {
130
- try {
131
- await syncIdentity();
132
- await oxyServices.getTokenBySession(activeSessionId, deviceId);
133
- // Retry the request after getting token
134
- return await oxyServices.getUserDevices();
135
- } catch (retryError) {
136
- throw new Error('Authentication failed. Please sign in again.');
137
- }
138
- } else {
139
- throw new Error('No active session. Please sign in.');
140
- }
116
+ throw error;
141
117
  }
142
118
 
143
119
  // TanStack Query will automatically retry on network errors
@@ -13,20 +13,17 @@ interface UseSessionSocketProps {
13
13
  clearSessionState: () => Promise<void>;
14
14
  baseURL: string;
15
15
  getAccessToken: () => string | null;
16
- getTransferCode?: (transferId: string) => { code: string; sourceDeviceId: string | null; publicKey: string; timestamp: number } | null;
17
16
  onRemoteSignOut?: () => void;
18
17
  onSessionRemoved?: (sessionId: string) => void;
19
- onIdentityTransferComplete?: (data: { transferId: string; sourceDeviceId: string; publicKey: string; transferCode?: string; completedAt: string }) => void;
20
18
  }
21
19
 
22
- export function useSessionSocket({ userId, activeSessionId, currentDeviceId, refreshSessions, logout, clearSessionState, baseURL, getAccessToken, getTransferCode, onRemoteSignOut, onSessionRemoved, onIdentityTransferComplete }: UseSessionSocketProps) {
20
+ export function useSessionSocket({ userId, activeSessionId, currentDeviceId, refreshSessions, logout, clearSessionState, baseURL, getAccessToken, onRemoteSignOut, onSessionRemoved }: UseSessionSocketProps) {
23
21
  const socketRef = useRef<any>(null);
24
22
  const joinedRoomRef = useRef<string | null>(null);
25
23
  const accessTokenRef = useRef<string | null>(null);
26
24
  const handlersSetupRef = useRef<boolean>(false);
27
25
  const lastRegisteredSocketIdRef = useRef<string | null>(null);
28
26
  const getAccessTokenRef = useRef(getAccessToken);
29
- const getTransferCodeRef = useRef(getTransferCode);
30
27
 
31
28
  // Store callbacks in refs to avoid re-joining when they change
32
29
  const refreshSessionsRef = useRef(refreshSessions);
@@ -34,7 +31,6 @@ export function useSessionSocket({ userId, activeSessionId, currentDeviceId, ref
34
31
  const clearSessionStateRef = useRef(clearSessionState);
35
32
  const onRemoteSignOutRef = useRef(onRemoteSignOut);
36
33
  const onSessionRemovedRef = useRef(onSessionRemoved);
37
- const onIdentityTransferCompleteRef = useRef(onIdentityTransferComplete);
38
34
  const activeSessionIdRef = useRef(activeSessionId);
39
35
  const currentDeviceIdRef = useRef(currentDeviceId);
40
36
 
@@ -45,12 +41,10 @@ export function useSessionSocket({ userId, activeSessionId, currentDeviceId, ref
45
41
  clearSessionStateRef.current = clearSessionState;
46
42
  onRemoteSignOutRef.current = onRemoteSignOut;
47
43
  onSessionRemovedRef.current = onSessionRemoved;
48
- onIdentityTransferCompleteRef.current = onIdentityTransferComplete;
49
44
  activeSessionIdRef.current = activeSessionId;
50
45
  currentDeviceIdRef.current = currentDeviceId;
51
46
  getAccessTokenRef.current = getAccessToken;
52
- getTransferCodeRef.current = getTransferCode;
53
- }, [refreshSessions, logout, clearSessionState, onRemoteSignOut, onSessionRemoved, onIdentityTransferComplete, activeSessionId, currentDeviceId, getAccessToken, getTransferCode]);
47
+ }, [refreshSessions, logout, clearSessionState, onRemoteSignOut, onSessionRemoved, activeSessionId, currentDeviceId, getAccessToken]);
54
48
 
55
49
  useEffect(() => {
56
50
  if (!userId || !baseURL) {
@@ -307,104 +301,6 @@ export function useSessionSocket({ userId, activeSessionId, currentDeviceId, ref
307
301
  }
308
302
  });
309
303
  }
310
- } else if (data.type === 'identity_transfer_complete') {
311
- // Handle identity transfer completion notification
312
- const transferData = data as {
313
- type: 'identity_transfer_complete';
314
- transferId: string;
315
- sourceDeviceId: string;
316
- publicKey: string;
317
- transferCode?: string;
318
- completedAt: string;
319
- };
320
-
321
- logger.debug('Received identity_transfer_complete event', {
322
- component: 'useSessionSocket',
323
- transferId: transferData.transferId,
324
- sourceDeviceId: transferData.sourceDeviceId,
325
- currentDeviceId,
326
- activeSessionId: activeSessionIdRef.current,
327
- socketConnected: socket.connected,
328
- userId,
329
- room: joinedRoomRef.current,
330
- publicKey: transferData.publicKey.substring(0, 16) + '...',
331
- });
332
-
333
- // CRITICAL: Only call handler on the SOURCE device (the one that initiated the transfer)
334
- // The new device (target) should NEVER process this event - it would delete its own identity!
335
-
336
- // Check if this device has a stored transfer code (most reliable check - only source device has this)
337
- const hasStoredTransferCode = getTransferCodeRef.current && !!getTransferCodeRef.current(transferData.transferId);
338
-
339
- // Also check deviceId match (exact match required)
340
- const deviceIdMatches = transferData.sourceDeviceId &&
341
- currentDeviceId &&
342
- transferData.sourceDeviceId === currentDeviceId;
343
-
344
- // ONLY call handler if BOTH conditions are met:
345
- // 1. Has stored transfer code (definitive proof this is the source device)
346
- // 2. DeviceId matches (additional verification)
347
- // If deviceId is null/undefined, we still allow if stored code exists (logged out source device)
348
- // But we NEVER process if no stored code exists (definitely not the source device)
349
- const shouldCallHandler = !!transferData.transferId &&
350
- hasStoredTransferCode &&
351
- (deviceIdMatches || !currentDeviceId); // Allow if deviceId matches OR device is logged out (but has stored code)
352
-
353
- if (shouldCallHandler) {
354
- const matchReason = deviceIdMatches
355
- ? 'deviceId-exact-with-stored-code'
356
- : (currentDeviceId ? 'deviceId-mismatch-but-has-stored-code' : 'logged-out-source-device-with-stored-code');
357
-
358
- logger.debug('Matched source device, calling transfer complete handler', {
359
- component: 'useSessionSocket',
360
- transferId: transferData.transferId,
361
- sourceDeviceId: transferData.sourceDeviceId,
362
- currentDeviceId,
363
- matchReason,
364
- hasHandler: !!onIdentityTransferCompleteRef.current,
365
- socketConnected: socket.connected,
366
- socketId: socket.id,
367
- });
368
-
369
- if (onIdentityTransferCompleteRef.current) {
370
- try {
371
- logger.debug('Calling onIdentityTransferComplete handler', {
372
- component: 'useSessionSocket',
373
- transferId: transferData.transferId,
374
- });
375
-
376
- onIdentityTransferCompleteRef.current({
377
- transferId: transferData.transferId,
378
- sourceDeviceId: transferData.sourceDeviceId,
379
- publicKey: transferData.publicKey,
380
- transferCode: transferData.transferCode,
381
- completedAt: transferData.completedAt,
382
- });
383
-
384
- logger.debug('onIdentityTransferComplete handler called successfully', {
385
- component: 'useSessionSocket',
386
- transferId: transferData.transferId,
387
- });
388
- } catch (error) {
389
- logger.error('Error calling onIdentityTransferComplete handler', error instanceof Error ? error : new Error(String(error)), {
390
- component: 'useSessionSocket',
391
- transferId: transferData.transferId,
392
- });
393
- }
394
- } else {
395
- logger.debug('No onIdentityTransferComplete handler registered', {
396
- component: 'useSessionSocket',
397
- transferId: transferData.transferId,
398
- });
399
- }
400
- } else {
401
- logger.debug('Not the source device, ignoring transfer completion', {
402
- component: 'useSessionSocket',
403
- sourceDeviceId: transferData.sourceDeviceId,
404
- currentDeviceId,
405
- hasActiveSession: activeSessionIdRef.current !== null,
406
- });
407
- }
408
304
  } else {
409
305
  // For other event types (e.g., session_created), refresh sessions (with error handling)
410
306
  refreshSessionsRef.current().catch((error) => {