From ae35a2c93928313a075dbc21eb47d70abe0eb50d Mon Sep 17 00:00:00 2001 From: daikaginza Date: Sat, 19 Sep 2026 20:12:36 +0700 Subject: [PATCH] docs(attribution): credit adsbdb and carry its route-data terms adsbdb supplies the aircraft type, model name and registration behind every enriched flight, and the airline and origin/destination pair behind the tracked contact's FROM -> TO strip. It appeared in neither attribution surface: DATA_SOURCES.md and src/data/dataCredits.js each held zero occurrences of it, against the rule both files state for themselves and CONTRIBUTING's fourth pull-request item. adsb.lol is a different operator and its ODbL credit does not reach this data. The reporter of #256 left the patch off deliberately, saying the terms were what should not be guessed. They are published, so this takes them from the source rather than inventing them: adsbdb credits PlaneBase for the aircraft data and Guillaume Michel for the ICAO-to-N-number conversion, and states that the flight route data "is the work of David Taylor, Edinburgh and Jim Mason, Glasgow, and may not be copied, published, or incorporated into other databases without the explicit permission of David J Taylor, Edinburgh". No licence or rate limit is published for the service itself. That restriction is the reason the note records what the proxy does with what it fetches: responses are cached per key for 24 hours in .gev-cache/adsbdb.json, which is gitignored, so the data stays on the operator's machine and is never bundled with this repo or redistributed. A test pins the credit. The attribution is a requirement rather than a preference, so it should fail loudly if a later edit drops the names or the restriction, instead of surviving on luck. --- CHANGELOG.md | 10 +++++++++ DATA_SOURCES.md | 4 +++- scripts/format-scope.json | 1 + src/data/dataCredits.js | 10 +++++++++ src/data/dataCredits.test.mjs | 41 +++++++++++++++++++++++++++++++++++ 5 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 src/data/dataCredits.test.mjs diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f3fd7822..f2c044acd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +- Credit adsbdb, which supplies the aircraft type, model name and registration + on enriched flights and the airline and origin/destination pair behind the + tracked contact's route strip. `DATA_SOURCES.md` now records the terms adsbdb + publishes — aircraft data from PlaneBase, and route data that is the work of + David Taylor, Edinburgh, and Jim Mason, Glasgow, and may not be copied into + another database without his permission — along with the request bounds and + the gitignored 24-hour cache that keep the app inside them. A matching + `DATA_CREDITS` entry surfaces the credit in the in-app Data attribution + popover, and a test pins the wording the route data requires. + - Distinguish PARTIAL vessel snapshots from STALE data in the layer panel, with accepted-record counts and unchanged retention, freshness and outage safeguards. diff --git a/DATA_SOURCES.md b/DATA_SOURCES.md index 850d27e39..6e20435d8 100644 --- a/DATA_SOURCES.md +++ b/DATA_SOURCES.md @@ -20,6 +20,7 @@ How to read this: | **OpenSky Network** | Primary worldwide live-flight snapshot | Non-commercial research/education license | Schäfer et al., _"Bringing Up OpenSky"_, IPSN 2014 + opensky-network.org | | **adsb.lol point API** | Bounded live-flight fallback when OpenSky has no usable snapshot | ODbL 1.0 | adsb.lol contributors; `api.adsb.lol/v2/lat/{lat}/lon/{lon}/dist/{radius}` | | **adsb.lol** | Military flights + aircraft traces | ODbL 1.0 | "adsb.lol" (ODbL) | +| **adsbdb** (`api.adsbdb.com`) | Aircraft type, model name and registration by ICAO hex for enriched flights; airline and origin/destination airports for the tracked flight's callsign | No licence or rate limit is published for the service. Its own credits: aircraft data from PlaneBase, ICAO-to-N-number conversion by Guillaume Michel, and flight route data that "is the work of David Taylor, Edinburgh and Jim Mason, Glasgow, and may not be copied, published, or incorporated into other databases without the explicit permission of David J Taylor, Edinburgh" | "adsbdb — api.adsbdb.com" (courtesy); route data credited to David Taylor, Edinburgh, and Jim Mason, Glasgow | | **AISStream.io** | Live vessels (AIS) | Free, beta, no formal ToS; AIS is a public broadcast | "AISStream.io" (courtesy) | | **CelesTrak** | Satellite TLEs (SGP4) | US-government-origin data, no license; citation requested | "CelesTrak (celestrak.org), Dr. T.S. Kelso" | | **The Space Devs — Launch Library 2 v2.3** | Recent launch, payload, stage, and recovery metadata for Space Missions (30d) | [The Space Devs terms of use](https://github.com/TheSpaceDevs/Tutorials/blob/main/faqs/faq_TSD.md#terms-of-use): data may be used and shared in any form; avoid forwarding it without added value; attribution is encouraged (not mandatory). [Official API limits](https://ll.thespacedevs.com/docs/): 15 unauthenticated calls/hour; optional token | "Launch Library 2 — The Space Devs" (courtesy attribution) | @@ -62,6 +63,7 @@ How to read this: - **Google Maps Platform.** You supply your own API key and are bound by [Google's ToS](https://cloud.google.com/maps-platform/terms). Google Maps Content (tiles, geocodes, places) **may not be cached, stored, rehosted, or committed** — this app only ever uses it live, which is the compliant pattern. The "Google" attribution is displayed on the globe and must stay visible. Restrict your key (see [SECURITY.md](SECURITY.md)). - **OpenSky Network.** Its license is **non-commercial**, and operational use of the REST API in a live product can require a prior written agreement with OpenSky — even for non-profit/government use. If you deploy this commercially, contact OpenSky for your own terms. The flights layer is a toggle and runs anonymously by default. - **adsb.lol flight fallback.** When OpenSky is unavailable and no last-good OpenSky response exists, the server requests a cached, capped 250 nm adsb.lol point snapshot around the current camera subpoint. This is regional observed context, not worldwide completeness; provenance is exposed in the Flights stats/context row. Military ICAOs remain reconciled through the existing dedicated military registry rather than duplicated. +- **adsbdb enrichment.** `/api/adsbdb` resolves an ICAO hex to aircraft type, model name and registration, and the tracked flight's callsign to an airline and an origin/destination pair. Fan-out is deliberately small because adsbdb is a free community API that publishes no quota: at most 4 requests in flight, dispatches dripped to roughly 5/s, and each key asked for at most once per session, with route lookups reserved for the tracked aircraft. The dev-server proxy caches each key for 24 hours in `.gev-cache/adsbdb.json`, negative answers included, so a repeat session does not ask again. That cache is gitignored and stays on the operator's machine, which is what the route data's terms require: it may not be copied into another database without David J Taylor's permission, so it is never bundled with this repo or redistributed. Enrichment is best-effort and fail-silent — a flight that gets no answer keeps what the flight feed already gave it. - **Launch Library 2.** `/api/launches` makes a server-side rolling-30-day query against the supported v2.3 detailed launch endpoint, caches successful responses for 15 minutes in memory and on disk, and serves the last successful response during a throttle or transient outage. Anonymous access is limited to 15 calls/hour; deployments can provide `LL2_API_TOKEN` for authenticated access. The Space Devs' published terms permit using and sharing the API data in any form, ask users not to forward it without adding value, disclaim complete accuracy, and encourage—but do not require—attribution. This app keeps a courtesy credit. Payload and stage/recovery records are shown only when supplied. Failed launches expose their source status and never receive fallback orbit geometry or a live/estimated marker. LL2 supplies launch context and event timing, not continuous ascent telemetry or live orbital state. - **TfL JamCams.** The camera list comes from the keyless `api.tfl.gov.uk` endpoint (an optional `TFL_APP_KEY` raises its rate limit); frames come from TfL's public S3 bucket. The "Powered by TfL Open Data" attribution is required by TfL's terms and is registered in the Data attribution popover. - **Ontario 511 CCTV.** The camera list comes from the keyless `511on.ca/api/v2/get/cameras` endpoint; frames are server-registered still images under `511on.ca/map/Cctv/`. The source is live-fetched at runtime and attributed under the Open Government Licence - Ontario. @@ -191,4 +193,4 @@ Douglas-Peucker simplification, 6-decimal rounding). ## In-app attribution -The required Google Maps / Cesium credit renders on the on-globe credit line (`#cesium-credits`, bottom-left) and must stay visible — including in clean-view and recording modes (the whole line, logo + "Google Maps" + the "Data attribution" link, stays on screen; only the GEV panels/HUD fade). The layer-specific credits (adsb.lol, TeleGeography, OSM datacenters/dams/roads, NASA FIRMS, CelesTrak, USGS, City of Austin, Fintraffic, GBFS, Radio Browser, OpenSky, AISStream) are registered into the expandable **"Data attribution"** popover on that credit line via `viewer.creditDisplay.addStaticCredit(new Cesium.Credit(html, /* showOnScreen */ false))` — see `src/data/dataCredits.js`. When you add a new data source, add its license and attribution to this file **and** append an entry to `DATA_CREDITS` in `src/data/dataCredits.js` so it surfaces in the app. +The required Google Maps / Cesium credit renders on the on-globe credit line (`#cesium-credits`, bottom-left) and must stay visible — including in clean-view and recording modes (the whole line, logo + "Google Maps" + the "Data attribution" link, stays on screen; only the GEV panels/HUD fade). The layer-specific credits (adsb.lol, adsbdb, TeleGeography, OSM datacenters/dams/roads, NASA FIRMS, CelesTrak, USGS, City of Austin, Fintraffic, GBFS, Radio Browser, OpenSky, AISStream) are registered into the expandable **"Data attribution"** popover on that credit line via `viewer.creditDisplay.addStaticCredit(new Cesium.Credit(html, /* showOnScreen */ false))` — see `src/data/dataCredits.js`. When you add a new data source, add its license and attribution to this file **and** append an entry to `DATA_CREDITS` in `src/data/dataCredits.js` so it surfaces in the app. diff --git a/scripts/format-scope.json b/scripts/format-scope.json index caffd41d2..1104f30c7 100644 --- a/scripts/format-scope.json +++ b/scripts/format-scope.json @@ -495,6 +495,7 @@ "src/layers/cctv/source.test.mjs", "src/data/alprCameras.js", "src/data/alprCameras.test.mjs", + "src/data/dataCredits.test.mjs", "src/layers/alpr/index.js", "src/layers/alpr/model.js", "src/layers/alpr/policy.js", diff --git a/src/data/dataCredits.js b/src/data/dataCredits.js index 76029ace8..196256930 100644 --- a/src/data/dataCredits.js +++ b/src/data/dataCredits.js @@ -42,6 +42,16 @@ export const DATA_CREDITS = [ 'adsb.lol ' + '(ODbL 1.0)', }, + { + key: 'adsbdb', + html: + 'Aircraft type, registration & flight routes: ' + + 'adsbdb ' + + '· aircraft data from PlaneBase · route data is the work of ' + + 'David Taylor, Edinburgh, and Jim Mason, Glasgow, and may not be ' + + 'copied, published, or incorporated into other databases without the ' + + 'explicit permission of David J Taylor, Edinburgh', + }, { key: 'aisstream', html: diff --git a/src/data/dataCredits.test.mjs b/src/data/dataCredits.test.mjs new file mode 100644 index 000000000..89d7fed87 --- /dev/null +++ b/src/data/dataCredits.test.mjs @@ -0,0 +1,41 @@ +import { test } from 'node:test'; +import assert from 'node:assert/strict'; +import { DATA_CREDITS } from './dataCredits.js'; + +test('every credit carries a unique key and some markup to render', () => { + const keys = DATA_CREDITS.map((entry) => entry.key); + assert.equal( + new Set(keys).size, + keys.length, + 'a duplicate key would silently shadow one provider’s credit', + ); + for (const entry of DATA_CREDITS) { + assert.ok(entry.key, 'a credit without a key cannot be registered'); + assert.ok( + entry.html && entry.html.trim().length > 0, + `credit ${entry.key} has nothing to show`, + ); + } +}); + +test('adsbdb is credited, and keeps the wording its route data requires', () => { + const credit = DATA_CREDITS.find((entry) => entry.key === 'adsbdb'); + assert.ok( + credit, + 'adsbdb supplies aircraft type and routes and must be credited', + ); + // Not a stylistic preference: adsbdb states that the route data "may not be + // copied, published, or incorporated into other databases without the + // explicit permission of David J Taylor, Edinburgh". The names and that + // restriction are the attribution, so they are pinned here rather than left + // to survive the next edit by luck. + assert.match(credit.html, /David Taylor, Edinburgh/); + assert.match(credit.html, /Jim Mason, Glasgow/); + assert.match( + credit.html, + /may not be\s+copied, published, or incorporated into other databases/, + ); + assert.match(credit.html, /explicit permission of David J Taylor, Edinburgh/); + assert.match(credit.html, /PlaneBase/); + assert.match(credit.html, /href="https:\/\/www\.adsbdb\.com"/); +});