Skip to content

Commit 5731958

Browse files
committed
fix: abort background Discord lookups on auto-map modal close
Background fetches to /api/discord-user/:userId were fire-and-forget — cancelling the modal left them running, draining the API rate limit budget and causing subsequent requests (bot status, user mappings) to receive rate-limit responses with an `error` key instead of `message`, breaking the dashboard state until restart. - Add AbortController for background Discord resolution; abort on modal close - Fall back to `data.error` when `data.message` is absent in error toasts (handles rate-limiter responses from express-rate-limit)
1 parent 4eb77ea commit 5731958

File tree

1 file changed

+17
-5
lines changed

1 file changed

+17
-5
lines changed

web/script.js

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2571,6 +2571,8 @@ document.addEventListener("DOMContentLoaded", async () => {
25712571

25722572
// Auto-Map from Seerr button
25732573
const autoMapSeerrBtn = document.getElementById("auto-map-seerr-btn");
2574+
let autoMapAbortController = null;
2575+
25742576
if (autoMapSeerrBtn) {
25752577
autoMapSeerrBtn.addEventListener("click", async () => {
25762578
autoMapSeerrBtn.disabled = true;
@@ -2582,7 +2584,7 @@ document.addEventListener("DOMContentLoaded", async () => {
25822584
const data = await res.json();
25832585

25842586
if (!data.success) {
2585-
showToast(`Error: ${data.message}`);
2587+
showToast(`Error: ${data.message || data.error || "Unknown error"}`);
25862588
return;
25872589
}
25882590

@@ -2619,10 +2621,14 @@ document.addEventListener("DOMContentLoaded", async () => {
26192621

26202622
modal._candidates = data.candidates;
26212623

2622-
// Resolve Discord names + avatars in the background
2624+
// Resolve Discord names + avatars in the background (aborted on modal close)
2625+
if (autoMapAbortController) autoMapAbortController.abort();
2626+
autoMapAbortController = new AbortController();
2627+
const { signal } = autoMapAbortController;
2628+
26232629
data.candidates.forEach(async (c, i) => {
26242630
try {
2625-
const r = await fetch(`/api/discord-user/${encodeURIComponent(c.discordId)}`);
2631+
const r = await fetch(`/api/discord-user/${encodeURIComponent(c.discordId)}`, { signal });
26262632
if (!r.ok) return;
26272633
const u = await r.json();
26282634
if (!u.success) return;
@@ -2633,7 +2639,9 @@ document.addEventListener("DOMContentLoaded", async () => {
26332639
avatarEl.src = u.avatar;
26342640
avatarEl.style.display = "block";
26352641
}
2636-
} catch (e) { console.warn("[AUTO-MAP] Could not resolve Discord user", c.discordId, e); }
2642+
} catch (e) {
2643+
if (e.name !== "AbortError") console.warn("[AUTO-MAP] Could not resolve Discord user", c.discordId, e);
2644+
}
26372645
});
26382646
}
26392647

@@ -2654,6 +2662,10 @@ document.addEventListener("DOMContentLoaded", async () => {
26542662
const autoMapModal = document.getElementById("auto-map-modal");
26552663

26562664
function closeAutoMapModal() {
2665+
if (autoMapAbortController) {
2666+
autoMapAbortController.abort();
2667+
autoMapAbortController = null;
2668+
}
26572669
autoMapModal.style.display = "none";
26582670
autoMapModal._candidates = null;
26592671
}
@@ -2697,7 +2709,7 @@ document.addEventListener("DOMContentLoaded", async () => {
26972709
showToast(`${result.saved} mapping${result.saved !== 1 ? "s" : ""} saved!`);
26982710
await loadMappings();
26992711
} else {
2700-
showToast(`Error: ${result.message}`);
2712+
showToast(`Error: ${result.message || result.error || "Unknown error"}`);
27012713
}
27022714
} catch (err) {
27032715
console.error("[AUTO-MAP] Save error:", err);

0 commit comments

Comments
 (0)