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
454export 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';
0 commit comments