diff --git a/src/islands/maps/MapExplorer.tsx b/src/islands/maps/MapExplorer.tsx index cbab136..556489e 100644 --- a/src/islands/maps/MapExplorer.tsx +++ b/src/islands/maps/MapExplorer.tsx @@ -192,6 +192,22 @@ export default function MapExplorer({ lang = 'en' }: { lang?: Lang }) { // never needs its own TileJSON fetch (avoids stale CDN edge responses). const styleInput = await fetchResolvedStyle(initialUrl); if (cancelled || !containerRef.current) return; + + // Diagnostic: probe one vector tile to verify the proxy returns valid PBF. + // Valid gzip-PBF starts with bytes 1f 8b; raw PBF starts with a protobuf tag. + // HTML/JSON/text responses (corrupted edge cache) start with ASCII bytes. + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const omtTiles = (styleInput as any)?.sources?.openmaptiles?.tiles; + if (Array.isArray(omtTiles) && omtTiles[0]) { + const probeUrl = (omtTiles[0] as string).replace('{z}', '5').replace('{x}', '26').replace('{y}', '16'); + fetch(probeUrl).then(async r => { + const buf = await r.arrayBuffer(); + const b = new Uint8Array(buf.slice(0, 8)); + const hex = Array.from(b).map(n => n.toString(16).padStart(2, '0')).join(' '); + console.log('[map] tile probe', probeUrl, '→ status:', r.status, 'ct:', r.headers.get('content-type'), 'size:', buf.byteLength, 'bytes:', hex); + }).catch(e => console.error('[map] tile probe error:', e)); + } + // Rewrite every OpenFreeMap URL that MapLibre would fetch on its own // (TileJSON, vector/raster tiles, glyphs, sprites) through our /ofm/ proxy. // This is the definitive safety net: even if fetchResolvedStyle leaves a diff --git a/worker/index.js b/worker/index.js index 38a5df5..5b93e6c 100644 --- a/worker/index.js +++ b/worker/index.js @@ -64,9 +64,15 @@ export default { return new Response('Method not allowed', { status: 405 }); } const upstream = 'https://tiles.openfreemap.org/' + url.pathname.slice('/ofm/'.length) + url.search; + // Fetch WITHOUT cf.cacheEverything so we bypass Cloudflare's edge cache. + // The Singapore edge had corrupted cached responses for OFM PBF tile URLs + // (HTTP 200 with wrong body), which were being served by the edge cache + // when cacheEverything:true was set. Going directly to OFM's origin via + // CF backbone avoids those stale entries. The browser's own HTTP cache + // (driven by the cache-control header we set below) handles client-side + // caching without touching the broken edge entries. const res = await fetch(upstream, { headers: { 'user-agent': 'goodwebtools-ofm-proxy' }, - cf: { cacheEverything: true, cacheTtl: 86400 }, }); if (!res.ok) { return new Response('Upstream OFM fetch failed', { status: res.status || 502 });