From 73e789489bdb830fa0c6bfdbcc60de5fd81bf9ad Mon Sep 17 00:00:00 2001 From: Sameh Khamis Date: Thu, 22 Oct 2026 19:00:35 -0700 Subject: [PATCH] chore: drop exports nothing imports Knip, configured with the application, package exports, scripts, QA harnesses, workers, tools and tests as entry points, reports exports that no module imports. Each was checked by hand against string-based and namespace imports. - Symbols that are still used inside their own module lose only the `export` keyword (176 constants and helpers). - Unused re-exports are removed from barrel modules (flight, military, vessel, CCTV, directions, transit history, local ADS-B and street-level policy modules). - Declarations that nothing uses at all are deleted, among them AIS_WATCHDOG_STATUSES, applyFilter, isRadioCountryCode, compactText, DENSITY_STOPS, the unused CCTV endpoint constants, and the SDR band constants. - Default exports that nothing imports are removed. The ones in src/data/earthquakes.js, src/data/telegeographySubmarineCables.js, src/data/wind.js and src/data/bhoteKoshiLocator.js each constructed a layer instance at import time that nothing used; those instances are no longer created. Every export of a package.json entry stays, as does TOMTOM_CREDIT, which the traffic layer reads from the credits namespace it is given. --- server/providers/cctv/constants.js | 2 +- server/providers/cctv/groundHeights.js | 2 +- server/providers/cctv/media.js | 4 +- server/providers/cctv/normalize.js | 6 +-- server/providers/cctv/sources.js | 2 +- server/providers/cctv/stream.js | 2 +- server/providers/cctv/taiwan.js | 6 +-- server/providers/local-receivers.js | 18 ++++---- server/providers/mapillary/tiles.js | 2 +- server/providers/openai/codex-auth.js | 2 +- server/providers/openai/debug-log.js | 2 +- server/providers/radio/catalog.js | 2 +- server/providers/transitHistory.js | 1 - server/providers/wind/ifs.js | 2 +- src/annotations/drawMode.js | 8 ++-- src/annotations/drawTool.js | 2 +- src/annotations/resolver.js | 2 +- src/app/embed.js | 6 +-- src/app/sourceComposition.js | 2 +- src/cameraGroundGuard.js | 4 +- src/cctvFocusPolicy.js | 2 +- src/cockpitCloudEffects.js | 2 +- src/data/adminBoundaries.js | 2 +- src/data/aisStreamAdapter.js | 2 +- src/data/aisWatchdog.js | 22 +--------- src/data/analystEngine.js | 44 ++----------------- src/data/bhoteKoshiLocator.js | 5 +-- src/data/bikeshare.js | 1 - src/data/cctvFootprint.js | 4 +- src/data/cctvLod.js | 6 +-- src/data/dataCredits.js | 4 +- src/data/detectionCohort.js | 2 +- src/data/detectionPolicy.js | 3 +- src/data/directions.js | 6 +-- src/data/earthquakes.js | 1 - src/data/geoFileImport.js | 8 ++-- src/data/geoImportImages.js | 2 +- src/data/gtfsRealtime.js | 5 +-- src/data/localGeojson.js | 1 - src/data/militaryNames.js | 2 +- src/data/radioCountry.js | 5 --- src/data/telegeographySubmarineCables.js | 1 - src/data/wind.js | 8 ---- src/i18n/index.js | 2 +- src/layers/alpr/records.js | 6 +-- src/layers/alpr/tileRecords.js | 2 +- src/layers/awareness/policy.js | 5 +-- src/layers/bikeshare/policy.js | 2 +- src/layers/cctv/policy.js | 11 +---- src/layers/cctv/sourcePolicy.js | 4 -- src/layers/cyclones/labels.js | 4 +- src/layers/flights/policy.js | 8 ---- src/layers/installations/policy.js | 2 - src/layers/localAdsb/feeds.js | 4 +- src/layers/localAdsb/index.js | 14 +----- src/layers/localAdsb/motion.js | 2 +- src/layers/localAdsb/status.js | 4 +- src/layers/military/policy.js | 7 --- src/layers/radio/policy.js | 2 +- src/layers/recentImagery/model.js | 2 +- src/layers/satellites/policy.js | 4 +- src/layers/streetLevel/photoViewer.js | 10 ++--- .../streetLevel/providers/kartaview/policy.js | 4 +- .../streetLevel/providers/panoramax/index.js | 2 - .../streetLevel/providers/panoramax/policy.js | 2 +- src/layers/streetLevel/registry.js | 2 +- src/layers/streetLevel/sequenceCones.js | 4 +- src/layers/streetLevel/tileCache.js | 4 +- src/layers/streetLevel/uiState.js | 4 +- src/layers/submarineCables/geometry.js | 6 +-- src/layers/traffic/footprint.js | 6 +-- src/layers/traffic/policy.js | 10 ----- src/layers/transit/policy.js | 14 +++--- src/layers/vessels/policy.js | 5 --- src/layers/weather/source.js | 2 +- src/layers/wind/gpuRendering.js | 4 +- src/locationStatus.js | 2 - src/maps/imageryComparison.js | 2 +- src/maps/terrainRetry.js | 2 +- src/scenes/recipes.js | 4 +- src/sdr/controller.js | 12 ++--- src/sdr/gain.js | 2 +- src/sky/stars.js | 4 +- src/sources/adsbRecords.js | 8 ++-- src/sources/featureGeometry.js | 12 ++--- src/sources/openFreeMap.js | 2 +- src/sources/transitHistoryStore.js | 2 +- src/testSupport/kartaViewFakes.mjs | 2 +- src/tools/queries/panelRequest.js | 2 +- src/tools/queries/share.js | 2 +- src/ui/cameraOrientationControls.js | 4 +- src/ui/cctvFrames.js | 2 +- src/ui/statusText.js | 2 +- src/voice/deixis.js | 2 +- src/voice/narration.js | 2 +- src/voice/pointerContext.js | 8 ++-- src/voice/pointerPick.js | 2 +- src/voice/pointerReticle.js | 2 +- src/voice/realtimeDiagnostics.js | 29 +++++------- src/voice/realtimePreferences.js | 6 +-- src/voice/realtimeTurns.js | 2 +- src/voice/realtimeViewport.js | 16 +++---- src/voice/resultDisplay.js | 2 +- src/voice/speechLint.js | 2 +- src/voice/turnMetrics.js | 2 +- src/voice/voiceCard.js | 2 +- 106 files changed, 180 insertions(+), 342 deletions(-) diff --git a/server/providers/cctv/constants.js b/server/providers/cctv/constants.js index 257c292b3..a26fa6c20 100644 --- a/server/providers/cctv/constants.js +++ b/server/providers/cctv/constants.js @@ -18,7 +18,7 @@ export const CCTV_MAX_SOURCES_CEILING = 5000; export const AUSTIN_DOWNTOWN = { lat: 30.2672, lon: -97.7431 }; /** Caltrans CCTV: one JSON feed per district, identical schema statewide. */ /** TxDOT ITS: one keyless JSON catalog per district (25 districts statewide). */ -export const TXDOT_ORIGIN = 'https://its.txdot.gov'; +const TXDOT_ORIGIN = 'https://its.txdot.gov'; export const TXDOT_CCTV_STATUS_URL = (district) => `${TXDOT_ORIGIN}/its/DistrictIts/GetCctvStatusListByDistrict?districtCode=${encodeURIComponent(district)}`; /** Per-camera frame. Returns JSON `{snippet:}`, not an image body; diff --git a/server/providers/cctv/groundHeights.js b/server/providers/cctv/groundHeights.js index c73b6e840..f20b9758d 100644 --- a/server/providers/cctv/groundHeights.js +++ b/server/providers/cctv/groundHeights.js @@ -3,7 +3,7 @@ import path from 'node:path'; import { poseHash } from '../../../src/data/cctvFootprint.js'; /** Sidecar written by scripts/precompute-cctv-heights.mjs. */ -export const DEFAULT_GROUND_HEIGHTS_FILE = +const DEFAULT_GROUND_HEIGHTS_FILE = 'src/data/local_data/cctv_ground_heights/cctv_ground_heights.json'; /** @type {{path:string, mtimeMs:number, cameras:object}|null} */ diff --git a/server/providers/cctv/media.js b/server/providers/cctv/media.js index 1323bc841..206a24888 100644 --- a/server/providers/cctv/media.js +++ b/server/providers/cctv/media.js @@ -92,7 +92,7 @@ export function buildSyntheticCctvSvg({ cameraId, label, city, status }) { * @param {ReadableStream|NodeJS.ReadableStream|null} body * @returns {import('stream').Readable|null} */ -export function toReadable(body) { +function toReadable(body) { if (!body) return null; if (typeof body.pipe === 'function') return body; if (typeof body.getReader === 'function') { @@ -108,7 +108,7 @@ export function toReadable(body) { * @returns {{essence:string,params:Map}|null} Null when the * value is missing or is not a `type/subtype` media type. */ -export function parseMediaType(value) { +function parseMediaType(value) { const [head, ...rest] = String(value ?? '').split(';'); const essence = head.trim().toLowerCase(); if (!/^[a-z0-9!#$&^_.+-]+\/[a-z0-9!#$&^_.+-]+$/.test(essence)) return null; diff --git a/server/providers/cctv/normalize.js b/server/providers/cctv/normalize.js index 74f693dd8..f190f257e 100644 --- a/server/providers/cctv/normalize.js +++ b/server/providers/cctv/normalize.js @@ -64,7 +64,7 @@ export function toFiniteNumber(value, fallback = NaN) { * @param {string} text * @returns {string} */ -export function normalizeKey(text) { +function normalizeKey(text) { return String(text || '') .trim() .toLowerCase() @@ -80,7 +80,7 @@ export function normalizeKey(text) { * @param {string} value * @returns {{lat:number, lon:number}} */ -export function parsePointString(value) { +function parsePointString(value) { const match = String(value || '').match( /POINT\s*\(\s*(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)\s*\)/i, ); @@ -100,7 +100,7 @@ export function parsePointString(value) { * @param {string|object|null} value * @returns {{lat:number, lon:number}} */ -export function coerceLatLon(value) { +function coerceLatLon(value) { if (!value) return { lat: NaN, lon: NaN }; if (typeof value === 'string') { diff --git a/server/providers/cctv/sources.js b/server/providers/cctv/sources.js index c7def2284..a479a945c 100644 --- a/server/providers/cctv/sources.js +++ b/server/providers/cctv/sources.js @@ -1868,7 +1868,7 @@ export function normalizeCataloniaImageUrl(rawUrl) { * @param {string} imageUrl - A URL normalizeCataloniaImageUrl accepted. * @returns {string} */ -export function cataloniaCameraId(imageUrl) { +function cataloniaCameraId(imageUrl) { const parsed = new URL(imageUrl); const slug = (text) => text diff --git a/server/providers/cctv/stream.js b/server/providers/cctv/stream.js index 14d1743bb..da811f5f9 100644 --- a/server/providers/cctv/stream.js +++ b/server/providers/cctv/stream.js @@ -70,7 +70,7 @@ export async function fetchHlsBytes( } } -export function sameOriginHlsUrl(value, base) { +function sameOriginHlsUrl(value, base) { const url = new URL(value, base); if ( !['https:', 'http:'].includes(url.protocol) || diff --git a/server/providers/cctv/taiwan.js b/server/providers/cctv/taiwan.js index 830ed47fd..a14aabf9a 100644 --- a/server/providers/cctv/taiwan.js +++ b/server/providers/cctv/taiwan.js @@ -12,14 +12,14 @@ export const TAIWAN_FREEWAY_CCTV_URL = 'https://tisvcloud.freeway.gov.tw/history/motc20/CCTV.xml'; /** The whole network is ~1.2 MB. */ export const TAIWAN_MAX_CATALOG_BYTES = 6 * 1024 * 1024; -export const DEFAULT_TAIWAN_MAX_SOURCES = 600; +const DEFAULT_TAIWAN_MAX_SOURCES = 600; /** After a failed download, wait this long before asking again. The catalog * host does not answer from some networks outside Taiwan, and every attempt * there holds the shared catalog refresh until the connect timeout. */ export const TAIWAN_RETRY_AFTER_FAILURE_MS = 60 * 60 * 1000; /** The table is republished daily; a good copy stands in for a failed * download for up to this long. */ -export const TAIWAN_LAST_GOOD_MAX_AGE_MS = 24 * 60 * 60 * 1000; +const TAIWAN_LAST_GOOD_MAX_AGE_MS = 24 * 60 * 60 * 1000; // The table publishes each camera's MJPEG stream. The same camera servers // answer a single JPEG for the same camera ID on a sibling path, which is what @@ -50,7 +50,7 @@ const ANCHORS = [ /** Taiwan main island with slack for the coast; the freeway network has no * offshore-island cameras. */ -export function isLikelyTaiwanCoordinate(lat, lon) { +function isLikelyTaiwanCoordinate(lat, lon) { return ( Number.isFinite(lat) && Number.isFinite(lon) && diff --git a/server/providers/local-receivers.js b/server/providers/local-receivers.js index 994da7bd8..f3f340b54 100644 --- a/server/providers/local-receivers.js +++ b/server/providers/local-receivers.js @@ -27,13 +27,13 @@ import { normalizeDump1090Aircraft } from '../../src/sources/adsbRecords.js'; */ export const LOCAL_RECEIVERS_ROUTE = '/api/local-receivers/aircraft'; -export const LOCAL_RECEIVER_FEEDS_ENV = 'LOCAL_RECEIVER_FEEDS'; -export const LOCAL_RECEIVER_BANDS = Object.freeze(['1090', '978']); -export const LOCAL_RECEIVER_TIMEOUT_MS = 2_000; -export const LOCAL_RECEIVER_MAX_BODY_BYTES = 2 * 1024 * 1024; -export const LOCAL_RECEIVER_CACHE_MS = 1_000; +const LOCAL_RECEIVER_FEEDS_ENV = 'LOCAL_RECEIVER_FEEDS'; +const LOCAL_RECEIVER_BANDS = Object.freeze(['1090', '978']); +const LOCAL_RECEIVER_TIMEOUT_MS = 2_000; +const LOCAL_RECEIVER_MAX_BODY_BYTES = 2 * 1024 * 1024; +const LOCAL_RECEIVER_CACHE_MS = 1_000; /** A feed whose own `now` is older than this is reported stale. */ -export const LOCAL_RECEIVER_STALE_MS = 10_000; +const LOCAL_RECEIVER_STALE_MS = 10_000; const MAX_FEEDS = 8; const LOG_PREFIX = '[local-receivers]'; @@ -139,7 +139,7 @@ class FeedError extends Error { * @param {string} address Resolved IP address. * @returns {boolean} */ -export function isLocalReceiverAddress(address) { +function isLocalReceiverAddress(address) { const value = String(address || '').toLowerCase(); if (value === '::1') return true; const mapped = /^::ffff:(\d{1,3}(?:\.\d{1,3}){3})$/.exec(value); @@ -152,7 +152,7 @@ export function isLocalReceiverAddress(address) { * @param {typeof dnsLookup} lookupImpl `dns.promises.lookup`-compatible. * @returns {Promise>} */ -export async function resolveLocalReceiverAddresses(hostname, lookupImpl) { +async function resolveLocalReceiverAddresses(hostname, lookupImpl) { let resolved; try { resolved = await lookupImpl(hostname, { all: true, verbatim: true }); @@ -274,7 +274,7 @@ function fetchLocalReceiverFeed(url, options) { * @param {object} options * @returns {Promise} Parsed JSON document. */ -export async function fetchLocalReceiverDocument( +async function fetchLocalReceiverDocument( url, { fetchImpl = fetchLocalReceiverFeed, diff --git a/server/providers/mapillary/tiles.js b/server/providers/mapillary/tiles.js index 569e7e45f..6e2207848 100644 --- a/server/providers/mapillary/tiles.js +++ b/server/providers/mapillary/tiles.js @@ -42,7 +42,7 @@ export class TileUpstreamError extends Error { } /** Seconds a Retry-After header asks for (an integer or an HTTP date), else null. */ -export function retryAfterSeconds(header, now = Date.now()) { +function retryAfterSeconds(header, now = Date.now()) { const text = String(header ?? '').trim(); if (!text) return null; const seconds = /^\d+$/.test(text) diff --git a/server/providers/openai/codex-auth.js b/server/providers/openai/codex-auth.js index 5f16ee824..4d3f992da 100644 --- a/server/providers/openai/codex-auth.js +++ b/server/providers/openai/codex-auth.js @@ -145,7 +145,7 @@ const CODEX_LOGIN_ENV = /^(?:PATH|PATHEXT|HOME|USER|USERNAME|LOGNAME|SHELL|LANG|LANGUAGE|LC_[A-Z_]+|TERM|TZ|TMPDIR|TEMP|TMP|XDG_[A-Z_]+|DISPLAY|WAYLAND_DISPLAY|DBUS_SESSION_BUS_ADDRESS|BROWSER|WSL_[A-Z_]+|WSLENV|(?:HTTPS?|ALL|NO)_PROXY|SSL_CERT_(?:FILE|DIR)|NODE_EXTRA_CA_CERTS|SYSTEMROOT|WINDIR|COMSPEC|USERPROFILE|APPDATA|LOCALAPPDATA|PROGRAMDATA|HOMEDRIVE|HOMEPATH|CODEX_[A-Z_]+)$/i; /** The environment `codex login` runs with: the allowlist, then `CODEX_HOME`. */ -export function codexLoginEnvironment(environment, codexHome) { +function codexLoginEnvironment(environment, codexHome) { const env = {}; for (const [name, value] of Object.entries(environment || {})) if (CODEX_LOGIN_ENV.test(name) && value !== undefined) env[name] = value; diff --git a/server/providers/openai/debug-log.js b/server/providers/openai/debug-log.js index 956569642..c8151d2f6 100644 --- a/server/providers/openai/debug-log.js +++ b/server/providers/openai/debug-log.js @@ -157,4 +157,4 @@ function createDebugLogHandler({ }; } -export { createDebugLogHandler, omitVoiceContent }; +export { createDebugLogHandler }; diff --git a/server/providers/radio/catalog.js b/server/providers/radio/catalog.js index 36a3eb730..2864c8986 100644 --- a/server/providers/radio/catalog.js +++ b/server/providers/radio/catalog.js @@ -26,7 +26,7 @@ import { RADIO_UUID_RE, RADIO_FALLBACK_MIRRORS, } from './constants.js'; -export async function mapRadioConcurrent(values, concurrency, mapper) { +async function mapRadioConcurrent(values, concurrency, mapper) { const results = new Array(values.length); let cursor = 0; const workers = Array.from( diff --git a/server/providers/transitHistory.js b/server/providers/transitHistory.js index f396f3d8f..4da5a8891 100644 --- a/server/providers/transitHistory.js +++ b/server/providers/transitHistory.js @@ -1,5 +1,4 @@ export { createTransitHistory, - TRANSIT_HISTORY_LIMITS, validTransitIdentifier, } from '../../src/sources/transitHistoryStore.js'; diff --git a/server/providers/wind/ifs.js b/server/providers/wind/ifs.js index 7767d3905..076baf064 100644 --- a/server/providers/wind/ifs.js +++ b/server/providers/wind/ifs.js @@ -3,7 +3,7 @@ import { decodeWindGribMessage } from './decode.js'; import { resampleWeatherSnapshot, weatherScalarMetadata } from './grid.js'; /** Keyless ECMWF Open Data root for real-time IFS forecasts. */ -export const IFS_BASE = 'https://data.ecmwf.int/forecasts'; +const IFS_BASE = 'https://data.ecmwf.int/forecasts'; /** * Select the latest IFS cycle that should be available. diff --git a/src/annotations/drawMode.js b/src/annotations/drawMode.js index 02a501010..fcfe08be6 100644 --- a/src/annotations/drawMode.js +++ b/src/annotations/drawMode.js @@ -31,10 +31,10 @@ export const MIN_VERTICES = Object.freeze({ area: 3, line: 2, pin: 1 }); */ export const MAX_VERTICES = 512; /** Two clicks closer than this are one vertex: a double-click to finish must not add a stray point. */ -export const MIN_VERTEX_SEPARATION_M = 0.5; +const MIN_VERTEX_SEPARATION_M = 0.5; /** A line shorter than this, or an area thinner than this, is a mis-click rather than a shape. */ -export const MIN_PATH_LENGTH_M = 1; -export const MIN_AREA_M2 = 1; +const MIN_PATH_LENGTH_M = 1; +const MIN_AREA_M2 = 1; /** @param {string} shape @returns {'area'|'line'|'pin'} */ export function normalizeShape(shape) { @@ -50,7 +50,7 @@ export function createDrawSession(shape = 'area') { } /** Great-circle distance in metres between two {lon, lat} points. */ -export function greatCircleM(a, b) { +function greatCircleM(a, b) { return greatCircleMeters(a, b); } diff --git a/src/annotations/drawTool.js b/src/annotations/drawTool.js index 0f4e0fc76..9467406dd 100644 --- a/src/annotations/drawTool.js +++ b/src/annotations/drawTool.js @@ -52,7 +52,7 @@ import { import { msg, registerUnsavedWork, t, translateKnown } from '../i18n/index.js'; /** The id this tool claims the pointer under. */ -export const DRAW_POINTER_OWNER = 'draw'; +const DRAW_POINTER_OWNER = 'draw'; const PREVIEW_DATA_SOURCE_NAME = 'gev-draw-preview'; const COLORS = ['primary', 'amber', 'cyan', 'green', 'red']; diff --git a/src/annotations/resolver.js b/src/annotations/resolver.js index fb5795d53..226caf140 100644 --- a/src/annotations/resolver.js +++ b/src/annotations/resolver.js @@ -29,7 +29,7 @@ import { unavailablePlaceSearch } from '../search/placeSearch.js'; import { isPickedWorldPosition } from '../data/scenePick.js'; /** Ms the analyst region lookup waits on geocode + admin boundary. */ -export const REGION_FALLBACK_BUDGET_MS = 3_000; +const REGION_FALLBACK_BUDGET_MS = 3_000; /** Entity facts that rule out a state/county reading of the ask. */ const NON_ADMIN_ENTITY_KINDS = new Set([ diff --git a/src/app/embed.js b/src/app/embed.js index a1485fe7e..f0d6cad0a 100644 --- a/src/app/embed.js +++ b/src/app/embed.js @@ -15,9 +15,9 @@ import * as Cesium from 'cesium'; import { announceNavigationAuthority } from '../navigationPolicy.js'; import { annotationsFromParams, createView } from '../view/index.js'; -export const EMBED_VIEW_MESSAGE = 'gev:view'; -export const EMBED_APPLIED_MESSAGE = 'gev:view-applied'; -export const EMBED_READY_MESSAGE = 'gev:ready'; +const EMBED_VIEW_MESSAGE = 'gev:view'; +const EMBED_APPLIED_MESSAGE = 'gev:view-applied'; +const EMBED_READY_MESSAGE = 'gev:ready'; const FOLLOW_LAYERS = { aircraft: 'flights', diff --git a/src/app/sourceComposition.js b/src/app/sourceComposition.js index 0fc619142..04794ab13 100644 --- a/src/app/sourceComposition.js +++ b/src/app/sourceComposition.js @@ -53,7 +53,7 @@ export const CATALOG_SOURCE_CONTRACTS = Object.freeze({ }); /** An omitted provider is unavailable, never an authoritative empty dataset. */ -export class SourceUnavailableError extends Error { +class SourceUnavailableError extends Error { constructor(name) { super(`Data source not configured: ${name}`); this.name = 'SourceUnavailableError'; diff --git a/src/cameraGroundGuard.js b/src/cameraGroundGuard.js index 5a5fa3775..3f9de0cab 100644 --- a/src/cameraGroundGuard.js +++ b/src/cameraGroundGuard.js @@ -20,8 +20,8 @@ import { ownCameraArrival } from './data/cameraArrival.js'; /** Minimum eye height above the rendered surface for a usable view. */ export const MIN_EYE_CLEARANCE_M = 120; /** Retries while tiles stream in; sampling fails until the mesh exists. */ -export const GUARD_ATTEMPTS = 8; -export const GUARD_INTERVAL_MS = 600; +const GUARD_ATTEMPTS = 8; +const GUARD_INTERVAL_MS = 600; /** Ignore sub-metre noise rather than nudging the camera forever. */ const GUARD_EPSILON_M = 2; diff --git a/src/cctvFocusPolicy.js b/src/cctvFocusPolicy.js index 7fb2ebe1b..e11c1e1ca 100644 --- a/src/cctvFocusPolicy.js +++ b/src/cctvFocusPolicy.js @@ -27,7 +27,7 @@ export function runCctvLayerEnableFocus({ * @param {Object} [after={}] Ownership immediately after the await. * @returns {{ trackedEntity: *, cockpitActive: boolean }} Conservative ownership. */ -export function mergeCctvEnableOwnership(before = {}, after = {}) { +function mergeCctvEnableOwnership(before = {}, after = {}) { return { trackedEntity: before.trackedEntity || after.trackedEntity || null, cockpitActive: !!(before.cockpitActive || after.cockpitActive), diff --git a/src/cockpitCloudEffects.js b/src/cockpitCloudEffects.js index ccbf31831..c9117b7d3 100644 --- a/src/cockpitCloudEffects.js +++ b/src/cockpitCloudEffects.js @@ -174,7 +174,7 @@ export function cockpitWeatherEnabledFromStoredValue(value) { * Weather-backed volumetric cloud pass that exists only while cockpit mode is * active. It owns no Cesium fog/post-process stages and cannot affect map mode. */ -export class CockpitCloudEffectsController { +class CockpitCloudEffectsController { constructor(viewer, { weatherService = applicationServices.weather } = {}) { this.weatherService = weatherService; this.viewer = viewer; diff --git a/src/data/adminBoundaries.js b/src/data/adminBoundaries.js index e9f97cf8f..9efa967d4 100644 --- a/src/data/adminBoundaries.js +++ b/src/data/adminBoundaries.js @@ -123,7 +123,7 @@ export function decodeRing(encoded, decimals) { } /** Even-odd point-in-ring test; ring is [[lon, lat], …], open or closed. */ -export function pointInRing(ring, lat, lon) { +function pointInRing(ring, lat, lon) { if (!Array.isArray(ring) || ring.length < 3) return false; let inside = false; for (let i = 0, j = ring.length - 1; i < ring.length; j = i, i += 1) { diff --git a/src/data/aisStreamAdapter.js b/src/data/aisStreamAdapter.js index 1f7b0ef9b..05e747308 100644 --- a/src/data/aisStreamAdapter.js +++ b/src/data/aisStreamAdapter.js @@ -215,7 +215,7 @@ export const AIS_RECOGNIZED_MESSAGE_TYPES = Object.freeze( * @param {Object} body * @returns {string|null} */ -export function aisEnvelopeMmsi(envelope, body = {}) { +function aisEnvelopeMmsi(envelope, body = {}) { const metadata = envelope?.MetaData || envelope?.Metadata || {}; const raw = metadata.MMSI ?? body.UserID ?? body.UserId ?? body.Mmsi; if (raw === null || raw === undefined) return null; diff --git a/src/data/aisWatchdog.js b/src/data/aisWatchdog.js index a83c281d9..f024a6f67 100644 --- a/src/data/aisWatchdog.js +++ b/src/data/aisWatchdog.js @@ -46,28 +46,8 @@ export const AIS_WATCHDOG_DEFAULTS = Object.freeze({ authProbeMs: 3_600_000, }); -/** - * Statuses reported to the browser. 'missing-key' and 'unsupported' keep their - * pre-watchdog meaning so a keyless install still reads as "feature off". - */ -export const AIS_WATCHDOG_STATUSES = Object.freeze([ - 'idle', - 'missing-key', - 'unsupported', - 'connecting', - 'live', - 'stale', - 'reconnecting', - 'down', - 'auth-failed', -]); - /** Failure classes. Only 'transport' is allowed to walk the fast ladder. */ -export const AIS_FAILURE_KINDS = Object.freeze([ - 'transport', - 'auth', - 'rate-limit', -]); +const AIS_FAILURE_KINDS = Object.freeze(['transport', 'auth', 'rate-limit']); /** Statuses that must not flip back to a hopeful 'connecting' on a retry. */ const QUIET_TERMINAL = new Set(['down', 'auth-failed']); diff --git a/src/data/analystEngine.js b/src/data/analystEngine.js index 6a31c5a20..5175fec48 100644 --- a/src/data/analystEngine.js +++ b/src/data/analystEngine.js @@ -62,7 +62,7 @@ const COMMON_FIELDS = Object.freeze(['id', 'lat', 'lon']); /** Derived per-record field for layers with a time field (hours before now). */ const AGE_FIELD = 'ageHours'; /** Spatial scope kinds `query()` accepts. */ -export const ANALYST_SCOPE_KINDS = Object.freeze([ +const ANALYST_SCOPE_KINDS = Object.freeze([ 'view', 'region', 'radius', @@ -74,7 +74,7 @@ export const ANALYST_SCOPE_KINDS = Object.freeze([ * @param {string[]} layerKeys Queried layer ids. * @returns {string[]} Field names, common fields first. */ -export function analystFieldsFor(layerKeys) { +function analystFieldsFor(layerKeys) { const fields = new Set(COMMON_FIELDS); for (const key of layerKeys) { const layer = ANALYST_LAYERS[key]; @@ -104,44 +104,6 @@ export function haversineKm(lat1, lon1, lat2, lon2) { return greatCircleKm({ lat: lat1, lon: lon1 }, { lat: lat2, lon: lon2 }); } -/** - * One filter: {field, op:'gt'|'lt'|'gte'|'lte'|'eq'|'neq'|'contains', value}. - * With `time: true`, both sides compare as epoch ms (ISO strings accepted). - */ -export function applyFilter(records, filter, { time = false } = {}) { - const { field, op } = filter || {}; - if (!field || !op) return records; - const value = time ? toEpochMs(filter.value) : filter.value; - return records.filter((r) => { - const got = time ? toEpochMs(r[field]) : r[field]; - if (got === null || got === undefined || (time && !Number.isFinite(got))) - return false; - if (time && (op === 'eq' || op === 'neq')) - return (got === value) === (op === 'eq'); - switch (op) { - case 'gt': - return Number(got) > Number(value); - case 'gte': - return Number(got) >= Number(value); - case 'lt': - return Number(got) < Number(value); - case 'lte': - return Number(got) <= Number(value); - case 'eq': { - if (typeof got === 'boolean' || typeof value === 'boolean') - return Boolean(got) === Boolean(value); - return String(got).toLowerCase() === String(value).toLowerCase(); - } - case 'neq': - return String(got).toLowerCase() !== String(value).toLowerCase(); - case 'contains': - return String(got).toLowerCase().includes(String(value).toLowerCase()); - default: - return false; - } - }); -} - /** Scope records spatially. scope: {kind:'view'|'region'|'radius'|'anywhere', …}. */ export function applyScope(records, scope, resolved) { if (!scope || scope.kind === 'anywhere') return records; @@ -191,7 +153,7 @@ const COMMON_UNITS = Object.freeze({ * @param {string} field Field name. * @returns {'number'|'text'|'flag'|'time'|null} Field type. */ -export function analystFieldType(layerKeys, field) { +function analystFieldType(layerKeys, field) { if (!analystFieldsFor(layerKeys).includes(field)) return null; if (COMMON_TYPES[field]) return COMMON_TYPES[field]; for (const key of layerKeys) { diff --git a/src/data/bhoteKoshiLocator.js b/src/data/bhoteKoshiLocator.js index 79aab080f..369465680 100644 --- a/src/data/bhoteKoshiLocator.js +++ b/src/data/bhoteKoshiLocator.js @@ -14,7 +14,7 @@ import { BHOTE_KOSHI_FLOOD_PATH } from './bhoteKoshiFloodPath.js'; import { INCIDENT_OVERVIEW_PLACES } from './bhoteKoshiIncidentPlaces.js'; import { t, msg, getLocale } from '../i18n/index.js'; -export const BHOTE_KOSHI_LOCATOR_LAYER_ID = 'bhote-koshi-locator'; +const BHOTE_KOSHI_LOCATOR_LAYER_ID = 'bhote-koshi-locator'; export const BHOTE_KOSHI_LOCATOR_OVERLAY_SOURCE_ID = 'bhote-koshi-locator-callout'; export const NEPAL_CONTEXT_PRESENTATION = 'nepal-context'; @@ -1247,6 +1247,3 @@ export function createBhoteKoshiLocatorLayer({ }, }; } - -const bhoteKoshiLocatorLayer = createBhoteKoshiLocatorLayer(); -export default bhoteKoshiLocatorLayer; diff --git a/src/data/bikeshare.js b/src/data/bikeshare.js index 15c9dc802..6370c790e 100644 --- a/src/data/bikeshare.js +++ b/src/data/bikeshare.js @@ -23,4 +23,3 @@ export { BIKESHARE_SELECTED_OVERLAY_SOURCE_ID, BIKESHARE_SELECTED_OVERLAY_SOURCE_OPTIONS, } from '../layers/bikeshare/index.js'; -export default layer; diff --git a/src/data/cctvFootprint.js b/src/data/cctvFootprint.js index 42a3ad424..93f2b48ed 100644 --- a/src/data/cctvFootprint.js +++ b/src/data/cctvFootprint.js @@ -17,7 +17,7 @@ */ const EARTH_RADIUS_M = 6371000; -export const PLANE_VERT_ASPECT = 16 / 9; +const PLANE_VERT_ASPECT = 16 / 9; export const SUPPORT_KEYS = Object.freeze([ 'bl', 'bm', @@ -128,7 +128,7 @@ export function planeSupportPoints(pose) { * @param {number} capAltM @param {-1|0|1} row @param {{upVert:number}} dims * @returns {number} */ -export function supportAltitude(capAltM, row, dims) { +function supportAltitude(capAltM, row, dims) { return capAltM + row * dims.upVert; } diff --git a/src/data/cctvLod.js b/src/data/cctvLod.js index 44b2e8ba3..834dd964f 100644 --- a/src/data/cctvLod.js +++ b/src/data/cctvLod.js @@ -94,7 +94,7 @@ export function incumbentRankKm( export const CCTV_CARD_CENTER_WEIGHT = 0.5; /** Robust pool-distance percentile used to scale the screen-space term. */ -export const CCTV_CARD_SPREAD_PERCENTILE = 0.9; +const CCTV_CARD_SPREAD_PERCENTILE = 0.9; /** True only when both viewport dimensions are finite positive pixels. */ export function hasFiniteCctvViewport(viewW, viewH) { @@ -172,8 +172,8 @@ export function blendCenterRankKm( // viewport is bucketed into this grid and every occupied cell gets its best // candidate before global rank fills the rest. Owner-tunable together with // the budgets above. -export const CCTV_CARD_GRID_COLS = 5; -export const CCTV_CARD_GRID_ROWS = 4; +const CCTV_CARD_GRID_COLS = 5; +const CCTV_CARD_GRID_ROWS = 4; /** * Screen-space distribution pass (owner round 2, item C). Buckets the diff --git a/src/data/dataCredits.js b/src/data/dataCredits.js index 12dd7682a..aff87aeb7 100644 --- a/src/data/dataCredits.js +++ b/src/data/dataCredits.js @@ -25,11 +25,11 @@ import * as Cesium from 'cesium'; * follows DATA_SOURCES.md (live sources, then bundled snapshots). * @type {{ key: string, html: string }[]} */ -export const OSM_CREDIT = { +const OSM_CREDIT = { key: 'openstreetmap', html: 'Map and place data © OpenStreetMap contributors (ODbL)', }; -export const OPENMAPTILES_CREDIT = { +const OPENMAPTILES_CREDIT = { key: 'openfreemap', html: 'Vector tiles: OpenFreeMap © OpenMapTiles', }; diff --git a/src/data/detectionCohort.js b/src/data/detectionCohort.js index ed9f46c52..95cda50f0 100644 --- a/src/data/detectionCohort.js +++ b/src/data/detectionCohort.js @@ -18,7 +18,7 @@ export function stableIdentityHash(layerId, sourceId) { } /** Negative means a is a better deterministic contender than b. */ -export function compareCohortContenders(a, b) { +function compareCohortContenders(a, b) { const priorityDelta = (Number(b?._cohortPriority) || 0) - (Number(a?._cohortPriority) || 0); if (priorityDelta) return priorityDelta; diff --git a/src/data/detectionPolicy.js b/src/data/detectionPolicy.js index bf47785fd..0105d3beb 100644 --- a/src/data/detectionPolicy.js +++ b/src/data/detectionPolicy.js @@ -5,7 +5,6 @@ * module so density cannot drift into contradictory mode semantics again. */ -export const DENSITY_STOPS = Object.freeze([0, 25, 50, 75, 100]); export const ALLOCATION_ELASTIC = 'ELASTIC'; export const ALLOCATION_WEIGHTED = 'WEIGHTED'; export const ALLOCATION_STRATEGIES = Object.freeze([ @@ -118,7 +117,7 @@ export function detectionHorizontalSector(screenX, viewportWidth) { return 'front'; } -export const VIEW_SCALE_BUDGETS = Object.freeze({ +const VIEW_SCALE_BUDGETS = Object.freeze({ street: Object.freeze({ 0: 9, 25: 23, 50: 45, 75: 68, 100: 90 }), city: Object.freeze({ 0: 7, 25: 18, 50: 35, 75: 53, 100: 70 }), metro: Object.freeze({ 0: 6, 25: 14, 50: 28, 75: 41, 100: 55 }), diff --git a/src/data/directions.js b/src/data/directions.js index ef5565488..8a871bfbf 100644 --- a/src/data/directions.js +++ b/src/data/directions.js @@ -24,7 +24,7 @@ import * as input from './inputOwnership.js'; import { createDirectionsLayer } from '../layers/directions/index.js'; /** The shared scene owners every Directions instance runs on. */ -export const directionsServices = Object.freeze({ +const directionsServices = Object.freeze({ credits, render, sprites, @@ -49,15 +49,11 @@ export { DIRECTIONS_MODES, DIRECTIONS_POINTER_OWNER, DIRECTIONS_ROUTE_COLOR, - DIRECTIONS_STEP_OVERLAY_SOURCE_ID, - DIRECTIONS_STEP_OVERLAY_SOURCE_OPTIONS, - FLIGHT_PROGRESS_MS, POINTER_TOOL_EXITS, STEP_ANCHOR_DEADLINE_MS, STEP_ANCHOR_FAST_ATTEMPTS, STEP_ANCHOR_RETRY_MS, STEP_ANCHOR_SLOW_RETRY_MS, - createDirectionsLayer, createDirectionsStepOverlayEntry, directionsRequestUrl, directionsRowControls, diff --git a/src/data/earthquakes.js b/src/data/earthquakes.js index f003bf712..aac775d92 100644 --- a/src/data/earthquakes.js +++ b/src/data/earthquakes.js @@ -8,4 +8,3 @@ export function createEarthquakesLayer({ } = {}) { return createApplicationEarthquakes({ source, ...options }); } -export default createEarthquakesLayer(); diff --git a/src/data/geoFileImport.js b/src/data/geoFileImport.js index fc6a5e079..cf7037388 100644 --- a/src/data/geoFileImport.js +++ b/src/data/geoFileImport.js @@ -5,9 +5,9 @@ import { createImportedPins } from './geoImportPins.js'; import { msg } from '../i18n/marker.js'; /** Largest file accepted, in bytes. */ -export const MAX_IMPORT_BYTES = 50 * 1024 * 1024; +const MAX_IMPORT_BYTES = 50 * 1024 * 1024; /** Largest total a KMZ may inflate to — a zip bomb stops here. */ -export const MAX_KMZ_INFLATED_BYTES = 120 * 1024 * 1024; +const MAX_KMZ_INFLATED_BYTES = 120 * 1024 * 1024; /** Most files on the globe at once. */ export const MAX_IMPORTED_FILES = 12; /** Most entities one file may create before it is refused. */ @@ -15,9 +15,9 @@ export const MAX_IMPORT_ENTITIES = 20_000; /** Most vertices (points of every line, ring and marker) in one file. */ export const MAX_IMPORT_POSITIONS = 250_000; /** Most normalized style definitions and local image links in one KML/KMZ. */ -export const MAX_KML_LINKS = 2_000; +const MAX_KML_LINKS = 2_000; /** Longest plain-text name kept from a file's features. */ -export const MAX_IMPORT_NAME_LENGTH = 120; +const MAX_IMPORT_NAME_LENGTH = 120; /** What the file picker offers. */ export const GEO_FILE_ACCEPT = '.geojson,.json,.kml,.kmz,.gpx'; diff --git a/src/data/geoImportImages.js b/src/data/geoImportImages.js index 86f8e98e2..71133df26 100644 --- a/src/data/geoImportImages.js +++ b/src/data/geoImportImages.js @@ -1,5 +1,5 @@ // Inspect encoded headers before allowing the browser to decode local images. -export const MAX_IMPORT_IMAGE_PIXELS = 16 * 1024 * 1024; +const MAX_IMPORT_IMAGE_PIXELS = 16 * 1024 * 1024; const MAX_SIDE = 8192; /** Width and height from a supported raster header; no image is decoded. */ diff --git a/src/data/gtfsRealtime.js b/src/data/gtfsRealtime.js index 96d6b28a5..1fe888d4a 100644 --- a/src/data/gtfsRealtime.js +++ b/src/data/gtfsRealtime.js @@ -35,14 +35,14 @@ import { PbfReader } from 'pbf'; /** VehiclePosition.VehicleStopStatus enum → label. */ -export const VEHICLE_STOP_STATUS = Object.freeze({ +const VEHICLE_STOP_STATUS = Object.freeze({ 0: 'INCOMING_AT', 1: 'STOPPED_AT', 2: 'IN_TRANSIT_TO', }); /** VehiclePosition.OccupancyStatus enum → label. */ -export const OCCUPANCY_STATUS = Object.freeze({ +const OCCUPANCY_STATUS = Object.freeze({ 0: 'EMPTY', 1: 'MANY_SEATS_AVAILABLE', 2: 'FEW_SEATS_AVAILABLE', @@ -64,7 +64,6 @@ export const GTFS_MAX_ENTITIES = 50_000; export const GTFS_MAX_STRING_CHARS = 256; /** FeedHeader.Incrementality: only FULL_DATASET carries a complete snapshot. */ export const GTFS_INCREMENTALITY_FULL_DATASET = 0; -export const GTFS_INCREMENTALITY_DIFFERENTIAL = 1; /** * Read a length-delimited string, refusing one that is implausibly long. diff --git a/src/data/localGeojson.js b/src/data/localGeojson.js index 8871cfe39..61f6c3abf 100644 --- a/src/data/localGeojson.js +++ b/src/data/localGeojson.js @@ -1,5 +1,4 @@ import { localGeoJsonServices } from '../app/localGeojsonServices.js'; -export { localGeoJsonServices } from '../app/localGeojsonServices.js'; import { createLocalGeoJsonLayer as createLayer, createLocalInfrastructureOverlayPublisher as createPublisher, diff --git a/src/data/militaryNames.js b/src/data/militaryNames.js index b26ab04e6..d4b4b8846 100644 --- a/src/data/militaryNames.js +++ b/src/data/militaryNames.js @@ -7,7 +7,7 @@ import { createRetryableLoader } from './retryableLoad.js'; export const MILITARY_POINT_CAP = 512; export const MILITARY_LABEL_CAP = 24; -export const MILITARY_NAMES_TIMEOUT_MS = 10_000; +const MILITARY_NAMES_TIMEOUT_MS = 10_000; /** Share a bounded acquisition; failed assets become retryable after cooldown. */ export function createMilitaryNamesLoader({ diff --git a/src/data/radioCountry.js b/src/data/radioCountry.js index 55d9b36a5..1f77d8e98 100644 --- a/src/data/radioCountry.js +++ b/src/data/radioCountry.js @@ -117,8 +117,3 @@ export function normalizeRadioCountryInput(value) { name: canonicalCountryName(code), }); } - -/** Return whether a value is a recognized ISO 3166-1 alpha-2 code. */ -export function isRadioCountryCode(value) { - return typeof value === 'string' && ISO_ALPHA_2_SET.has(value.toUpperCase()); -} diff --git a/src/data/telegeographySubmarineCables.js b/src/data/telegeographySubmarineCables.js index 6aaba700f..6bee7c56d 100644 --- a/src/data/telegeographySubmarineCables.js +++ b/src/data/telegeographySubmarineCables.js @@ -28,4 +28,3 @@ export { createCableReferenceSweepGate, updateCableReferenceStem, } from '../layers/submarineCables/index.js'; -export default createTeleGeographySubmarineCableLayer(); diff --git a/src/data/wind.js b/src/data/wind.js index 38bc10688..59b9aaf5d 100644 --- a/src/data/wind.js +++ b/src/data/wind.js @@ -1,5 +1,4 @@ import { createSourceSlot } from '../sources/sourceSlot.js'; -import { createWindLayer as createLayer } from '../layers/wind/index.js'; import { createWindSource } from '../layers/wind/source.js'; const sourceSlot = createSourceSlot( @@ -8,10 +7,3 @@ const sourceSlot = createSourceSlot( 'Wind source', ); export const configureWindSource = sourceSlot.configure; - -/** Create a wind layer using the configured application source by default. */ -export function createWindLayer(options = {}) { - return createLayer({ ...options, feed: options.feed ?? sourceSlot.source }); -} - -export default createWindLayer(); diff --git a/src/i18n/index.js b/src/i18n/index.js index d5698aa5b..48b63b2f6 100644 --- a/src/i18n/index.js +++ b/src/i18n/index.js @@ -210,7 +210,7 @@ export function formatRelativeTime(value, unit = 'second', options) { } /** Collapse markup whitespace so a message reads the same in HTML and JS. */ -export function normalizeMarkupText(text) { +function normalizeMarkupText(text) { return String(text ?? '') .replace(/\s+/g, ' ') .trim(); diff --git a/src/layers/alpr/records.js b/src/layers/alpr/records.js index 0d751f12d..10cd88062 100644 --- a/src/layers/alpr/records.js +++ b/src/layers/alpr/records.js @@ -1,11 +1,11 @@ import { QUERY_LIMIT, QUERY_SNAP_DEGREES } from './policy.js'; -export function textTag(value) { +function textTag(value) { const t = String(value ?? '').trim(); return t || null; } -export function numTag(value) { +function numTag(value) { // `Number('')` and `Number(' ')` are 0, not NaN — a blank or whitespace-only // tag value must read as missing, never as a due-north bearing. if (value == null) return null; @@ -102,7 +102,7 @@ export function normalizeAlprNode(el) { }; } -export function normalizeDirection(value) { +function normalizeDirection(value) { const degrees = numTag(value); return degrees != null && degrees >= 0 && degrees <= 360 ? degrees % 360 diff --git a/src/layers/alpr/tileRecords.js b/src/layers/alpr/tileRecords.js index 5db9192b3..0368f53fb 100644 --- a/src/layers/alpr/tileRecords.js +++ b/src/layers/alpr/tileRecords.js @@ -3,7 +3,7 @@ import { VectorTile } from '@mapbox/vector-tile'; import { normalizeAlprNode } from './records.js'; /** Map extract attributes without treating an OSM edit date as a field verification. */ -export function normalizeAlprTileFeature(feature) { +function normalizeAlprTileFeature(feature) { const p = feature?.properties || {}; if (feature?.geometry?.type !== 'Point' || p.osmType !== 'node') return null; const [lon, lat] = feature.geometry.coordinates; diff --git a/src/layers/awareness/policy.js b/src/layers/awareness/policy.js index eda5a46e6..22cc8eb98 100644 --- a/src/layers/awareness/policy.js +++ b/src/layers/awareness/policy.js @@ -1,9 +1,6 @@ export const AIRCRAFT_DEPENDENCIES = ['flights', 'military']; -export const DEFERRED_DEPENDENCIES = [ - 'ais-live-vessels', - 'military-installations', -]; +const DEFERRED_DEPENDENCIES = ['ais-live-vessels', 'military-installations']; export const DEPENDENCIES = [ ...AIRCRAFT_DEPENDENCIES, diff --git a/src/layers/bikeshare/policy.js b/src/layers/bikeshare/policy.js index 14f1edf6e..1b9c1579f 100644 --- a/src/layers/bikeshare/policy.js +++ b/src/layers/bikeshare/policy.js @@ -11,7 +11,7 @@ export const BIKESHARE_SELECTED_OVERLAY_SOURCE_OPTIONS = Object.freeze({ // --- Activation / display thresholds --- /** Altitude (m) at which bikeshare layer becomes eligible for display. */ -export const ACTIVATION_ALTITUDE_M = 50000; +const ACTIVATION_ALTITUDE_M = 50000; /** Hysteresis enter threshold — layer activates when camera drops below this. */ diff --git a/src/layers/cctv/policy.js b/src/layers/cctv/policy.js index 96d7985f1..bc369c02a 100644 --- a/src/layers/cctv/policy.js +++ b/src/layers/cctv/policy.js @@ -1,10 +1,4 @@ -export { - FRAME_ENDPOINT, - SOURCE_ENDPOINT, - HEALTH_ENDPOINT, - MEDIA_ENDPOINT, - ACTIVE_FRAME_REFRESH_MS, -} from './sourcePolicy.js'; +export { ACTIVE_FRAME_REFRESH_MS } from './sourcePolicy.js'; import * as Cesium from 'cesium'; import { CCTV_CARD_FETCH_BURST_SPACING_MS } from '../../data/cctvCards.js'; import { CCTV_AMBIENT_CARD_MAX } from '../../data/cctvLod.js'; @@ -90,9 +84,6 @@ export const CCTV_CALIBRATION_STORAGE_KEY_V2 = export const PROJECTION_TEXTURE_SWAP_MS = 1000; -export const PROJECTION_VERT_ASPECT = - PROJECTION_CANVAS_WIDTH / PROJECTION_CANVAS_HEIGHT; - // V2 frustum geometry (design §2a/§6): the far-cap center + corners never sink // below groundAlt + this clearance, so a fabricated pitch (-24°) cannot bury // the monitor plane in the 3D tiles. Exported for the unit suite. diff --git a/src/layers/cctv/sourcePolicy.js b/src/layers/cctv/sourcePolicy.js index 5ce0cd024..3341a4ce9 100644 --- a/src/layers/cctv/sourcePolicy.js +++ b/src/layers/cctv/sourcePolicy.js @@ -1,9 +1,5 @@ export const FRAME_ENDPOINT = '/api/cctv/frame'; -export const SOURCE_ENDPOINT = '/api/cctv/sources'; - -export const HEALTH_ENDPOINT = '/api/cctv/health'; - export const MEDIA_ENDPOINT = '/api/cctv/media'; export const ACTIVE_FRAME_REFRESH_MS = 10000; diff --git a/src/layers/cyclones/labels.js b/src/layers/cyclones/labels.js index e95b5a28c..cb418865f 100644 --- a/src/layers/cyclones/labels.js +++ b/src/layers/cyclones/labels.js @@ -64,7 +64,7 @@ const SHARED_CARD = Object.freeze({ * @param {boolean} selected * @returns {object} */ -export function cycloneStormEntry(storm, selected) { +function cycloneStormEntry(storm, selected) { return { ...SHARED_CARD, ...markerClearance( @@ -92,7 +92,7 @@ export function cycloneStormEntry(storm, selected) { * @param {{tauHours:number,position:object}} point * @returns {object} */ -export function cycloneLeadEntry(stormId, point) { +function cycloneLeadEntry(stormId, point) { return { ...SHARED_CARD, ...markerClearance(CYCLONE_MARKER_PX.forecast), diff --git a/src/layers/flights/policy.js b/src/layers/flights/policy.js index 2c015e6c9..2ecb0a8a4 100644 --- a/src/layers/flights/policy.js +++ b/src/layers/flights/policy.js @@ -1,11 +1,3 @@ -export { - GROUND_FLOOR_CLAMP_RADIUS_KM, - GROUND_FLOOR_WARM_MAX_ALT_M, - POSITION_HISTORY_LIMIT, - LANDED_MISSING_POLL_LIMIT, - MISSING_POLL_LIMIT, - ERROR_BACKOFF_INTERVAL, -} from './recordPolicy.js'; import * as Cesium from 'cesium'; import { EMERGENCY_TINT_CSS } from '../../data/aircraftEmergency.js'; diff --git a/src/layers/installations/policy.js b/src/layers/installations/policy.js index fae021cf3..92da9dd7b 100644 --- a/src/layers/installations/policy.js +++ b/src/layers/installations/policy.js @@ -2,8 +2,6 @@ export const LAYER_ID = 'military-installations'; export const REQUEST_DEBOUNCE_MS = 180; -export const MAX_VIEWPORT_DEGREES = 10; - export const MAX_RENDERED = 700; export const GOOGLE_MILITARY_PLACE_TYPES = new Set(['military_base']); diff --git a/src/layers/localAdsb/feeds.js b/src/layers/localAdsb/feeds.js index 4bb4bced7..5899729af 100644 --- a/src/layers/localAdsb/feeds.js +++ b/src/layers/localAdsb/feeds.js @@ -5,12 +5,12 @@ import { /** Same-origin route served by `server/providers/local-receivers.js`. */ export const LOCAL_RECEIVERS_URL = '/api/local-receivers/aircraft'; -export const LOCAL_RECEIVER_POLL_MS = 1_000; +const LOCAL_RECEIVER_POLL_MS = 1_000; /** * Browser-side deadline for one route request, body included. The server * bounds each upstream read at 2 s; this bounds the browser-to-server leg. */ -export const LOCAL_RECEIVER_REQUEST_TIMEOUT_MS = 5_000; +const LOCAL_RECEIVER_REQUEST_TIMEOUT_MS = 5_000; function abortError() { const error = new Error('Local receiver request aborted'); diff --git a/src/layers/localAdsb/index.js b/src/layers/localAdsb/index.js index fcf54b5d5..4db1e2852 100644 --- a/src/layers/localAdsb/index.js +++ b/src/layers/localAdsb/index.js @@ -36,18 +36,8 @@ import { } from './policy.js'; import { localAdsbStatus } from './status.js'; -export { - LAYER_ID as LOCAL_ADSB_LAYER_ID, - HEARD_BY_RECEIVER, -} from './policy.js'; -export { - localAdsbCardModel, - localAdsbClassLine, - localAdsbIsUat, - localAdsbReceiverLine, - localAdsbTitle, -} from './card.js'; -export { localAdsbClass } from './enrichment.js'; +export { HEARD_BY_RECEIVER } from './policy.js'; +export { localAdsbCardModel, localAdsbReceiverLine } from './card.js'; export { localAdsbStatus } from './status.js'; const FEET_TO_METERS = 0.3048; diff --git a/src/layers/localAdsb/motion.js b/src/layers/localAdsb/motion.js index 279bef6d3..084f3aa7e 100644 --- a/src/layers/localAdsb/motion.js +++ b/src/layers/localAdsb/motion.js @@ -26,7 +26,7 @@ import { export const LOCAL_ADSB_HISTORY_MS = 10 * 60_000; export const LOCAL_ADSB_HISTORY_POINTS = 600; /** A display correction larger than this snaps instead of sliding. */ -export const LOCAL_ADSB_SNAP_M = 3_000; +const LOCAL_ADSB_SNAP_M = 3_000; /** Chord course uses the newest fix at least this much older than the anchor. */ const CHORD_BASELINE_MS = 2_000; /** Turn rate is estimated over this window of heard fixes. */ diff --git a/src/layers/localAdsb/status.js b/src/layers/localAdsb/status.js index d264c5e15..2e084cffb 100644 --- a/src/layers/localAdsb/status.js +++ b/src/layers/localAdsb/status.js @@ -24,7 +24,7 @@ function plural(count, one, many) { * @param {object[]} feeds Feed statuses from the route. * @returns {string} */ -export function describeFeedProblems(feeds) { +function describeFeedProblems(feeds) { const byStatus = new Map(); for (const feed of feeds) { if (feed?.status === 'live') continue; @@ -41,7 +41,7 @@ export function describeFeedProblems(feeds) { } /** Whether the server reported at least one configured feed. */ -export function feedsConfigured(feedState) { +function feedsConfigured(feedState) { return Boolean( feedState?.configured === true && Array.isArray(feedState.feeds) && diff --git a/src/layers/military/policy.js b/src/layers/military/policy.js index f375e5419..bb1d89127 100644 --- a/src/layers/military/policy.js +++ b/src/layers/military/policy.js @@ -1,10 +1,3 @@ -export { - GROUND_FLOOR_WARM_MAX_ALT_M, - POSITION_HISTORY_LIMIT, - LANDED_MISSING_POLL_LIMIT, - MISSING_POLL_LIMIT, - ERROR_BACKOFF_INTERVAL, -} from './recordPolicy.js'; import * as Cesium from 'cesium'; import { EMERGENCY_TINT_CSS } from '../../data/aircraftEmergency.js'; diff --git a/src/layers/radio/policy.js b/src/layers/radio/policy.js index 85777ed74..0d4ad174a 100644 --- a/src/layers/radio/policy.js +++ b/src/layers/radio/policy.js @@ -10,7 +10,7 @@ export const MARKER_LIFT_M = 2.5; export const SELECTED_LIFT_M = 5; -export const RADIO_PICK_TOLERANCE_PX = 8; +const RADIO_PICK_TOLERANCE_PX = 8; export const RADIO_TUNER_DIRECTORY_LIMIT = 750; diff --git a/src/layers/recentImagery/model.js b/src/layers/recentImagery/model.js index 406dc3e19..3fbcf1123 100644 --- a/src/layers/recentImagery/model.js +++ b/src/layers/recentImagery/model.js @@ -300,7 +300,7 @@ export function hhmm(iso) { } /** Candidate key: `PRODUCT:YYYY-MM-DD`. */ -export function candidateKey(product, day) { +function candidateKey(product, day) { return `${product}:${day}`; } diff --git a/src/layers/satellites/policy.js b/src/layers/satellites/policy.js index 656374fc6..e7ea5456d 100644 --- a/src/layers/satellites/policy.js +++ b/src/layers/satellites/policy.js @@ -94,9 +94,9 @@ export const TRACK_VIEW_FROM_HIGH_SCALE = 4; * attribute, so classification costs nothing per frame. */ -export const POINT_OUTLINE = Cesium.Color.WHITE.withAlpha(0.3); +const POINT_OUTLINE = Cesium.Color.WHITE.withAlpha(0.3); -export const _classColor = (group) => +const _classColor = (group) => Cesium.Color.fromCssColorString(satelliteClassColor(group)); export const POINT_STYLES = { diff --git a/src/layers/streetLevel/photoViewer.js b/src/layers/streetLevel/photoViewer.js index c083879db..0ca4e3eb2 100644 --- a/src/layers/streetLevel/photoViewer.js +++ b/src/layers/streetLevel/photoViewer.js @@ -17,18 +17,18 @@ const EXPANDED_SELECTORS = [ ]; /** A photo download (tens of kilobytes to a few megabytes). */ -export const IMAGE_TIMEOUT_MS = 15_000; +const IMAGE_TIMEOUT_MS = 15_000; /** A picture file or decoded side past these is refused (a photo is a few MB). */ export const MAX_IMAGE_BYTES = 48 * 1024 * 1024; export const MAX_IMAGE_SIDE = 16_384; /** 64 MP: 256 MB once decoded to RGBA. A 16,384 px square is four times that. */ -export const MAX_IMAGE_PIXELS = 8_192 * 8_192; +const MAX_IMAGE_PIXELS = 8_192 * 8_192; /** Where in a file to look for its dimensions (a JPEG's EXIF comes first). */ const HEADER_BYTES = 256 * 1024; /** Whether a picture this size is past what the viewer decodes. */ -export function tooManyPixels(width, height) { +function tooManyPixels(width, height) { return ( width > MAX_IMAGE_SIDE || height > MAX_IMAGE_SIDE || @@ -37,7 +37,7 @@ export function tooManyPixels(width, height) { } /** Panorama texture widths: enough for a docked viewer, and for an expanded one. */ -export const PANO_MID_SIZE = Object.freeze([2048, 1024]); +const PANO_MID_SIZE = Object.freeze([2048, 1024]); export const PANO_FULL_SIZE = Object.freeze([4096, 2048]); /** @@ -155,7 +155,7 @@ async function loadBitmap(url, timeoutMs, resize, failure, signal) { * A picture refused for its size (`tooLarge`): the viewer will not load * that file another way, an having no size limit at all. */ -export function oversized(failure) { +function oversized(failure) { return Object.assign(new Error(failure), { tooLarge: true }); } diff --git a/src/layers/streetLevel/providers/kartaview/policy.js b/src/layers/streetLevel/providers/kartaview/policy.js index 939e0ec1c..b4533c1b5 100644 --- a/src/layers/streetLevel/providers/kartaview/policy.js +++ b/src/layers/streetLevel/providers/kartaview/policy.js @@ -14,7 +14,7 @@ export const KARTAVIEW_LABEL = 'KARTAVIEW'; */ export const KARTAVIEW_API_HOST = 'https://api.kartaview.org'; /** KartaView's image proxy: resizes a photo given its base64url address. */ -export const KARTAVIEW_CDN_HOST = 'https://cdn.kartaview.org'; +const KARTAVIEW_CDN_HOST = 'https://cdn.kartaview.org'; /** Stable id prefixes for picked primitives; every one starts with `kv:`. */ export const PICK_PREFIX = Object.freeze({ @@ -140,8 +140,6 @@ export const MASK_SLOW_MESSAGE = msg( export const FILTERED_OUT_MESSAGE = msg( 'None of KartaView’s photos here pass the imagery filter', ); -/** Under the SINCE slider while KartaView is lit. */ -export const SINCE_NOTE = '(by upload date)'; /** The UTC calendar day of `ms`, as KartaView's startDate reads it. */ function utcDay(ms) { diff --git a/src/layers/streetLevel/providers/panoramax/index.js b/src/layers/streetLevel/providers/panoramax/index.js index 4dfa023ef..e855c9c72 100644 --- a/src/layers/streetLevel/providers/panoramax/index.js +++ b/src/layers/streetLevel/providers/panoramax/index.js @@ -41,8 +41,6 @@ import { normalizeItem, } from './policy.js'; -export { PANORAMAX_PROVIDER_ID } from './policy.js'; - /** * A tile's bytes decoded by `decode`; a body that is not a vector tile * (an HTML error page, a cut-off answer) reads as such, not as a parser's diff --git a/src/layers/streetLevel/providers/panoramax/policy.js b/src/layers/streetLevel/providers/panoramax/policy.js index e9a51c10e..670772c6a 100644 --- a/src/layers/streetLevel/providers/panoramax/policy.js +++ b/src/layers/streetLevel/providers/panoramax/policy.js @@ -15,7 +15,7 @@ export const PANORAMAX_LABEL = 'PANORAMAX'; */ export const PANORAMAX_API = 'https://api.panoramax.xyz/api'; /** The meta-catalogue's web viewer, where the caption link goes. */ -export const PANORAMAX_VIEWER = 'https://api.panoramax.xyz/'; +const PANORAMAX_VIEWER = 'https://api.panoramax.xyz/'; /** Stable id prefixes for picked primitives; every one starts with `pnx:`. */ export const PICK_PREFIX = Object.freeze({ diff --git a/src/layers/streetLevel/registry.js b/src/layers/streetLevel/registry.js index 6770cd133..5e51929a6 100644 --- a/src/layers/streetLevel/registry.js +++ b/src/layers/streetLevel/registry.js @@ -1,6 +1,6 @@ import { encodeIdSwitches } from '../../data/idSwitches.js'; -export const IMAGERY_FILTERS = Object.freeze(['pano', 'since']); +const IMAGERY_FILTERS = Object.freeze(['pano', 'since']); export function filtersOf(provider) { return provider?.filters ?? IMAGERY_FILTERS; diff --git a/src/layers/streetLevel/sequenceCones.js b/src/layers/streetLevel/sequenceCones.js index b18f2cc57..b6c068d49 100644 --- a/src/layers/streetLevel/sequenceCones.js +++ b/src/layers/streetLevel/sequenceCones.js @@ -5,8 +5,8 @@ import { createHorizonCull, metresBetween } from './view.js'; import { msg } from '../../i18n/index.js'; /** Cones closer than this to the previous kept one are dropped. */ -export const IMAGE_CONE_MIN_SPACING_M = 3; -export const IMAGE_CONE_SIZE_PX = 26; +const IMAGE_CONE_MIN_SPACING_M = 3; +const IMAGE_CONE_SIZE_PX = 26; /** * @typedef {object} ConeImage One image of a sequence, as the cones draw it. diff --git a/src/layers/streetLevel/tileCache.js b/src/layers/streetLevel/tileCache.js index d6c0a91e5..6ee0897ef 100644 --- a/src/layers/streetLevel/tileCache.js +++ b/src/layers/streetLevel/tileCache.js @@ -1,6 +1,6 @@ /** Decoded coverage tiles kept, and for how long. */ -export const TILE_CACHE_SIZE = 24; -export const TILE_CACHE_TTL_MS = 10 * 60_000; +const TILE_CACHE_SIZE = 24; +const TILE_CACHE_TTL_MS = 10 * 60_000; /** Least-recently-used map: reading an entry renews it. */ export function createLru(limit) { diff --git a/src/layers/streetLevel/uiState.js b/src/layers/streetLevel/uiState.js index 577bb8ae1..04c6ed6c4 100644 --- a/src/layers/streetLevel/uiState.js +++ b/src/layers/streetLevel/uiState.js @@ -64,7 +64,7 @@ export function keyAlternatives(providers) { * The filter controls a switched-on provider honours (both when none is on). * @param {Array} providers */ -export function filterControls(providers) { +function filterControls(providers) { const active = providers.filter((p) => p.on); const honoured = (key) => active.length === 0 || @@ -78,7 +78,7 @@ export function filterControls(providers) { * note needs no provider name. * @param {Array} providers */ -export function sinceNote(providers) { +function sinceNote(providers) { return providers.some((p) => p.on && p.sinceBasis === 'upload') ? t('(by upload date)') : null; diff --git a/src/layers/submarineCables/geometry.js b/src/layers/submarineCables/geometry.js index 08366dba4..b4b434710 100644 --- a/src/layers/submarineCables/geometry.js +++ b/src/layers/submarineCables/geometry.js @@ -33,7 +33,7 @@ export function featureReference(feature) { }; } -export function coordsFromProperty(value) { +function coordsFromProperty(value) { if (!Array.isArray(value) || value.length < 2) return null; const lon = Number(value[0]); const lat = Number(value[1]); @@ -41,7 +41,7 @@ export function coordsFromProperty(value) { return [lon, lat]; } -export function coordsFromPoint(value) { +function coordsFromPoint(value) { if (!Array.isArray(value) || value.length < 2) return null; const lon = Number(value[0]); const lat = Number(value[1]); @@ -49,7 +49,7 @@ export function coordsFromPoint(value) { return [lon, lat]; } -export function collectLonLat(value, out) { +function collectLonLat(value, out) { if (!Array.isArray(value)) return; if (typeof value[0] === 'number' && typeof value[1] === 'number') { const lon = Number(value[0]); diff --git a/src/layers/traffic/footprint.js b/src/layers/traffic/footprint.js index d75947941..9a241d997 100644 --- a/src/layers/traffic/footprint.js +++ b/src/layers/traffic/footprint.js @@ -1,9 +1,9 @@ import * as Cesium from 'cesium'; import { tilesForBounds, tileToBBox } from '../../data/tomtomTiles.js'; -export const RETICLE_RANGE_KM = 10; -export const RETICLE_TILE_CAP = 16; -export const tileKey = (tile) => `${tile.z}/${tile.x}/${tile.y}`; +const RETICLE_RANGE_KM = 10; +const RETICLE_TILE_CAP = 16; +const tileKey = (tile) => `${tile.z}/${tile.x}/${tile.y}`; const cross = (a, b, c) => (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]); diff --git a/src/layers/traffic/policy.js b/src/layers/traffic/policy.js index 81b01f299..c20b15e41 100644 --- a/src/layers/traffic/policy.js +++ b/src/layers/traffic/policy.js @@ -175,13 +175,3 @@ export const STYLED_MIN_BASE_PX = 5; /** @const {number} Maximum tile cache entries before LRU eviction */ export const TILE_CACHE_MAX_ENTRIES = 64; - -/** - * Milliseconds the first dot paint will wait for flow data. Cached flow - * settles within this window (decode cache, 120 s TTL) and renders fully - * colored; a cold tile fetch loses the race, dots paint immediately in - * white, and recolorDotsInPlace applies the colors when flow arrives — - * field-test round 1's "takes forever to load" was the sequential wait. - */ - -export const FLOW_RENDER_RACE_MS = 250; diff --git a/src/layers/transit/policy.js b/src/layers/transit/policy.js index 2fb5101ce..010a2efc2 100644 --- a/src/layers/transit/policy.js +++ b/src/layers/transit/policy.js @@ -99,7 +99,7 @@ export const VISIBILITY_REFRESH_MS = 250; * on screen. Generous on purpose: a vehicle that crosses the edge mid-glide * should already have been moving, not pop into motion at the border. */ -export const VIEW_MARGIN_RATIO = 0.6; +const VIEW_MARGIN_RATIO = 0.6; /** * Whether a vehicle is close enough to the camera's look-at area to be worth @@ -516,10 +516,10 @@ export function createTransitSelectedOverlayEntry(key, position, copy, mode) { } /** Modes that ordinarily run below the street, drawn on the surface above themselves. */ -export const UNDERGROUND_MODES = new Set(['subway']); +const UNDERGROUND_MODES = new Set(['subway']); /** The mode in plain words, for a card a person reads rather than scans. */ -export const TRANSIT_MODE_WORD = Object.freeze({ +const TRANSIT_MODE_WORD = Object.freeze({ bus: msg('Bus'), tram: msg('Tram'), subway: msg('Subway'), @@ -529,7 +529,7 @@ export const TRANSIT_MODE_WORD = Object.freeze({ }); /** Short, fixed-width mode word for the detection card's class field. */ -export const TRANSIT_MODE_ABBR = Object.freeze({ +const TRANSIT_MODE_ABBR = Object.freeze({ bus: 'BUS', tram: 'TRAM', subway: 'METRO', @@ -588,7 +588,7 @@ export function transitDetectionId(record, feed = null) { } /** Longest route text the single-line detection label can carry. */ -export const DETECTION_ID_MAX_CHARS = 14; +const DETECTION_ID_MAX_CHARS = 14; /** * Cut long route text with an ellipsis, so a reader can see it was cut. @@ -600,7 +600,7 @@ export const DETECTION_ID_MAX_CHARS = 14; * @param {string} text * @returns {string} Uppercase, at most DETECTION_ID_MAX_CHARS characters. */ -export function elideRouteText(text) { +function elideRouteText(text) { const value = String(text || '').toUpperCase(); if (value.length <= DETECTION_ID_MAX_CHARS) return value; return `${value.slice(0, DETECTION_ID_MAX_CHARS - 1)}\u2026`; @@ -659,6 +659,6 @@ export function transitDetectionMetric( * @param {number} [nowMs] * @returns {string} */ -export function transitVehicleState(entry, nowMs = Date.now()) { +function transitVehicleState(entry, nowMs = Date.now()) { return displayMotion(entry, nowMs).word; } diff --git a/src/layers/vessels/policy.js b/src/layers/vessels/policy.js index 75e5cdd67..9ab06fbb8 100644 --- a/src/layers/vessels/policy.js +++ b/src/layers/vessels/policy.js @@ -1,8 +1,3 @@ -export { - PARTIAL_RETENTION_MS, - SELECTED_PIN_REFRESHES, - AIS_FIRST_CONNECT_LABEL, -} from './recordPolicy.js'; import { VESSEL_LABEL_GRID_PX } from '../../data/vesselLabels.js'; import { msg } from '../../i18n/index.js'; diff --git a/src/layers/weather/source.js b/src/layers/weather/source.js index cf004476f..5386bfad7 100644 --- a/src/layers/weather/source.js +++ b/src/layers/weather/source.js @@ -4,7 +4,7 @@ import { readResponseJsonCapped } from '../../sources/httpBody.js'; // the weather layer translates them where it shows them (t / translateKnown). const msg = (text) => text; -export const WEATHER_PRODUCTS = Object.freeze([ +const WEATHER_PRODUCTS = Object.freeze([ 'radar', 'clouds', 'clouds-regional', diff --git a/src/layers/wind/gpuRendering.js b/src/layers/wind/gpuRendering.js index 27d71dcd5..0873fa63b 100644 --- a/src/layers/wind/gpuRendering.js +++ b/src/layers/wind/gpuRendering.js @@ -6,8 +6,8 @@ import { WIND_NARROW_PATH_LIMIT, } from './streamlines.js'; -export const WIND_FADE_LOW_METERS = 15000; -export const WIND_FADE_HIGH_METERS = 60000; +const WIND_FADE_LOW_METERS = 15000; +const WIND_FADE_HIGH_METERS = 60000; // Original material: a persistent fine curve plus a moving, tapered highlight. // The integer part of s identifies a path; its fractional part follows the wind. diff --git a/src/locationStatus.js b/src/locationStatus.js index 1d90582c9..2c9e406f3 100644 --- a/src/locationStatus.js +++ b/src/locationStatus.js @@ -64,5 +64,3 @@ export function locationMiniStatus({ return { ...EMPTY }; } - -export default locationMiniStatus; diff --git a/src/maps/imageryComparison.js b/src/maps/imageryComparison.js index 5586bd86e..cf7d266ae 100644 --- a/src/maps/imageryComparison.js +++ b/src/maps/imageryComparison.js @@ -1,5 +1,5 @@ /** Basemap that before/after imagery comparisons are read against. */ -export const IMAGERY_COMPARISON_STACK_ID = 'esri-imagery'; +const IMAGERY_COMPARISON_STACK_ID = 'esri-imagery'; const SWITCH_POLICIES = new Set(['preserve', 'esri', 'esri-if-photoreal']); const leases = new WeakMap(); diff --git a/src/maps/terrainRetry.js b/src/maps/terrainRetry.js index 26fc95576..6cf0fe2af 100644 --- a/src/maps/terrainRetry.js +++ b/src/maps/terrainRetry.js @@ -24,7 +24,7 @@ */ export const TERRAIN_RETRY_ATTEMPTS = 3; -export const TERRAIN_RETRY_STATUSES = Object.freeze([429, 502, 503, 504]); +const TERRAIN_RETRY_STATUSES = Object.freeze([429, 502, 503, 504]); export const TERRAIN_RETRY_BASE_MS = 750; export const TERRAIN_RETRY_MAX_MS = 15_000; export const TERRAIN_RETRY_SPREAD_MS = 1_500; diff --git a/src/scenes/recipes.js b/src/scenes/recipes.js index 191bb1ac1..ba3940a57 100644 --- a/src/scenes/recipes.js +++ b/src/scenes/recipes.js @@ -994,7 +994,7 @@ const PUBLIC_SCENE_RECIPES = [ ]; /** Build the recipe list without mutating stored user-authored projects. */ -export function createSceneRecipes({ localDemoRecipes = EVENT_RECIPES } = {}) { +function createSceneRecipes({ localDemoRecipes = EVENT_RECIPES } = {}) { return [...localDemoRecipes, ...PUBLIC_SCENE_RECIPES]; } @@ -1004,7 +1004,7 @@ export const SCENE_APPEND_RECIPES = BHOTE_KOSHI_NEPAL_APPEND_RECIPE ? [BHOTE_KOSHI_NEPAL_APPEND_RECIPE] : []; -export function getSceneRecipeById(id) { +function getSceneRecipeById(id) { return SCENE_RECIPES.find((recipe) => recipe.id === id) || null; } diff --git a/src/sdr/controller.js b/src/sdr/controller.js index 50fec4a38..019b768a1 100644 --- a/src/sdr/controller.js +++ b/src/sdr/controller.js @@ -38,12 +38,12 @@ const READ_PIPELINE_DEPTH = 4; const RATE_WINDOW_MS = 1_000; // A bulk read that has not completed in this long is treated as a stalled // USB transfer: the session is torn down instead of waiting forever. -export const SDR_READ_STALL_MS = 5_000; +const SDR_READ_STALL_MS = 5_000; // Decoder admission. Every block sent to the worker is numbered and must be // acknowledged; past these bounds the receiver stops with an overload error // rather than queueing raw IQ the decoder cannot keep up with. Eight 16 ms // blocks is 128 ms of input, about forty times the measured decode cost. -export const SDR_WORKER_ADMISSION = Object.freeze({ +const SDR_WORKER_ADMISSION = Object.freeze({ maxBlocks: 8, maxBytes: 8 * 65_536, maxAgeMs: 1_000, @@ -66,7 +66,7 @@ const DECODER_WINDOW_SAMPLES = 256; // raw USB device is closed directly, which aborts any pending transfer. The // raw close is bounded by the same deadline, so a teardown settles within // twice this even when `USBDevice.close()` itself never settles. -export const SDR_CLOSE_TIMEOUT_MS = 2_000; +const SDR_CLOSE_TIMEOUT_MS = 2_000; /** Tuning presets per receiver mode; gain is a separate per-mode setting. */ export const SDR_RECEIVER_PRESETS = Object.freeze({ @@ -1912,9 +1912,3 @@ function formatMhz(hz) { function positiveModulo(value, divisor) { return ((value % divisor) + divisor) % divisor; } - -export const SDR_FM_BAND = Object.freeze({ - minHz: FM_MIN_HZ, - maxHz: FM_MAX_HZ, -}); -export const SDR_ADSB_FREQUENCY_HZ = ADSB_FREQUENCY_HZ; diff --git a/src/sdr/gain.js b/src/sdr/gain.js index 761edf013..94d525fe2 100644 --- a/src/sdr/gain.js +++ b/src/sdr/gain.js @@ -10,7 +10,7 @@ * about 1 msg/s and 28.0 dB about 9 msg/s on the same antenna. */ -export const SDR_GAIN_AUTO = 'auto'; +const SDR_GAIN_AUTO = 'auto'; /** R820T tuner gain steps in dB, as listed by librtlsdr. */ export const R820T_GAIN_STEPS_DB = Object.freeze([ diff --git a/src/sky/stars.js b/src/sky/stars.js index 9fd5aa698..f4139c3c5 100644 --- a/src/sky/stars.js +++ b/src/sky/stars.js @@ -18,7 +18,7 @@ export const STAR_MAX_SIGMA_PX = 1.35; /** Peak opacity of the faintest star. */ export const STAR_MIN_ALPHA = 0.22; /** B−V for stars the catalogue gives no colour (a solar-type white). */ -export const STAR_DEFAULT_BV = 0.6; +const STAR_DEFAULT_BV = 0.6; /** Floats per star in the vertex buffer: xyz, σ, rgb, alpha. */ export const STAR_VERTEX_FLOATS = 8; @@ -76,7 +76,7 @@ export function bvToTemperature(bv) { } /** Black-body colour of a temperature, sRGB 0..1 (Helland's fit). */ -export function temperatureToRgb(kelvin) { +function temperatureToRgb(kelvin) { const t = clamp(kelvin, 1000, 40000) / 100; const red = t <= 66 ? 255 : 329.698727446 * (t - 60) ** -0.1332047592; const green = diff --git a/src/sources/adsbRecords.js b/src/sources/adsbRecords.js index 9c0082700..814da60b2 100644 --- a/src/sources/adsbRecords.js +++ b/src/sources/adsbRecords.js @@ -41,12 +41,12 @@ const CATEGORY_PATTERN = /^[A-D][0-7]$/; /** A previous accepted fix older than this is no reference for a new one. */ export const LOCAL_ADSB_REFERENCE_MAX_AGE_MS = 10 * 60_000; /** Speed limit (kt) for an aircraft that has not reported a ground speed. */ -export const LOCAL_ADSB_UNKNOWN_SPEED_LIMIT_KT = 1_000; +const LOCAL_ADSB_UNKNOWN_SPEED_LIMIT_KT = 1_000; /** Tighter limit (kt) for light aircraft and rotorcraft without a speed. */ -export const LOCAL_ADSB_SLOW_CATEGORY_LIMIT_KT = 350; +const LOCAL_ADSB_SLOW_CATEGORY_LIMIT_KT = 350; /** Reported ground speed is multiplied by this, plus the margin below. */ -export const LOCAL_ADSB_SPEED_FACTOR = 1.5; -export const LOCAL_ADSB_SPEED_MARGIN_KT = 50; +const LOCAL_ADSB_SPEED_FACTOR = 1.5; +const LOCAL_ADSB_SPEED_MARGIN_KT = 50; /** Distance always allowed between two fixes (CPR and reception error). */ export const LOCAL_ADSB_POSITION_MARGIN_M = 500; /** diff --git a/src/sources/featureGeometry.js b/src/sources/featureGeometry.js index 429dbe826..a18d5f22f 100644 --- a/src/sources/featureGeometry.js +++ b/src/sources/featureGeometry.js @@ -77,7 +77,7 @@ export function simplifyRing(ring, tolM) { return out.length >= 4 ? out : ring; } -export function douglasPeucker(points, tol) { +function douglasPeucker(points, tol) { const n = points.length; if (n < 3) return points.slice(); // Iterative, index-based (no per-call array slicing / recursion), so a large @@ -113,7 +113,7 @@ export function douglasPeucker(points, tol) { return out; } -export function perpDistance(p, a, b) { +function perpDistance(p, a, b) { const dx = b[0] - a[0]; const dy = b[1] - a[1]; const len2 = dx * dx + dy * dy; @@ -149,7 +149,7 @@ export function stitchRing(ways) { return endpointGapM(largest) <= allow ? largest : []; } -export function largestByArea(components) { +function largestByArea(components) { let best = components[0]; let bestArea = approximateAreaM2(best); for (let i = 1; i < components.length; i += 1) { @@ -162,7 +162,7 @@ export function largestByArea(components) { return best; } -export function ringSpanM(chain) { +function ringSpanM(chain) { let minLat = Infinity; let maxLat = -Infinity; let minLon = Infinity; @@ -176,7 +176,7 @@ export function ringSpanM(chain) { return approximateDistanceM(minLat, minLon, maxLat, maxLon); } -export function buildRingComponents(ways) { +function buildRingComponents(ways) { const same = (a, b) => Math.abs(a.lon - b.lon) < 1e-7 && Math.abs(a.lat - b.lat) < 1e-7; const remaining = ways.map((w) => w.slice()); @@ -207,7 +207,7 @@ export function buildRingComponents(ways) { return components; } -export function endpointGapM(chain) { +function endpointGapM(chain) { if (!chain || chain.length < 2) return Infinity; const a = chain[0]; const b = chain[chain.length - 1]; diff --git a/src/sources/openFreeMap.js b/src/sources/openFreeMap.js index 274c2ace7..00c288a8b 100644 --- a/src/sources/openFreeMap.js +++ b/src/sources/openFreeMap.js @@ -24,7 +24,7 @@ const ROAD_TYPES = Object.freeze({ * OpenMapTiles folds private access into `no`. Tunnels cannot be placed on * the surface above them; ramps/bridges remain valid only on a motor road. */ -export function isDrivableOpenMapRoad(properties = {}) { +function isDrivableOpenMapRoad(properties = {}) { return ( Object.hasOwn(ROAD_TYPES, properties.class) && !properties.subclass && diff --git a/src/sources/transitHistoryStore.js b/src/sources/transitHistoryStore.js index 9fe29f59d..cf82835c1 100644 --- a/src/sources/transitHistoryStore.js +++ b/src/sources/transitHistoryStore.js @@ -1,7 +1,7 @@ import { validTransitIdentifier } from './transitHistory.js'; export { validTransitIdentifier } from './transitHistory.js'; /** Bounded, process-local operator position history. No upstream or scene access. */ -export const TRANSIT_HISTORY_LIMITS = Object.freeze({ +const TRANSIT_HISTORY_LIMITS = Object.freeze({ retentionMs: 900000, fixes: 128, feedBytes: 16 * 1024 * 1024, diff --git a/src/testSupport/kartaViewFakes.mjs b/src/testSupport/kartaViewFakes.mjs index a2e6452f6..326ba9d77 100644 --- a/src/testSupport/kartaViewFakes.mjs +++ b/src/testSupport/kartaViewFakes.mjs @@ -1,7 +1,7 @@ // DOM stand-ins for the KartaView viewer's tests (no browser in Node). /** A DOM element with what the viewer touches: children, events, attributes. */ -export function fakeElement(tag) { +function fakeElement(tag) { const listeners = new Map(); const element = { tagName: tag.toUpperCase(), diff --git a/src/tools/queries/panelRequest.js b/src/tools/queries/panelRequest.js index 3864c9889..51ecd6406 100644 --- a/src/tools/queries/panelRequest.js +++ b/src/tools/queries/panelRequest.js @@ -55,7 +55,7 @@ const COMPRESS_MIN_BYTES = 1024; * rather than fail; past `PANEL_QUEUED_REQUESTS` waiting, they are refused. */ export const PANEL_CONCURRENT_REQUESTS = 6; -export const PANEL_QUEUED_REQUESTS = 256; +const PANEL_QUEUED_REQUESTS = 256; /** * Each server's panel state: bodies too large for one call, kept for the diff --git a/src/tools/queries/share.js b/src/tools/queries/share.js index 0c59ca7f0..5284e8a06 100644 --- a/src/tools/queries/share.js +++ b/src/tools/queries/share.js @@ -7,7 +7,7 @@ import { AREA_SCHEMA, resolveArea } from '../area.js'; import { cameraForArea, cameraLookingAt } from '../views.js'; /** Tool arguments that describe a view: an area to frame, or a camera. */ -export const VIEW_ARGUMENTS = Object.freeze({ +const VIEW_ARGUMENTS = Object.freeze({ view: Object.freeze({ type: 'object', description: diff --git a/src/ui/cameraOrientationControls.js b/src/ui/cameraOrientationControls.js index 0fb67f1d4..d10bacf2f 100644 --- a/src/ui/cameraOrientationControls.js +++ b/src/ui/cameraOrientationControls.js @@ -107,7 +107,7 @@ export function readCameraTargetFrame(viewer) { } /** Apply an orbit frame, then return the camera to Cesium's fixed-world frame. */ -export function setCameraTargetFrame(viewer, frame) { +function setCameraTargetFrame(viewer, frame) { const camera = viewer?.camera; if (!camera || !frame?.target || !Number.isFinite(frame.range)) return false; try { @@ -156,7 +156,7 @@ export function setCameraTargetFrame(viewer, frame) { * * @param {{pitch: number}|null} frame From {@link readCameraTargetFrame}. */ -export function frameIsTilted(frame) { +function frameIsTilted(frame) { const pitch = Number(frame?.pitch); return Number.isFinite(pitch) ? pitch > OBLIQUE_THRESHOLD : false; } diff --git a/src/ui/cctvFrames.js b/src/ui/cctvFrames.js index ac6687f54..33818984d 100644 --- a/src/ui/cctvFrames.js +++ b/src/ui/cctvFrames.js @@ -46,7 +46,7 @@ const SOURCE_LABELS = Object.freeze({ }); /** "SNAPSHOT" / "СНИМОК"; unknown codes (HLS, MJPEG…) stay as uppercase codes. */ -export function cctvSourceKindLabel(kind) { +function cctvSourceKindLabel(kind) { const key = String(kind || 'unknown').toLowerCase(); return SOURCE_KIND_LABELS[key] ? t(SOURCE_KIND_LABELS[key]) diff --git a/src/ui/statusText.js b/src/ui/statusText.js index b0899d55e..677c9b886 100644 --- a/src/ui/statusText.js +++ b/src/ui/statusText.js @@ -218,7 +218,7 @@ function statusPatternText(piece) { } /** One piece of a status line in the UI language, or as it came. */ -export function translateStatusPiece(piece) { +function translateStatusPiece(piece) { const known = translateKnown(piece); if (known !== piece) return known; return statusPatternText(piece) ?? piece; diff --git a/src/voice/deixis.js b/src/voice/deixis.js index d68fcd61a..25d7939eb 100644 --- a/src/voice/deixis.js +++ b/src/voice/deixis.js @@ -18,7 +18,7 @@ import { finiteOrNull } from './pointerContext.js'; -export const POINTER_SENTINEL = 'pointer'; +const POINTER_SENTINEL = 'pointer'; const TRACKABLE_LAYERS = new Set([ 'flights', diff --git a/src/voice/narration.js b/src/voice/narration.js index a91dbbe2b..ae97931f7 100644 --- a/src/voice/narration.js +++ b/src/voice/narration.js @@ -4,7 +4,7 @@ import { progressLine } from './speech.js'; * Timing policy for filling silence while tools run. Tuned against the turn * spans' `max_silence_ms`. */ -export const NARRATION_TIMING = Object.freeze({ +const NARRATION_TIMING = Object.freeze({ /** Start the earcon when nothing is audible this long after end of speech. */ earconAfterMs: 700, /** First spoken progress line when a tool is still running after this. */ diff --git a/src/voice/pointerContext.js b/src/voice/pointerContext.js index 3f9d09b6d..590e33a52 100644 --- a/src/voice/pointerContext.js +++ b/src/voice/pointerContext.js @@ -20,15 +20,15 @@ */ /** Movement below this many CSS pixels is still the same dwell. */ -export const POINTER_DWELL_PX = 12; +const POINTER_DWELL_PX = 12; /** Stillness that makes a dwell point. */ export const POINTER_DWELL_MS = 250; /** A resting pointer stays a referent this long after it last moved. */ export const POINTER_FRESH_MS = 30000; /** Pixels from the canvas edge that count as "parked", never a referent. */ -export const POINTER_EDGE_PX = 8; +const POINTER_EDGE_PX = 8; /** A dwell pick is reused by a snapshot only while this recent (contacts move). */ -export const POINTER_DWELL_REUSE_MS = 1000; +const POINTER_DWELL_REUSE_MS = 1000; /** * Open mic has no gesture, so the pointer only counts when it moved or * settled on the map this recently: a cursor resting there for minutes is @@ -76,7 +76,7 @@ export function cameraPoseKey(viewer) { } /** Bound and de-control a label before it goes to the model or the card. */ -export function pointerLabel(value, max = LABEL_MAX) { +function pointerLabel(value, max = LABEL_MAX) { const clean = String(value ?? '') .replace(/[\p{Cc}\p{Cf}]+/gu, ' ') .replace(/\s+/g, ' ') diff --git a/src/voice/pointerPick.js b/src/voice/pointerPick.js index 33ccab9cb..e74671eda 100644 --- a/src/voice/pointerPick.js +++ b/src/voice/pointerPick.js @@ -4,7 +4,7 @@ import { cameraPoseKey } from './pointerContext.js'; import * as defaultAnnotationResolver from '../annotations/annotationResolver.js'; /** "Around here" radius as a share of camera height, clamped to sane bounds. */ -export function pointerRadiusKm(cameraHeightM) { +function pointerRadiusKm(cameraHeightM) { const heightKm = Number(cameraHeightM) / 1000; if (!Number.isFinite(heightKm) || heightKm <= 0) return 50; return Math.round(Math.min(400, Math.max(5, heightKm * 0.75))); diff --git a/src/voice/pointerReticle.js b/src/voice/pointerReticle.js index 96729a933..0702d7345 100644 --- a/src/voice/pointerReticle.js +++ b/src/voice/pointerReticle.js @@ -14,7 +14,7 @@ export const RETICLE_MAX_MS = 10000; export const RETICLE_LINGER_MS = 1500; /** Tools that move the camera away from the pointed spot. */ -export const CAMERA_TOOLS = new Set([ +const CAMERA_TOOLS = new Set([ 'fly_to_location', 'track_entity', 'zoom_to_globe', diff --git a/src/voice/realtimeDiagnostics.js b/src/voice/realtimeDiagnostics.js index 630e29433..55e078280 100644 --- a/src/voice/realtimeDiagnostics.js +++ b/src/voice/realtimeDiagnostics.js @@ -1,10 +1,10 @@ -export const ERROR_LOG_LIMIT = 30; +const ERROR_LOG_LIMIT = 30; -export const ERROR_STORAGE_KEY = 'gev-realtime-errors'; +const ERROR_STORAGE_KEY = 'gev-realtime-errors'; -export const DEBUG_LOG_URL = '/api/realtime/debug-log'; +const DEBUG_LOG_URL = '/api/realtime/debug-log'; -export function createDebugSessionId() { +function createDebugSessionId() { const randomPart = Math.random().toString(36).slice(2, 10); return `gev-${Date.now().toString(36)}-${randomPart}`; } @@ -47,7 +47,7 @@ export function sanitizeDebugValue(value, depth = 0) { return output; } -export function sanitizeDebugString(value) { +function sanitizeDebugString(value) { if (value.startsWith('data:image/')) { return `[Redacted image data URL, ${value.length} chars]`; } @@ -65,13 +65,13 @@ export function sanitizeDebugString(value) { : redacted; } -export function isSecretLikeKey(key) { +function isSecretLikeKey(key) { return /(?:api[_-]?key|authorization|bearer|client[_-]?secret|token|secret|password)/i.test( key, ); } -export function createErrorRecord(source, error, extra = {}) { +function createErrorRecord(source, error, extra = {}) { const rtcError = error?.error || error; return { timestamp: new Date().toISOString(), @@ -90,7 +90,7 @@ export function createErrorRecord(source, error, extra = {}) { }; } -export function formatErrorForDisplay(record) { +function formatErrorForDisplay(record) { const primary = [record.source, record.message].filter(Boolean).join(': '); const state = [ record.errorDetail && `detail=${record.errorDetail}`, @@ -105,7 +105,7 @@ export function formatErrorForDisplay(record) { return state ? `${primary}\n${state}` : primary; } -export function removeEmptyValues(value) { +function removeEmptyValues(value) { return Object.fromEntries( Object.entries(value || {}).filter( ([, item]) => item !== null && item !== undefined && item !== '', @@ -113,14 +113,7 @@ export function removeEmptyValues(value) { ); } -export function compactText(value, maxLength) { - const text = String(value || '') - .replace(/\s+/g, ' ') - .trim(); - return text.length <= maxLength ? text : `${text.slice(0, maxLength - 1)}…`; -} - -export function loadStoredErrors() { +function loadStoredErrors() { try { const value = JSON.parse(localStorage.getItem(ERROR_STORAGE_KEY) || '[]'); return Array.isArray(value) ? value.slice(0, ERROR_LOG_LIMIT) : []; @@ -129,7 +122,7 @@ export function loadStoredErrors() { } } -export function storeErrors(errors) { +function storeErrors(errors) { try { localStorage.setItem( ERROR_STORAGE_KEY, diff --git a/src/voice/realtimePreferences.js b/src/voice/realtimePreferences.js index 1d4d1dd23..d3b78a922 100644 --- a/src/voice/realtimePreferences.js +++ b/src/voice/realtimePreferences.js @@ -8,12 +8,12 @@ import { // Voice cost control (repo-wide `godsEyeView..` convention; // the neighbouring ERROR_STORAGE_KEY predates it). -export const VOICE_TIER_STORAGE_KEY = 'godsEyeView.voiceCost.tier'; +const VOICE_TIER_STORAGE_KEY = 'godsEyeView.voiceCost.tier'; -export const VOICE_LIMITS_STORAGE_KEY = 'godsEyeView.voiceCost.limits'; +const VOICE_LIMITS_STORAGE_KEY = 'godsEyeView.voiceCost.limits'; /** Best-effort localStorage handle; absent in tests and locked-down browsers. */ -export function voiceStorage(storage) { +function voiceStorage(storage) { if (storage) return storage; try { return typeof localStorage === 'undefined' ? null : localStorage; diff --git a/src/voice/realtimeTurns.js b/src/voice/realtimeTurns.js index cbc8d5dbc..2073be06d 100644 --- a/src/voice/realtimeTurns.js +++ b/src/voice/realtimeTurns.js @@ -13,7 +13,7 @@ import { import { narrationLabel } from './speech.js'; /** Out-of-band progress responses carry this metadata tag. */ -export const PROGRESS_RESPONSE_TAG = 'progress'; +const PROGRESS_RESPONSE_TAG = 'progress'; /** * Speaks one code-authored progress line out of band. The line travels as diff --git a/src/voice/realtimeViewport.js b/src/voice/realtimeViewport.js index 755913906..e229b6cc2 100644 --- a/src/voice/realtimeViewport.js +++ b/src/voice/realtimeViewport.js @@ -5,17 +5,17 @@ import { import { cameraPoseKey } from './pointerContext.js'; /** The live viewer's camera pose identity (Cesium-free read). */ -export function readViewerCameraKey() { +function readViewerCameraKey() { return cameraPoseKey(globalThis.window?.__godsEyeView?.viewer); } // Viewport-screenshot size guards (M13). The old code clamped WIDTH only, so a // tall portrait window produced an oversized capture whose dc.send could throw. // Cap total pixels (clamps both dimensions) and drop the image entirely if the // encoded data URL is still too big for the data channel. -export const VIEWPORT_MAX_PIXELS = 1200 * 900; +const VIEWPORT_MAX_PIXELS = 1200 * 900; // ~1.08 MP, matches the old 1200px-wide landscape budget -export const VIEWPORT_MAX_ENCODED_BYTES = 200 * 1024; +const VIEWPORT_MAX_ENCODED_BYTES = 200 * 1024; export async function captureViewportImage() { const viewer = window.__godsEyeView?.viewer; @@ -66,11 +66,11 @@ export async function captureViewportImage() { } /** Side of the point-and-ask crop, in CSS pixels, and its output size. */ -export const POINTER_CROP_SIZE = 512; +const POINTER_CROP_SIZE = 512; /** A pointer snapshot older than this no longer matches the frame. */ -export const POINTER_CROP_MAX_AGE_MS = 20000; +const POINTER_CROP_MAX_AGE_MS = 20000; /** View scales where a crop shows buildings and terrain, not a smear. */ -export const POINTER_CROP_SCALES = new Set(['local', 'city']); +const POINTER_CROP_SCALES = new Set(['local', 'city']); /** * Square source rectangle around a canvas point, clamped inside the canvas, @@ -128,7 +128,7 @@ export function pointerCropRect({ * @returns {Promise<{dataUrl: string, rect: object}|null>} JPEG data URL and * the crop's normalized bounds in the full canvas, or null. */ -export async function capturePointerCrop(screenPx) { +async function capturePointerCrop(screenPx) { const viewer = window.__godsEyeView?.viewer; const source = viewer?.scene?.canvas; if (!source?.width || !source?.height || !screenPx) return null; @@ -259,7 +259,7 @@ export async function renderFreshCesiumFrame(viewer) { } } -export function isNearlyBlackFrame(ctx, width, height) { +function isNearlyBlackFrame(ctx, width, height) { const sampleWidth = Math.min(48, width); const sampleHeight = Math.min(32, height); if (!sampleWidth || !sampleHeight) return true; diff --git a/src/voice/resultDisplay.js b/src/voice/resultDisplay.js index 642db2bb4..ac99f86d7 100644 --- a/src/voice/resultDisplay.js +++ b/src/voice/resultDisplay.js @@ -59,7 +59,7 @@ function notesOf(...values) { ]; } -export function analystNounFor(layerKeys) { +function analystNounFor(layerKeys) { const keys = [...new Set(layerKeys.filter(Boolean))]; if (keys.length !== 1) return 'results'; const key = keys[0]; diff --git a/src/voice/speechLint.js b/src/voice/speechLint.js index 9b6c02ab4..f1b1c1878 100644 --- a/src/voice/speechLint.js +++ b/src/voice/speechLint.js @@ -7,7 +7,7 @@ * Phrases that add length without adding an answer. Tool numbers are spoken * verbatim, so approximations are hedges too. */ -export const HEDGE_PHRASES = Object.freeze([ +const HEDGE_PHRASES = Object.freeze([ 'keep in mind', "it's worth noting", 'it is worth noting', diff --git a/src/voice/turnMetrics.js b/src/voice/turnMetrics.js index 13e9c6940..b2c447cee 100644 --- a/src/voice/turnMetrics.js +++ b/src/voice/turnMetrics.js @@ -1,7 +1,7 @@ import { countWords, findHedges } from './speechLint.js'; /** Quiet period after the last audio or response before a turn is closed. */ -export const TURN_SETTLE_MS = 2500; +const TURN_SETTLE_MS = 2500; /** * Per-turn latency and speech spans for one voice session. diff --git a/src/voice/voiceCard.js b/src/voice/voiceCard.js index 72b754287..09619bb54 100644 --- a/src/voice/voiceCard.js +++ b/src/voice/voiceCard.js @@ -5,7 +5,7 @@ import { } from './voiceCardPresentation.js'; /** Hide an idle card this long after its last update. */ -export const VOICE_CARD_IDLE_MS = 14000; +const VOICE_CARD_IDLE_MS = 14000; const ELEMENT_IDS = Object.freeze({ card: 'gev-voice-card',