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)); } }