Commit Graph
411 Commits
Author SHA1 Message Date
bb74071dc2 fix(server): throttle the cost-bearing proxies by default
The OpenAI endpoints (/api/realtime/token, /api/openai/hud-summary) now
allow 30 requests per minute per client IP and the Google Places endpoints
120, the caps the Pinokio build already ships. GEV_RATELIMIT_OPENAI_PER_MIN
and GEV_RATELIMIT_GOOGLE_PER_MIN still override them and exactly 0 disables
them; an unreadable value falls back to the default rather than to
unlimited.

Salvaged from #683 onto current main.

Co-authored-by: Sameh Khamis <[email protected]>
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-02 19:57:29 -07:00
7aa9bbd3be fix(server): gate cost/log endpoints against cross-site requests and ship a full CSP
The cost-bearing endpoints (/api/realtime/token, /api/openai/hud-summary,
/api/google/nearby-places) and the voice debug log refuse cross-site browser
requests: a foreign or opaque Origin, a Sec-Fetch-Site other than
same-origin/none, or proxy forwarding headers. Loopback tools without an
Origin and the LAN opt-in keep working. The dev and preview servers send one
shared Content-Security-Policy, and embed-mode framing rewrites only the
frame-ancestors directive of it.

Salvaged from #242 onto current main.

Co-authored-by: Sameh Khamis <[email protected]>
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-02 19:56:42 -07:00
Sameh Khamis de1e0836b3 fix: send "vessels" to the ships layer in voice
Voice hears audio directly, and "vessels" is easily heard as "visuals",
which the instructions route to visual styles, so asking for vessels turned
on other layers or a CRT style. The instructions now say a vessels request
without a style name means the ships layer, and a style needs its name.
2026-10-02 15:21:36 -07:00
Sameh Khamis 759d05db4e fix: name only tools voice offers in its instructions
The voice instructions recommended aircraft_in_area, vessels_in_area and
get_earthquakes, which voice no longer offers, and the docs said voice gets
nearly every query. The instructions now name tools voice has and send
aircraft, ship and hazard questions to analyst_query; a test keeps the
instructions to tools the voice session lists.
2026-10-02 15:21:36 -07:00
Sameh Khamis f610de77dc fix: judge camera catalog trimming by region, not by returned cameras
Coverage was checked only for packs among the cameras found, so an area
whose cameras were all trimmed away answered zero cameras, complete. The
catalog now reports where each trimmed pack's cameras are, and the tool
marks an answer partial whenever its area overlaps that region.
2026-10-02 15:21:36 -07:00
Sameh Khamis 66b07418bd fix: say when the camera catalog serves only part of a region
Camera packs keep their nearest cameras and the catalog cap thins them
further, so London answered 250 cameras while TfL offers many more. The
catalog now records each pack's full count, tags cameras with their pack,
and serves the packs it trimmed; find_cctv_cameras names them.
2026-10-02 15:21:36 -07:00
manjunath22466 01979bba1e chore(stack): refresh voice core and outlines parents
merge the latest #837 and #842 draft heads

keep the stack parent-only so #846 shows geometry changes once
2026-10-02 23:28:25 +05:30
manjunath22466 177b5951a0 fix(outlines): harden shared cache and provider lifecycle 2026-10-02 22:32:46 +05:30
Michael Johnston d866f9b01c Merge current upstream and resolve PR 581 conflicts 2026-10-01 21:36:44 -04:00
Sameh Khamis b4067f9859 fix: time-limit OpenSky snapshot requests and retry once
A stalled global snapshot held the request for over a minute. Each attempt
now gets 10 seconds, a timed-out or failed attempt is retried once, and a
second failure is answered from the stale cache or the regional fallback.
The OAuth token request gets the same limit.
2026-10-01 14:26:20 -07:00
Sameh Khamis 1a03e7483d feat: share the tool catalog with voice 2026-10-01 13:52:36 -07:00
bassem chagra 0cfb795845 Merge remote-tracking branch 'origin/main' into feat/wsdot-camera-pack
# Conflicts:
#	CHANGELOG.md
#	docs/CURRENT-STATE.md
2026-10-01 12:23:41 +02:00
bassem chagra 031df60014 Merge remote-tracking branch 'origin/main' into feat/king-county-camera-pack
# Conflicts:
#	CHANGELOG.md
#	docs/CURRENT-STATE.md
2026-10-01 12:20:32 +02:00
Niccolò Saggese 5083a74413 Merge remote-tracking branch 'upstream/main' into fix/363-geocode-proxy
# Conflicts:
#	CHANGELOG.md
2026-09-29 19:16:15 +02:00
Said Turksever c4514784fc Merge branch 'main' into pr/mapillary-layer 2026-09-29 15:44:25 +01:00
ulihhhh 3bae92fce7 Merge upstream/main into feature/catalonia-cctv-cameras
# Conflicts:
#	docs/CURRENT-STATE.md
2026-09-29 10:08:59 +02:00
Bilawal Sidhu 9559e7a282 feat(outlines): voice outlines without Overpass — bundled US places and neighborhoods, guarded Nominatim, OpenFreeMap streets and buildings 2026-09-28 22:49:23 -05:00
Bilawal Sidhu a19897ad15 feat(voice): voice core — honest layer reach, spoken summary with on-screen card, narration, point-and-ask
- Voice layer manifest (src/voice/layerManifest.js) generates the layer enums,
  aliases and analyst field hints; a test fails when a catalog layer has no entry.
