diff --git a/src/modules/lolschedule/api-client.js b/src/modules/lolschedule/api-client.js index 2e57939..d91a54d 100644 --- a/src/modules/lolschedule/api-client.js +++ b/src/modules/lolschedule/api-client.js @@ -51,10 +51,35 @@ async function cargoQuery(params) { body, cf: { cacheTtl: 30, cacheEverything: true }, }); - if (!res.ok) throw new Error(`Leaguepedia API HTTP ${res.status}`); - const json = await res.json(); - if (json?.error) throw new Error(`Leaguepedia error: ${json.error.info || json.error.code}`); - return (json?.cargoquery || []).map((r) => r.title); + const text = await res.text(); + if (!res.ok) { + console.log( + JSON.stringify({ msg: "lolschedule_fetch", status: res.status, body: text.slice(0, 500) }), + ); + throw new Error(`Leaguepedia API HTTP ${res.status}`); + } + let json; + try { + json = JSON.parse(text); + } catch { + console.log( + JSON.stringify({ msg: "lolschedule_parse_fail", body: text.slice(0, 500) }), + ); + throw new Error("Leaguepedia non-JSON response"); + } + if (json?.error) { + console.log( + JSON.stringify({ + msg: "lolschedule_api_error", + code: json.error.code, + info: json.error.info, + }), + ); + throw new Error(`Leaguepedia error: ${json.error.info || json.error.code}`); + } + const rows = (json?.cargoquery || []).map((r) => r.title); + console.log(JSON.stringify({ msg: "lolschedule_fetch_ok", rows: rows.length })); + return rows; } /** Format a JS Date as Leaguepedia's UTC literal: `YYYY-MM-DD HH:MM:SS`. */ diff --git a/src/modules/lolschedule/handlers.js b/src/modules/lolschedule/handlers.js index b3e6142..14cfbd1 100644 --- a/src/modules/lolschedule/handlers.js +++ b/src/modules/lolschedule/handlers.js @@ -41,7 +41,9 @@ export async function handleToday(ctx, db) { const rows = await getCachedMatches(db, from, to, CACHE_TTL_TODAY_SEC); await ctx.reply(renderToday(rows, from), { parse_mode: "HTML" }); } catch (err) { - console.warn("lolschedule /lol_today failed", String(err)); + console.log( + JSON.stringify({ msg: "lolschedule_today_fail", err: String(err) }), + ); await ctx.reply("Could not fetch today's matches. Try again later."); } } @@ -61,7 +63,9 @@ export async function handleWeek(ctx, db) { const rows = await getCachedMatches(db, from, to, CACHE_TTL_WEEK_SEC); await ctx.reply(renderWeek(rows, from, to), { parse_mode: "HTML" }); } catch (err) { - console.warn("lolschedule /lol_week failed", String(err)); + console.log( + JSON.stringify({ msg: "lolschedule_week_fail", err: String(err) }), + ); await ctx.reply("Could not fetch this week's matches. Try again later."); } } diff --git a/tests/modules/lolschedule/api-client.test.js b/tests/modules/lolschedule/api-client.test.js index 43d7b54..9638294 100644 --- a/tests/modules/lolschedule/api-client.test.js +++ b/tests/modules/lolschedule/api-client.test.js @@ -7,10 +7,12 @@ import { import { makeFakeKv } from "../../fakes/fake-kv-namespace.js"; function cargoResponse(rows) { + const payload = { cargoquery: rows.map((title) => ({ title })) }; return { ok: true, status: 200, - json: async () => ({ cargoquery: rows.map((title) => ({ title })) }), + text: async () => JSON.stringify(payload), + json: async () => payload, }; } @@ -53,10 +55,12 @@ describe("fetchMatchesInRange", () => { }); it("surfaces Leaguepedia API error field", async () => { + const errPayload = { error: { info: "Bad query", code: "x" } }; global.fetch = vi.fn().mockResolvedValue({ ok: true, status: 200, - json: async () => ({ error: { info: "Bad query", code: "x" } }), + text: async () => JSON.stringify(errPayload), + json: async () => errPayload, }); await expect( fetchMatchesInRange(new Date("2026-04-21T00:00:00Z"), new Date("2026-04-22T00:00:00Z")),