From f1a0951fd14879abb80db688ac22ea9855bad04a Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Sat, 3 Oct 2026 22:43:54 -0700 Subject: CORS write-off only on a refusal corsFetch confirmed, not a body cut off mid-download Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_011bvzKaZosXGHkigcGcSzAR --- src/features/messages.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/features/messages.js b/src/features/messages.js index a517407..c1e39d7 100644 --- a/src/features/messages.js +++ b/src/features/messages.js @@ -727,7 +727,7 @@ export function messagesFeature(ctx) { // is left alone for a week rather than asked about every new face. // v2: the first list was mostly wrong (primal's CDN, coinos.io) — see corsFetch // v3: v2 also caught dropped connections (primal again, on a phone) - const NOCORS_KEY = 'coinos-thumb-nocors-v3'; + const NOCORS_KEY = 'coinos-thumb-nocors-v4'; const NOCORS_MS = 7 * 24 * 3600_000; let noCors = null; // host -> { n, until } const noCorsNow = () => { if (!noCors) { try { noCors = JSON.parse(localStorage.getItem(NOCORS_KEY) || '{}'); } catch { noCors = {}; } } return noCors; }; @@ -764,7 +764,7 @@ export function messagesFeature(ctx) { if (!e2 || e2.name !== 'TypeError') throw e2; let reachable = false; try { await fetch(url, { mode: 'no-cors', signal }); reachable = true; } catch {} - if (reachable) throw e2; + if (reachable) { e2.corsRefused = true; throw e2; } const net = new Error('network'); net.name = 'NetworkError'; throw net; } @@ -844,7 +844,9 @@ export function messagesFeature(ctx) { done({ thumb: data, thumbFor: url, thumbPx: THUMB_PX }); } catch (e) { // a quick TypeError is the CORS refusal (a dead host takes longer) - if (e && e.name === 'TypeError' && Date.now() - t0 < 4000) noteNoCors(url); + // only a refusal corsFetch confirmed (a body cut off mid-download + // is a TypeError too) + if (e && e.corsRefused) noteNoCors(url); failed(); } finally { try { bmp && bmp.close(); } catch {} } })(); @@ -5384,15 +5386,13 @@ export function messagesFeature(ctx) { } async function makeMediaThumb(url) { if (noCorsHost(url) || typeof createImageBitmap === 'undefined' || typeof OffscreenCanvas === 'undefined') return null; - const t0 = Date.now(); let blob; try { const res = await corsFetch(url, AbortSignal.timeout(READY_MS)); if (!res.ok) return null; blob = await res.blob(); } catch (e) { - // a quick TypeError is the CORS refusal (a dead host takes longer) - if (e && e.name === 'TypeError' && Date.now() - t0 < 4000) noteNoCors(url); + if (e && e.corsRefused) noteNoCors(url); // refused, as corsFetch confirmed return null; } let bmp; -- cgit v1.2.3