fix(chat): restrict to authenticated users only, fix overlay transparency
Some checks failed
ci/woodpecker/push/ci Pipeline failed

This commit is contained in:
2026-03-04 11:33:32 -06:00
parent 44fb402ef2
commit 44da50d0b3
3 changed files with 51 additions and 148 deletions

View File

@@ -4,12 +4,7 @@
*/
import { useState, useCallback, useRef } from "react";
import {
sendChatMessage,
streamChatMessage,
streamGuestChat,
type ChatMessage as ApiChatMessage,
} from "@/lib/api/chat";
import { streamChatMessage, type ChatMessage as ApiChatMessage } from "@/lib/api/chat";
import { createConversation, updateConversation, getIdea, type Idea } from "@/lib/api/ideas";
import { safeJsonParse, isMessageArray } from "@/lib/utils/safe-json";
@@ -219,8 +214,6 @@ export function useChat(options: UseChatOptions = {}): UseChatReturn {
const controller = new AbortController();
abortControllerRef.current = controller;
let streamingSucceeded = false;
try {
await new Promise<void>((resolve, reject) => {
let hasReceivedData = false;
@@ -248,7 +241,6 @@ export function useChat(options: UseChatOptions = {}): UseChatReturn {
});
},
() => {
streamingSucceeded = true;
setIsStreaming(false);
abortControllerRef.current = null;
resolve();
@@ -279,140 +271,26 @@ export function useChat(options: UseChatOptions = {}): UseChatReturn {
return;
}
// Streaming failed - check if auth error, try guest mode
const isAuthError =
err instanceof Error &&
(err.message.includes("403") ||
err.message.includes("401") ||
err.message.includes("auth") ||
err.message.includes("Forbidden"));
// Streaming failed — show error (no guest fallback, auth required)
console.warn("Streaming failed", {
error: err instanceof Error ? err : new Error(String(err)),
});
if (isAuthError) {
console.warn("Auth failed, trying guest chat mode");
setMessages((prev) => {
const withoutPlaceholder = prev.filter((m) => m.id !== assistantMessageId);
messagesRef.current = withoutPlaceholder;
return withoutPlaceholder;
});
setIsStreaming(false);
setIsLoading(false);
// Try guest chat streaming
try {
await new Promise<void>((guestResolve, guestReject) => {
let hasReceivedData = false;
streamGuestChat(
request,
(chunk: string) => {
if (!hasReceivedData) {
hasReceivedData = true;
setIsLoading(false);
setIsStreaming(true);
setMessages((prev) => {
const updated = [...prev, { ...placeholderMessage }];
messagesRef.current = updated;
return updated;
});
}
setMessages((prev) => {
const updated = prev.map((msg) =>
msg.id === assistantMessageId ? { ...msg, content: msg.content + chunk } : msg
);
messagesRef.current = updated;
return updated;
});
},
() => {
streamingSucceeded = true;
setIsStreaming(false);
guestResolve();
},
(guestErr: Error) => {
guestReject(guestErr);
},
controller.signal
);
});
} catch (guestErr: unknown) {
// Guest also failed
setMessages((prev) => {
const withoutPlaceholder = prev.filter((m) => m.id !== assistantMessageId);
messagesRef.current = withoutPlaceholder;
return withoutPlaceholder;
});
const errorMsg = guestErr instanceof Error ? guestErr.message : "Chat unavailable";
setError(`Unable to connect to chat: ${errorMsg}`);
setIsLoading(false);
return;
}
} else {
// Streaming failed — fall back to non-streaming
console.warn("Streaming failed, falling back to non-streaming", {
error: err instanceof Error ? err : new Error(String(err)),
});
setMessages((prev) => {
const withoutPlaceholder = prev.filter((m) => m.id !== assistantMessageId);
messagesRef.current = withoutPlaceholder;
return withoutPlaceholder;
});
setIsStreaming(false);
try {
const response = await sendChatMessage(request);
const assistantMessage: Message = {
id: `assistant-${Date.now().toString()}`,
role: "assistant",
content: response.message.content,
createdAt: new Date().toISOString(),
model: response.model,
promptTokens: response.promptEvalCount ?? 0,
completionTokens: response.evalCount ?? 0,
totalTokens: (response.promptEvalCount ?? 0) + (response.evalCount ?? 0),
};
setMessages((prev) => {
const updated = [...prev, assistantMessage];
messagesRef.current = updated;
return updated;
});
streamingSucceeded = true;
} catch (fallbackErr: unknown) {
const errorMsg =
fallbackErr instanceof Error ? fallbackErr.message : "Failed to send message";
setError("Unable to send message. Please try again.");
onError?.(fallbackErr instanceof Error ? fallbackErr : new Error(errorMsg));
console.error("Failed to send chat message", {
error: fallbackErr,
errorType: "LLM_ERROR",
conversationId: conversationIdRef.current,
messageLength: content.length,
messagePreview: content.substring(0, 50),
model,
messageCount: messagesRef.current.length,
timestamp: new Date().toISOString(),
});
const errorMessage: Message = {
id: `error-${String(Date.now())}`,
role: "assistant",
content: "Something went wrong. Please try again.",
createdAt: new Date().toISOString(),
};
setMessages((prev) => {
const updated = [...prev, errorMessage];
messagesRef.current = updated;
return updated;
});
setIsLoading(false);
return;
}
}
const errorMsg = err instanceof Error ? err.message : "Chat unavailable";
setError(`Chat error: ${errorMsg}`);
return;
}
setIsLoading(false);
if (!streamingSucceeded) {
return;
}
const finalMessages = messagesRef.current;
const isFirstMessage =