@aguacerowx/mapsgl 0.0.54 → 0.0.56
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +5 -6
- package/package.json +3 -3
- package/src/NexradWeatherController.js +11 -1
- package/src/WeatherLayerManager.js +3 -5
- package/src/nexrad/loadNexradSites.ts +85 -7
- package/src/nexrad/nexradArchiveDiag.ts +26 -0
- package/src/nexrad/nexradMapboxFrameOpts.bundled.js +3 -2
- package/src/nexrad/nexradMapboxFrameOpts.ts +3 -2
- package/src/nexrad/nexradSitesDefault.json +1700 -0
- package/src/nexrad/radarArchiveCore.bundled.js +2724 -37
- package/src/nexrad/radarArchiveCore.ts +149 -30
- package/src/nexrad/radarDecode.worker.bundled.js +130 -126
- package/src/nexrad/radarDecode.worker.ts +13 -215
- package/src/nexrad/radarDecodeSlot.ts +195 -0
- package/src/NwsWatchesWarningsOverlay.js +0 -973
- package/src/nwsAlertsFetchSpec.js +0 -114
- package/src/nwsAlertsSupport.js +0 -1337
- package/src/nwsEventColorsDefaults.js +0 -133
- package/src/nwsSdkConstants.js +0 -360
- package/src/nwsWarningCustomizationKey.gen.js +0 -493
package/index.js
CHANGED
|
@@ -1,23 +1,22 @@
|
|
|
1
|
-
// In packages/mapsgl/
|
|
1
|
+
// In packages/mapsgl/index.js (The final, correct version)
|
|
2
2
|
|
|
3
3
|
// Import the specific classes you want to make public from this package's internal files.
|
|
4
4
|
import { WeatherLayerManager } from './src/WeatherLayerManager.js';
|
|
5
5
|
import { MapManager } from './src/MapManager.js';
|
|
6
|
-
import { NwsWatchesWarningsOverlay, NWS_DEFAULT_LINE_BEFORE_LAYER_ID } from './src/NwsWatchesWarningsOverlay.js';
|
|
7
6
|
import {
|
|
7
|
+
NwsWatchesWarningsOverlay,
|
|
8
|
+
NWS_DEFAULT_LINE_BEFORE_LAYER_ID,
|
|
8
9
|
collectNwsExpressionEventKeys,
|
|
9
10
|
NWS_ALERT_EVENT_NAMES,
|
|
10
11
|
NWS_EVENT_COLORS,
|
|
11
12
|
NWS_SDK_EVENT_COLOR,
|
|
12
13
|
NWS_SDK_EVENT_NAMES,
|
|
13
|
-
} from './src/nwsSdkConstants.js';
|
|
14
|
-
import {
|
|
15
14
|
filterNwsAlertsByIncludedList,
|
|
16
15
|
filterNwsAlertsByScope,
|
|
17
16
|
filterToConvectiveSdkEvents,
|
|
18
17
|
isNwsEventIncludedInAllowlist,
|
|
19
18
|
SDK_ALLOWED_EVENT_SET,
|
|
20
|
-
} from '
|
|
19
|
+
} from '@aguacerowx/javascript-sdk';
|
|
21
20
|
|
|
22
21
|
// Now, export them both so your test app can import them.
|
|
23
22
|
// This is the "public face" of your @aguacerowx/mapsgl package.
|
|
@@ -43,4 +42,4 @@ export {
|
|
|
43
42
|
DEFAULT_SATELLITE_WATER_VAPOR_COLORMAP,
|
|
44
43
|
} from './src/satelliteDefaultColormaps.js';
|
|
45
44
|
|
|
46
|
-
export { JSDELIVR_BASIS_BASE_URL } from './src/defaultBasisBaseUrl.js';
|
|
45
|
+
export { JSDELIVR_BASIS_BASE_URL } from './src/defaultBasisBaseUrl.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aguacerowx/mapsgl",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.56",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"scripts": {
|
|
11
11
|
"prepublishOnly": "npm run bundle-nexrad",
|
|
12
12
|
"bundle-nexrad": "esbuild src/nexrad/radarDecode.worker.ts --bundle --format=esm --platform=browser --outfile=src/nexrad/radarDecode.worker.bundled.js && esbuild src/nexrad/radarArchiveCore.ts --bundle --format=esm --platform=browser --outfile=src/nexrad/radarArchiveCore.bundled.js --external:@aguacerowx/javascript-sdk && esbuild src/nexrad/MapboxRadarLayer.ts --bundle --format=esm --platform=browser --outfile=src/nexrad/MapboxRadarLayer.bundled.js --external:mapbox-gl --external:@aguacerowx/javascript-sdk && esbuild src/nexrad/nexradCrossSectionSampleAtLatLon.ts --format=esm --platform=browser --outfile=src/nexrad/nexradCrossSectionSampleAtLatLon.bundled.js && esbuild src/nexrad/radarFrameGpuMatch.ts --format=esm --platform=browser --outfile=src/nexrad/radarFrameGpuMatch.bundled.js && esbuild src/nexrad/nexradMapboxFrameOpts.ts --bundle --format=esm --platform=browser --outfile=src/nexrad/nexradMapboxFrameOpts.bundled.js --external:@aguacerowx/javascript-sdk",
|
|
13
|
-
"
|
|
13
|
+
"bundle-nexrad-rn": "node scripts/bundle-nexrad-rn.mjs"
|
|
14
14
|
},
|
|
15
15
|
"files": [
|
|
16
16
|
"index.js",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"esbuild": "^0.21.5"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@aguacerowx/javascript-sdk": "^0.0.
|
|
24
|
+
"@aguacerowx/javascript-sdk": "^0.0.26",
|
|
25
25
|
"buffer": "^6.0.3",
|
|
26
26
|
"fzstd": "^0.1.1",
|
|
27
27
|
"mapbox-gl": "^3.4.0",
|
|
@@ -3,7 +3,13 @@
|
|
|
3
3
|
* Preloads all timestamps on the active timeline (MRMS/satellite-style) so scrubbing does not trigger loads.
|
|
4
4
|
*/
|
|
5
5
|
import { getUnitConversionFunction, getDefaultRadarTilt } from '@aguacerowx/javascript-sdk';
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
fetchAndParseArchive,
|
|
8
|
+
objectKeyToUrl,
|
|
9
|
+
setNexradArchiveApiKey,
|
|
10
|
+
setNexradArchiveBundleId,
|
|
11
|
+
setNexradSitesFetchAuth,
|
|
12
|
+
} from './nexrad/radarArchiveCore.bundled.js';
|
|
7
13
|
import { MapboxRadarLayer } from './nexrad/MapboxRadarLayer.bundled.js';
|
|
8
14
|
import { nexradBinGroupIdForKey, variableToNexradGroup } from '@aguacerowx/javascript-sdk';
|
|
9
15
|
import { sampleNexradFrameAtLatLon } from './nexrad/nexradCrossSectionSampleAtLatLon.bundled.js';
|
|
@@ -268,6 +274,8 @@ export class NexradWeatherController {
|
|
|
268
274
|
this._frameCache.clear();
|
|
269
275
|
|
|
270
276
|
setNexradArchiveApiKey(this.core.apiKey || '');
|
|
277
|
+
setNexradArchiveBundleId(this.core.bundleId || '');
|
|
278
|
+
setNexradSitesFetchAuth(this.core.apiKey || '', this.core.bundleId || '');
|
|
271
279
|
|
|
272
280
|
const times = [...(state.availableNexradTimestamps || [])]
|
|
273
281
|
.map(Number)
|
|
@@ -353,6 +361,8 @@ export class NexradWeatherController {
|
|
|
353
361
|
}
|
|
354
362
|
|
|
355
363
|
setNexradArchiveApiKey(this.core.apiKey || '');
|
|
364
|
+
setNexradArchiveBundleId(this.core.bundleId || '');
|
|
365
|
+
setNexradSitesFetchAuth(this.core.apiKey || '', this.core.bundleId || '');
|
|
356
366
|
|
|
357
367
|
const unix = Number(state.nexradTimestamp);
|
|
358
368
|
const p = this._buildFetchParamsForUnix(state, unix);
|
|
@@ -5,8 +5,7 @@ import { GridRenderLayer } from './GridRenderLayer.js'; // <-- IMPORT THE WEB RE
|
|
|
5
5
|
import { SatelliteShaderManager } from './SatelliteShaderManager.js';
|
|
6
6
|
import { NexradWeatherController } from './NexradWeatherController.js';
|
|
7
7
|
import { NexradSitesOverlay } from './NexradSitesOverlay.js';
|
|
8
|
-
import { NwsWatchesWarningsOverlay } from '
|
|
9
|
-
import { computeNwsAlertsFetchHoursFromAguaceroState } from './nwsAlertsFetchSpec.js';
|
|
8
|
+
import { NwsWatchesWarningsOverlay, computeNwsAlertsFetchHoursFromAguaceroState } from '@aguacerowx/javascript-sdk';
|
|
10
9
|
import WorkerPool from './WorkerPool.js';
|
|
11
10
|
|
|
12
11
|
import { DEFAULT_BASIS_BASE_URL } from './defaultBasisBaseUrl.js';
|
|
@@ -37,7 +36,7 @@ function findLatestModelRun(modelsData, modelName) {
|
|
|
37
36
|
* @param {string} [options.weatherBeforeLayerId] - Same as `belowID`.
|
|
38
37
|
* @param {string} [options.nexradLayerId] - Override Mapbox id for the NEXRAD custom layer (default: derived from `layerId`).
|
|
39
38
|
* @param {boolean} [options.mrmsTimelineLog] - When `true`, logs MRMS duration / raw vs filtered timeline counts (prefix `[WeatherLayerManager MRMS]`). Off by default.
|
|
40
|
-
* @param {string} [options.
|
|
39
|
+
* @param {string} [options.gridRequestSiteOrigin] - Forwarded to {@link AguaceroCore}: base URL without trailing slash (e.g. production site or `http://localhost:5173`) so grid `fetch` sends `Origin`/`Referer` outside the browser.
|
|
41
40
|
*/
|
|
42
41
|
export class WeatherLayerManager extends EventEmitter {
|
|
43
42
|
constructor(map, options = {}) {
|
|
@@ -640,8 +639,7 @@ export class WeatherLayerManager extends EventEmitter {
|
|
|
640
639
|
if (!apiKey) {
|
|
641
640
|
return null;
|
|
642
641
|
}
|
|
643
|
-
const
|
|
644
|
-
const url = `https://d3dc62msmxkrd7.cloudfront.net/satellite/${s3FileName}?userId=${encodeURIComponent(uid)}&apiKey=${encodeURIComponent(apiKey)}`;
|
|
642
|
+
const url = `https://d3dc62msmxkrd7.cloudfront.net/satellite/${s3FileName}?userId=${encodeURIComponent('sdk-user')}&apiKey=${encodeURIComponent(apiKey)}`;
|
|
645
643
|
return { url, shaderFileName, frameKey: Number(satelliteTimestamp), apiKey };
|
|
646
644
|
}
|
|
647
645
|
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { NexradSite } from './PreprocessedSweepParser.js';
|
|
2
|
+
import nexradSitesDefault from './nexradSitesDefault.json';
|
|
3
|
+
import { nexradArchiveDiag, redactApiKeyFromUrl } from './nexradArchiveDiag.js';
|
|
2
4
|
|
|
3
5
|
type NexradSitesPayload = {
|
|
4
6
|
sites?: NexradSite[];
|
|
@@ -13,22 +15,98 @@ export function setNexradSitesJsonUrl(url: string) {
|
|
|
13
15
|
sitesUrl = url || sitesUrl;
|
|
14
16
|
}
|
|
15
17
|
|
|
18
|
+
/**
|
|
19
|
+
* When sitesUrl is HTTPS (e.g. CloudFront), use the same auth as AguaceroCore grid fetches:
|
|
20
|
+
* `?apiKey=`, `x-api-key`, and `x-app-identifier` on React Native when bundle id is set.
|
|
21
|
+
*/
|
|
22
|
+
let SITES_FETCH_API_KEY = '';
|
|
23
|
+
let SITES_FETCH_BUNDLE_ID = '';
|
|
24
|
+
export function setNexradSitesFetchAuth(apiKey: string, bundleId?: string) {
|
|
25
|
+
SITES_FETCH_API_KEY = apiKey || '';
|
|
26
|
+
if (bundleId !== undefined) {
|
|
27
|
+
SITES_FETCH_BUNDLE_ID = bundleId || '';
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
16
31
|
let nexradSitesPayloadPromise: Promise<NexradSitesPayload> | null = null;
|
|
17
32
|
|
|
33
|
+
function sitesFetchUrl(): string {
|
|
34
|
+
if (!sitesUrl.startsWith('http') || !SITES_FETCH_API_KEY) {
|
|
35
|
+
return sitesUrl;
|
|
36
|
+
}
|
|
37
|
+
const sep = sitesUrl.includes('?') ? '&' : '?';
|
|
38
|
+
return `${sitesUrl}${sep}apiKey=${SITES_FETCH_API_KEY}`;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function sitesFetchHeaders(): Record<string, string> | undefined {
|
|
42
|
+
if (!SITES_FETCH_API_KEY) {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
const headers: Record<string, string> = {
|
|
46
|
+
'x-api-key': SITES_FETCH_API_KEY,
|
|
47
|
+
};
|
|
48
|
+
const nav = (globalThis as { navigator?: { product?: string } }).navigator;
|
|
49
|
+
if (nav?.product === 'ReactNative' && SITES_FETCH_BUNDLE_ID) {
|
|
50
|
+
headers['x-app-identifier'] = SITES_FETCH_BUNDLE_ID;
|
|
51
|
+
}
|
|
52
|
+
return headers;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function embeddedSitesPayload(): NexradSitesPayload {
|
|
56
|
+
return nexradSitesDefault as NexradSitesPayload;
|
|
57
|
+
}
|
|
58
|
+
|
|
18
59
|
export function loadNexradSitesPayload(): Promise<NexradSitesPayload> {
|
|
19
60
|
if (nexradSitesPayloadPromise) {
|
|
20
61
|
return nexradSitesPayloadPromise;
|
|
21
62
|
}
|
|
22
|
-
nexradSitesPayloadPromise =
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
63
|
+
nexradSitesPayloadPromise = (async (): Promise<NexradSitesPayload> => {
|
|
64
|
+
const url = sitesFetchUrl();
|
|
65
|
+
const headers = sitesFetchHeaders();
|
|
66
|
+
const headerKeys = headers ? Object.keys(headers).join(',') : '';
|
|
67
|
+
nexradArchiveDiag('sites.fetch.start', {
|
|
68
|
+
canonicalUrl: sitesUrl,
|
|
69
|
+
fetchUrl: redactApiKeyFromUrl(url),
|
|
70
|
+
hasApiKeyQuery: url.includes('apiKey='),
|
|
71
|
+
headerKeys: headerKeys || '(none)',
|
|
72
|
+
apiKeyLen: SITES_FETCH_API_KEY.length,
|
|
73
|
+
bundleIdLen: SITES_FETCH_BUNDLE_ID.length,
|
|
74
|
+
});
|
|
75
|
+
try {
|
|
76
|
+
const response = await fetch(url, headers ? { headers } : undefined);
|
|
77
|
+
if (response.ok) {
|
|
78
|
+
nexradArchiveDiag('sites.fetch.ok', {
|
|
79
|
+
status: response.status,
|
|
80
|
+
canonicalUrl: sitesUrl,
|
|
81
|
+
});
|
|
82
|
+
return (await response.json()) as NexradSitesPayload;
|
|
83
|
+
}
|
|
84
|
+
if (sitesUrl.startsWith('https://')) {
|
|
85
|
+
console.warn(
|
|
86
|
+
`[mapsgl] nexrad.json HTTP ${response.status} for ${sitesUrl} — using embedded site list`,
|
|
87
|
+
);
|
|
88
|
+
nexradArchiveDiag('sites.fetch.fallbackEmbedded', {
|
|
89
|
+
httpStatus: response.status,
|
|
90
|
+
reason: 'HTTPS non-OK — CloudFront may not host /data/nexrad.json; embedded list used',
|
|
91
|
+
canonicalUrl: sitesUrl,
|
|
92
|
+
});
|
|
93
|
+
return embeddedSitesPayload();
|
|
94
|
+
}
|
|
95
|
+
throw new Error(`nexrad.json fetch failed: HTTP ${response.status}`);
|
|
96
|
+
} catch (error) {
|
|
97
|
+
if (sitesUrl.startsWith('https://')) {
|
|
98
|
+
console.warn('[mapsgl] nexrad.json load failed — using embedded site list:', error);
|
|
99
|
+
nexradArchiveDiag('sites.fetch.catchFallbackEmbedded', {
|
|
100
|
+
message: error instanceof Error ? error.message : String(error),
|
|
101
|
+
canonicalUrl: sitesUrl,
|
|
102
|
+
});
|
|
103
|
+
return embeddedSitesPayload();
|
|
104
|
+
}
|
|
28
105
|
console.error('[mapsgl] Could not load nexrad.json:', error);
|
|
29
106
|
nexradSitesPayloadPromise = null;
|
|
30
107
|
throw error;
|
|
31
|
-
}
|
|
108
|
+
}
|
|
109
|
+
})();
|
|
32
110
|
return nexradSitesPayloadPromise;
|
|
33
111
|
}
|
|
34
112
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verbose NEXRAD archive pipeline logs for React Native (Hermes / Logcat).
|
|
3
|
+
* Filter: {@code [Aguacero][NEXRAD][archive]}
|
|
4
|
+
*
|
|
5
|
+
* Omits raw API keys; use lengths / booleans only.
|
|
6
|
+
*/
|
|
7
|
+
export type NexradArchiveDiagDetail = Record<string, string | number | boolean | null | undefined>;
|
|
8
|
+
|
|
9
|
+
export function redactApiKeyFromUrl(u: string): string {
|
|
10
|
+
return u.replace(/([?&])apiKey=[^&]*/gi, '$1apiKey=(redacted)');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function isReactNative(): boolean {
|
|
14
|
+
const nav = (globalThis as { navigator?: { product?: string } }).navigator;
|
|
15
|
+
return nav?.product === 'ReactNative';
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Logs only on React Native to avoid noisy web consoles (mapsgl path is already observable in DevTools). */
|
|
19
|
+
export function nexradArchiveDiag(phase: string, detail?: NexradArchiveDiagDetail): void {
|
|
20
|
+
if (!isReactNative()) return;
|
|
21
|
+
if (detail !== undefined) {
|
|
22
|
+
console.warn(`[Aguacero][NEXRAD][archive] ${phase}`, detail);
|
|
23
|
+
} else {
|
|
24
|
+
console.warn(`[Aguacero][NEXRAD][archive] ${phase}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -221,7 +221,8 @@ function nexradLevel3S3ProductForSiteTilt(siteId, radarVariable, tilt) {
|
|
|
221
221
|
return products[idx];
|
|
222
222
|
}
|
|
223
223
|
function mapboxFrameUploadOptionsForNexradState(state) {
|
|
224
|
-
if (!state
|
|
224
|
+
if (!state) return { geometryLayoutKey: "canonical" };
|
|
225
|
+
if (state.nexradDataSource !== "level3") return { geometryLayoutKey: "canonical" };
|
|
225
226
|
const site = state.nexradSite;
|
|
226
227
|
const radarVar = (state.nexradProduct || "REF").toUpperCase();
|
|
227
228
|
if (nexradLevel3UsesTiltIndexedS3Products(radarVar) && site) {
|
|
@@ -235,7 +236,7 @@ function mapboxFrameUploadOptionsForNexradState(state) {
|
|
|
235
236
|
const mnemonic = nexradLevel3S3VelocityProductForSiteTilt(site, tilt);
|
|
236
237
|
return { geometryLayoutKey: `${site}|${radarVar}|${mnemonic}` };
|
|
237
238
|
}
|
|
238
|
-
return {
|
|
239
|
+
return { geometryLayoutKey: "canonical" };
|
|
239
240
|
}
|
|
240
241
|
export {
|
|
241
242
|
mapboxFrameUploadOptionsForNexradState,
|
|
@@ -104,7 +104,8 @@ type NexradStateForMapbox = {
|
|
|
104
104
|
export function mapboxFrameUploadOptionsForNexradState(
|
|
105
105
|
state: NexradStateForMapbox | null | undefined,
|
|
106
106
|
): MapboxRadarFrameUploadOptions | undefined {
|
|
107
|
-
if (!state
|
|
107
|
+
if (!state) return { geometryLayoutKey: 'canonical' };
|
|
108
|
+
if (state.nexradDataSource !== 'level3') return { geometryLayoutKey: 'canonical' };
|
|
108
109
|
const site = state.nexradSite;
|
|
109
110
|
const radarVar = (state.nexradProduct || 'REF').toUpperCase();
|
|
110
111
|
|
|
@@ -121,5 +122,5 @@ export function mapboxFrameUploadOptionsForNexradState(
|
|
|
121
122
|
return { geometryLayoutKey: `${site}|${radarVar}|${mnemonic}` };
|
|
122
123
|
}
|
|
123
124
|
|
|
124
|
-
return {
|
|
125
|
+
return { geometryLayoutKey: 'canonical' };
|
|
125
126
|
}
|