fluxy-bot 0.3.2 → 0.3.3

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.
@@ -4,7 +4,7 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0, interactive-widget=resizes-content" />
6
6
  <title>Fluxy Chat</title>
7
- <script type="module" crossorigin src="/fluxy/assets/fluxy-Cejh7HRl.js"></script>
7
+ <script type="module" crossorigin src="/fluxy/assets/fluxy-C6-vL18Q.js"></script>
8
8
  <link rel="modulepreload" crossorigin href="/fluxy/assets/globals-Bu5tVsgN.js">
9
9
  <link rel="stylesheet" crossorigin href="/fluxy/assets/globals-DYOj4b0m.css">
10
10
  </head>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fluxy-bot",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "description": "Self-hosted AI bot — run your own AI assistant from anywhere",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -5,7 +5,7 @@ import { WsClient } from './src/lib/ws-client';
5
5
  import { useFluxyChat } from './src/hooks/useFluxyChat';
6
6
  import OnboardWizard from './OnboardWizard';
7
7
  import LoginScreen from './src/components/LoginScreen';
8
- import { getAuthToken, setAuthToken, clearAuthToken, authFetch } from './src/lib/auth';
8
+ import { getAuthToken, setAuthToken, clearAuthToken, authFetch, onAuthFailure } from './src/lib/auth';
9
9
  import MessageList from './src/components/Chat/MessageList';
10
10
  import InputBar from './src/components/Chat/InputBar';
11
11
  import './src/styles/globals.css';
@@ -74,6 +74,14 @@ function FluxyApp() {
74
74
  setAuthenticated(true);
75
75
  };
76
76
 
77
+ // Handle mid-session token expiry (authFetch gets 401)
78
+ useEffect(() => {
79
+ onAuthFailure(() => {
80
+ setAuthenticated(false);
81
+ setAuthRequired(true);
82
+ });
83
+ }, []);
84
+
77
85
  // Connect WebSocket only when authenticated
78
86
  useEffect(() => {
79
87
  if (!authenticated) return;
@@ -145,7 +153,7 @@ function FluxyApp() {
145
153
  }, [menuOpen]);
146
154
 
147
155
  const { messages, streaming, streamBuffer, tools, sendMessage, stopStreaming, clearContext } =
148
- useFluxyChat(clientRef.current, reloadTrigger);
156
+ useFluxyChat(clientRef.current, reloadTrigger, authenticated);
149
157
 
150
158
  // Auth gate: show spinner while checking, login screen if needed
151
159
  if (!authChecked) {
@@ -8,7 +8,7 @@ import { authFetch } from '../lib/auth';
8
8
  * Loads/persists messages via the DB (worker API).
9
9
  * Supports cross-device sync via chat:sync WS events.
10
10
  */
11
- export function useFluxyChat(ws: WsClient | null, triggerReload?: number) {
11
+ export function useFluxyChat(ws: WsClient | null, triggerReload?: number, enabled = true) {
12
12
  const [messages, setMessages] = useState<ChatMessage[]>([]);
13
13
  const [conversationId, setConversationId] = useState<string | null>(null);
14
14
  const [streaming, setStreaming] = useState(false);
@@ -62,19 +62,19 @@ export function useFluxyChat(ws: WsClient | null, triggerReload?: number) {
62
62
  } catch { /* worker not ready yet */ }
63
63
  }, []);
64
64
 
65
- // Load on mount
65
+ // Load on mount (only when enabled/authenticated)
66
66
  useEffect(() => {
67
- if (loaded.current) return;
67
+ if (!enabled || loaded.current) return;
68
68
  loaded.current = true;
69
69
  loadFromDb();
70
- }, [loadFromDb]);
70
+ }, [enabled, loadFromDb]);
71
71
 
72
72
  // Reload on reconnect (triggerReload changes)
73
73
  useEffect(() => {
74
- if (triggerReload && triggerReload > 0) {
74
+ if (enabled && triggerReload && triggerReload > 0) {
75
75
  loadFromDb();
76
76
  }
77
- }, [triggerReload, loadFromDb]);
77
+ }, [enabled, triggerReload, loadFromDb]);
78
78
 
79
79
  useEffect(() => {
80
80
  if (!ws) return;
@@ -1,5 +1,7 @@
1
1
  const TOKEN_KEY = 'fluxy_token';
2
2
 
3
+ let authFailureCallback: (() => void) | null = null;
4
+
3
5
  export function getAuthToken(): string | null {
4
6
  return localStorage.getItem(TOKEN_KEY);
5
7
  }
@@ -12,6 +14,11 @@ export function clearAuthToken(): void {
12
14
  localStorage.removeItem(TOKEN_KEY);
13
15
  }
14
16
 
17
+ /** Register a callback for when a 401 is received (token expired mid-session) */
18
+ export function onAuthFailure(cb: () => void): void {
19
+ authFailureCallback = cb;
20
+ }
21
+
15
22
  export async function authFetch(url: string, options: RequestInit = {}): Promise<Response> {
16
23
  const token = getAuthToken();
17
24
  const headers = new Headers(options.headers);
@@ -21,9 +28,10 @@ export async function authFetch(url: string, options: RequestInit = {}): Promise
21
28
 
22
29
  const res = await fetch(url, { ...options, headers });
23
30
 
24
- if (res.status === 401) {
31
+ if (res.status === 401 && token) {
32
+ // Token was present but rejected — it expired
25
33
  clearAuthToken();
26
- window.location.reload();
34
+ authFailureCallback?.();
27
35
  }
28
36
 
29
37
  return res;