@thrillee/aegischat 0.1.12 → 0.1.15
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/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +30 -11
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +46 -27
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/hooks/useAutoRead.ts +9 -11
- package/src/hooks/useChat.ts +30 -9
package/src/hooks/useAutoRead.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// AegisChat React SDK - useAutoRead Hook
|
|
3
3
|
// ============================================================================
|
|
4
4
|
|
|
5
|
-
import { useCallback, useEffect,
|
|
5
|
+
import { useCallback, useEffect, useRef } from 'react';
|
|
6
6
|
import { channelsApi } from '../services/api';
|
|
7
7
|
|
|
8
8
|
const SESSION_STORAGE_KEY = '@aegischat/activeChannel';
|
|
@@ -18,13 +18,11 @@ export interface UseAutoReadReturn {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
export function useAutoRead(options: UseAutoReadOptions = {}): UseAutoReadReturn {
|
|
21
|
-
const
|
|
21
|
+
const isFocusedRef = useRef(typeof document !== 'undefined' && document.hasFocus());
|
|
22
22
|
|
|
23
23
|
useEffect(() => {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const handleFocus = () => setIsFocused(true);
|
|
27
|
-
const handleBlur = () => setIsFocused(false);
|
|
24
|
+
const handleFocus = () => { isFocusedRef.current = true; };
|
|
25
|
+
const handleBlur = () => { isFocusedRef.current = false; };
|
|
28
26
|
|
|
29
27
|
window.addEventListener('focus', handleFocus);
|
|
30
28
|
window.addEventListener('blur', handleBlur);
|
|
@@ -36,17 +34,17 @@ export function useAutoRead(options: UseAutoReadOptions = {}): UseAutoReadReturn
|
|
|
36
34
|
}, []);
|
|
37
35
|
|
|
38
36
|
const markAsRead = useCallback(async (channelId: string) => {
|
|
39
|
-
if (!
|
|
37
|
+
if (!isFocusedRef.current) return;
|
|
40
38
|
try {
|
|
41
39
|
await channelsApi.markAsRead(channelId);
|
|
42
40
|
options.onMarkAsRead?.(channelId);
|
|
43
41
|
} catch (error) {
|
|
44
42
|
console.error('[AegisChat] useAutoRead: Failed to mark as read:', error);
|
|
45
43
|
}
|
|
46
|
-
}, [
|
|
44
|
+
}, [options.onMarkAsRead]);
|
|
47
45
|
|
|
48
46
|
const markAllAsRead = useCallback(async () => {
|
|
49
|
-
if (!
|
|
47
|
+
if (!isFocusedRef.current) return;
|
|
50
48
|
try {
|
|
51
49
|
const response = await channelsApi.list({});
|
|
52
50
|
const channels = response.channels || [];
|
|
@@ -56,9 +54,9 @@ export function useAutoRead(options: UseAutoReadOptions = {}): UseAutoReadReturn
|
|
|
56
54
|
} catch (error) {
|
|
57
55
|
console.error('[AegisChat] useAutoRead: Failed to mark all as read:', error);
|
|
58
56
|
}
|
|
59
|
-
}, [
|
|
57
|
+
}, []);
|
|
60
58
|
|
|
61
|
-
return { markAsRead, markAllAsRead, isFocused };
|
|
59
|
+
return { markAsRead, markAllAsRead, isFocused: isFocusedRef.current };
|
|
62
60
|
}
|
|
63
61
|
|
|
64
62
|
export default useAutoRead;
|
package/src/hooks/useChat.ts
CHANGED
|
@@ -84,6 +84,7 @@ export interface UseChatReturn {
|
|
|
84
84
|
deleteFailedMessage: (tempId: string) => void;
|
|
85
85
|
markAsRead: (channelId: string) => Promise<void>;
|
|
86
86
|
setup: (options: UseChatOptions) => void;
|
|
87
|
+
updateChannel: (channelId: string, updates: Partial<ChannelListItem>) => void;
|
|
87
88
|
}
|
|
88
89
|
|
|
89
90
|
export function useChat(options: Partial<UseChatOptions> = {}): UseChatReturn {
|
|
@@ -101,8 +102,12 @@ export function useChat(options: Partial<UseChatOptions> = {}): UseChatReturn {
|
|
|
101
102
|
const [session, setSession] = useState<ChatSession | null>(null);
|
|
102
103
|
const [isConnected, setIsConnected] = useState(false);
|
|
103
104
|
const [isConnecting, setIsConnecting] = useState(false);
|
|
105
|
+
const getStoredActiveChannel = (): string | null => {
|
|
106
|
+
if (typeof window === "undefined") return null;
|
|
107
|
+
return sessionStorage.getItem(SESSION_STORAGE_KEY);
|
|
108
|
+
};
|
|
104
109
|
const [activeChannelId, setActiveChannelIdState] = useState<string | null>(
|
|
105
|
-
|
|
110
|
+
getStoredActiveChannel,
|
|
106
111
|
);
|
|
107
112
|
const [channels, setChannels] = useState<ChannelListItem[]>([]);
|
|
108
113
|
const [messages, setMessages] = useState<Message[]>([]);
|
|
@@ -126,9 +131,14 @@ export function useChat(options: Partial<UseChatOptions> = {}): UseChatReturn {
|
|
|
126
131
|
const roleRef = useRef<string | undefined>(undefined);
|
|
127
132
|
const clientIdRef = useRef<string | undefined>(undefined);
|
|
128
133
|
const autoConnectRef = useRef(true);
|
|
129
|
-
const onMessageRef =
|
|
130
|
-
|
|
131
|
-
const
|
|
134
|
+
const onMessageRef =
|
|
135
|
+
useRef<(message: Message) => void | undefined>(undefined);
|
|
136
|
+
const onTypingRef = useRef<
|
|
137
|
+
((channelId: string, user: TypingUser) => void) | undefined
|
|
138
|
+
>(undefined);
|
|
139
|
+
const onConnectionChangeRef = useRef<
|
|
140
|
+
((connected: boolean) => void) | undefined
|
|
141
|
+
>(undefined);
|
|
132
142
|
|
|
133
143
|
useEffect(() => {
|
|
134
144
|
activeChannelIdRef.current = activeChannelId;
|
|
@@ -140,6 +150,7 @@ export function useChat(options: Partial<UseChatOptions> = {}): UseChatReturn {
|
|
|
140
150
|
}, []);
|
|
141
151
|
|
|
142
152
|
const setActiveChannelId = useCallback((id: string | null) => {
|
|
153
|
+
activeChannelIdRef.current = id;
|
|
143
154
|
setActiveChannelIdState(id);
|
|
144
155
|
if (typeof window !== "undefined") {
|
|
145
156
|
if (id) {
|
|
@@ -459,7 +470,9 @@ export function useChat(options: Partial<UseChatOptions> = {}): UseChatReturn {
|
|
|
459
470
|
|
|
460
471
|
setIsLoadingChannels(true);
|
|
461
472
|
try {
|
|
462
|
-
const response = await fetchFromComms<{ channels: ChannelListItem[] }>(
|
|
473
|
+
const response = await fetchFromComms<{ channels: ChannelListItem[] }>(
|
|
474
|
+
"/channels",
|
|
475
|
+
);
|
|
463
476
|
setChannels(response.channels || []);
|
|
464
477
|
} catch (error) {
|
|
465
478
|
console.error("[AegisChat] Failed to fetch channels:", error);
|
|
@@ -503,7 +516,6 @@ export function useChat(options: Partial<UseChatOptions> = {}): UseChatReturn {
|
|
|
503
516
|
if (response.oldest_id) {
|
|
504
517
|
oldestMessageId.current = response.oldest_id;
|
|
505
518
|
}
|
|
506
|
-
|
|
507
519
|
} catch (error) {
|
|
508
520
|
console.error("[AegisChat] Failed to load messages:", error);
|
|
509
521
|
setMessages([]);
|
|
@@ -525,6 +537,15 @@ export function useChat(options: Partial<UseChatOptions> = {}): UseChatReturn {
|
|
|
525
537
|
[fetchFromComms],
|
|
526
538
|
);
|
|
527
539
|
|
|
540
|
+
const updateChannel = useCallback(
|
|
541
|
+
(channelId: string, updates: Partial<ChannelListItem>) => {
|
|
542
|
+
setChannels((prev) =>
|
|
543
|
+
prev.map((ch) => (ch.id === channelId ? { ...ch, ...updates } : ch)),
|
|
544
|
+
);
|
|
545
|
+
},
|
|
546
|
+
[],
|
|
547
|
+
);
|
|
548
|
+
|
|
528
549
|
const loadMoreMessages = useCallback(async () => {
|
|
529
550
|
if (!activeChannelId || !hasMoreMessages || isLoadingMessages) return;
|
|
530
551
|
|
|
@@ -961,9 +982,8 @@ export function useChat(options: Partial<UseChatOptions> = {}): UseChatReturn {
|
|
|
961
982
|
|
|
962
983
|
if (!config) {
|
|
963
984
|
const url = initialSession.api_url;
|
|
964
|
-
const normalizedUrl =
|
|
965
|
-
? url
|
|
966
|
-
: `${url}/api/v1`;
|
|
985
|
+
const normalizedUrl =
|
|
986
|
+
url.includes("/api/v1") || url.includes("/v") ? url : `${url}/api/v1`;
|
|
967
987
|
configureApiClient({
|
|
968
988
|
baseUrl: normalizedUrl,
|
|
969
989
|
getAccessToken: async () => sessionRef.current?.access_token || "",
|
|
@@ -1047,6 +1067,7 @@ export function useChat(options: Partial<UseChatOptions> = {}): UseChatReturn {
|
|
|
1047
1067
|
retryMessage,
|
|
1048
1068
|
deleteFailedMessage,
|
|
1049
1069
|
markAsRead,
|
|
1070
|
+
updateChannel,
|
|
1050
1071
|
setup,
|
|
1051
1072
|
};
|
|
1052
1073
|
}
|