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]>
This commit is contained in:
Said TurkseverandClaude Fable 5.1 committed 2026-09-23 19:05:59 +01:00
commit 817716f0c1
234 files changed
+45441 -1430

No files matched your search

+39 -5
View File
@@ -8,6 +8,8 @@ import { projectRoot } from './project-root.mjs';
import { selectMapStartupRoute } from '../src/mapStartup.js';
const ROOT = projectRoot(import.meta.url);
const OPENSKY_AUTH_MODE_DEFAULT = 'oauth';
const OPENSKY_AUTH_MODES = new Set(['basic', 'oauth', 'auto', 'anon']);
export const CREDENTIALS = Object.freeze([
{ name: 'GOOGLE_MAPS_API_KEY', label: 'Google Maps', keychain: [['google-maps-api', 'api-key'], ['google-maps-api', 'default'], ['google-maps-api', 'key']] },
@@ -103,6 +105,21 @@ export function readDoctorDotenvValue(
return String(values[key] ?? '');
}
/** Resolve the OpenSky auth mode using the same environment and dotenv precedence as the launcher. */
export function resolveOpenSkyAuthMode({
authoritativeEnvironment = false,
environment = process.env,
rootDir = ROOT,
} = {}) {
const environmentDefinesMode = Object.prototype.hasOwnProperty.call(environment, 'OPENSKY_AUTH_MODE');
const environmentMode = String(environment.OPENSKY_AUTH_MODE || '').trim();
const dotenvMode = authoritativeEnvironment && environmentDefinesMode
? ''
: readDoctorDotenvValue('OPENSKY_AUTH_MODE', rootDir);
const mode = (environmentMode || dotenvMode).trim().toLowerCase();
return OPENSKY_AUTH_MODES.has(mode) ? mode : OPENSKY_AUTH_MODE_DEFAULT;
}
function hasKeychainItem(service, account) {
if (process.platform !== 'darwin') return false;
const result = spawnSync('security', [
@@ -130,8 +147,25 @@ export function resolveCredential(spec, {
return { configured: false, source: null };
}
export function buildCapabilitySummary(credentials) {
export function buildCapabilitySummary(
credentials,
{ openSkyAuthMode = OPENSKY_AUTH_MODE_DEFAULT } = {},
) {
const configured = (name) => credentials[name]?.configured === true;
const hasOAuthCredentials = configured('OPENSKY_CLIENT_ID') && configured('OPENSKY_CLIENT_SECRET');
const requestedOpenSkyMode = String(openSkyAuthMode || '').trim().toLowerCase();
const openSkyMode = OPENSKY_AUTH_MODES.has(requestedOpenSkyMode)
? requestedOpenSkyMode
: OPENSKY_AUTH_MODE_DEFAULT;
const flights = openSkyMode === 'anon'
? 'OpenSky keyless anonymous access (rate-limited)'
: openSkyMode === 'basic'
? 'OpenSky Basic mode selected (credential presence and validity not verified)'
: openSkyMode === 'auto'
? 'OpenSky auto mode selected (runtime credential choice and validity not verified)'
: hasOAuthCredentials
? 'OpenSky OAuth credentials present (runtime mode and validity not verified)'
: 'OpenSky keyless anonymous access (rate-limited)';
const route = selectMapStartupRoute({
googleApiKey: configured('GOOGLE_MAPS_API_KEY') ? 'configured' : '',
cesiumToken: configured('CESIUM_ION_TOKEN') ? 'configured' : '',
@@ -142,9 +176,7 @@ export function buildCapabilitySummary(credentials) {
: route === 'google-ion'
? 'Google Photorealistic 3D Tiles through Cesium ion; Bing and world-terrain stacks available'
: 'Esri World Imagery (keyless satellite basemap) with keyless terrain',
flights: configured('OPENSKY_CLIENT_ID') && configured('OPENSKY_CLIENT_SECRET')
? 'OpenSky OAuth credentials present (runtime mode and validity not verified)'
: 'OpenSky OAuth credentials not configured',
flights,
voice: configured('OPENAI_API_KEY') ? 'available' : 'off until an OpenAI key is added',
vessels: configured('AISSTREAM_API_KEY') ? 'live AISStream feed' : 'off until an AISStream key is added',
fires: configured('FIRMS_MAP_KEY') ? 'live NASA FIRMS feed' : 'off until a FIRMS key is added',
@@ -175,7 +207,9 @@ export function inspectSetup({ includeKeychain = true, authoritativeEnvironment
: { available: false, version: null },
dependenciesInstalled,
credentials,
capabilities: buildCapabilitySummary(credentials),
capabilities: buildCapabilitySummary(credentials, {
openSkyAuthMode: resolveOpenSkyAuthMode({ authoritativeEnvironment, rootDir }),
}),
};
}