import * as Cesium from 'cesium';
/**
* Per-layer data attribution registered into Cesium's credit display.
*
* Legal requirement (see DATA_SOURCES.md, findings H10/H11 in
* docs/pre-ship-audit-2026-07-01.md): every third-party data layer this app can
* display carries its own license and required attribution — ODbL (OSM
* datacenters/dams, adsb.lol, Overpass roads), CC BY-NC-SA (TeleGeography
* cables), NASA FIRMS, CelesTrak, USGS, City of Austin, Fintraffic (CC BY 4.0),
* The MIT code license does NOT cover this data.
*
* These credits are registered ONCE at init as STATIC credits with
* showOnScreen=false, so they live in the expandable bottom-left "Data
* attribution" lightbox (Cesium's credit popover) rather than cluttering the
* on-globe line. Always-present is intentional and reversible: the lightbox is
* the app's canonical attribution surface and DATA_SOURCES.md is the
* machine-readable index. Strings are copied verbatim from DATA_SOURCES.md — if
* you add a data source, add it there AND here.
*/
/**
* Attribution entries. `html` is the credit markup; keep it minimal and
* link out where DATA_SOURCES.md provides a canonical URL. Order roughly
* follows DATA_SOURCES.md (live sources, then bundled snapshots).
* @type {{ key: string, html: string }[]}
*/
export const DATA_CREDITS = [
// ── Live sources ────────────────────────────────────────────────
{
key: 'opensky',
html:
'Flights: OpenSky Network — Schäfer et al., ' +
'“Bringing Up OpenSky”, IPSN 2014 · ' +
'opensky-network.org ' +
'(non-commercial)',
},
{
key: 'adsblol',
html:
'Military flights, aircraft traces & bounded regional flight fallback: ' +
'adsb.lol ' +
'(ODbL 1.0)',
},
{
key: 'aisstream',
html:
'Live vessels (AIS): ' +
'AISStream.io',
},
{
key: 'celestrak',
html:
'Satellites (TLEs): CelesTrak ' +
'(celestrak.org), ' +
'Dr. T.S. Kelso',
},
{
key: 'launch-library-2',
html:
'Space mission launch, payload & recovery metadata: ' +
'Launch Library 2 — The Space Devs ' +
'(API documentation and rate limits)',
},
{
key: 'usgs',
html: 'Earthquakes: Data courtesy of the U.S. Geological Survey',
},
{
key: 'overpass',
html:
'Road geometry (traffic): ' +
'© OpenStreetMap contributors ' +
'(ODbL 1.0)',
},
{
key: 'photon-geocoder',
html:
'Keyless place search: ' +
'Photon (komoot) over ' +
'© OpenStreetMap contributors ' +
'(ODbL 1.0)',
},
{
key: 'military-installations-osm',
html:
'Mapped installation context: ' +
'© OpenStreetMap contributors ' +
'(ODbL 1.0; incomplete mapped context)',
},
{
key: 'cockpit-place-osm',
html:
'Cockpit place context: ' +
'© OpenStreetMap contributors ' +
'via Nominatim (ODbL 1.0)',
},
{
key: 'open-meteo',
html:
'Cockpit current conditions: ' +
'Weather data by Open-Meteo.com ' +
'(CC BY 4.0)',
},
{
key: 'google-news-rss',
html:
'Cockpit regional headlines: ' +
'Google News RSS ' +
'(location-matched article links; publisher terms apply)',
},
{
key: 'gdelt',
html:
'Cockpit regional headlines: ' +
'GDELT Project ' +
'(location-matched article links; publisher terms apply)',
},
{
key: 'austin-cctv',
html:
'CCTV cameras & frames: City of Austin, TX — ' +
'data.austintexas.gov',
},
{
key: 'txdot-cctv',
html:
'CCTV cameras & frames (Texas): ' +
'Texas Department of Transportation (courtesy)',
},
{
key: 'caltrans-cctv',
html:
'CCTV cameras & frames (California): Caltrans — ' +
'cwwp2.dot.ca.gov',
},
{
key: 'tfl-cctv',
html:
'CCTV cameras & frames (London): ' +
'Powered by TfL Open Data. ' +
'Contains OS data © Crown copyright and database rights.',
},
{
key: 'ontario-511-cctv',
html:
'CCTV cameras & frames (Ontario): ' +
'Ontario 511 ' +
'(Open Government Licence - Ontario)',
},
{
key: 'fintraffic-cctv',
html:
'CCTV cameras & frames (Finland): Fintraffic / ' +
'digitraffic.fi, ' +
'license CC BY 4.0',
},
{
key: 'gbfs',
html: 'Bikeshare availability: GBFS operator feeds (e.g. Austin BCycle)',
},
{
key: 'radio-browser',
html:
'Internet-radio station directory: ' +
'Radio Browser ' +
'(public domain; audio delivered directly by each broadcaster)',
},
{
key: 'reearth-terrain',
html:
'Terrain (keyless globe stacks): ' +
'Re:Earth Terrain / ' +
'Mapterhorn (CC BY 4.0) / EGM2008 (NGA)',
},
// ── Bundled snapshots ───────────────────────────────────────────
{
key: 'datacenters',
html:
'Datacenters: ' +
'© OpenStreetMap contributors ' +
'(ODbL 1.0)',
},
{
key: 'dams',
html:
'Dams: ' +
'© OpenStreetMap contributors ' +
'(ODbL 1.0) + Open Infrastructure Map',
},
{
key: 'firms',
html:
'Active fires: NASA FIRMS — we acknowledge the use of data and/or imagery ' +
'from NASA’s Fire Information for Resource Management System ' +
'(earthdata.nasa.gov/firms), ' +
'part of NASA’s Earth Observing System Data and Information System (EOSDIS)',
},
{
key: 'drivebc-cctv',
html:
'CCTV cameras & frames (British Columbia): ' +
'DriveBC. ' +
'Contains information licensed under the ' +
'Open Government Licence – British Columbia. ' +
'Some cameras are supplied by partners (TransLink, the City of Vancouver, the City of Surrey, Parks Canada and others); each names its provider in the CCTV panel.',
},
{
key: 'tallinn-cctv',
html:
'CCTV cameras & frames (Tallinn): City of Tallinn — ' +
'ristmikud.tallinn.ee (courtesy)',
},
{
key: 'tarktee-cctv',
html:
'CCTV cameras & frames (Estonia road weather): Transpordiamet / Tarktee — ' +
'tarktee.transpordiamet.ee (courtesy)',
},
{
key: 'warendorf-cctv',
html:
'Webcam (Warendorf): Stadt Warendorf (courtesy); ' +
'camera poses derived from OpenStreetMap geometry, © OpenStreetMap contributors (ODbL)',
},
{
key: 'nsw-cctv',
html:
'CCTV cameras & frames (New South Wales): ' +
'Live Traffic NSW — Transport for NSW ' +
'(CC BY 4.0)',
},
{
key: 'telegeography',
html:
'Submarine cables: © TeleGeography — ' +
'submarinecablemap.com ' +
'(CC BY-NC-SA 3.0 — NonCommercial)',
},
];
/**
* Conditional credits — registered via `registerDynamicCredit` only when the
* corresponding capability actually activates (deliberately NOT part of
* DATA_CREDITS, which is always-on). TomTom terms require attribution when
* their flow data is displayed; keyless installs never show it, so the
* credit only appears once live traffic-flow mode activates.
* @type {{ key: string, html: string }}
*/
export const TOMTOM_CREDIT = {
key: 'tomtom',
html:
'Traffic flow data © ' +
'TomTom',
};
/** Registered when the first Natural Earth region outline resolves (public
* domain — no attribution required; credited as a courtesy). */
export const NATURAL_EARTH_CREDIT = {
key: 'natural-earth',
html:
'Physical region boundaries from ' +
'Natural Earth (public domain)',
};
/** @type {Set} Keys of dynamic credits already registered this session. */
const _dynamicCreditKeys = new Set();
/**
* Register a conditional credit at the moment its data source activates.
* Idempotent per `credit.key`; lands in the same "Data attribution" popover
* as the static credits (showOnScreen=false).
* @param {Cesium.Viewer} viewer — the initialized Cesium viewer
* @param {{ key: string, html: string }} credit — e.g. `TOMTOM_CREDIT`
* @returns {boolean} True when the credit is (now) registered.
*/
export function registerDynamicCredit(viewer, credit) {
const creditDisplay = viewer?.creditDisplay;
if (!creditDisplay || typeof creditDisplay.addStaticCredit !== 'function') {
return false;
}
if (!credit?.key || !credit?.html) return false;
if (_dynamicCreditKeys.has(credit.key)) return true;
creditDisplay.addStaticCredit(new Cesium.Credit(credit.html, false));
_dynamicCreditKeys.add(credit.key);
return true;
}
/**
* Register every per-layer data credit into the viewer's credit display.
* Idempotent: safe to call once at init. Credits are static and always
* present in the "Data attribution" popover.
* @param {Cesium.Viewer} viewer — the initialized Cesium viewer
*/
export function registerDataCredits(viewer) {
const creditDisplay = viewer?.creditDisplay;
if (!creditDisplay || typeof creditDisplay.addStaticCredit !== 'function') {
return;
}
for (const { html } of DATA_CREDITS) {
// showOnScreen=false → lives in the expandable "Data attribution" popover,
// not the on-globe credit line.
creditDisplay.addStaticCredit(new Cesium.Credit(html, false));
}
}