File size: 1,864 Bytes
5710dd0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/**
 * React binding for the session activity hub: one hub per (server, token),
 * torn down on server switch or unmount. Consumers read per-session coarse
 * activity (`get(sessionId)`) and re-render on every store bump; list-level
 * signals invalidate the `['sessions']` / `['v2-sessions']` react-query lists
 * directly.
 *
 * The hub is created inside `useEffect` (not `useMemo`): under StrictMode
 * the mount → cleanup → re-mount cycle runs the cleanup of the FIRST mount,
 * and a memo-created hub would stay closed for the rest of the page's life.
 */

import { useQueryClient } from '@tanstack/react-query';
import { useEffect, useState, useSyncExternalStore } from 'react';

import { useConnection } from '../connection';
import { SessionActivityHub, SessionActivityStore, type SessionWorkFacts } from './store';

const EMPTY_STORE = new SessionActivityStore();

export function useSessionActivities(): {
  get(sessionId: string): SessionWorkFacts | undefined;
} {
  const { baseUrl, config } = useConnection();
  const queryClient = useQueryClient();
  const token = config.token.trim();
  const [hub, setHub] = useState<SessionActivityHub | null>(null);

  useEffect(() => {
    const created = new SessionActivityHub({
      url: baseUrl,
      token: token === '' ? undefined : token,
      onListChanged: () => {
        void queryClient.invalidateQueries({ queryKey: ['sessions'] });
        void queryClient.invalidateQueries({ queryKey: ['v2-sessions'] });
        void queryClient.invalidateQueries({ queryKey: ['workspaces'] });
      },
    });
    setHub(created);
    return () => {
      setHub(null);
      created.close();
    };
  }, [baseUrl, token, queryClient]);

  const store = hub?.store ?? EMPTY_STORE;
  useSyncExternalStore(
    (listener) => store.subscribe(listener),
    () => store.getVersion(),
  );
  return store;
}