chore(release): v1.17.1 - map center, CARTO key, and docs fixes - #24
Merged
Conversation
Four related configuration/documentation problems. 1. Map center env vars had no effect (#23) MapContainer hardcoded Portland, OR and never read VITE_MAP_LAT/VITE_MAP_LNG. Two faults were stacked: the variables were unused in the source, and a VITE_-prefixed variable is inlined by Vite at build time, so setting one in docker-compose.yml could never reach the prebuilt image regardless. The initial view now resolves through a new src/utils/runtimeConfig.js (window._env_ -> import.meta.env.VITE_* -> default), and docker-entrypoint.sh writes MAP_LAT/MAP_LNG/MAP_ZOOM into env-config.js at container start. VITE_MAP_LAT/VITE_MAP_LNG remain accepted as deprecated aliases. Invalid or out-of-range values warn and fall back instead of handing Leaflet a NaN. public/env-config.js no longer ships populated defaults: because window._env_ takes priority, its baked-in values silently shadowed the VITE_* layer in dev. 2. CARTO basemap API key CARTO began watermarking unauthenticated raster tiles in August 2026. The key is applied server-side only -- the browser requests same-origin /basemaps/... and nginx (prod) or the Vite dev/preview server (dev) appends the key on the way out, so it is absent from the bundle, from env-config.js and from devtools. CARTO_API_KEY is deliberately unprefixed; a VITE_ prefix would inline it. nginx.conf became a template rendered at container start. The proxy clears the client query string so a caller cannot substitute their own key, restricts the path to well-formed tile URLs so it is not a general-purpose open proxy, and caches tiles locally to protect the monthly quota. Verified end to end: nginx config parses with and without a key, real tiles return as valid PNGs, cache goes MISS then HIT, and a build with a canary key leaves no trace in dist/. 3. .env.example realigned It documented only two elevation variables. It now covers the basemap key, frontend defaults, elevation, Redis and dev-only settings, and Compose substitutes from it so one .env drives both stacks. 4. Documentation README version corrected (was pinned at v1.16.1), config table rebuilt -- it listed a dark_matter style that does not exist and omitted topo_dark and most backend variables. Documentation/README.md linked elevation-scan.md, which has never existed. interactions.md had a duplicated step and a stale tool name. hardware-settings.md was missing presets and all cable types. site-analyzer.md and rf-simulator.md predated features the README already advertised. Also removes VITE_ELEVATION_DATASET, which configured nothing: the /elevation-batch endpoint ignores the dataset field in the request body. Closes #23 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UqP5vFS3rXNwGUgAvtRQt6
envsubst comes from gettext, which is not something we can rely on being installed in the nginx base image -- the alpine Dockerfile in nginx's own repository installs only curl and ca-certificates. If it is absent, the entrypoint fails under `set -e` and the container crash-loops on every start, which is a poor trade for a single string substitution. sed is part of busybox and therefore always present. The replacement escapes the characters sed treats specially (backslash, `&`, and the `|` delimiter) so an API key containing any of them still renders correctly. Verified: entrypoint renders correctly for plain keys and keys containing & | \ / + =, and for the no-key case; no placeholder is left behind; nginx -t passes on the rendered config in both states; and the proxy still injects the key and discards a client-supplied query string when run against a mock upstream. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UqP5vFS3rXNwGUgAvtRQt6
Patch release for the map-center, CARTO basemap key, and documentation fixes in this branch -- no new user-facing features, consistent with the 1.16.1 patch release that preceded it. - package.json / package-lock.json: 1.17.0 -> 1.17.1 - CHANGELOG.md: [Unreleased] -> [1.17.1] - 2026-09-13 - RELEASE_NOTES.md: rewritten for 1.17.1, following the 1.16.1 patch-release format - README.md: version header updated to match Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UqP5vFS3rXNwGUgAvtRQt6
d3mocide
marked this pull request as ready for review
September 13, 2026 03:29
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Addresses four related configuration and documentation problems, released as v1.17.1 (patch — bug fixes only, no new user-facing features).
1. Map center environment variables had no effect (closes #23)
MapContainerhardcoded Portland, OR and never readVITE_MAP_LAT/VITE_MAP_LNG.Two faults were stacked here. The variables were unused in the source, and a
VITE_-prefixed variable is inlined by Vite at build time — so setting one indocker-compose.ymlagainst the prebuiltghcr.ioimage could never have worked regardless of the first bug. Fixing only the hardcoded coordinate would have left the reporter's exact workflow still broken.src/utils/runtimeConfig.js:window._env_→import.meta.env.VITE_*→ default.docker-entrypoint.shwritesMAP_LAT/MAP_LNG/MAP_ZOOMintoenv-config.jsat container start, so a prebuilt image is configurable without a rebuild.VITE_MAP_LAT/VITE_MAP_LNGstill accepted as deprecated aliases, so existing compose files keep working.NaN.public/env-config.jsno longer ships populated defaults — becausewindow._env_takes priority, its baked-in values silently shadowed theVITE_*layer duringnpm run dev.New
MAP_ZOOMsetting for the initial zoom level.2. CARTO basemap API key
CARTO began watermarking unauthenticated raster tiles in August 2026, so the
dark,dark_greenandlightstyles now render with an "API KEY REQUIRED" stamp.The key is applied server-side only. The browser requests tiles from a same-origin
/basemaps/...path; nginx (production) or the Vite dev/preview server (development) appends the key on the way out to CARTO. It is therefore absent from the JS bundle, fromenv-config.js, and from anything visible in devtools.CARTO_API_KEYis deliberately notVITE_-prefixed — that prefix is exactly what would inline it into the client bundle and publish it to every visitor.Hardening in the nginx proxy:
key=ours&key=theirs).{style}/{z}/{x}/{y}.pngpaths, so it cannot be driven as a general-purpose open proxy.nginx.confis now a template rendered bydocker-entrypoint.sh, so the key is supplied at deploy time rather than baked into the published image. Rendering usessed, notenvsubst— the latter comes from gettext, which is not guaranteed present in the nginx base image, and a missing binary there would crash-loop the container on every start.Without a key nothing hard-breaks — tiles still load watermarked, and the entrypoint logs how to get a free one.
3.
.env.examplerealignedIt documented only two elevation variables and omitted everything else the stack reads. Now covers the basemap key, frontend defaults, elevation, Redis and dev-only settings. Compose substitutes from it (
${MAP_LAT:-45.5152}), so a single.envdrives both the production and development stacks.4. Documentation
dark_matterstyle that does not exist, omittedtopo_dark, and covered none of the backend variables; new Basemap API Key section.Documentation/README.md: linkedelevation-scan.md, which has never existed (the tool is now Site Analysis). Added the missing Tool Interactions and PWA guide links.interactions.md: duplicated step 3/4 from a copy-paste error; still named the renamed "Elevation Scan" tool; recommended Hata for verifying links, which assumes flat terrain.hardware-settings.md: missing the Lilygo T-Deck and Custom Device presets, misnamed "Station G2 (High Power)", and documented no cable types despite six shipping.site-analyzer.md/rf-simulator.md: predated the Link Matrix, Mesh Topology, Marginal Coverage, per-node coverage colors, WASM ITM and Reliability modes that the README already advertised.Also removes the
VITE_ELEVATION_DATASETread — the/elevation-batchendpoint ignores thedatasetfield in its request body, so the variable configured nothing.Version bump
Since this branch is entirely bug fixes, bumped
1.17.0→1.17.1(patch), matching the1.16.1patch release that preceded it:package.json/package-lock.jsonversion bump (lockfile regenerated vianpm install --package-lock-only, not hand-edited)CHANGELOG.md:[Unreleased]→[1.17.1] - 2026-09-13RELEASE_NOTES.mdrewritten for 1.17.1, following the existing patch-release formatREADME.mdversion header updated to matchVerification
npm run lint,npm test(66 passing, including 15 newruntimeConfigtests),npm run build— all clean.nginx -t) both with and without a key set. The regex needed quoting: nginx reads a bare{in\d{1,2}as the start of a block.?key=is discarded, in both the key-set and no-key states, and again after switching the render step fromenvsubsttosed(including keys containing&,|,\,/,+,=).MISSthenHIT.CARTO_API_KEYand confirmed no trace of it indist/, and that no directcartocdn.comURLs remain in the bundle.docker-entrypoint.shacross three cases (key set, deprecatedVITE_aliases, no key) and confirmed the generatedenv-config.jscarries the map settings but never the key.Docker image build itself was not exercised locally — no daemon available in this environment — so the
Dockerfile/entrypoint template path is verified by config-rendering simulation rather than a local image build; this repo's own CI does build the images on this PR.🤖 Generated with Claude Code
https://claude.ai/code/session_01UqP5vFS3rXNwGUgAvtRQt6