mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-13 06:42:23 +00:00
Merge upstream main into pr/street-level-show-action
gevActions.test.mjs: keep the PR's street-level tests and main's analyst display tests.
This commit is contained in:
commit
5370b8a268
258 files changed
+20257
-734
No files matched your search
@@ -7,13 +7,16 @@
|
||||
* Natural Earth 10m admin-1 states and provinces (public domain).
|
||||
* src/data/local_data/us_census_counties/counties.json
|
||||
* US Census Bureau cartographic boundary counties (public domain).
|
||||
* src/data/local_data/natural_earth/populated_places.json
|
||||
* Natural Earth 10m populated places as points, for the orbital view's
|
||||
* "near <city>" (`src/data/placeBelow.js`; public domain).
|
||||
*
|
||||
* Both sources are pinned by URL and SHA-256, so a rerun reproduces the packs
|
||||
* byte for byte. Downloads are cached outside the repository (default: the
|
||||
* system temp directory) and are never committed.
|
||||
*
|
||||
* Usage:
|
||||
* node scripts/build-admin-packs.mjs [--cache <dir>] [--only countries|admin1|counties]
|
||||
* node scripts/build-admin-packs.mjs [--cache <dir>] [--only countries|admin1|counties|places]
|
||||
*
|
||||
* The provenance READMEs beside each pack record these parameters.
|
||||
*/
|
||||
@@ -101,6 +104,9 @@ export const PARAMS = Object.freeze({
|
||||
elsewhereMinPopulation: 50_000,
|
||||
cityStateMaxKm2: 1_000,
|
||||
},
|
||||
// Every populated place, kept as a point: name, position and the two
|
||||
// prominence ranks the orbital view picks "near <city>" by.
|
||||
places: { decimals: 3 },
|
||||
});
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
@@ -688,6 +694,47 @@ async function buildAdmin1() {
|
||||
};
|
||||
}
|
||||
|
||||
async function buildPlaces() {
|
||||
const params = PARAMS.places;
|
||||
const source = await fetchPinned('places');
|
||||
const factor = 10 ** params.decimals;
|
||||
const round = (value) => Math.round(value * factor) / factor;
|
||||
const places = JSON.parse(source.bytes.toString('utf8'))
|
||||
.features.map((f) => f.properties)
|
||||
.filter(
|
||||
(p) =>
|
||||
p.name &&
|
||||
Number.isFinite(p.latitude) &&
|
||||
Number.isFinite(p.longitude) &&
|
||||
Number.isFinite(p.scalerank),
|
||||
)
|
||||
.map((p) => [
|
||||
p.name,
|
||||
round(p.latitude),
|
||||
round(p.longitude),
|
||||
p.scalerank,
|
||||
Number.isFinite(p.rank_max) ? p.rank_max : 0,
|
||||
])
|
||||
.sort((a, b) => a[3] - b[3] || b[4] - a[4] || a[0].localeCompare(b[0]));
|
||||
return {
|
||||
meta: {
|
||||
title: 'Natural Earth populated places',
|
||||
source: 'ne_10m_populated_places_simple',
|
||||
url: SOURCES.places.url,
|
||||
sha256: source.digest,
|
||||
commit: NE_COMMIT,
|
||||
license:
|
||||
'Public domain (https://www.naturalearthdata.com/about/terms-of-use/)',
|
||||
schema:
|
||||
'places[]: [name, latitude, longitude, scalerank (0 most prominent .. 10), rank_max (population class, 0..14; higher is larger)]',
|
||||
decimals: params.decimals,
|
||||
curation: params,
|
||||
script: 'scripts/build-admin-packs.mjs',
|
||||
},
|
||||
places,
|
||||
};
|
||||
}
|
||||
|
||||
async function buildCounties() {
|
||||
const params = PARAMS.counties;
|
||||
const source = await fetchPinned('counties');
|
||||
@@ -768,4 +815,13 @@ if (isMain) {
|
||||
'src/data/local_data/us_census_counties/counties.json',
|
||||
await buildCounties(),
|
||||
);
|
||||
if (!only || only === 'places') {
|
||||
const relative = 'src/data/local_data/natural_earth/populated_places.json';
|
||||
const pack = await buildPlaces();
|
||||
const text = JSON.stringify(pack) + '\n';
|
||||
await writeFile(path.join(ROOT, relative), text);
|
||||
console.log(
|
||||
`${relative}: ${pack.places.length} places, ${Buffer.byteLength(text)} bytes`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Build the owner flag sheet the orbital Cockpit marks a satellite's owner
|
||||
* country with (`src/ui/ownerFlag.js`): every flag in OWNER_COUNTRY_CODES
|
||||
* (`src/layers/satellites/classes.js`), drawn from the flag-icons 4:3 SVGs
|
||||
* at twice the readout's 20 × 15 px, in one PNG the app loads at startup.
|
||||
*
|
||||
* src/data/local_data/owner_flags/owner_flags.png the sheet
|
||||
* src/ui/ownerFlagSheet.js its layout (generated)
|
||||
*
|
||||
* Flag i (in the sorted code list) sits at column i % COLUMNS, row
|
||||
* floor(i / COLUMNS), each cell followed by a GUTTER of transparent pixels. A rerun with the same flag-icons and sharp versions
|
||||
* reproduces both files.
|
||||
*
|
||||
* Usage: node scripts/build-owner-flags.mjs
|
||||
*/
|
||||
|
||||
import { readFile, writeFile } from 'node:fs/promises';
|
||||
import { createRequire } from 'node:module';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import * as prettier from 'prettier';
|
||||
import sharp from 'sharp';
|
||||
import { OWNER_COUNTRY_CODES } from '../src/layers/satellites/classes.js';
|
||||
|
||||
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
||||
const require = createRequire(import.meta.url);
|
||||
const FLAGS_DIR = path.join(
|
||||
path.dirname(require.resolve('flag-icons/package.json')),
|
||||
'flags/4x3',
|
||||
);
|
||||
const FLAG_ICONS_VERSION = require('flag-icons/package.json').version;
|
||||
|
||||
/** One flag's cell, CSS pixels × 2. */
|
||||
export const CELL = Object.freeze({ width: 40, height: 30 });
|
||||
/**
|
||||
* Transparent sheet pixels after each flag, so a browser smoothing a scaled
|
||||
* flag (a 125% display) never reaches into its neighbour.
|
||||
*/
|
||||
export const GUTTER = 2;
|
||||
export const COLUMNS = 16;
|
||||
|
||||
const SHEET = path.join(
|
||||
ROOT,
|
||||
'src/data/local_data/owner_flags/owner_flags.png',
|
||||
);
|
||||
const LAYOUT = path.join(ROOT, 'src/ui/ownerFlagSheet.js');
|
||||
|
||||
async function flagCell(code) {
|
||||
const svg = await readFile(path.join(FLAGS_DIR, `${code.toLowerCase()}.svg`));
|
||||
return sharp(svg, { density: 300 })
|
||||
.resize(CELL.width, CELL.height, { fit: 'fill' })
|
||||
.png()
|
||||
.toBuffer();
|
||||
}
|
||||
|
||||
const codes = [...OWNER_COUNTRY_CODES];
|
||||
const rows = Math.ceil(codes.length / COLUMNS);
|
||||
const pitchX = CELL.width + GUTTER;
|
||||
const pitchY = CELL.height + GUTTER;
|
||||
const cells = await Promise.all(codes.map(flagCell));
|
||||
const sheet = await sharp({
|
||||
create: {
|
||||
width: COLUMNS * pitchX,
|
||||
height: rows * pitchY,
|
||||
channels: 4,
|
||||
background: { r: 0, g: 0, b: 0, alpha: 0 },
|
||||
},
|
||||
})
|
||||
.composite(
|
||||
cells.map((input, i) => ({
|
||||
input,
|
||||
left: (i % COLUMNS) * pitchX,
|
||||
top: Math.floor(i / COLUMNS) * pitchY,
|
||||
})),
|
||||
)
|
||||
.png({ compressionLevel: 9, palette: true, quality: 100, effort: 10 })
|
||||
.toBuffer();
|
||||
await writeFile(SHEET, sheet);
|
||||
|
||||
const layout = `// Generated by scripts/build-owner-flags.mjs from flag-icons ${FLAG_ICONS_VERSION}; do not edit.
|
||||
/** The owner flag sheet's layout: flag i at column i % columns, row i / columns. */
|
||||
export const OWNER_FLAG_SHEET = Object.freeze({
|
||||
cellWidthPx: ${CELL.width},
|
||||
cellHeightPx: ${CELL.height},
|
||||
gutterPx: ${GUTTER},
|
||||
columns: ${COLUMNS},
|
||||
rows: ${rows},
|
||||
codes: Object.freeze(${JSON.stringify(codes)}),
|
||||
});
|
||||
`;
|
||||
await writeFile(
|
||||
LAYOUT,
|
||||
await prettier.format(layout, {
|
||||
...(await prettier.resolveConfig(LAYOUT)),
|
||||
filepath: LAYOUT,
|
||||
}),
|
||||
);
|
||||
console.log(
|
||||
`Wrote ${codes.length} flags (${COLUMNS} × ${rows}), ${(sheet.length / 1024).toFixed(1)} KB.`,
|
||||
);
|
||||
@@ -2,9 +2,9 @@
|
||||
'''Maintainer-only UCS Satellite Database pack build (openpyxl).
|
||||
|
||||
Reads the UCS Excel release and writes the compact pack the satellites layer
|
||||
loads: one row per satellite, keyed by NORAD number, with a string-table index
|
||||
for its purpose, the one column the layer's classes read. Starlink rows are
|
||||
left out: the layer files every STARLINK object under its own class by name.
|
||||
loads: one row per satellite, keyed by NORAD number, with string-table indexes
|
||||
for the repeated text columns. Starlink rows are left out: the layer files
|
||||
every STARLINK object under its own class and operator without them.
|
||||
|
||||
Usage: python scripts/build-ucs-satellites.py "<path>/UCS-Satellite-Database 5-1-2023.xlsx"
|
||||
'''
|
||||
@@ -26,6 +26,8 @@ URL = 'https://www.ucsusa.org/satellite_database'
|
||||
|
||||
# Output column -> spreadsheet header.
|
||||
COLUMNS = {
|
||||
'operator': 'Operator/Owner',
|
||||
'operatorCountry': 'Country of Operator/Owner',
|
||||
'purpose': 'Purpose',
|
||||
}
|
||||
STARLINK = re.compile(r'\bstarlink\b', re.I)
|
||||
|
||||
@@ -112,6 +112,8 @@
|
||||
"src/data/terrainHeightsProxy.test.mjs",
|
||||
"src/data/tomtomTiles.js",
|
||||
"src/data/tomtomTiles.test.mjs",
|
||||
"src/data/tileBudget.js",
|
||||
"src/data/tileBudget.test.mjs",
|
||||
"src/data/firmsCsv.js",
|
||||
"src/data/firmsCsv.test.mjs",
|
||||
"src/tooling/environmentProviders.test.mjs",
|
||||
@@ -330,6 +332,10 @@
|
||||
"src/ui/styles/cockpit.css",
|
||||
"src/ui/styles/cockpitBridge.css",
|
||||
"src/ui/styles/cockpitRadar.css",
|
||||
"src/ui/styles/cockpitOrbital.css",
|
||||
"src/layers/satellites/sensors.js",
|
||||
"src/layers/satellites/sensors.test.mjs",
|
||||
"src/data/imagingSensors.js",
|
||||
"src/ui/styles/command-dock-compact.css",
|
||||
"src/app/stateChannel.js",
|
||||
"src/app/stateChannel.test.mjs",
|
||||
@@ -1071,6 +1077,7 @@
|
||||
"src/layers/traffic/roadModes.test.mjs",
|
||||
"scripts/qa-traffic-motion.mjs",
|
||||
"src/layers/traffic/motion.test.mjs",
|
||||
"src/layers/traffic/lineRebuild.test.mjs",
|
||||
"scripts/qa-journey-recorder.mjs",
|
||||
"scripts/qa-alpr-journey.mjs",
|
||||
"scripts/qa-context-arrivals.mjs",
|
||||
@@ -1122,6 +1129,7 @@
|
||||
"src/sky/starrySky.test.mjs",
|
||||
"src/tooling/skyAssets.test.mjs",
|
||||
"src/tooling/skyAssets.paintOut.test.mjs",
|
||||
"src/tooling/responseCompression.test.mjs",
|
||||
"scripts/qa-anime-sky.mjs",
|
||||
"scripts/qa-sky-model-lighting.mjs",
|
||||
"server/providers/overpass/requestAdmission.test.mjs",
|
||||
@@ -1359,5 +1367,10 @@
|
||||
"src/layers/wildlifeSightings/cache.integration.test.mjs",
|
||||
"src/layers/wildlifeSightings/density.test.mjs",
|
||||
"src/layers/wildlifeSightings/selection.test.mjs",
|
||||
"server/providers/inaturalist/proxy.fixture.mjs"
|
||||
"server/providers/inaturalist/proxy.fixture.mjs",
|
||||
"scripts/build-owner-flags.mjs",
|
||||
"src/ui/ownerFlagSheet.js",
|
||||
"src/data/placePacksLoading.test.mjs",
|
||||
"src/ui/placePacksLoading.js",
|
||||
"src/ui/placePacksLoading.test.mjs"
|
||||
]
|
||||
@@ -40,6 +40,9 @@
|
||||
"src/ui/views/panels/CockpitContext.vue",
|
||||
"src/ui/views/panels/CockpitRoute.vue",
|
||||
"src/ui/views/panels/CockpitRadar.vue",
|
||||
"src/ui/views/panels/CockpitOrbital.vue",
|
||||
"src/ui/ownerFlag.js",
|
||||
"src/ui/ownerFlagSheet.js",
|
||||
"src/ui/cockpitPresentation.js",
|
||||
"src/data/headingDegrees.js",
|
||||
"src/data/distanceFormat.js",
|
||||
@@ -202,6 +205,7 @@
|
||||
"modules": [
|
||||
"src/sources/adsbFields.js",
|
||||
"server/providers/live.js",
|
||||
"server/providers/common/compress.js",
|
||||
"server/providers/common/http.js",
|
||||
"server/providers/common/query.js",
|
||||
"server/providers/aircraft/opensky.js",
|
||||
@@ -238,6 +242,11 @@
|
||||
"modules": ["src/data/adsbLolFallback.js", "src/sources/adsbFields.js"],
|
||||
"external": []
|
||||
},
|
||||
"planespotters-source": {
|
||||
"exports": ["./sources/planespotters"],
|
||||
"modules": ["src/data/planespottersPhoto.js"],
|
||||
"external": []
|
||||
},
|
||||
"place-providers": {
|
||||
"runtime": "node",
|
||||
"exports": ["./server/providers/places"],
|
||||
@@ -315,6 +324,7 @@
|
||||
"src/sources/httpBody.js",
|
||||
"src/i18n/marker.js",
|
||||
"src/data/tomtomTiles.js",
|
||||
"src/data/tileBudget.js",
|
||||
"server/providers/common/same-site.js",
|
||||
"src/localRequestGate.mjs"
|
||||
],
|
||||
@@ -322,7 +332,7 @@
|
||||
},
|
||||
"traffic-source": {
|
||||
"exports": ["./sources/traffic"],
|
||||
"modules": ["src/data/tomtomTiles.js"],
|
||||
"modules": ["src/data/tomtomTiles.js", "src/data/tileBudget.js"],
|
||||
"external": []
|
||||
},
|
||||
"firms-csv": {
|
||||
@@ -900,6 +910,19 @@
|
||||
"src/ui/cockpitInstrumentState.js",
|
||||
"src/ui/cockpitRollingValue.js",
|
||||
"src/ui/cockpitCamera.js",
|
||||
"src/ui/cockpitOrbitalView.js",
|
||||
"src/ui/cockpitOrbitalFocus.js",
|
||||
"src/ui/cockpitOrbitalSignals.js",
|
||||
"src/ui/cockpitOrbitalSatellites.js",
|
||||
"src/cockpitOrbitalSatellites.js",
|
||||
"src/layers/installations/classLabel.js",
|
||||
"src/data/installationNames.js",
|
||||
"src/i18n/marker.js",
|
||||
"src/data/placeBelow.js",
|
||||
"src/layers/satellites/sensors.js",
|
||||
"src/data/adminBoundaries.js",
|
||||
"src/data/bundledJson.js",
|
||||
"src/data/retryableLoad.js",
|
||||
"src/ui/cockpitContext.js",
|
||||
"src/ui/cockpitController.js",
|
||||
"src/ui/cockpitDisplayPortal.js",
|
||||
@@ -917,6 +940,8 @@
|
||||
"src/cockpitSubjects.js",
|
||||
"src/cockpitRadar.js",
|
||||
"src/cockpitLook.js",
|
||||
"src/cockpitOrbital.js",
|
||||
"src/cockpitOrbitalFocus.js",
|
||||
"src/geoDistance.js",
|
||||
"src/data/motionModel.js",
|
||||
"src/ui/panelRailGeometry.js",
|
||||
@@ -990,6 +1015,8 @@
|
||||
"src/cockpitSubjects.js",
|
||||
"src/cockpitRadar.js",
|
||||
"src/cockpitLook.js",
|
||||
"src/cockpitOrbital.js",
|
||||
"src/cockpitOrbitalFocus.js",
|
||||
"src/geoDistance.js",
|
||||
"src/data/motionModel.js",
|
||||
"src/contactsDetectionPolicy.js",
|
||||
@@ -1042,6 +1069,20 @@
|
||||
"src/ui/cockpitInstrumentState.js",
|
||||
"src/ui/cockpitRollingValue.js",
|
||||
"src/ui/cockpitCamera.js",
|
||||
"src/ui/cockpitOrbitalView.js",
|
||||
"src/ui/cockpitOrbitalFocus.js",
|
||||
"src/ui/cockpitOrbitalSignals.js",
|
||||
"src/ui/cockpitOrbitalSatellites.js",
|
||||
"src/cockpitOrbitalSatellites.js",
|
||||
"src/layers/installations/classLabel.js",
|
||||
"src/data/placeBelow.js",
|
||||
"src/ui/placePacksLoading.js",
|
||||
"src/ui/ownerFlag.js",
|
||||
"src/ui/ownerFlagSheet.js",
|
||||
"src/layers/satellites/sensors.js",
|
||||
"src/data/adminBoundaries.js",
|
||||
"src/data/bundledJson.js",
|
||||
"src/data/retryableLoad.js",
|
||||
"src/ui/cockpitContext.js",
|
||||
"src/ui/cockpitController.js",
|
||||
"src/ui/cockpitDisplayPortal.js",
|
||||
@@ -1359,7 +1400,8 @@
|
||||
"src/sources/live/contract.js",
|
||||
"src/sources/live/index.js",
|
||||
"src/sources/live/standalone.js",
|
||||
"src/sources/live/vessels.js"
|
||||
"src/sources/live/vessels.js",
|
||||
"src/data/planespottersPhoto.js"
|
||||
],
|
||||
"external": []
|
||||
},
|
||||
@@ -1426,7 +1468,8 @@
|
||||
"src/i18n/locales/zh-Hant.json",
|
||||
"src/ui/unitLabels.js",
|
||||
"src/time/worldClock.js",
|
||||
"src/time/julian.js"
|
||||
"src/time/julian.js",
|
||||
"src/data/planespottersPhoto.js"
|
||||
],
|
||||
"external": ["cesium"]
|
||||
},
|
||||
@@ -1651,6 +1694,7 @@
|
||||
"src/data/satellitePass.js",
|
||||
"src/sources/tle.js",
|
||||
"src/layers/satellites/catalog.js",
|
||||
"src/layers/satellites/cockpitSubject.js",
|
||||
"src/layers/satellites/controls.js",
|
||||
"src/layers/satellites/index.js",
|
||||
"src/layers/satellites/ingestion.js",
|
||||
@@ -1681,7 +1725,9 @@
|
||||
"src/i18n/locales/zh-Hant.json",
|
||||
"src/ui/unitLabels.js",
|
||||
"src/layers/satellites/classes.js",
|
||||
"src/layers/satellites/sensors.js",
|
||||
"src/data/ucsSatellites.js",
|
||||
"src/data/imagingSensors.js",
|
||||
"src/data/bundledJson.js",
|
||||
"src/data/retryableLoad.js",
|
||||
"src/time/worldClock.js"
|
||||
@@ -1749,6 +1795,7 @@
|
||||
"src/layers/installations/viewport.js",
|
||||
"src/data/inputOwnership.js",
|
||||
"src/data/tomtomTiles.js",
|
||||
"src/data/tileBudget.js",
|
||||
"src/sources/capability.js",
|
||||
"src/sources/httpBody.js",
|
||||
"src/i18n/marker.js",
|
||||
@@ -1837,6 +1884,7 @@
|
||||
"src/data/cameraSensitivity.js",
|
||||
"src/data/flowMatch.js",
|
||||
"src/data/tomtomTiles.js",
|
||||
"src/data/tileBudget.js",
|
||||
"src/data/trafficBounds.js",
|
||||
"src/geoDistance.js",
|
||||
"src/data/trafficFlowStyle.js",
|
||||
@@ -2067,8 +2115,10 @@
|
||||
"src/layers/alpr/overlay.js",
|
||||
"src/layers/alpr/source.js",
|
||||
"src/data/inputOwnership.js",
|
||||
"src/data/displayText.js",
|
||||
"src/layers/alpr/records.js",
|
||||
"src/data/tomtomTiles.js",
|
||||
"src/data/tileBudget.js",
|
||||
"src/layers/alpr/tileRecords.js",
|
||||
"src/sources/capability.js",
|
||||
"src/sources/httpBody.js",
|
||||
@@ -2428,6 +2478,8 @@
|
||||
"src/cockpitSubjects.js",
|
||||
"src/cockpitRadar.js",
|
||||
"src/cockpitLook.js",
|
||||
"src/cockpitOrbital.js",
|
||||
"src/cockpitOrbitalFocus.js",
|
||||
"src/contactsDetectionPolicy.js",
|
||||
"src/contextModePolicy.js",
|
||||
"src/creditKeyboard.js",
|
||||
@@ -2538,6 +2590,7 @@
|
||||
"src/data/telegeographySubmarineCables.js",
|
||||
"src/data/terrainHeights.js",
|
||||
"src/data/tomtomTiles.js",
|
||||
"src/data/tileBudget.js",
|
||||
"src/data/tr3bRegistry.js",
|
||||
"src/data/trackedCamera.js",
|
||||
"src/data/trackedModelRegime.js",
|
||||
@@ -2722,6 +2775,7 @@
|
||||
"src/layers/radio/tuningNoise.js",
|
||||
"src/layers/radio/volume.js",
|
||||
"src/layers/satellites/catalog.js",
|
||||
"src/layers/satellites/cockpitSubject.js",
|
||||
"src/layers/satellites/controls.js",
|
||||
"src/layers/satellites/index.js",
|
||||
"src/layers/satellites/ingestion.js",
|
||||
@@ -2871,6 +2925,15 @@
|
||||
"src/ui/cockpitInstrumentState.js",
|
||||
"src/ui/cockpitRollingValue.js",
|
||||
"src/ui/cockpitCamera.js",
|
||||
"src/ui/cockpitOrbitalView.js",
|
||||
"src/ui/cockpitOrbitalFocus.js",
|
||||
"src/ui/cockpitOrbitalSignals.js",
|
||||
"src/ui/cockpitOrbitalSatellites.js",
|
||||
"src/cockpitOrbitalSatellites.js",
|
||||
"src/data/placeBelow.js",
|
||||
"src/ui/placePacksLoading.js",
|
||||
"src/ui/ownerFlag.js",
|
||||
"src/ui/ownerFlagSheet.js",
|
||||
"src/ui/cockpitContext.js",
|
||||
"src/ui/cockpitController.js",
|
||||
"src/ui/cockpitDisplayPortal.js",
|
||||
@@ -2961,6 +3024,7 @@
|
||||
"src/voice/chatPreferences.js",
|
||||
"src/voice/panelLayout.js",
|
||||
"src/voice/voiceMiniPreview.js",
|
||||
"src/data/displayText.js",
|
||||
"src/voice/gevActions.js",
|
||||
"src/agent/worldPacket.js",
|
||||
"src/voice/speech.js",
|
||||
@@ -3381,7 +3445,10 @@
|
||||
"src/layers/wildlifeSightings/photoText.js",
|
||||
"src/layers/wildlifeSightings/performance.js",
|
||||
"src/layers/satellites/classes.js",
|
||||
"src/data/ucsSatellites.js"
|
||||
"src/layers/satellites/sensors.js",
|
||||
"src/data/ucsSatellites.js",
|
||||
"src/data/imagingSensors.js",
|
||||
"src/data/planespottersPhoto.js"
|
||||
],
|
||||
"external": [
|
||||
"hls.js",
|
||||
@@ -3522,6 +3589,7 @@
|
||||
"src/data/scenePick.js",
|
||||
"src/data/spriteOrder.js",
|
||||
"src/data/tomtomTiles.js",
|
||||
"src/data/tileBudget.js",
|
||||
"src/data/tr3bRegistry.js",
|
||||
"src/data/trackedCamera.js",
|
||||
"src/data/trackedModelRegime.js",
|
||||
@@ -3695,6 +3763,7 @@
|
||||
"src/layers/radio/tuningNoise.js",
|
||||
"src/layers/radio/volume.js",
|
||||
"src/layers/satellites/catalog.js",
|
||||
"src/layers/satellites/cockpitSubject.js",
|
||||
"src/layers/satellites/controls.js",
|
||||
"src/layers/satellites/index.js",
|
||||
"src/layers/satellites/ingestion.js",
|
||||
@@ -3804,6 +3873,7 @@
|
||||
"src/search/coordinateParser.js",
|
||||
"src/search/presetGeocoder.js",
|
||||
"src/app/localGeojsonServices.js",
|
||||
"src/data/displayText.js",
|
||||
"src/layers/alpr/records.js",
|
||||
"src/layers/earthquakes/records.js",
|
||||
"src/app/layers/perimeters.js",
|
||||
@@ -4037,7 +4107,10 @@
|
||||
"src/layers/wildlifeSightings/photoText.js",
|
||||
"src/layers/wildlifeSightings/performance.js",
|
||||
"src/layers/satellites/classes.js",
|
||||
"src/data/ucsSatellites.js"
|
||||
"src/layers/satellites/sensors.js",
|
||||
"src/data/ucsSatellites.js",
|
||||
"src/data/imagingSensors.js",
|
||||
"src/data/planespottersPhoto.js"
|
||||
],
|
||||
"external": [
|
||||
"hls.js",
|
||||
@@ -4116,6 +4189,7 @@
|
||||
"src/sources/phaseTiming.js",
|
||||
"src/sources/militaryTileGeometry.js",
|
||||
"src/data/tomtomTiles.js",
|
||||
"src/data/tileBudget.js",
|
||||
"src/data/installationNames.js",
|
||||
"src/annotations/outlineRungs.js",
|
||||
"src/sources/openFreeMapOutlines.js",
|
||||
@@ -4208,6 +4282,9 @@
|
||||
"src/cockpitSubjects.js",
|
||||
"src/cockpitRadar.js",
|
||||
"src/cockpitLook.js",
|
||||
"src/cockpitOrbital.js",
|
||||
"src/cockpitOrbitalFocus.js",
|
||||
"src/cockpitOrbitalSatellites.js",
|
||||
"src/geoDistance.js",
|
||||
"src/data/motionModel.js",
|
||||
"src/contactsDetectionPolicy.js",
|
||||
@@ -4473,9 +4550,11 @@
|
||||
"exports": ["./layers/alpr/source"],
|
||||
"modules": [
|
||||
"src/layers/alpr/policy.js",
|
||||
"src/data/displayText.js",
|
||||
"src/layers/alpr/records.js",
|
||||
"src/layers/alpr/source.js",
|
||||
"src/data/tomtomTiles.js",
|
||||
"src/data/tileBudget.js",
|
||||
"src/layers/alpr/tileRecords.js",
|
||||
"src/sources/httpBody.js",
|
||||
"src/i18n/marker.js",
|
||||
@@ -4514,6 +4593,7 @@
|
||||
"src/data/militaryInstallationData.js",
|
||||
"src/data/installationNames.js",
|
||||
"src/data/tomtomTiles.js",
|
||||
"src/data/tileBudget.js",
|
||||
"src/sources/capability.js",
|
||||
"src/sources/httpBody.js",
|
||||
"src/i18n/marker.js",
|
||||
@@ -4544,7 +4624,9 @@
|
||||
"modules": [
|
||||
"src/layers/satellites/source.js",
|
||||
"src/layers/satellites/classes.js",
|
||||
"src/layers/satellites/sensors.js",
|
||||
"src/data/ucsSatellites.js",
|
||||
"src/data/imagingSensors.js",
|
||||
"src/data/bundledJson.js",
|
||||
"src/data/retryableLoad.js"
|
||||
],
|
||||
@@ -4554,6 +4636,7 @@
|
||||
"exports": ["./layers/traffic/source"],
|
||||
"modules": [
|
||||
"src/data/tomtomTiles.js",
|
||||
"src/data/tileBudget.js",
|
||||
"src/layers/traffic/flowDecode.js",
|
||||
"src/layers/traffic/flowSource.js",
|
||||
"src/layers/traffic/footprint.js",
|
||||
@@ -5128,6 +5211,7 @@
|
||||
"src/sources/vectorTiles.js",
|
||||
"src/sources/phaseTiming.js",
|
||||
"src/data/tomtomTiles.js",
|
||||
"src/data/tileBudget.js",
|
||||
"src/sources/capability.js",
|
||||
"src/data/militaryInstallationData.js",
|
||||
"src/layers/launches/source.js",
|
||||
@@ -5166,12 +5250,16 @@
|
||||
"src/layers/submarineCables/bundledSource.js",
|
||||
"src/layers/alpr/source.js",
|
||||
"src/layers/alpr/policy.js",
|
||||
"src/data/displayText.js",
|
||||
"src/layers/alpr/records.js",
|
||||
"src/layers/alpr/tileRecords.js",
|
||||
"src/sources/infrastructureData.js",
|
||||
"src/sources/eventPacks.js",
|
||||
"src/layers/satellites/classes.js",
|
||||
"src/data/ucsSatellites.js"
|
||||
"src/layers/satellites/sensors.js",
|
||||
"src/data/ucsSatellites.js",
|
||||
"src/data/imagingSensors.js",
|
||||
"src/data/planespottersPhoto.js"
|
||||
],
|
||||
"external": ["@mapbox/vector-tile", "pbf"]
|
||||
},
|
||||
|
||||
@@ -4,6 +4,7 @@ import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import puppeteer from 'puppeteer';
|
||||
import { stubPlanespotters } from './qa-photo-stub.mjs';
|
||||
|
||||
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
||||
const shotsDir = path.join(repoRoot, 'qa-shots', 'cockpit-utility');
|
||||
@@ -29,6 +30,7 @@ const browser = await puppeteer.launch({
|
||||
],
|
||||
});
|
||||
const page = await browser.newPage();
|
||||
await stubPlanespotters(page);
|
||||
const failures = [];
|
||||
const consoleErrors = [];
|
||||
const localHttpErrors = [];
|
||||
@@ -825,6 +827,7 @@ try {
|
||||
// a legitimate retained snapshot cannot satisfy or invalidate a FIRST-fetch
|
||||
// assertion when camera motion supersedes the manager's initial update.
|
||||
const readinessPage = await browser.newPage();
|
||||
await stubPlanespotters(readinessPage);
|
||||
let deferredInstallationReadiness;
|
||||
try {
|
||||
await readinessPage.setViewport({ width: 1440, height: 900 });
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import puppeteer from 'puppeteer';
|
||||
import { stubPlanespotters } from './qa-photo-stub.mjs';
|
||||
import { createScreencast, moveCamera } from './qa-journey-recorder.mjs';
|
||||
|
||||
const argv = process.argv.slice(2);
|
||||
@@ -77,6 +78,7 @@ const browser = await puppeteer.launch({
|
||||
|
||||
async function openPage({ aircraft = false } = {}) {
|
||||
const page = await browser.newPage();
|
||||
await stubPlanespotters(page);
|
||||
await page.setViewport({ width: 1440, height: 900 });
|
||||
page.on('console', (message) => {
|
||||
if (message.type() === 'error') result.consoleErrors.push(message.text());
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
*/
|
||||
|
||||
import puppeteer from 'puppeteer';
|
||||
import { stubPlanespotters } from './qa-photo-stub.mjs';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
@@ -223,6 +224,7 @@ async function main() {
|
||||
const errors = [];
|
||||
try {
|
||||
const page = await browser.newPage();
|
||||
await stubPlanespotters(page);
|
||||
await page.setViewport({ width: 1440, height: 900 });
|
||||
page.on('pageerror', (e) => errors.push(e.message));
|
||||
const { lon, lat } = CENTER;
|
||||
|
||||
@@ -21,6 +21,7 @@ import fs from 'node:fs';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import puppeteer from 'puppeteer';
|
||||
import { stubPlanespotters } from './qa-photo-stub.mjs';
|
||||
|
||||
const argv = process.argv.slice(2);
|
||||
const getOpt = (name, fallback = null) => {
|
||||
@@ -651,6 +652,7 @@ async function main() {
|
||||
],
|
||||
});
|
||||
const page = await browser.newPage();
|
||||
await stubPlanespotters(page);
|
||||
await page.setViewport(VIEWPORT);
|
||||
const consoleMessages = [];
|
||||
page.on('console', (message) => {
|
||||
|
||||
@@ -99,6 +99,7 @@
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import puppeteer from 'puppeteer';
|
||||
import { stubPlanespotters } from './qa-photo-stub.mjs';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Args (same shape as track-regression.mjs)
|
||||
@@ -466,6 +467,7 @@ async function main() {
|
||||
const failedResponses = [];
|
||||
try {
|
||||
const page = await browser.newPage();
|
||||
await stubPlanespotters(page);
|
||||
await page.setViewport({ width: 1280, height: 800 });
|
||||
page.on('console', (msg) => {
|
||||
if (msg.type() === 'error') {
|
||||
|
||||
+12
-12
@@ -239,11 +239,11 @@ function satisfiesEngines(version, range) {
|
||||
* re-resolve the interpreter from PATH and hand the gate a different Node than
|
||||
* the one the check believes it selected.
|
||||
* @param {string} version e.g. "v24.19.0"
|
||||
* @returns {boolean} true only for a parseable Node 24.
|
||||
* @returns {boolean} true for a parseable supported Node 24 or 26.
|
||||
*/
|
||||
function isCalibratedAllocationRuntime(version) {
|
||||
const [maj] = String(version || '').trim().replace(/^v/, '').split('.').map((n) => Number.parseInt(n, 10));
|
||||
return maj === 24;
|
||||
return maj === 24 || maj === 26;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -546,7 +546,7 @@ const check = (spec) => { CHECKS.push(spec); };
|
||||
|
||||
// ─── A · REPO GATES ───────────────────────────────────────────────────────
|
||||
check({
|
||||
id: 'A1', group: 'A', desc: 'Node runtime satisfies package.json engines (allocation budgets are pinned to Node 24)',
|
||||
id: 'A1', group: 'A', desc: 'Node runtime satisfies package.json engines (allocation budgets cover supported Node majors)',
|
||||
run: async () => {
|
||||
const pkg = JSON.parse(readFileSync(resolve(REPO_ROOT, 'package.json'), 'utf8'));
|
||||
const range = pkg.engines?.node || '(unset)';
|
||||
@@ -557,7 +557,7 @@ check({
|
||||
if (satisfied) return pass(`node ${process.versions.node} satisfies "${range}"`);
|
||||
// An off-range runtime is an environment problem, not a product defect —
|
||||
// but it silently disables the allocation gate, so say so loudly. A3 then
|
||||
// runs that gate under a discovered Node 24.
|
||||
// runs that gate under a discovered calibrated Node 24 fallback.
|
||||
return env.node24
|
||||
? skip(`node ${process.versions.node} is OUTSIDE "${range}"; A3 runs the allocation gate under ${env.node24.label}, but prefer running the whole L9 pass on Node 24`, 'ENV')
|
||||
: fail(`node ${process.versions.node} is OUTSIDE "${range}" and no Node 24 runtime was found — the allocation gate cannot run at all`);
|
||||
@@ -579,13 +579,13 @@ check({
|
||||
});
|
||||
|
||||
check({
|
||||
id: 'A3', group: 'A', desc: 'Allocation microbenchmarks actually EXECUTE (they silently skip off Node 24)',
|
||||
id: 'A3', group: 'A', desc: 'Allocation microbenchmarks actually EXECUTE on supported Node majors',
|
||||
run: async () => {
|
||||
// npm test prints "[unit] SKIPPED n allocation microbenchmarks" and still
|
||||
// exits 0 when the runtime is not Node 24. A green suite is therefore NOT
|
||||
// proof the gate ran. Force it, under Node 24 when one is discoverable.
|
||||
// exits 0 when the runtime is outside the calibrated supported majors. A green
|
||||
// suite is therefore NOT proof the gate ran. Force it under a calibrated runtime.
|
||||
//
|
||||
// ALWAYS invoke the Node 24 BINARY directly — never `npm test`. npm
|
||||
// ALWAYS invoke the calibrated Node binary directly — never `npm test`. npm
|
||||
// re-resolves the interpreter from PATH and can land back on the system
|
||||
// Node even when THIS process is already 24: running the whole matrix under
|
||||
// `mise exec [email protected] --`, the npm shell-out still re-execed system
|
||||
@@ -597,10 +597,10 @@ check({
|
||||
const v = await sh(bin, ['--version'], { timeoutMs: 60000 });
|
||||
const version = (v.out || '').trim();
|
||||
if (!isCalibratedAllocationRuntime(version)) {
|
||||
// run-unit-tests.mjs refuses to measure calibrated budgets off Node 24,
|
||||
// run-unit-tests.mjs refuses to measure calibrated budgets off supported Node majors,
|
||||
// so a wrong binary means the gate never ran. That is this check failing
|
||||
// to establish its own claim — not evidence about the product.
|
||||
return crash(`the runtime selected for the allocation gate (${label}) reports ${version || 'no parseable version'}, not Node 24 — the gate would refuse or silently skip, so this check verified nothing`);
|
||||
return crash(`the runtime selected for the allocation gate (${label}) reports ${version || 'no parseable version'}, not Node 24 or 26 — the gate would refuse or silently skip, so this check verified nothing`);
|
||||
}
|
||||
const r = await sh(bin, [resolve(REPO_ROOT, 'scripts/run-unit-tests.mjs')], {
|
||||
timeoutMs: 600000, env: { GEV_REQUIRE_ALLOCATION_GATE: '1' },
|
||||
@@ -611,9 +611,9 @@ check({
|
||||
};
|
||||
|
||||
const [maj] = process.versions.node.split('.').map(Number);
|
||||
if (maj === 24) return runGate(process.execPath, 'this runtime');
|
||||
if (maj === 24 || maj === 26) return runGate(process.execPath, 'this runtime');
|
||||
if (env.node24) return runGate(env.node24.bin, env.node24.label);
|
||||
return skip(`no Node 24 runtime found (running ${process.versions.node}); the gate SKIPS silently — install Node 24 and re-run`, 'OWNER-RUN');
|
||||
return skip(`no calibrated Node 24/26 runtime found (running ${process.versions.node}); the gate SKIPS silently — install a supported Node runtime and re-run`, 'OWNER-RUN');
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* Keep browser QA off third-party aircraft photo services.
|
||||
*
|
||||
* Tracking a civil flight asks Planespotters for the aircraft's photo. QA
|
||||
* runs track synthetic hexes, so a real request only adds a third-party
|
||||
* dependency and, when the service refuses a headless browser, a console
|
||||
* error that fails the "no console errors" checks. Every photo lookup is
|
||||
* answered with no photos instead, without leaving the browser.
|
||||
*/
|
||||
|
||||
/** Origin of the aircraft photo lookup. */
|
||||
export const PLANESPOTTERS_ORIGIN = 'https://api.planespotters.net';
|
||||
|
||||
/** The answer every stubbed lookup gets: no photos for this aircraft. */
|
||||
export const PLANESPOTTERS_EMPTY_BODY = JSON.stringify({ photos: [] });
|
||||
|
||||
/** Whether a URL is a photo lookup the stub answers. */
|
||||
export function isPlanespottersRequest(url) {
|
||||
try {
|
||||
return new URL(String(url)).origin === PLANESPOTTERS_ORIGIN;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Answer an intercepted photo lookup from a page that already uses request
|
||||
* interception. Returns false for any other request, which the caller
|
||||
* handles as before.
|
||||
* @param {import('puppeteer').HTTPRequest} request
|
||||
* @returns {boolean} Whether the request was answered.
|
||||
*/
|
||||
export function respondToPlanespotters(request) {
|
||||
if (!isPlanespottersRequest(request.url())) return false;
|
||||
request.respond({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
headers: { 'Access-Control-Allow-Origin': '*' },
|
||||
body: PLANESPOTTERS_EMPTY_BODY,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stub photo lookups in a page that does not intercept requests: wraps
|
||||
* `fetch` before any app code runs, so a lookup never reaches the network.
|
||||
* Composes with other `fetch` shims in either order.
|
||||
* @param {import('puppeteer').Page} page
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function stubPlanespotters(page) {
|
||||
await page.evaluateOnNewDocument(
|
||||
(origin, body) => {
|
||||
const original = window.fetch.bind(window);
|
||||
window.fetch = (input, init) => {
|
||||
const href =
|
||||
typeof input === 'string' ? input : input?.url || String(input);
|
||||
let target = '';
|
||||
try {
|
||||
target = new URL(href, location.href).origin;
|
||||
} catch {
|
||||
/* not a URL */
|
||||
}
|
||||
if (target === origin) {
|
||||
return Promise.resolve(
|
||||
new Response(body, {
|
||||
status: 200,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
}),
|
||||
);
|
||||
}
|
||||
return original(input, init);
|
||||
};
|
||||
},
|
||||
PLANESPOTTERS_ORIGIN,
|
||||
PLANESPOTTERS_EMPTY_BODY,
|
||||
);
|
||||
}
|
||||
@@ -32,6 +32,7 @@
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import puppeteer from 'puppeteer';
|
||||
import { stubPlanespotters } from './qa-photo-stub.mjs';
|
||||
import { classifyAircraft, CLASS_SCALE_2D, CLASS_SCALE_3D, CLASS_MODEL_REAL } from '../src/data/aircraftClass.js';
|
||||
// Hangar fleet (2026-08-16): real per-class GLBs render at scale 1; military
|
||||
// heavies (airliner/quadjet/glider) render airplane.glb at 1 x class; only
|
||||
@@ -186,6 +187,7 @@ async function main() {
|
||||
const httpErrors = [];
|
||||
try {
|
||||
const page = await browser.newPage();
|
||||
await stubPlanespotters(page);
|
||||
await page.setViewport({ width: 1280, height: 800 });
|
||||
page.on('console', (msg) => {
|
||||
if (msg.type() === 'error') {
|
||||
|
||||
+11
-11
@@ -8,15 +8,16 @@ export const ALLOCATION_TEST_FILES = Object.freeze([
|
||||
'src/overlays/worldOverlayAllocation.test.mjs',
|
||||
]);
|
||||
|
||||
/** Whether this runtime matches the one the allocation budgets were calibrated on. */
|
||||
/** Whether this runtime matches a supported major the allocation budgets are calibrated on. */
|
||||
export function isCalibratedAllocationRuntime(version = process.versions.node) {
|
||||
return Number.parseInt(String(version).split('.')[0], 10) === 24;
|
||||
const major = Number.parseInt(String(version).split('.')[0], 10);
|
||||
return major === 24 || major === 26;
|
||||
}
|
||||
|
||||
/** Require the runtime on which allocation budgets were calibrated. */
|
||||
export function assertNode24AllocationRuntime(version = process.versions.node) {
|
||||
/** Require a runtime on which allocation budgets are calibrated. */
|
||||
export function assertCalibratedAllocationRuntime(version = process.versions.node) {
|
||||
if (!isCalibratedAllocationRuntime(version)) {
|
||||
throw new Error(`Allocation budgets require the calibrated Node 24 runtime; received ${version}`);
|
||||
throw new Error(`Allocation budgets require calibrated Node 24 or 26; received ${version}`);
|
||||
}
|
||||
return version;
|
||||
}
|
||||
@@ -92,19 +93,18 @@ export function runUnitTests() {
|
||||
const parallelStatus = runTests(['--test', ...plan.parallel]);
|
||||
if (parallelStatus !== 0) return parallelStatus;
|
||||
|
||||
// The GC-bracketed budgets are calibrated on Node 24 and are meaningless on
|
||||
// other allocators. A contributor's suite must stay green on any supported
|
||||
// engine (package.json permits >=24), so uncalibrated runtimes skip the
|
||||
// The GC-bracketed budgets are calibrated on every supported Node major.
|
||||
// Unsupported runtimes may still run ordinary tests, so uncalibrated runtimes skip the
|
||||
// probes with a warning. Set GEV_REQUIRE_ALLOCATION_GATE=1 (pinned CI /
|
||||
// release batteries) to make an uncalibrated runtime a hard failure.
|
||||
if (!isCalibratedAllocationRuntime()) {
|
||||
if (process.env.GEV_REQUIRE_ALLOCATION_GATE === '1') {
|
||||
assertNode24AllocationRuntime();
|
||||
assertCalibratedAllocationRuntime();
|
||||
}
|
||||
console.warn(
|
||||
`[unit] SKIPPED ${ALLOCATION_TEST_FILES.length} allocation microbenchmarks: `
|
||||
+ `budgets are calibrated for Node 24, running ${process.versions.node}. `
|
||||
+ 'Run under Node 24 (or set GEV_REQUIRE_ALLOCATION_GATE=1 to fail instead).',
|
||||
+ `budgets are calibrated for Node 24 and 26, running ${process.versions.node}. `
|
||||
+ 'Run under Node 24 or 26 (or set GEV_REQUIRE_ALLOCATION_GATE=1 to fail instead).',
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -94,6 +94,7 @@
|
||||
|
||||
import fs from 'node:fs';
|
||||
import puppeteer from 'puppeteer';
|
||||
import { respondToPlanespotters } from './qa-photo-stub.mjs';
|
||||
import { arrivalAngleViolated, arrivalRotationPassed } from '../src/tooling/trackArrivalObservation.mjs';
|
||||
import { classifyAircraft, CLASS_SCALE_3D, CLASS_MODEL_REAL } from '../src/data/aircraftClass.js';
|
||||
import { ensureGeoidReady, geoidHeight } from '../src/data/geoid.js';
|
||||
@@ -287,6 +288,8 @@ async function main() {
|
||||
});
|
||||
return;
|
||||
}
|
||||
// Aircraft photo lookups never reach the third party: no photos.
|
||||
if (respondToPlanespotters(request)) return;
|
||||
if (url.origin === APP_ORIGIN && url.pathname === '/api/openai/hud-summary') {
|
||||
request.respond({
|
||||
status: 200,
|
||||
|
||||
Reference in new issue
Block a user