Review follow-up:
- Drop the Next.js route. CARTO_API_KEY is now a regular backend registry
key (env, .env, or the API Keys panel) served by public
GET /api/basemap-config. Every frontend mode already proxies /api/* to
the backend (Next.js proxy in web mode, companion server in packaged
desktop), so this covers web and desktop with one mechanism and leaves
the static export untouched. Also removes the invalid non-handler
export from the route module by removing the module.
- useBasemapConfig: fail open to the unkeyed style after 3 s, abort the
request at 15 s, apply a late key when it arrives, cache successes per
page and retry failures on the next mount.
- Declare OSM/CARTO attribution on the raster source (same markup as the
viewer's existing AttributionControl so MapLibre de-duplicates it).
- Tests: backend endpoint (unset / set+trimmed / persisted operator key /
registry), hook behaviour (success, non-OK, network error, soft timeout
then late key, hard abort, shared request and retry), attribution and
gating source checks.
- CARTO_API_KEY moves to the backend service in docker-compose.yml; docs
updated accordingly.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Wire AISHUB_USERNAME into API Keys and onboarding, and surface backup status on the AIS outage banner so operators can keep vessel coverage without changing the AISStream proxy.
Co-authored-by: Cursor <cursoragent@cursor.com>
Remove sampling, viewport bbox truncation, and buffer ceilings that were cherry-picking ships, flights, and related layers.
Co-authored-by: Cursor <cursoragent@cursor.com>
Persist OPENCLAW_HMAC_SECRET to data/openclaw.env so empty Docker env vars no longer block auth after UI bootstrap. Add verify_hmac.py, silence Rust warnings (#423), and document Docker signing (#424).
Co-authored-by: Cursor <cursoragent@cursor.com>
Expose observed aircraft/vessel paths, route enrichment, VIP metadata, datalink, and nearby context so agents can reconstruct movement without full telemetry dumps.
Co-authored-by: Cursor <cursoragent@cursor.com>
Parse common position, OOOI, performance, and ops formats across major carriers while hiding VDL binary fragments and duplicate frames from the dossier feed.
Co-authored-by: Cursor <cursoragent@cursor.com>
Bulk-ingest Airframes messages on a rate-limited staggered queue with instant cache lookups and priority per-aircraft refresh when opening a dossier; add Meshtastic manual SCAN PLANET control in the SIGINT panel.
Co-authored-by: Cursor <cursoragent@cursor.com>
DGT migrated its public traffic site in 2026: the old image path
infocar.dgt.es/etraffic/data/camaras/{id}.jpg now 302-redirects to the
new etrafficWEB SPA and no longer serves JPEGs, so every DGT camera
showed FEED UNAVAILABLE (proxy and direct source both failed).
New working pattern: https://etraffic.dgt.es/camarasEtraffic/{id}.jpg
- cctv_pipeline.py: DGTNationalIngestor media_url + probe Referer
- routers/cctv.py & main.py: allowlist etraffic.dgt.es + dgt-spain proxy profile
Add Earthdata token entry on the SAR tab with accurate Mode B status, expose optional FIRMS_MAP_KEY in API settings, and remove the frontend operator-unlock gate that blocked localhost saves. Run network-heavy layer-enable fetches on a background executor with frontend retry polling so FIRMS toggles no longer freeze the single API worker.
Drop duplicate slow-tier weather/ukraine jobs, gate correlations when off, slim health probes, keyed layer-panel subscriptions, align backend layer defaults with the dashboard, and fetch CCTV/FIRMS/PSK/etc. synchronously on enable so toggles stay responsive without background prefetch waste.
Replace spoofable Host/Origin WebSocket auth with short-lived bootstrap
tokens minted over the existing local-operator HTTP path. Docker/browser
shell sessions prefetch a token before connecting; loopback peers remain
unchanged.
Also bump backend ws to 8.21.0 and refresh frontend lockfile to clear
npm audit findings (dev toolchain only for frontend).
Fixes#405, #406, #407
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(gdelt): publish enriched copies instead of mutating live features
_enrich_gdelt_titles_background ran in a daemon thread that mutated the
nested properties dicts of GDELT features already published into
latest_data[gdelt]. HTTP readers hold live references to those dicts and
serialize them outside the data lock, so the in-place mutation raced the
serializer and raised RuntimeError: dictionary changed size during
iteration on /api/live-data/slow and /api/bootstrap/critical.
Enrich deep copies instead and atomically swap the top-level key under
_data_lock, with an identity guard so a newer fetch_gdelt() is not clobbered.
Honors the replace-don't-mutate contract documented in fetchers/_store.py.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* test(gdelt): regression test for background enrichment isolation
Asserts _enrich_gdelt_titles_background does not mutate already-published features and instead atomically swaps latest_data["gdelt"] with enriched copies (with the identity guard). Locks in the fix for the dictionary-changed-size race.
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
get_latest_data_deepcopy_snapshot deep-copies layers outside the data lock; a writer mutating a nested object in place races it and raises "dictionary changed size during iteration" (500 on /api/health, /api/live-data). Two changes: (1) _merge_sigint_snapshot now shallow-copies each entry so latest_data["sigint"] no longer aliases the SIGINT bridge dicts or the meshtastic_map_nodes layer (the concrete offender); (2) the snapshot retries a few times as defense-in-depth for any other in-place mutator. Plus regression tests.
Retry announce/manifest while Tor circuits warm on NODE and startup bootstrap.
Add verify_swarm_fresh_participant.py for empty-volume GHCR smoke tests.
Co-authored-by: Cursor <cursoragent@cursor.com>
Auto-relay connect DMs with End Contact severing, signed fleet prekey lookup,
OpenClaw private Infonet channel intents, headless relay Tor bootstrap on redeploy,
and swarm/DM live verification scripts.
Co-authored-by: Cursor <cursoragent@cursor.com>
Ship sb-testnet fleet defaults, swarm/join API, NODE launcher registration step, and meshnode script defaults so users discover peers via the signed seed manifest without manual peer lists.
Co-authored-by: Cursor <cursoragent@cursor.com>
Signed peer manifest pull/announce on the seed, immediate hashchain push for gate messages, seed-only Docker defaults, and stale-genesis sync diagnostics.
Co-authored-by: Cursor <cursoragent@cursor.com>
Uses a local-operator WebSocket bash session, keeps the map interactive, and SNAP docks the shell back into Mesh Chat instead of a floating blurred panel.
Co-authored-by: Cursor <cursoragent@cursor.com>
Align backend, desktop, helm, and frontend package versions for the Telegram OSINT and OpenClaw recon release.
Co-authored-by: Cursor <cursoragent@cursor.com>
Add Telegram OSINT with hourly incremental t.me scraping, metro geocoding
separate from news centroids, threat-intercept popup UI with inline media,
and HTML markers above alert boxes so pins stay clickable. Expose GFW_API_TOKEN
in onboarding and Settings Maritime; harden GFW/CCTV/geo fetchers. Port Osiris-
derived recon, SCM, entity graph, malware/cyber feeds, sanctions, and submarine
cable layers with tests and documentation.
Co-authored-by: Cursor <cursoragent@cursor.com>