4 Commits
Author SHA1 Message Date
Bram KragtenandClaude Opus 5 8e061973ee Send the map tiles token in a header, so tile URLs stop rotating (#54452)
The access token rotates every half hour and lives in the query string, so it
is part of the browser's cache key: every rotation orphans every cached tile,
and the week-long max-age core sends is worth nothing. The service worker works
around it by stripping the token from its own cache key, but a service worker
only runs on https or localhost - on a plain http LAN origin, which is how a
lot of instances and the companion apps are reached, there is no cache at all
between the map and the network.

Anything that can set a header sends the token there instead, which leaves the
URL, and with it the cache key, stable across rotations. Raster tiles come from
an <img> and stay on the query parameter, and so does Cast: cross-origin a
custom header would cost a CORS preflight per tile.

Needs the matching core change; against a core without it the proxy refuses
every tile.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-29 16:30:54 +00:00
a9d7712fb2 Load the base map through core's tile proxy (#53845)
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-09-01 10:26:18 +02:00
Bram Kragten 7f86074e07 Revert "Load the base map through core's tile proxy"
This reverts commit 4b9e47079c.
2026-08-27 19:15:16 +02:00
Bram KragtenandClaude Opus 5 4b9e47079c Load the base map through core's tile proxy
Core now proxies both vector and raster tiles, which is what lets them be
requested with an application User-Agent and without a referrer - a
browser can set neither. So the frontend stops talking to OpenStreetMap
and CARTO directly and goes through /api/map_tiles.

The proxy is token gated, so `ha-map` fetches one over the WebSocket
before setting up, following the brands token pattern: cached at module
level, refreshed well inside its lifetime so a dashboard left open for
days keeps working. The blocking wait is kept to about a second - a
backend without the proxy must not hold the map hostage - and the
remaining retries run in the background to ride through the window after
a restart where the WebSocket is up but the handler is not registered
yet.

Two things that are not obvious and cost a measurement each:

MapLibre's `transformRequest` has to return absolute URLs. Tiles are
fetched from a worker, which has no document to resolve a relative URL
against, and the TileJSON that core serves has relative `tiles`. Measured
with a relative TileJSON on one origin: with absolute URLs the style
loads and 8,456 features render; without them exactly one request is made
- the style - and nothing else loads, with no error reported anywhere.

Leaflet bakes its URL template at layer creation and throws while
building a tile URL if a template variable is undefined. So the raster
layer takes the token as an option Leaflet substitutes per request, which
also means a refreshed token is picked up without recreating the layer,
and an absent one is empty rather than missing: the tiles 403 and the
markers still draw.

The asset pipeline shrinks to generating two styles. Glyphs and sprites
come from the proxy, so the 48 MB build-time download, the digest
verification, the glyph range filtering and the bold-range guard are all
gone, along with 5.4 MB from the wheel. `localIdeographFontFamily` goes
too: the complete glyph set is reachable now, so CJK renders in Noto
rather than a device font.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 18:14:59 +02:00