- taiwan.js: a failed download serves the last good table (up to 24 h)
and is not retried for an hour. The table host does not answer from
some networks outside Taiwan, and each attempt held the shared catalog
refresh for the ~10 s connect timeout.
- Own server/providers/cctv/taiwan.js in package-boundaries.json
(check:boundaries failed).
- Decode numeric character references; name falls back to the CCTVID
when a row has no road details.
- Credit names the dataset and links the OGDL Taiwan licence.
- Document CCTV_TAIWAN_URL; list Taiwan in the CURRENT-STATE source table.
- Tests: isolate catalog env, reset loader state, cover the byte cap,
failed fetch, backoff, last-good fallback, cap clamping, redirect with
a valid body, name fallback, numeric entities and UUID camera ids.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Fetch keyless DATA.GOV.HK camera locations at runtime and pin stills to
tdcctv.data.one.gov.hk with required attribution. Default cap 1,100 covers
the ~1,013-camera TD catalog, prioritized across Hong Kong Island, Kowloon
and the New Territories.
Co-authored-by: Cursor <[email protected]>
- Google 3D: the OPEN button re-measures a ground whose tiles are still
loading (a few times, a second apart) and on a map change, not only
after the next camera move.
- Mapillary: two mounts on one host during the first download share one
build instead of leaking a second WebGL viewer.
- Retired floating-panel keys (v8 panelPos, panelFloatHintShown) are
dropped from localStorage; dead inline-position resets, the drag JSDoc
and the dead qa-ui-disposal observer branch are gone.
- Docs: z ladder, panel chrome, position storage and the fixture gate's
actual coverage; changelog fragment for #974 (old .gev-cache/mapillary
can be deleted).
- ru/es: the layer is named as everywhere else in the UI.
- Fixtures and test fakes: unused exports removed; a fake credit removal
of an absent credit no longer drops another one; the tile test reset
frees upstream slots.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Resolve conflicts with #1234: keep redirect: 'manual' on both DATEX
fetches and keep main's 30 s TARKTEE_FETCH_TIMEOUT_MS. Drop this
branch's 15 s constant and its import, which auto-merged into a
duplicate export. Keep both sets of Estonia tests and drop the 15 s
claim from the changelog fragment.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Conflicts: the Street Level and Gemini voice strings both appended to the
es/ru catalogs, and both sides' modules to package-boundaries.json — kept
both. scripts/qa-panel-resize.mjs stays deleted (floating panels removed).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
in push-to-talk, answer a Gemini tool call that arrives with no input, reply
or tool result outstanding with a failure instead of running it, and refuse
every other call in the reply it starts, including one after unprompted
speech; the reply stays tracked so the next input retires it and its late
boundary cannot close the user's turn
in push-to-talk, a caption that arrives after its turn ended no longer opens
a reply, so the next request is not retired with its tool calls discarded
open mic cannot tell either case from a new reply and stays unchanged
check packet ownership after the narration callback before queuing tools,
and raise the per-connection call history to 4096 IDs
move the pointer turn event, context item and announcement into
pointerContext so the OpenAI and Gemini controllers share them, and drop the
Gemini token route's copy of the shared exact-Origin comparison
- Default backoff is 30 min, longer than the 15-minute catalog refresh,
so a failing Kartverket costs one attempt per backoff, not per refresh.
- A point a 200 answer leaves out is cached as no height (6 h TTL)
instead of being asked again, and waited on, every refresh.
- Only 408, 429 and 5xx stop the lookup; any other 4xx marks that
request's points as no height and the lookup carries on.
- Each request has its own 10 s timeout inside the shared 30 s deadline;
a lookup cut short only by the deadline resumes without a backoff.
- The lane waits only on a cold cache (>10% of cameras missing); a few
new cameras or expired misses are looked up in the background.
- applyVegvesenGroundHeights skips cameras without finite coordinates,
so it really never throws.
- clearKartverketHeightCache bumps a generation, so a lookup started
before a clear cannot write to the cache, backoff or pending slot.
- Credit and DATA_SOURCES note the modification (water set to 0 m,
rounded to 0.1 m) as CC BY 4.0 asks; docs match the stop rules.
- Tests for the deadline being shared, per-request timeouts, 503,
oversized and non-JSON bodies, 4xx, left-out points, Retry-After end
to end, overlapping refreshes, the warm-cache wait, bad coordinates,
the cache-clear generation and the loader's wait budget.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- A background catalog refresh that rejects now keeps the old catalog for
another TTL, as an empty refresh already did, so a refresh that keeps
failing is retried once per TTL instead of on every request.
- Trim notes are keyed by the source list they describe, and /sources asks
for the list it served, so a request answered during a refresh never pairs
the old cameras with the new list's notes.
- Tests: a failed background refresh (one warning, no unhandled rejection,
no retry before the TTL, trim notes stay with their list) and an empty
background refresh (old catalog kept, no upstream fetch before the TTL).
The race assertion's message now names the failure; its timer is cleared.
- The Tarktee test no longer imports the new constant, so on main it fails
on its own assertion instead of taking the whole file down.
- precompute-cctv-heights waits 60 s for a cold catalog, past Tarktee's 30 s.
- CURRENT-STATE notes the 30 s bound and the retry spacing.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- Assert the key never reaches the camera records sent to the browser or
the "Loaded" log line.
- Count fetches in the keyless test instead of relying on assert.fail
inside the mock, which the loader's catch would swallow; a
whitespace-only key is treated as missing.
- Cover the key hint for 400/401/403 and its absence for 429/500/503,
and log the failure as one string without a trailing empty argument.
- Add _resetOntarioKeyWarningForTest so the logged-once check no longer
depends on test order.
- Read CCTV_ONTARIO_MAX_SOURCES from the same env as the key, and keep
console output out of the suite.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- State FL511's terms the same way everywhere: individual, personal use
only, and any other use (a public deployment included) needs FDOT's
express written consent. .env.example, README, dataCredits, the source
licence string, the catalog comment and the changelog fragment said only
"individual, non-commercial use".
- Page the ArcGIS catalog on exceededTransferLimit alone and advance the
offset by the rows each page returned, so a lower server-side max
record count no longer cuts the catalog short at the first short page.
- Order pages by OBJECTID_1 (this layer's object id; a plain OBJECTID is
rejected with HTTP 400) so offset paging is stable.
- Raise the page ceiling to 40 and warn when it is hit.
- Tests: short pages with exceededTransferLimit keep paging, orderByFields
is sent, and a service that ignores resultOffset stops at the ceiling.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Attach the background-refresh warning where the refresh starts, so a
failed refresh logs once instead of once per request served meanwhile.
The test now checks that requests during a refresh share it, and turns
the hang off before releasing the fetches so a retrying loader can't
stall it.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Read ~1,800 national freeway cameras at runtime from the Freeway Bureau's
keyless MOTC 2.0 CCTV.xml table. Each published MJPEG stream maps to the
same camera server's single-JPEG path; only those exact HTTPS pairs on the
four freeway.gov.tw camera servers are registered. On by default,
CCTV_TAIWAN_ENABLED=0 skips it.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Main gained three imagery providers (Google Street View, KartaView,
Panoramax), shared line-coverage, cone and photo-viewer modules, one source
lit at a time and the translated interface. Their shared modules still
carried what this branch removes, so the merge ports them onto it:
- lineCoverage.js is this branch's coverage.js made provider-neutral
(draped lines near the ground only, the selection drawn over them, key
and rate-limit blocking); sequenceCones.js is sequences.js the same way.
Mapillary, KartaView and Panoramax all build on them; Mapillary moves
back to providers/mapillary/ beside the others.
- No ground casting, mesh sampling, surface modes, FOLLOW, legend, prewarm,
orbit overview points (Panoramax's density dots included), stale-tile
swaps or water-filled point budget come back.
- Kept from main because the new providers need them: requiresMapStack and
attachMapStackController (Street View on Google 3D only), ground clicks,
openNearest with an optional provider nearestImage, openImage {frame},
reportError, the view-cone marker (now an SVG glyph), filters /
coverageLabel / sinceBasis, OPEN STREET VIEW, keyAlternatives and i18n.
- photoViewer.js treats the viewer as expanded when its wrap is full screen
or the iPhone popover, as EXPAND now is.
- The fixture browser gate keeps its 8 steps and adds one each for
KartaView and Panoramax; catalogs, docs, boundaries and format scope
follow.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
An expired catalog made every /api/cctv request (camera list and frames)
wait for the full refresh, which lasts as long as the slowest of the live
packs: Tarktee's DATEX feeds took 2 to 16.6 s across ten requests. With
Tarktee's timeout raised to 30 s, that wait could reach 30 s at each
15-minute refresh. The cached list is now returned while a single-flight
refresh replaces it in the background; only a first load, with nothing
to serve, waits. A background refresh that throws is logged.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The Estonian Transpordiamet feeds answered in 2 to 16.6 s across ten
requests (120 and 160 KB), and both must arrive for any camera to load,
so the shared 15 s catalog timeout dropped the whole pack on about a
third of loads ("Tarktee DATEX download error: The operation was aborted
due to timeout"), for the 15 minutes until the next catalog refresh.
TARKTEE_FETCH_TIMEOUT_MS gives the two requests 30 s; other packs keep
15 s.
Live: 175 cameras in 3.3 s.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Review fixes for #1228: CURRENT-STATE.md and the constants comment no
longer call Ontario 511 keyless. DATA_SOURCES.md notes Ontario 511's
Developer's Access Agreement (511on.ca/developers/resources): the data
stays under the Open Government Licence - Ontario, key requests are
reviewed case by case, attribution by link is encouraged and the logo
rules don't apply because the app shows none, and the "as is" disclaimer
should be passed on, which the credit now does.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A wrong or revoked key logged only "download failed: 400"; a 400, 401 or
403 now adds "(check ONTARIO_511_API_KEY)". The README's CCTV row listed
Ontario among the default cameras with no mention of the key it now
needs.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
511on.ca/developers is a 404. Sign up at 511on.ca/my511/register, then
request the key while logged in at 511on.ca/developers/doc (both checked).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The Ontario 511 camera list answered 400 "Invalid Key" on every catalog load
("[CCTV] Ontario 511 camera download failed: 400"), so the pack loaded
nothing. 511on.ca's developer docs now say the API "Requires a developer
key" (free, from 511on.ca/developers; 10 calls a minute). The loader reads
ONTARIO_511_API_KEY and sends it as `key`; without it the pack is skipped
with one log line instead of a failed request on every load. The key is
never logged. .env.example and DATA_SOURCES no longer call the endpoint
keyless.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Providers write cache files and logs into .gev-cache and .gev-logs while the app runs. A serve-only standalone plugin adds both to server.watch.ignored, so the dev watcher no longer stats them; source changes still reload.
Review follow-up on #975. The shared same-site gate refuses any forwarding header, which is right for routes that spend a key, but terrain is keyless and needed for rendering: behind the reverse proxy the README documents, every /api/terrain/heights chunk got 403 and fell back to the geoid. Terrain now uses admitSameSiteKeyless, which keeps the Sec-Fetch-Site and exact-Origin checks (comparing Origin against a single X-Forwarded-Proto scheme) but does not refuse forwarding headers. The shared admitSameSite gate is unchanged for every other route. The changelog entry moves to changelog.d/975-terrain-cross-site-gate.md.
Co-authored-by: daikaginza <[email protected]>