The Driver wants MapLibre as the default everywhere, on cost and on how it looks, with Mapbox supported as an explicit choice. One line decided it. resolveMapProvider read explicit || (token present ? 'mapbox' : 'maplibre') so merely HOLDING a Mapbox token selected Mapbox. That conflated two different things: having a token is a capability, wanting Mapbox is a decision, and only the decision belongs in this function. It now reads explicit || 'maplibre'. The token is still honoured for what it is — with provider:'mapbox' it authenticates the map, and the token argument stays in the signature because callers pass one they hold outside the config. It simply no longer votes. The migration surface is exactly one shape: a host that pasted a real token into a published embed snippet and set no provider. All 36 shipped snippets carry a tk placeholder and no provider key, so any host who filled one in is in it. An unfilled snippet was already MapLibre, because hasMapToken rejects YOUR_ placeholders, and the DX Life branches pass no token at all. Such a host keeps Mapbox by adding "provider":"mapbox"; ?provider= and window.MAP_PROVIDER are unchanged. The gate's four token-selects-Mapbox assertions were the old specification, so they are inverted rather than deleted — the diff should show what changed for whom. Two are added: the opt-in still works with a token in hand, which is the path a migrating host takes, and a real token is still SEEN, asserted apart from the engine because otherwise the engine could be right while authentication broke silently. check:map-props-unit was not in gates:pre, so it proved nothing on a normal run. It is now, and the suite reads 32 of 32 with it named. |
||
|---|---|---|
| .. | ||
| api | ||
| charts | ||
| colors | ||
| components | ||
| composables | ||
| constants | ||
| data | ||
| elements | ||
| i18n | ||
| layouts | ||
| lists | ||
| maps | ||
| packet | ||
| packets | ||
| scripts | ||
| stores | ||
| styles | ||
| utils | ||
| vendor/cldr | ||
| index.js | ||
| ProfileLoader.vue | ||
| README.md | ||
library/ (@map) — the shared map template
The other half of the architecture (see ../plugin-designs/README.md):
every map in plugin-designs/<your-map>/ composes the reusable, parameterized pieces that live here.
Fix something here and every map benefits on the next build; break something here and every map
breaks — read components/WARNING.md before touching shared pieces.
| Folder | What lives there |
|---|---|
ProfileLoader.vue |
The root of every bundle: parses profile-config, loads the profile, provides the stores + config |
components/ |
Shared UI — map, legends, controls, popup (PeopleGroupDetail), tables, charts, hints (README) |
composables/ |
Shared logic — map engine (useMapInstance), provider switch, shadow-DOM styles, theming |
stores/ |
Per-instance Pinia stores (ui / map / data) — provided by ProfileLoader, injected by children |
api/ |
Data-source registry (sources.json) + fetch layer — the JAMstack runtime wiring |
colors/ |
Color sets maps opt into via profile-config.colorSet |
i18n/ |
The shared string catalogs (all maps speak the same languages) |
data/ |
Small shared datasets baked at build time (big served data lives in ../data/) |
constants/ |
Shared constants |
scripts/ |
Maintainer pipelines (posters, research) — not part of any bundle |
The rule of thumb (same as WARNING.md): custom code in your app-profile, reusable code here — and things only move from the first to the second once they've earned it.