- analyst_query validates fields, operators, units, values and scopes, counts up
  to 250,000 loaded records per layer, reports complete/partial/unanswered, tells
  LAYER_OFF / NOT_READY / FEED_UNAVAILABLE apart from zero, refuses mismatched
  follow-ups and never lets a superseded query replace follow-up memory. Seven
  more layers expose analyst records.
- Tool results carry a code-built say line and a display card; the voice card in
  the mic control shows captions, plan steps and the result
  (src/voice/resultDisplay.js is the one adapter). Slow tools narrate their
  current step out of band; holding Space while the assistant talks cuts it off.
  Turn spans go to the debug log; caption transcription is metered; the log
  omits what was said unless GEV_VOICE_LOG_CONTENT=1.
- Point and ask: the Space-down pointer snapshot resolves "this", "that one" and
  "around here" through 'pointer' targets, and "the second one" through
  referent:n from the last numbered list.
- Prompt states each policy once (instructions + tools 48.5k -> 46.7k chars).
- Voice benchmark harness (scripts/qa-voice-bench.mjs, scripts/voice-bench/)
  shares its phrase table and grading with scripts/qa-voice-routing.mjs.
2026-09-28 21:19:23 -05:00
Bilawal Sidhu 9c15f093a1 fix(cyclones): accept advisories NHC publishes before their nominal time
NHC stamps an advisory with its nominal time and writes it about half an
hour early, so the 5-minute future limit rejected the whole feed each
advisory cycle and the layer showed no storms. Allow 90 minutes ahead.
2026-09-28 20:47:06 -05:00
f4fcf267c6 fix(osm): stop using public Overpass by default (#648) (#742)
Traffic roads come from OpenFreeMap vector tiles, or TomTom flow tiles with a
key (Hybrid by default). Military areas use OpenFreeMap polygons with a bundled
worldwide name index; wide views show named points. ALPR reads an hourly
OpenStreetMap extract. Cockpit place context and country, state and US county
outlines use bundled Natural Earth and US Census data. Overpass is used only
when an operator configures their own endpoint.

Also: camera arrivals no longer land below ground, keyless terrain retries on
429, bounded relation geometry for configured Overpass, one shared
OpenStreetMap credit, and separate tile and API transports for embedders.

Co-authored-by: theGaryLarson <[email protected]>
Co-authored-by: Milan Khanal <[email protected]>
2026-09-28 19:07:57 -05:00
Said TurkseverandClaude Opus 5.5 d7d5bec752 fix(mapillary): tile flights own their abort, callers only wait on them
fetchTile coalesced concurrent requests for one tile onto a single
upstream fetch, but that fetch ran on the first caller's signal. When the
first request was abandoned (an older pan), every joined request lost a
tile it still needed; and a joined caller that aborted stayed subscribed
until the shared fetch finished.

A flight now owns its AbortController and counts waiters, the pattern the
weather and wind providers use. Each caller's own abort rejects that caller
at once; the upstream fetch is cancelled only when the last waiter leaves,
and a later request after that starts a fresh fetch.

Regression tests (fail on the previous tiles.js, pass now): a joined
request survives the first caller aborting with one upstream request; a
joined caller that aborts leaves at once while the first still gets the
tile; both waiters leaving cancels the owned fetch.

Reported by kvnloo in review.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-28 21:53:40 +01:00
devv-shayan a398a25934 fix(voice): validate Codex OAuth and report unknown usage 2026-09-27 21:09:26 +05:00
devv-shayan 881e24485c feat(voice): add ChatGPT OAuth auth option 2026-09-27 20:58:08 +05:00
daikaginza 7c7563d91b fix(gbfs): rate-limit /api/gbfs
The proxy already restricted WHERE it would go — https, an allowlisted host, a
station_information/station_status path, no redirects, a 12-second deadline and
a 5 MB body cap — but nothing restricted HOW OFTEN, so the dev server would
relay an unbounded stream of requests at a third-party bikeshare operator on
any caller's behalf, one outbound fetch and one timeout timer each.

Admit 120 requests/minute per client address, global backstop 3x, refused with
429 and `Retry-After` before the target is even parsed. The ceiling comes from
the layer's own demand: `src/layers/bikeshare/registry.js` catalogues 15
systems, station information is cached per city after its first fetch, and
station status refreshes once per city every STATUS_POLL_MS (60s) with
in-flight requests deduplicated — about 15 requests a minute with everything
in range, so 120 is eight times a maximal session.

The method, host, path, redirect, deadline and size guards are unchanged.

Refs #264
2026-09-27 22:32:36 +07:00
daikaginza be7187cea7 fix(server): bound the terrain-heights cache and its request rate
Every distinct 5-decimal point was a permanent in-memory entry, a
permanent line in an uncapped `.gev-cache/terrain-heights.json`, and a
live upstream call. Nothing limited the rate, and coordinates were
checked for being finite rather than for being on Earth, so an
out-of-range pair was still a valid cache key.

Four bounds, each following a pattern this repo already uses:

- WGS-84 range is enforced in `parseTerrainPoints`, at the edge, so no
  later stage has to. Poles and the antimeridian still parse.
- The point cache holds at most 50,000 entries and evicts oldest-first,
  the shape `trackBackfillProxies` uses. Sized from measurement: this
  checkout's cache file held 6,189 entries in 1.0 MB of real use, so the
  ceiling is eight times that working set. Terrain does not move, so an
  evicted point costs one refetch and never a wrong answer.
- A cache file above 24 MB is not read back, mirroring
  `rocketLaunchesProxy`. An unmeasurable file is not treated as an
  oversized one: without stat, readFile decides, exactly as before.
- The route carries an always-on limiter of 90/min per client, 270
  global — the `/api/overpass` band, and an order of magnitude above
  measured demand (a full test:track run drove 10 requests, peak 8/min).

The ceilings are constructor options so they can be exercised as
behaviour rather than asserted as constants; production passes none.
They are destructured in the body because `proxyErrorResponses.test.mjs`
slices these proxies to the first column-zero closing brace.
2026-09-27 22:10:43 +07:00
bassem chagra c4f18169eb fix(cctv): raise the default catalog cap to 4,500 and enforce it over every pack
The per-pack defaults already summed to 4,054 before WSDOT (4,304 with
it), past the documented 4,000 cap, so a default install was trimming.
The existing sum check in the DriveBC test listed packs by hand and
missed Calgary and DelDOT. Replace it with a check in
cctvCatalogCap.test.mjs that sums every exported DEFAULT_*_MAX_SOURCES,
and drop the Calgary test that pinned the cap at exactly 4,000.
2026-09-27 12:20:45 +00:00
bassem chagra c3f197823e fix(cctv): serve King County model/manufacturer through /api/cctv/sources
The loader and normalizer carried the hardware model, but the /sources
response projection and the browser catalog both whitelist fields and
dropped it, so no client consumer ever saw it. Project model and
manufacturer (manufacturer disambiguates bare model strings like "3950")
at both boundaries, and add a test that drives the real middleware and
browser catalog end to end.
2026-09-27 12:09:27 +00:00
bassem chagra 481d0c327a fix(cctv): map WSDOT diagonal and BW compass codes; document WSDOT env
WSDOT's layer metadata defines BW (Bothways) plus the diagonals
NE/SE/SW/NW alongside N/E/S/W. Diagonal cameras were being demoted to the
low-confidence id-hash fallback; map them to 45/135/225/315 degrees and
treat BW (not B) as the no-single-facing code. Add CCTV_WSDOT_ENABLED and
CCTV_WSDOT_MAX_SOURCES to .env.example with the other pack controls.
2026-09-27 12:09:27 +00:00
ulihhhhandClaude Opus 5.5 320a1d6bfd fix(cctv): harden the Catalonia catalog fetch and frame-link allowlist
Address review feedback on #595:

- Reject frame links carrying userinfo (user:pass@) in
  normalizeCataloniaImageUrl, so catalog data cannot inject credentials
  into the server-side frame request on an allowlisted host.
- Fetch cameres.xml over https (verified: same 200 body, no redirect),
  refuse redirects with the unread body released, and read the body
  through readResponseTextCapped with a 1 MiB CATALONIA_MAX_CATALOG_BYTES
  cap instead of an unbounded resp.text().
- Add regression tests for userinfo links on every allowed host, the
  refused redirect, and declared and streamed oversize bodies.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 12:01:17 +02:00
Michael JohnstonandClaude Opus 5 5f8a275487 fix(providers): bound the remaining upstream body reads
Route the six proxied fetches that still buffered upstream bodies without
a limit through the shared capped readers in src/sources/httpBody.js:
FIRMS CSV, CelesTrak TLE groups, adsb.lol /v2/mil (both the OK and
relayed-status paths), TomTom flow tiles, OpenSky states/all and adsbdb
enrichment lookups. Each cap is a bound sized well above the measured
payload, not a budget.

readResponseBytesCapped gains the same optional abort signal as the text
reader, with the same cancel-on-abort plumbing and reader release, so the
TomTom tile path can share the route deadline instead of reading
arrayBuffer() unbounded. Where a route already had a deadline, the same
signal now covers the body read as well as the headers. Two polls had no
deadline at all: the adsb.lol military poll gains a 12-second one and the
OpenSky states/all exchange, including its Basic-auth retry, a 20-second
one; both miss into their existing STALE paths.

FIRMS map-key status, the OpenSky token exchange and CCTV media are left
as they are.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-26 14:40:08 -04:00
Said TurkseverandClaude Fable 5.1 547b706f67 refactor(mapillary): remove the plain-English query feature
Street Level is imagery only from here on: coverage, sequences and the
embedded viewer. The Claude planner, map-feature and traffic-sign tiles,
the NDJSON feature stream, sprites, detection outlines and analyst records
go, along with @anthropic-ai/sdk, zod and the Anthropic key entry.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-25 18:08:43 +01:00
Said TurkseverandClaude Fable 5.1 9ba6f96d87 Merge upstream/main into pr/mapillary-layer
Upstream took share token '2' for fire perimeters, so Street Level moves to
'3'. mapillary-js joins upstream's optimizeDeps include list instead of
overriding it; catalog and registry tests count the new upstream layers.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-25 17:58:27 +01:00
bassem chagra 5b00dd0980 feat(cctv): King County road camera source pack (Washington State)
Adds King County DOT Road Services' cameras as a keyless source pack, from
the county's public ArcGIS FeatureServer layer ("King County and WSDOT
Traffic Cameras"). 59 live cameras against the current feed.

- The `outFields` list is explicit on purpose: the layer also carries
  asset-administration columns (including staff names) that must never be
  fetched.
- Only live, active cameras with frames on the county's own
  info.kingcounty.gov image handler are registered; the feed writes http://
  and the handler serves HTTPS, so URLs are upgraded and pinned before
  registration. WSDOT-owned rows are skipped so a camera never appears twice
  when a statewide WSDOT pack is present; the few city-owned cameras the
  county hosts (Redmond, Sammamish, Newcastle, Snoqualmie) carry their owner
  as the per-camera credit, DriveBC-style.
- The layer publishes no facing: headings use the shared id-hash fallback at
  low confidence, correctable with the calibration gizmo.
- Uniquely among the packs, the county publishes each camera's hardware
  Manufacturer/Model (Cohu 3950/3965, Bosch AUTODOME IP 5000i, Axis
  Q6135-LE, Siqura PD910). The model string is whitespace-collapsed (the
  feed carries stray newlines) and carried on the source as `model`, with an
  additive passthrough in normalizeSourceItem (same pattern as poseSource)
  so identified-hardware consumers can use it. All 59 live cameras carry a
  model value.
- Attribution per the KCGIS Center terms, registered in the attribution
  popover and documented in DATA_SOURCES.md.
- Defaults: the whole catalog loads (125 cap); CCTV_KINGCOUNTY_MAX_SOURCES
  changes the cap, CCTV_KINGCOUNTY_ENABLED=0 turns the pack off.
- Tests: filtering (owner/live/status/host/geometry/bbox), HTTPS upgrade,
  model whitespace-collapse and passthrough, partner-city credit, env cap,
  upstream-failure fallback, and normalizeSourceItem model semantics.
2026-09-25 12:35:06 +02:00
bassem chagra ee3e3c7a41 feat(cctv): WSDOT highway camera source pack (Washington State)
Adds Washington State's highway cameras as a keyless source pack, from the
Esri JSON layer WSDOT's own Travel Center map consumes
(data.wsdot.wa.gov/travelcenter/Cameras.json, ~1,700 point features).
Closes #624.

- Geometry arrives in EPSG:3857; converted to WGS84 on load and bounded to
  a Washington bounding box.
- Only frames on WSDOT's own images.wsdot.wa.gov host are registered — the
  catalog also lists ~70 partner cameras (Oregon DOT, City of Seattle,
  lodges, airports) whose own terms apply; those are skipped rather than
  proxied. 1,630 cameras survive the filters against the live feed.
- CompassDirection letters (N/E/S/W) give a high-confidence heading; the
  majority `B` ("both directions") rows carry no single facing and use the
  shared id-hash fallback at low confidence, with the usual two pose
  personalities.
- The feed body carries Windows-1252 bytes (en-dashes in titles) with no
  charset declaration, so it is decoded explicitly before parsing.
- WSDOT's layer metadata marks the feed "low volume": the 15-minute catalog
  cache and per-request frame fetches respect that, frames are never stored
  or redistributed, and the WSDOT credit is registered in the attribution
  popover. A keyed WSDOT Traveler Information API serves the same population
  for higher-volume use and is deliberately not required.
- Defaults: 250 cameras nearest Seattle and Spokane; CCTV_WSDOT_MAX_SOURCES
  changes the cap, CCTV_WSDOT_ENABLED=0 turns the pack off.
- Tests: Mercator conversion against a real layer feature, official-host and
  malformed-row filtering, compass mapping and both pose personalities,
  cp1252 decoding, env cap, upstream-failure fallback.
2026-09-25 12:32:36 +02:00
ulihhhh 21a86c05bd Merge upstream/main into feature/catalonia-cctv-cameras 2026-09-25 12:01:51 +02:00
Sameh KhamisandClaude Opus 5.5 9b1c75e539 Merge main into pr-688
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-24 22:17:12 -07:00
Sameh KhamisandClaude Opus 5.5 3a23dc393d fix(live): cache the oversized-track 502 like other upstream errors (#722)
Keep the new 502, but store it in the 60 s cache as the proxy already does
for 404/429: /tracks/all costs OpenSky credits, so an oversized track must
not be re-downloaded on every reselect. Update the regression test and
credit the fix in CHANGELOG.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-24 22:09:17 -07:00
ulihhhhandClaude Opus 5.5 b27e8a35c8 Merge upstream/main into feature/catalonia-cctv-cameras
Keeps PR #595 current with #730-#743. Clean merge, no conflicts.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-24 10:50:18 +02:00
Raushankumar0720 b22dd34f45 Merge remote-tracking branch 'upstream/main' into fix/track-proxy-oversized-response 2026-09-24 09:19:33 +05:30
513dc87a0e feat(hud): Cyber HUD theme with GPU contact sonar (#706)
Add the opt-in Cyber HUD layout with coordinated map and cockpit panel
styling, GPU-only contact sonar (rings, range, power, opacity, sector) with
native-rendering fallback, and set_cyber_sonar voice controls. Sonar visual
style inspired by kk376's tactical naval sonar (#214).

Co-authored-by: Sameh Khamis <[email protected]>
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-23 20:31:56 -07:00
f913066cf2 feat(fires): MODIS in Active Fires and a Fire Perimeters layer (#737)
Adds MODIS NRT to Active Fires and a keyless Fire Perimeters layer (NIFC WFIGS) with
InciWeb incident links, served through a capped, cached /api/fire-perimeters proxy.

Co-authored-by: Gustavo Beneduzi <[email protected]>
Co-authored-by: James Cooke <[email protected]>
2026-09-23 21:21:52 -05:00
1fc795577a feat(sdr): local receivers — browser RTL-SDR, Local ADS-B layer and decoder feeds (#732)
Adds a Local ADS-B layer fed by your own receivers: a browser WebUSB
RTL-SDR (with FM listening) and local 1090/978 MHz decoder feeds
(LOCAL_RECEIVER_FEEDS, local and private addresses only). Local aircraft
draw in magenta with class, silhouettes, 3D models, trails and a position
sanity filter; the click card names the band and input that heard them.

Builds on Sameh Khamis's SDR prototype and the initial GEV port by
Mazeyar Moeini Feizabadi (#134); the decoder-feed design follows the
notes on #57. Closes #57.

Co-authored-by: Sameh Khamis <[email protected]>
Co-authored-by: Mazeyar Moeini Feizabadi <[email protected]>
2026-09-23 16:00:53 -05:00
Said TurkseverandClaude Fable 5.1 817716f0c1 Merge upstream/main into pr/mapillary-layer
Twenty layers now (weather, wind, cyclones and recent imagery landed
upstream); Street Level sits after Recent Imagery in the right rail and the
Cameras group, and the rail CSS names it beside the other panels.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-23 19:05:59 +01:00
Said TurkseverandClaude Fable 5.1 791e77fa33 feat(mapillary): dev-server provider — cached tiles, feature stream, sprites, optional Claude planner
Vite middleware for /api/mapillary: status (capabilities, never values),
vector tiles cached in memory and on disk with the 12 MB z14 image layer
stripped in transit, an NDJSON feature stream capped at 600 tiles, MIT
sprite icons behind a grammar-guarded path, and a structured-output planner
that only activates when ANTHROPIC_API_KEY is set server-side.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-23 15:44:32 +01:00
Said TurkseverandClaude Fable 5.1 fa5710bcf2 feat(mapillary): street-level layer core — coverage, sequences, viewer bridge, query engine
Camera-driven Mapillary coverage (z0–5 overview points from orbit, z11–14
ground-clamped sequence lines below 60 km), per-sequence image cones, an
embedded MapillaryJS viewer bridge with a camera-follow mode, sprite icons
for map features, and a query engine that turns a plan into a streamed
z14 tile fan-out. Registers an on-globe CC BY-SA 4.0 credit while enabled.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-23 15:44:32 +01:00
Raushankumar0720 34d258b394 fix(live): return 502 and prevent caching on oversized track responses (fixes #720) 2026-09-23 15:52:21 +05:30
ulihhhh 5b4931572a Merge upstream/main into feature/catalonia-cctv-cameras
Keeps PR #595's Catalonia CCTV pack in sync with upstream's DelDOT
CCTV pack (#699) and the wind/weather doc updates from #617. The
sources.js conflict was a false positive from git's line-based diff
interleaving two structurally similar but independent loader
functions (loadCataloniaSourcesFromOpenData / loadDelDOTSourcesFromOpenData);
resolved by keeping both as complete, separate functions.

Full unit suite passes (4743/4743, 1 pre-existing Node-version skip).
2026-09-23 12:12:58 +02:00
0251c74109 feat(weather): add globe wind, observed weather and cyclone context (#617)
Wind (NOAA GFS and ECMWF IFS: animated particles, colour field, a reading at map centre), observed weather (NOAA MRMS radar, GOES and NESDIS infrared clouds, lightning density) on one shared history timeline, NHC and CPHC cyclone advisories with tracks and cones, and a WEATHER panel in the right rail. On 3D Tiles the observed products render as raised shells with a sharper window around the view.

Co-authored-by: Gustavo Beneduzi <[email protected]>
Co-authored-by: Daniel Slay <[email protected]>
Co-authored-by: Rehaan Delmotra <[email protected]>
Co-authored-by: Cursor Agent <[email protected]>
2026-09-22 17:45:39 -05:00
ulihhhh 49a322519a Merge remote-tracking branch 'upstream/main' into feature/catalonia-cctv-cameras
# Conflicts:
#	CHANGELOG.md
2026-09-21 19:00:01 +02:00
Niccolò Saggese 771c9e5632 fix(search): bound and sanitize the geocode proxy
- reject blank viewport-bias components before Number() reads them as 0
- give the upstream call a 10s deadline and a 256 KiB capped body read
- return fixed public text on failure instead of the upstream message
2026-09-21 11:56:33 +02:00