@aguacerowx/javascript-sdk 0.0.27 → 0.0.29

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aguacerowx/javascript-sdk",
3
- "version": "0.0.27",
3
+ "version": "0.0.29",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "publishConfig": {
@@ -68,7 +68,7 @@
68
68
  "src"
69
69
  ],
70
70
  "scripts": {
71
- "build": "babel src -d dist",
71
+ "build": "babel src -d dist --config-file ./babel.build.config.js",
72
72
  "gen:nws-key": "esbuild ../../../aguacero-frontend/src/components/WarningsMenu/nwsWarningCustomizationKey.ts --bundle --format=esm --platform=neutral --outfile=src/nws/nwsWarningCustomizationKey.gen.js"
73
73
  },
74
74
  "author": "Your Name",
@@ -19,6 +19,16 @@ export function getRadarTiltsManifest() {
19
19
  return manifestBySite;
20
20
  }
21
21
 
22
+ /** True when the tilt manifest has at least one g1 or g2 tilt row for this site. */
23
+ export function radarTiltsManifestHasUsableRow(siteId) {
24
+ const id = String(siteId ?? '')
25
+ .trim()
26
+ .toUpperCase();
27
+ if (!id) return false;
28
+ const row = manifestBySite[id];
29
+ return !!(row?.g1_tilts?.length || row?.g2_tilts?.length);
30
+ }
31
+
22
32
  export function isNexradTdwrSiteId(siteId) {
23
33
  const id = String(siteId ?? '').trim().toUpperCase();
24
34
  if (!id) return false;
@@ -7,6 +7,7 @@ import {
7
7
  clampNexradTiltForVariable,
8
8
  getDefaultRadarTilt,
9
9
  getRadarTilts,
10
+ radarTiltsManifestHasUsableRow,
10
11
  } from './nexradTilts.js';
11
12
  import { coalesceNexradTiltOptionsForDisplay } from './nexradTiltCoalesce.js';
12
13
  import {
@@ -49,11 +50,17 @@ export const NEXRAD_SWEEP_LAMBDA_URL = 'https://ddknicwcw2wyov7v5bzxmbqu440tzntf
49
50
  export const NEXRAD_LEVEL3_BASE_URL = 'https://unidata-nexrad-level3.s3.amazonaws.com';
50
51
 
51
52
  const NEXRAD_GROUP_G1 = ['REF', 'PHI', 'ZDR', 'RHO'];
52
- const NEXRAD_GROUP_G2 = ['VEL', 'SW'];
53
+ const NEXRAD_GROUP_G2 = ['SW'];
54
+
55
+ /** Level-II sweep Lambda may return unix ms; store + duration filters expect seconds. */
56
+ function nexradLevel2ListingTimesToUnixSec(times) {
57
+ return times.map((t) => (typeof t === 'number' && t > 10 ** 10 ? Math.floor(t / 1000) : t));
58
+ }
53
59
 
54
60
  export function variableToNexradGroup(variable) {
55
61
  const v = (variable || 'REF').toUpperCase();
56
- if (NEXRAD_GROUP_G2.includes(v)) return 'g2';
62
+ /** VEL listings shard under g2 for cache clears; display fetch is usually level3. */
63
+ if (v === 'VEL' || NEXRAD_GROUP_G2.includes(v)) return 'g2';
57
64
  return 'g1';
58
65
  }
59
66
 
@@ -61,6 +68,12 @@ export function nexradBinGroupIdForKey(cacheGroup) {
61
68
  return cacheGroup === 'g1' ? 1 : 2;
62
69
  }
63
70
 
71
+ /** S3 object key for a Level-II sweep (content-length suffix for overwrite cache busting). */
72
+ export function buildLevel2SweepObjectKey(stationId, elevNorm, ts, group, v2_clen) {
73
+ const groupId = nexradBinGroupIdForKey(group);
74
+ return `${stationId}_${elevNorm}_${ts}_${v2_clen}_g${groupId}.bin`;
75
+ }
76
+
64
77
  function getLevel3StationPrefix(stationId) {
65
78
  const upper = (stationId || '').toUpperCase();
66
79
  if (upper.startsWith('K') && upper.length === 4) return upper.slice(1);
@@ -217,6 +230,17 @@ export async function fetchNexradTimesListing(opts) {
217
230
  l3MotionTimeToKeyMap = l3Motion.timeToKeyMap;
218
231
  }
219
232
  } else {
233
+ if (!radarTiltsManifestHasUsableRow(stationId)) {
234
+ return {
235
+ cacheKey: key,
236
+ unixTimes: [],
237
+ timeToKeyMap: {},
238
+ level3MotionKey: level3MotionKey || null,
239
+ level3MotionUnixTimes: [],
240
+ level3MotionTimeToKeyMap: {},
241
+ l2StormMotionListKey: l2StormMotionListKey || null,
242
+ };
243
+ }
220
244
  const params = new URLSearchParams({
221
245
  station: stationId,
222
246
  field: group,
@@ -227,16 +251,26 @@ export async function fetchNexradTimesListing(opts) {
227
251
  const res = await fetch(url);
228
252
  if (!res.ok) throw new Error(`NEXRAD lambda HTTP ${res.status}`);
229
253
  const data = await res.json();
254
+ let clens = {};
230
255
  if (Array.isArray(data?.times)) {
231
- times = data.times;
256
+ times = nexradLevel2ListingTimesToUnixSec(data.times);
257
+ clens = data?.clens || {};
232
258
  } else if (data?.body) {
233
259
  const body = typeof data.body === 'string' ? JSON.parse(data.body) : data.body;
234
- times = Array.isArray(body?.times) ? body.times : [];
260
+ times = Array.isArray(body?.times) ? nexradLevel2ListingTimesToUnixSec(body.times) : [];
261
+ clens = body?.clens || {};
235
262
  }
236
- const groupId = nexradBinGroupIdForKey(group);
237
263
  const elevNorm = elevNormUse;
238
264
  times.forEach((t) => {
239
- timeToKeyMap[String(t)] = `${stationId}_${elevNorm}_${t}_g${groupId}.bin`;
265
+ const clen = clens[String(t)];
266
+ if (clen == null || !Number.isFinite(Number(clen))) return;
267
+ timeToKeyMap[String(t)] = buildLevel2SweepObjectKey(
268
+ stationId,
269
+ elevNorm,
270
+ t,
271
+ group,
272
+ Number(clen),
273
+ );
240
274
  });
241
275
  if (fetchL2VelMotion) {
242
276
  const l3Motion = await fetchLevel3ProductTimesForStation(