From aac9445a965227313131a8808042fd32a6dc5457 Mon Sep 17 00:00:00 2001 From: dborup Date: Wed, 7 Oct 2026 10:39:05 +0200 Subject: [PATCH 1/2] fix(map): take every tile URL and attribution from the configured provider MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keyless CARTO raster tiles have been stamped "API KEY REQUIRED" since August 2026, and this fork has no CARTO basemap-key plumbing. Several maps still built their tile URL from a hard-coded CARTO template instead of the operator's configured dark/light provider, so they rendered watermarked tiles even on an instance configured for Esri/OpenTopoMap. - map-tile-providers.js: the built-in fallback defaults become the keyless OSM baseline ('osm-dark' / 'osm-standard') instead of 'carto-dark' / 'carto-light'. Those two ids are now registered regardless of provider gating, so the active id always resolves and stays selectable in the layer picker. New MC_getTileSpec(type) is the single resolver for url + attribution + refUrl + maxZoom + invertFilter, per theme. - roles.js: TILE_DARK / TILE_LIGHT are no longer CARTO templates, and getTileUrl() honours the configured provider in LIGHT mode too — it previously returned TILE_LIGHT unconditionally, ignoring map.tiles.lightDefault. getActiveTileProvider() resolves both themes, so the node-detail inset map credits the configured light provider. - customize-v2.js: both geo-filter preview maps resolve the configured light provider through a shared _cv2PreviewTile() helper. - live.js / map.js: the tile resolvers go through MC_getTileSpec, and their url + attribution fallbacks no longer name CARTO. - geofilter-builder.html: this standalone page has no registry, so it uses the same keyless OSM baseline plus a tile-pane invert filter to keep its dark look. - config.example.json: defaults updated, with a note on why CARTO is no longer the default. Relates to #332 Co-Authored-By: Claude Opus 5 --- .github/workflows/deploy.yml | 4 + config.example.json | 7 +- public/customize-v2.js | 25 +- public/geofilter-builder.html | 15 +- public/live.js | 31 +- public/map-tile-providers.js | 52 ++- public/map.js | 31 +- public/roles.js | 87 ++-- test-all.sh | 1 + test-issue-1420-tile-providers.js | 44 +- test-issue-1470-node-tile-helper.js | 15 +- test-issue-332-no-carto-tiles-e2e.js | 210 +++++++++ test-issue-332-tile-provider-fallback.js | 545 +++++++++++++++++++++++ 13 files changed, 984 insertions(+), 83 deletions(-) create mode 100644 test-issue-332-no-carto-tiles-e2e.js create mode 100644 test-issue-332-tile-provider-fallback.js diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 229aa62b7..61b41af36 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -418,6 +418,10 @@ jobs: BASE_URL=http://localhost:13581 node test-channels-client-state-152-e2e.js 2>&1 | tee -a e2e-output.txt CHROMIUM_REQUIRE=1 BASE_URL=http://localhost:13581 node test-channels-154-155-e2e.js 2>&1 | tee -a e2e-output.txt BASE_URL=http://localhost:13581 node test-map-modal-fluid-e2e.js 2>&1 | tee -a e2e-output.txt + # #332 — no map may request a tile from basemaps.cartocdn.com. + # No config.json here, so this exercises the built-in non-CARTO + # fallback (tile.openstreetmap.org) a default install resolves to. + CHROMIUM_REQUIRE=1 BASE_URL=http://localhost:13581 node test-issue-332-no-carto-tiles-e2e.js 2>&1 | tee -a e2e-output.txt CHROMIUM_REQUIRE=1 BASE_URL=http://localhost:13581 node test-map-nodes-pagination-e2e.js 2>&1 | tee -a e2e-output.txt CHROMIUM_REQUIRE=1 BASE_URL=http://localhost:13581 node test-issue-123-map-lifecycle-e2e.js 2>&1 | tee -a e2e-output.txt BASE_URL=http://localhost:13581 node test-observer-iata-1188-e2e.js 2>&1 | tee -a e2e-output.txt diff --git a/config.example.json b/config.example.json index a89aff342..52896d086 100644 --- a/config.example.json +++ b/config.example.json @@ -94,10 +94,11 @@ }, "map": { "tiles": { - "darkDefault": "carto-dark", - "lightDefault": "carto-light", + "_comment_defaults": "#332 — the built-in defaults are 'osm-dark' / 'osm-standard' (keyless OpenStreetMap, tiles to zoom 19). Set darkDefault/lightDefault to any enabled style id to override; they take priority over the built-in fallback. Carto is NOT the default any more: since August 2026 keyless Carto raster tiles come back HTTP 200 with 'API KEY REQUIRED' stamped into the PNG, and CoreScope has no Carto basemap-key plumbing.", + "darkDefault": "osm-dark", + "lightDefault": "osm-standard", "providers": { - "_comment_carto": "Carto is the default free-tier provider. Optional: specify 'domain' for Carto enterprise (e.g. 'mycompany' for 'https://{s}.mycompany.cartocdn.com').", + "_comment_carto": "Carto styles stay available and selectable, but keyless raster tiles are watermarked 'API KEY REQUIRED' (see _comment_defaults). Optional: specify 'domain' for Carto enterprise (e.g. 'mycompany' for 'https://{s}.mycompany.cartocdn.com').", "carto": { "enabled": true, "domain": "" diff --git a/public/customize-v2.js b/public/customize-v2.js index d1d844cfd..b18a9379e 100644 --- a/public/customize-v2.js +++ b/public/customize-v2.js @@ -1766,6 +1766,21 @@ ''; } + /* #332 — both geo-filter preview maps used to hard-code the CARTO + * light_all template, so they rendered "API KEY REQUIRED" tiles even on + * instances configured for Esri/OpenTopoMap/OSM. Resolve the operator's + * configured LIGHT provider instead (these previews are always + * light-styled regardless of the app theme), falling back to roles.js + * TILE_LIGHT, which is itself non-CARTO. */ + function _cv2PreviewTile() { + var spec = (typeof window.MC_getTileSpec === 'function') ? window.MC_getTileSpec('light') : null; + return { + url: (spec && spec.url) || window.TILE_LIGHT, + attribution: (spec && spec.attribution) || '© OpenStreetMap contributors', + maxZoom: (spec && spec.maxZoom) || 19 + }; + } + function _gfOpenModal(container) { var existing = document.getElementById('cv2-gf-modal-overlay'); if (existing) existing.remove(); @@ -1835,8 +1850,9 @@ var modalClosingLine = null; _gfModalMap = L.map(mapDiv, { zoomControl: true }); - L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png', { - attribution: '© OpenStreetMap © CartoDB', maxZoom: 19 + var _cv2Tile = _cv2PreviewTile(); + L.tileLayer(_cv2Tile.url, { + attribution: _cv2Tile.attribution, maxZoom: _cv2Tile.maxZoom }).addTo(_gfModalMap); function renderModal() { @@ -2044,8 +2060,9 @@ if (!mapEl || typeof L === 'undefined') return; _gfMap = L.map(mapEl, { zoomControl: false, dragging: false, scrollWheelZoom: false, doubleClickZoom: false, touchZoom: false }); - L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png', { - attribution: '© OpenStreetMap © CartoDB', maxZoom: 19 + var _cv2Tile = _cv2PreviewTile(); + L.tileLayer(_cv2Tile.url, { + attribution: _cv2Tile.attribution, maxZoom: _cv2Tile.maxZoom }).addTo(_gfMap); if (!_gfLoaded) { diff --git a/public/geofilter-builder.html b/public/geofilter-builder.html index 2a55ca840..c2ae0fd5f 100644 --- a/public/geofilter-builder.html +++ b/public/geofilter-builder.html @@ -21,6 +21,11 @@ #btnClear:hover { background: #7a2020; } .hint { font-size: 0.8rem; color: #888; margin-left: auto; } #map { flex: 1; } + /* #332 — the keyless OSM basemap is a LIGHT style; invert the tile pane so + this builder keeps the dark map it had while it hard-coded CARTO + dark_all. Same filter string as INVERT_CSS in map-tile-providers.js. + Scoped to the tile pane, so markers and the polygon stay true-colour. */ + #map .leaflet-tile-pane { filter: invert(1) hue-rotate(180deg) brightness(0.9) contrast(1.05); } #output-panel { background: #0f0f23; border-top: 1px solid #333; padding: 12px 16px; display: flex; gap: 12px; align-items: flex-start; } #output-panel label { font-size: 0.75rem; color: #888; white-space: nowrap; padding-top: 6px; } #output { flex: 1; background: #111; border: 1px solid #333; border-radius: 6px; padding: 10px 12px; font-family: monospace; font-size: 0.78rem; color: #7ec8e3; white-space: pre; overflow-x: auto; min-height: 54px; max-height: 140px; overflow-y: auto; cursor: text; } @@ -88,8 +93,14 @@

GeoFilter Builder