Skip to content

Commit 920fd04

Browse files
authored
Merge pull request #6 from kashvigarg/frontend-test
Frontend Updates
2 parents 2cf3d58 + 73d1d2d commit 920fd04

File tree

5 files changed

+156
-42
lines changed

5 files changed

+156
-42
lines changed

web2/app/api/[...path]/route.ts

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -106,27 +106,20 @@ export async function GET(request: NextRequest, { params }: { params: { path: st
106106
return NextResponse.json({ error: "Failed to fetch data" }, { status: 500 });
107107
}
108108
}
109-
110109
export async function POST(request: NextRequest, { params }: { params: { path: string[] } }) {
111-
112110
const url = new URL(request.url);
113-
const path = url.pathname.replace("/api/", ""); // Remove "/api/" prefix
114-
115-
// if (!path) {
116-
// return new Response("Invalid request", { status: 400 });
117-
// }
118-
//const path = params.path.join("/")
111+
const path = url.pathname.replace("/api/", "");
112+
const token = request.headers.get("Authorization")?.split(" ")[1];
119113

120-
const token = request.headers.get("Authorization")?.split(" ")[1]
121-
let body = {}
114+
let body = {};
122115
try {
123-
body = request.body ? await request.json() : {};
116+
const text = await request.text();
117+
body = text ? JSON.parse(text) : {};
124118
} catch (error) {
125119
console.error("Invalid JSON:", error);
126120
return NextResponse.json({ error: "Invalid JSON input" }, { status: 400 });
127121
}
128122

129-
130123
try {
131124
const response = await fetch(`${process.env.API_URL}/api/${path}`, {
132125
method: "POST",
@@ -135,13 +128,20 @@ export async function POST(request: NextRequest, { params }: { params: { path: s
135128
"Content-Type": "application/json",
136129
},
137130
body: JSON.stringify(body),
138-
})
131+
});
139132

140-
const data = await response.json()
141-
return NextResponse.json(data, { status: response.status })
133+
const responseText = await response.text();
134+
console.log(responseText);
135+
136+
if (responseText.trim() !== "") {
137+
const responseData = JSON.parse(responseText);
138+
return NextResponse.json(responseData, { status: response.status });
139+
} else {
140+
return new Response(null, { status: response.status }); // <-- return something even if empty
141+
}
142142
} catch (error) {
143-
console.error("API error:", error)
144-
return NextResponse.json({ error: "Failed to post data" }, { status: 500 })
143+
console.error("API error:", error);
144+
return NextResponse.json({ error: "Failed to post data" }, { status: 500 });
145145
}
146146
}
147147

Lines changed: 121 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,55 @@
1+
// // app/api/sse/[...path]/route.ts
2+
// import { type NextRequest } from "next/server";
3+
4+
// export async function GET(request: NextRequest) {
5+
// const url = new URL(request.url);
6+
// const path = url.pathname.replace("/api/sse/", ""); // e.g., "timeline" or "comments/123"
7+
// const token =
8+
// url.searchParams.get("token") ||
9+
// request.headers.get("Authorization")?.split(" ")[1];
10+
11+
// try {
12+
// const backendResponse = await fetch(
13+
// `${process.env.API_URL}/api/${path}?${url.searchParams.toString()}`,
14+
// {
15+
// method: "GET",
16+
// headers: {
17+
// Authorization: token ? `Bearer ${token}` : "",
18+
// Accept: "text/event-stream",
19+
// },
20+
// }
21+
// );
22+
23+
// // Proxy the backend SSE stream directly to the client
24+
// console.log(backendResponse.body)
25+
// // let passedValue = await new Response(backendResponse.body).text();
26+
// // if (passedValue){
27+
// // let valueToJson = JSON.parse(passedValue);
28+
// // console.log("jsonval:", valueToJson)
29+
// // }
30+
// return new Response(backendResponse.body, {
31+
// status: 200,
32+
// headers: {
33+
// "Content-Type": "text/event-stream",
34+
// "Cache-Control": "no-cache",
35+
// Connection: "keep-alive",
36+
// // Optional headers for CORS (if needed):
37+
// // "Access-Control-Allow-Origin": "*",
38+
// },
39+
// });
40+
// } catch (error) {
41+
// console.log("SSE proxy error:", error);
42+
// return new Response("Failed to connect to SSE", { status: 502 });
43+
// }
44+
// }
45+
46+
47+
48+
49+
50+
151
// app/api/sse/[...path]/route.ts
2-
import { type NextRequest } from "next/server";
52+
import { type NextRequest, NextResponse } from "next/server";
353

454
export async function GET(request: NextRequest) {
555
const url = new URL(request.url);
@@ -8,37 +58,92 @@ export async function GET(request: NextRequest) {
858
url.searchParams.get("token") ||
959
request.headers.get("Authorization")?.split(" ")[1];
1060

61+
// --- Ensure token exists (optional but good practice) ---
62+
if (!token) {
63+
return new Response("Authentication token required", { status: 401 });
64+
}
65+
// --- ---
66+
1167
try {
68+
const backendUrl = `${process.env.API_URL}/api/${path}`;
69+
// Create a new URL object to safely append search params
70+
const targetUrl = new URL(backendUrl);
71+
72+
// Forward existing search params EXCEPT the token we added client-side
73+
url.searchParams.forEach((value, key) => {
74+
if (key !== 'token') { // Don't forward the token query param if backend expects header
75+
targetUrl.searchParams.append(key, value);
76+
}
77+
});
78+
79+
80+
console.log(`Proxying SSE request to:${targetUrl.toString()}`);
81+
1282
const backendResponse = await fetch(
13-
`${process.env.API_URL}/api/${path}?${url.searchParams.toString()}`,
83+
targetUrl.toString(), // Use the constructed URL with search params
1484
{
1585
method: "GET",
1686
headers: {
17-
Authorization: token ? `Bearer ${token}` : "",
87+
// Pass the token in the Authorization header to the actual backend
88+
Authorization: `Bearer ${token}`,
1889
Accept: "text/event-stream",
90+
// Forward other relevant headers if needed
91+
// 'X-Forwarded-For': request.ip ?? 'unknown',
1992
},
93+
// Important for streaming responses in Node fetch / Next.js Edge runtime
94+
cache: 'no-store', // Ensure fresh data
95+
// If using Node >= 18, duplex might be needed depending on the exact env
96+
// duplex: 'half'
2097
}
2198
);
2299

23-
// Proxy the backend SSE stream directly to the client
24-
console.log(backendResponse.body)
25-
let passedValue = await new Response(backendResponse.body).text();
26-
if (passedValue){
27-
let valueToJson = JSON.parse(passedValue);
28-
console.log("jsonval:", valueToJson)
100+
// Check if the backend responded successfully
101+
if (!backendResponse.ok) {
102+
console.error(`SSE Backend error (${backendResponse.status}): ${await backendResponse.text()}`);
103+
return new Response(`Backend request failed with status ${backendResponse.status}`, { status: backendResponse.status });
104+
}
105+
106+
// Check if the backend response is actually an event stream
107+
const contentType = backendResponse.headers.get("Content-Type");
108+
if (!contentType || !contentType.includes("text/event-stream")) {
109+
console.error(`Backend did not respond with Content-Type: text/event-stream. Received: ${contentType}`);
110+
// Return an error, maybe log the response body if small
111+
// const responseBody = await backendResponse.text();
112+
// console.error("Backend response body:", responseBody);
113+
return new Response("Backend did not return an event stream", { status: 502 }); // 502 Bad Gateway
114+
}
115+
116+
117+
// --- CORRECT WAY: Stream the backend response directly ---
118+
// Ensure the body exists and is a ReadableStream
119+
if (!backendResponse.body) {
120+
console.error("Backend response body is null.");
121+
return new Response("Backend response body is null", { status: 502 });
29122
}
30-
return new Response("", {
31-
status: 200,
123+
124+
// Return the backend's stream directly to the client
125+
console.log("body", backendResponse.body)
126+
return new Response(backendResponse.body, {
127+
status: 200, // Or backendResponse.status if you want to mirror it
32128
headers: {
33129
"Content-Type": "text/event-stream",
34130
"Cache-Control": "no-cache",
35-
Connection: "keep-alive",
36-
// Optional headers for CORS (if needed):
37-
// "Access-Control-Allow-Origin": "*",
131+
"Connection": "keep-alive",
132+
// Copy other relevant headers from backendResponse if needed
133+
// e.g., backendResponse.headers.get('X-My-Custom-Header')
38134
},
39135
});
136+
// --- ---
137+
40138
} catch (error) {
41-
console.log("SSE proxy error:", error);
42-
return new Response("Failed to connect to SSE", { status: 502 });
139+
console.error("SSE proxy fetch error:", error);
140+
// Check if it's a fetch error (e.g., connection refused)
141+
if (error instanceof TypeError && error.message === 'fetch failed') {
142+
return new Response("Failed to connect to the backend SSE service", { status: 502 }); // Bad Gateway might be appropriate
143+
}
144+
return new Response(`Internal Server Error: ${error instanceof Error ? error.message : 'Unknown error'}`, { status: 500 });
43145
}
44146
}
147+
148+
// Optional: Configure Edge Runtime for potentially better performance with streaming
149+
// export const runtime = 'edge';

web2/components/comments-list.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ export function CommentsList({ proseId }: { proseId: string }) {
4747
})
4848

4949
useEffect(() => {
50+
fetchComments()
51+
5052
if (data) {
5153
setComments(data)
5254
setIsLoading(false)
@@ -55,7 +57,7 @@ export function CommentsList({ proseId }: { proseId: string }) {
5557
if (sseError) {
5658
fetchComments()
5759
}
58-
}, [data, sseError])
60+
}, [sseError])
5961

6062
const fetchComments = async () => {
6163
try {
@@ -71,7 +73,10 @@ export function CommentsList({ proseId }: { proseId: string }) {
7173

7274
const data = await response.json()
7375
console.log(data)
74-
setComments(data)
76+
if (data!=null){
77+
setComments(data)
78+
}
79+
else setComments([])
7580
} catch (err) {
7681
toast({
7782
title: "Error",
@@ -90,6 +95,7 @@ export function CommentsList({ proseId }: { proseId: string }) {
9095
headers: {
9196
Authorization: `Bearer ${token}`,
9297
},
98+
body: null
9399
})
94100

95101
if (!response.ok) {

web2/components/timeline.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ export function Timeline() {
138138
headers: {
139139
Authorization: `Bearer ${token}`,
140140
},
141+
body: ""
141142
});
142143

143144
if (!response.ok) {

web2/lib/use-sse.tsx

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -191,14 +191,16 @@ export function useSSE<T>(
191191
eventSource.addEventListener(eventName, (event) => {
192192
try {
193193
console.log(`Received ${eventName} event:`, event);
194-
195-
if (event.data) {
196-
console.log(event.data)
197-
198-
const parsedData = JSON.parse(event.data) as T;
199-
setData(parsedData);
200-
options.onMessage?.(parsedData);
194+
if (event.data){
195+
console.log("raw data", event.data)
201196
}
197+
198+
// if (event.data) {
199+
// console.log(event.data)
200+
// const parsedData = JSON.parse(event.data) as T;
201+
// setData(parsedData);
202+
// options.onMessage?.(parsedData);
203+
// }
202204
} catch (err) {
203205
console.error('Error parsing SSE data:', err);
204206
const error = err instanceof Error ? err : new Error(String(err));

0 commit comments

Comments
 (0)