From ee1066781f64ae798606b332260fa08eaacc7a5b Mon Sep 17 00:00:00 2001 From: Kresna Date: Sat, 8 Aug 2026 14:05:39 +0700 Subject: [PATCH] fix(maps): use absolute URLs for OFM proxy (sprite/tile URL fix) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MapLibre rejects relative sprite/glyph URLs with a validation error. Web Workers also resolve relative tile URLs against their blob URL (not the page origin), causing silent tile fetch failures. Move the ofm() rewriter inside fetchResolvedStyle so location.origin is available, and produce fully absolute proxy URLs: https://tiles.openfreemap.org/... → https://goodwebtools.com/ofm/... Co-Authored-By: Claude Sonnet 4.6 --- src/islands/maps/MapExplorer.tsx | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/islands/maps/MapExplorer.tsx b/src/islands/maps/MapExplorer.tsx index ba83eec..cf12af2 100644 --- a/src/islands/maps/MapExplorer.tsx +++ b/src/islands/maps/MapExplorer.tsx @@ -10,18 +10,21 @@ import { resolveStyle, MAP_STYLES, haversineMeters, formatDistance, type StyleCh import { ddToDms, ddToUtm, encodeGeohash, formatDd, type LatLng } from '@/tools/geo/coord.lib'; import type { Lang } from '@/i18n/config'; -// Rewrite OFM absolute URLs to go through our same-origin /ofm/ proxy, which -// fetches from tiles.openfreemap.org server-side over Cloudflare's backbone. -// This bypasses the broken Singapore CDN edge that serves corrupt style/tile -// responses to Southeast Asian users. -const ofm = (u: unknown): unknown => - typeof u === 'string' ? u.replace('https://tiles.openfreemap.org/', '/ofm/') : u; - // Pre-fetch a MapLibre style URL through our proxy, inline any TileJSON-backed // vector sources, and rewrite all remaining OFM URLs so every subsequent fetch // (glyphs, sprites, tiles) also goes through the same-origin proxy. +// +// IMPORTANT: All rewritten URLs must be absolute. MapLibre rejects relative +// sprite/glyph URLs outright, and Web Workers resolve relative tile URLs +// against their own blob URL (not the page origin), causing silent failures. // eslint-disable-next-line @typescript-eslint/no-explicit-any async function fetchResolvedStyle(url: string): Promise> { + // Build absolute proxy base at call time — location is always available here + // (this function is only called inside useEffect, never during SSR). + const proxyBase = `${location.origin}/ofm/`; + const ofm = (u: unknown): unknown => + typeof u === 'string' ? u.replace('https://tiles.openfreemap.org/', proxyBase) : u; + try { const res = await fetch(url, { cache: 'no-cache' }); console.log('[map] style fetch', url, res.status, res.ok);