A page that asks for the keyless engine never silently gets the token-gated one
`const gl = engineGlobal(upgProvider) || window.mapboxgl` — and that fallback can ONLY fire when the requested provider is 'maplibre' and MapLibre failed to load. engineGlobal already resolves mapbox's own global for the mapbox case (useMapInstance.js:115 falls back to ENGINES.mapbox.global only for an UNKNOWN provider NAME, not for a missing engine). So the `||` silently handed MAPBOX to a page that asked for the KEYLESS engine, breaking the keyless contract that research-map.instances.json documents. Found by regions' C3 read, routed by dx-shepherd (END-SHEP-C3C). ⚠ AND THE FALLBACK COULD NOT EVEN WORK. `gl.accessToken = token` a few lines below is gated on `if (!isMaplibre)`, so a maplibre request that fell through to Mapbox would get Mapbox WITHOUT a token — 401s on every tile instead of a legible failure. Two defects in one expression: a silent engine switch, and a substitute that was broken by construction. THE FIX IS A DELETION, not a new path: the existing `if (!gl)` branch already fails visibly and well — it sets status + mapError, calls enrichLegendFromRecords() so the curated list and legend survive, and returns. It just was not being reached. Removing the `||` lets it run. MADE THE FAILURE DIAGNOSABLE while I was there. It said "The map engine did not load" — true but useless: a reader could not tell whether the keyless engine they asked for was even attempted, which is exactly the ambiguity a silent downgrade creates. It now NAMES the engine, so a partner who set ?provider=maplibre and sees "MapLibre did not load" knows their request was honoured and the script is the problem. Plus a console.warn stating the refusal to substitute — the notice is for the reader, the warn is for whoever is debugging the embed. Both strings go through messages.* in eleven locales rather than adding to the English-literal debt I cleared earlier this tick. VERIFIED HEADLESS ACROSS BOTH PROVIDERS x THREE LOAD STATES, which is the mutation test this needed: the ONLY behaviour that changes is provider=maplibre with MapLibre absent, where old=MB (silent Mapbox) becomes new=undefined (the visible failure path). mapbox/both, mapbox/only-mapbox, mapbox/none, maplibre/both and maplibre/none are all byte-identical to before. So the fix is surgical rather than a behaviour change dressed as a bugfix. check:i18n-parity PASS. BUNDLE=my-upg-100-list vite build clean.
This commit is contained in:
parent
1e08837756
commit
ade12e4c0b
13 changed files with 87 additions and 46 deletions
|
|
@ -14,5 +14,7 @@
|
|||
"selectionPosterFailed": "فشل إنشاء ملصق التحديد: {reason}",
|
||||
"mapUnavailable": "الخريطة غير متاحة",
|
||||
"copied": "تم النسخ!",
|
||||
"copyFailed": "فشل النسخ — اضغط Ctrl/Cmd-C"
|
||||
"copyFailed": "فشل النسخ — اضغط Ctrl/Cmd-C",
|
||||
"engineNotLoaded": "لم يتم تحميل محرك الخريطة",
|
||||
"engineNotLoadedDetail": "لم يتم تحميل محرك الخريطة {engine}. القائمة ووسيلة الإيضاح غير متأثرتين."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,5 +14,7 @@
|
|||
"selectionPosterFailed": "Plakat der Auswahl fehlgeschlagen: {reason}",
|
||||
"mapUnavailable": "Karte nicht verfügbar",
|
||||
"copied": "Kopiert!",
|
||||
"copyFailed": "Kopieren fehlgeschlagen — Strg/Cmd-C drücken"
|
||||
"copyFailed": "Kopieren fehlgeschlagen — Strg/Cmd-C drücken",
|
||||
"engineNotLoaded": "Karten-Engine nicht geladen",
|
||||
"engineNotLoadedDetail": "Die Karten-Engine {engine} wurde nicht geladen. Liste und Legende sind nicht betroffen."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,5 +14,7 @@
|
|||
"selectionPosterFailed": "Selection poster failed: {reason}",
|
||||
"mapUnavailable": "Map unavailable",
|
||||
"copied": "Copied!",
|
||||
"copyFailed": "Copy failed — press Ctrl/Cmd-C"
|
||||
"copyFailed": "Copy failed — press Ctrl/Cmd-C",
|
||||
"engineNotLoaded": "map engine not loaded",
|
||||
"engineNotLoadedDetail": "The {engine} map engine did not load. The list and legend are unaffected."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,5 +14,7 @@
|
|||
"selectionPosterFailed": "Error al generar el cartel de la selección: {reason}",
|
||||
"mapUnavailable": "Mapa no disponible",
|
||||
"copied": "¡Copiado!",
|
||||
"copyFailed": "Error al copiar: pulsa Ctrl/Cmd-C"
|
||||
"copyFailed": "Error al copiar: pulsa Ctrl/Cmd-C",
|
||||
"engineNotLoaded": "motor de mapas no cargado",
|
||||
"engineNotLoadedDetail": "El motor de mapas {engine} no se cargó. La lista y la leyenda no se ven afectadas."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,5 +14,7 @@
|
|||
"selectionPosterFailed": "Échec de l’affiche de la sélection : {reason}",
|
||||
"mapUnavailable": "Carte indisponible",
|
||||
"copied": "Copié !",
|
||||
"copyFailed": "Échec de la copie — appuyez sur Ctrl/Cmd-C"
|
||||
"copyFailed": "Échec de la copie — appuyez sur Ctrl/Cmd-C",
|
||||
"engineNotLoaded": "moteur cartographique non chargé",
|
||||
"engineNotLoadedDetail": "Le moteur cartographique {engine} ne s’est pas chargé. La liste et la légende ne sont pas affectées."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,5 +14,7 @@
|
|||
"selectionPosterFailed": "चयन का पोस्टर विफल: {reason}",
|
||||
"mapUnavailable": "मानचित्र अनुपलब्ध",
|
||||
"copied": "कॉपी हो गया!",
|
||||
"copyFailed": "कॉपी विफल — Ctrl/Cmd-C दबाएँ"
|
||||
"copyFailed": "कॉपी विफल — Ctrl/Cmd-C दबाएँ",
|
||||
"engineNotLoaded": "मानचित्र इंजन लोड नहीं हुआ",
|
||||
"engineNotLoadedDetail": "{engine} मानचित्र इंजन लोड नहीं हुआ। सूची और लेजेंड अप्रभावित हैं।"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,5 +14,7 @@
|
|||
"selectionPosterFailed": "Manifesto della selezione non riuscito: {reason}",
|
||||
"mapUnavailable": "Mappa non disponibile",
|
||||
"copied": "Copiato!",
|
||||
"copyFailed": "Copia non riuscita — premi Ctrl/Cmd-C"
|
||||
"copyFailed": "Copia non riuscita — premi Ctrl/Cmd-C",
|
||||
"engineNotLoaded": "motore di mappe non caricato",
|
||||
"engineNotLoadedDetail": "Il motore di mappe {engine} non si è caricato. L’elenco e la legenda non sono interessati."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,5 +14,7 @@
|
|||
"selectionPosterFailed": "Falha ao gerar o cartaz da seleção: {reason}",
|
||||
"mapUnavailable": "Mapa indisponível",
|
||||
"copied": "Copiado!",
|
||||
"copyFailed": "Falha ao copiar — pressione Ctrl/Cmd-C"
|
||||
"copyFailed": "Falha ao copiar — pressione Ctrl/Cmd-C",
|
||||
"engineNotLoaded": "motor de mapas não carregado",
|
||||
"engineNotLoadedDetail": "O motor de mapas {engine} não carregou. A lista e a legenda não são afetadas."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,5 +14,7 @@
|
|||
"selectionPosterFailed": "Afișul selecției a eșuat: {reason}",
|
||||
"mapUnavailable": "Harta indisponibilă",
|
||||
"copied": "Copiat!",
|
||||
"copyFailed": "Copierea a eșuat — apasă Ctrl/Cmd-C"
|
||||
"copyFailed": "Copierea a eșuat — apasă Ctrl/Cmd-C",
|
||||
"engineNotLoaded": "motorul de hărți nu s-a încărcat",
|
||||
"engineNotLoadedDetail": "Motorul de hărți {engine} nu s-a încărcat. Lista și legenda nu sunt afectate."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,5 +14,7 @@
|
|||
"selectionPosterFailed": "Не удалось создать плакат выбора: {reason}",
|
||||
"mapUnavailable": "Карта недоступна",
|
||||
"copied": "Скопировано!",
|
||||
"copyFailed": "Не удалось скопировать — нажмите Ctrl/Cmd-C"
|
||||
"copyFailed": "Не удалось скопировать — нажмите Ctrl/Cmd-C",
|
||||
"engineNotLoaded": "движок карты не загружен",
|
||||
"engineNotLoadedDetail": "Движок карты {engine} не загрузился. Список и легенда не затронуты."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,5 +14,7 @@
|
|||
"selectionPosterFailed": "所选内容的海报生成失败:{reason}",
|
||||
"mapUnavailable": "地图不可用",
|
||||
"copied": "已复制!",
|
||||
"copyFailed": "复制失败——请按 Ctrl/Cmd-C"
|
||||
"copyFailed": "复制失败——请按 Ctrl/Cmd-C",
|
||||
"engineNotLoaded": "地图引擎未加载",
|
||||
"engineNotLoadedDetail": "{engine} 地图引擎未能加载。列表和图例不受影响。"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1859,7 +1859,18 @@ onMounted(async () => {
|
|||
bootstrapLegend()
|
||||
// Load the engine the PROVIDER selects, not the one this file used to assume.
|
||||
try { await ensureEngineScript(upgProvider) } catch (_) { /* fall through to the !gl notice below */ }
|
||||
const gl = engineGlobal(upgProvider) || window.mapboxgl
|
||||
// ★ NEVER SWITCH ENGINES SILENTLY. This read `engineGlobal(upgProvider) || window.mapboxgl`, and that
|
||||
// fallback can ONLY fire when the requested provider is 'maplibre' and MapLibre failed to load —
|
||||
// engineGlobal already resolves mapbox's own global for the mapbox case (useMapInstance.js:115 falls back
|
||||
// to ENGINES.mapbox.global only for an UNKNOWN provider name, not for a missing engine). So the `||`
|
||||
// silently handed back MAPBOX to a page that asked for the KEYLESS engine, breaking the keyless contract
|
||||
// that research-map.instances.json documents.
|
||||
// ⚠ AND THE FALLBACK COULD NOT EVEN WORK: `gl.accessToken = token` a few lines below is gated on
|
||||
// `if (!isMaplibre)`, so a maplibre request that fell through to Mapbox would get Mapbox WITHOUT a token
|
||||
// — 401s on every tile instead of a legible failure. Two defects in one expression.
|
||||
// Found by regions' C3 read, routed via dx-shepherd (END-SHEP-C3C). Same shape in all three raw-map
|
||||
// plugins.
|
||||
const gl = engineGlobal(upgProvider)
|
||||
// ★ SHAPE RTL BASEMAP LABELS — HERE, not in index.js, and not after the map exists.
|
||||
// This profile builds its map RAW (`new gl.Map` below) instead of going through
|
||||
// useMapInstance, so it inherits none of the entry's side effects. It appeared to work only
|
||||
|
|
@ -1882,8 +1893,16 @@ onMounted(async () => {
|
|||
// notice in the MAP CELL, and still enrich the legend with live population data
|
||||
// (a plain fetch — it needs no map). The list stays fully usable without tiles.
|
||||
if (!gl) {
|
||||
status.value = '⚠ map engine not loaded'
|
||||
mapError.value = 'The map engine did not load. The list and legend are unaffected.'
|
||||
// FAIL VISIBLY AND NAME THE ENGINE. The old copy said "The map engine" — true but undiagnosable:
|
||||
// a reader could not tell whether the keyless engine they asked for was even attempted. It now says
|
||||
// WHICH engine, so a partner who set ?provider=maplibre and sees "MapLibre did not load" knows their
|
||||
// request was honoured and the script is the problem, rather than suspecting a silent downgrade.
|
||||
// A console.warn too, because the on-screen notice is for the reader and this line is for whoever is
|
||||
// debugging the embed.
|
||||
console.warn(`[upg-100-list] ${upgProvider} engine global is missing — refusing to substitute another `
|
||||
+ 'engine. A page that asked for the keyless engine must not silently receive the token-gated one.')
|
||||
status.value = `⚠ ${t('messages.engineNotLoaded')}`
|
||||
mapError.value = t('messages.engineNotLoadedDetail', { engine: isMaplibre ? 'MapLibre' : 'Mapbox' })
|
||||
enrichLegendFromRecords()
|
||||
return
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue