diff --git a/scripts/dev-server.mjs b/scripts/dev-server.mjs index 62b6c7dc..72198aa4 100644 --- a/scripts/dev-server.mjs +++ b/scripts/dev-server.mjs @@ -133,10 +133,14 @@ function execCurl(args, res) { return; } - // stdout = body + "\n" + statusCode (from -w "\n%{http_code}") + // stdout = body + "\n" + statusCode (from -w "\n%{http_code}"). When + // upstream returns an empty body the stdout starts with "\n", so a + // `> 0` check mis-treats the status as body and falls back to 200 — + // silently hiding real 4xx/5xx responses. Use `>= 0` and split + // unconditionally when the newline is present. const lastNewline = stdout.lastIndexOf("\n"); - const body = lastNewline > 0 ? stdout.substring(0, lastNewline) : stdout; - const statusStr = lastNewline > 0 ? stdout.substring(lastNewline + 1).trim() : "200"; + const body = lastNewline >= 0 ? stdout.substring(0, lastNewline) : stdout; + const statusStr = lastNewline >= 0 ? stdout.substring(lastNewline + 1).trim() : "200"; const status = parseInt(statusStr) || 200; const isJson = body.trimStart().startsWith("{") || body.trimStart().startsWith("["); diff --git a/src/features/flights-map/api.test.ts b/src/features/flights-map/api.test.ts index 93338e01..1c4ac571 100644 --- a/src/features/flights-map/api.test.ts +++ b/src/features/flights-map/api.test.ts @@ -68,8 +68,8 @@ describe("searchDestinations", () => { expect(url.pathname).toBe("/flights/1/ru/destinations"); expect(url.searchParams.get("departure")).toBe("SVO"); expect(url.searchParams.get("arrival")).toBe("LED"); - expect(url.searchParams.get("dateFrom")).toBe("20250601"); - expect(url.searchParams.get("dateTo")).toBe("20251201"); + expect(url.searchParams.get("dateFrom")).toBe("2025-06-01"); + expect(url.searchParams.get("dateTo")).toBe("2025-12-01"); expect(url.searchParams.get("connections")).toBe("0"); }); @@ -143,7 +143,7 @@ describe("getFlightsMapCalendar", () => { }); const url = extractUrl(mockFetch); - expect(url.pathname).toBe("/flights/v1/ru/days/20250601/200/route/SVO-LED/flights-map/"); + expect(url.pathname).toBe("/flights/v1/ru/days/2025-06-01/200/route/SVO-LED/flights-map/"); }); it("builds correct path for connecting route", async () => { @@ -158,7 +158,7 @@ describe("getFlightsMapCalendar", () => { const url = extractUrl(mockFetch); expect(url.pathname).toBe( - "/flights/v1/ru/days/20250601/200/connections/SVO-LED-1/flights-map/", + "/flights/v1/ru/days/2025-06-01/200/connections/SVO-LED-1/flights-map/", ); }); @@ -172,7 +172,7 @@ describe("getFlightsMapCalendar", () => { }); const url = extractUrl(mockFetch); - expect(url.pathname).toBe("/flights/v1/ru/days/20250601/200/departure/SVO/flights-map/"); + expect(url.pathname).toBe("/flights/v1/ru/days/2025-06-01/200/departure/SVO/flights-map/"); }); it("parses binary days string into available date strings", async () => { diff --git a/src/features/flights-map/api.ts b/src/features/flights-map/api.ts index f32b747f..7a47c9cc 100644 --- a/src/features/flights-map/api.ts +++ b/src/features/flights-map/api.ts @@ -27,10 +27,13 @@ export async function searchDestinations( client: ApiClient, params: FlightsMapSearchParams, ): Promise { + // Upstream expects yyyy-MM-DD with dashes on /destinations; internal callers + // pass the compact yyyyMMdd we use everywhere else in the app. Matches + // Angular's ApiFormatterService.formatDateOnly output. const query: Record = { departure: params.departure, - dateFrom: params.dateFrom, - dateTo: params.dateTo, + dateFrom: toDashedDate(params.dateFrom), + dateTo: toDashedDate(params.dateTo), connections: String(params.connections ?? 0), }; @@ -41,6 +44,14 @@ export async function searchDestinations( return client.get(`flights/1/${client.locale}/destinations`, query); } +function toDashedDate(yyyymmdd: string): string { + if (/^\d{8}$/.test(yyyymmdd)) { + return `${yyyymmdd.slice(0, 4)}-${yyyymmdd.slice(4, 6)}-${yyyymmdd.slice(6, 8)}`; + } + // Already dashed (or something else) — pass through. + return yyyymmdd; +} + /** * Get available calendar days for a flights-map route. * Maps to: `GET days/{date}/200/{routeSegment}/flights-map/v1` @@ -56,7 +67,8 @@ export async function getFlightsMapCalendar( const routeSegment = buildRouteSegment(params); if (!routeSegment) return []; - const path = `flights/v1/${client.locale}/days/${params.date}/200/${routeSegment}/flights-map/`; + // Upstream expects yyyy-MM-DD with dashes on the /days path too. + const path = `flights/v1/${client.locale}/days/${toDashedDate(params.date)}/200/${routeSegment}/flights-map/`; const response = await client.get(path); return parseBinaryDays(response.days, params.date); }