@mostlyrightmd/core 0.1.0-rc.7

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.
Files changed (95) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +3 -0
  3. package/dist/discovery/index.cjs +1646 -0
  4. package/dist/discovery/index.cjs.map +1 -0
  5. package/dist/discovery/index.d.cts +313 -0
  6. package/dist/discovery/index.d.ts +313 -0
  7. package/dist/discovery/index.mjs +1609 -0
  8. package/dist/discovery/index.mjs.map +1 -0
  9. package/dist/formats/index.cjs +498 -0
  10. package/dist/formats/index.cjs.map +1 -0
  11. package/dist/formats/index.d.cts +97 -0
  12. package/dist/formats/index.d.ts +97 -0
  13. package/dist/formats/index.mjs +465 -0
  14. package/dist/formats/index.mjs.map +1 -0
  15. package/dist/index.cjs +1624 -0
  16. package/dist/index.cjs.map +1 -0
  17. package/dist/index.d.cts +559 -0
  18. package/dist/index.d.ts +559 -0
  19. package/dist/index.global.js +1582 -0
  20. package/dist/index.global.js.map +1 -0
  21. package/dist/index.mjs +1557 -0
  22. package/dist/index.mjs.map +1 -0
  23. package/dist/internal/bounds.cjs +125 -0
  24. package/dist/internal/bounds.cjs.map +1 -0
  25. package/dist/internal/bounds.d.cts +36 -0
  26. package/dist/internal/bounds.d.ts +36 -0
  27. package/dist/internal/bounds.mjs +81 -0
  28. package/dist/internal/bounds.mjs.map +1 -0
  29. package/dist/internal/cache/fs.cjs +217 -0
  30. package/dist/internal/cache/fs.cjs.map +1 -0
  31. package/dist/internal/cache/fs.d.cts +57 -0
  32. package/dist/internal/cache/fs.d.ts +57 -0
  33. package/dist/internal/cache/fs.mjs +179 -0
  34. package/dist/internal/cache/fs.mjs.map +1 -0
  35. package/dist/internal/cache/index.browser.cjs +1184 -0
  36. package/dist/internal/cache/index.browser.cjs.map +1 -0
  37. package/dist/internal/cache/index.browser.d.cts +20 -0
  38. package/dist/internal/cache/index.browser.d.ts +20 -0
  39. package/dist/internal/cache/index.browser.mjs +36 -0
  40. package/dist/internal/cache/index.browser.mjs.map +1 -0
  41. package/dist/internal/cache/index.cjs +1389 -0
  42. package/dist/internal/cache/index.cjs.map +1 -0
  43. package/dist/internal/cache/index.d.cts +16 -0
  44. package/dist/internal/cache/index.d.ts +16 -0
  45. package/dist/internal/cache/index.mjs +40 -0
  46. package/dist/internal/cache/index.mjs.map +1 -0
  47. package/dist/internal/chunk-PKJXHY27.mjs +1137 -0
  48. package/dist/internal/chunk-PKJXHY27.mjs.map +1 -0
  49. package/dist/internal/convert.cjs +161 -0
  50. package/dist/internal/convert.cjs.map +1 -0
  51. package/dist/internal/convert.d.cts +44 -0
  52. package/dist/internal/convert.d.ts +44 -0
  53. package/dist/internal/convert.mjs +117 -0
  54. package/dist/internal/convert.mjs.map +1 -0
  55. package/dist/internal/fs-O6XR4WWW.mjs +183 -0
  56. package/dist/internal/fs-O6XR4WWW.mjs.map +1 -0
  57. package/dist/internal/keys-B7C8C88N.d.cts +191 -0
  58. package/dist/internal/keys-B7C8C88N.d.ts +191 -0
  59. package/dist/internal/merge/index.cjs +75 -0
  60. package/dist/internal/merge/index.cjs.map +1 -0
  61. package/dist/internal/merge/index.d.cts +74 -0
  62. package/dist/internal/merge/index.d.ts +74 -0
  63. package/dist/internal/merge/index.mjs +46 -0
  64. package/dist/internal/merge/index.mjs.map +1 -0
  65. package/dist/internal/pairs.cjs +328 -0
  66. package/dist/internal/pairs.cjs.map +1 -0
  67. package/dist/internal/pairs.d.cts +105 -0
  68. package/dist/internal/pairs.d.ts +105 -0
  69. package/dist/internal/pairs.mjs +298 -0
  70. package/dist/internal/pairs.mjs.map +1 -0
  71. package/dist/qc/index.cjs +247 -0
  72. package/dist/qc/index.cjs.map +1 -0
  73. package/dist/qc/index.d.cts +140 -0
  74. package/dist/qc/index.d.ts +140 -0
  75. package/dist/qc/index.mjs +212 -0
  76. package/dist/qc/index.mjs.map +1 -0
  77. package/dist/temporal/index.cjs +504 -0
  78. package/dist/temporal/index.cjs.map +1 -0
  79. package/dist/temporal/index.d.cts +121 -0
  80. package/dist/temporal/index.d.ts +121 -0
  81. package/dist/temporal/index.mjs +474 -0
  82. package/dist/temporal/index.mjs.map +1 -0
  83. package/dist/transforms/index.cjs +399 -0
  84. package/dist/transforms/index.cjs.map +1 -0
  85. package/dist/transforms/index.d.cts +193 -0
  86. package/dist/transforms/index.d.ts +193 -0
  87. package/dist/transforms/index.mjs +362 -0
  88. package/dist/transforms/index.mjs.map +1 -0
  89. package/dist/validator.cjs +1870 -0
  90. package/dist/validator.cjs.map +1 -0
  91. package/dist/validator.d.cts +30 -0
  92. package/dist/validator.d.ts +30 -0
  93. package/dist/validator.mjs +1843 -0
  94. package/dist/validator.mjs.map +1 -0
  95. package/package.json +115 -0
@@ -0,0 +1,1609 @@
1
+ // src/data/generated/stations.ts
2
+ var STATIONS = [
3
+ {
4
+ code: "EDDB",
5
+ country: "DE",
6
+ ghcnh_id: null,
7
+ icao: "EDDB",
8
+ latitude: 52.3667,
9
+ longitude: 13.5033,
10
+ name: "Berlin Brandenburg",
11
+ tz: "Europe/Berlin"
12
+ },
13
+ {
14
+ code: "EDDF",
15
+ country: "DE",
16
+ ghcnh_id: null,
17
+ icao: "EDDF",
18
+ latitude: 50.0379,
19
+ longitude: 8.5622,
20
+ name: "Frankfurt am Main",
21
+ tz: "Europe/Berlin"
22
+ },
23
+ {
24
+ code: "EDDM",
25
+ country: "DE",
26
+ ghcnh_id: null,
27
+ icao: "EDDM",
28
+ latitude: 48.3538,
29
+ longitude: 11.7861,
30
+ name: "Munich Franz Josef Strauss",
31
+ tz: "Europe/Berlin"
32
+ },
33
+ {
34
+ code: "EFHK",
35
+ country: "FI",
36
+ ghcnh_id: null,
37
+ icao: "EFHK",
38
+ latitude: 60.3172,
39
+ longitude: 24.9633,
40
+ name: "Helsinki-Vantaa",
41
+ tz: "Europe/Helsinki"
42
+ },
43
+ {
44
+ code: "EGKK",
45
+ country: "GB",
46
+ ghcnh_id: null,
47
+ icao: "EGKK",
48
+ latitude: 51.1481,
49
+ longitude: -0.1903,
50
+ name: "London Gatwick",
51
+ tz: "Europe/London"
52
+ },
53
+ {
54
+ code: "EGLL",
55
+ country: "GB",
56
+ ghcnh_id: null,
57
+ icao: "EGLL",
58
+ latitude: 51.4706,
59
+ longitude: -0.4619,
60
+ name: "London Heathrow",
61
+ tz: "Europe/London"
62
+ },
63
+ {
64
+ code: "EHAM",
65
+ country: "NL",
66
+ ghcnh_id: null,
67
+ icao: "EHAM",
68
+ latitude: 52.3086,
69
+ longitude: 4.7639,
70
+ name: "Amsterdam Schiphol",
71
+ tz: "Europe/Amsterdam"
72
+ },
73
+ {
74
+ code: "EKCH",
75
+ country: "DK",
76
+ ghcnh_id: null,
77
+ icao: "EKCH",
78
+ latitude: 55.6181,
79
+ longitude: 12.6561,
80
+ name: "Copenhagen Kastrup",
81
+ tz: "Europe/Copenhagen"
82
+ },
83
+ {
84
+ code: "EPWA",
85
+ country: "PL",
86
+ ghcnh_id: null,
87
+ icao: "EPWA",
88
+ latitude: 52.1657,
89
+ longitude: 20.9671,
90
+ name: "Warsaw Chopin",
91
+ tz: "Europe/Warsaw"
92
+ },
93
+ {
94
+ code: "ESSA",
95
+ country: "SE",
96
+ ghcnh_id: null,
97
+ icao: "ESSA",
98
+ latitude: 59.6519,
99
+ longitude: 17.9186,
100
+ name: "Stockholm Arlanda",
101
+ tz: "Europe/Stockholm"
102
+ },
103
+ {
104
+ code: "ATL",
105
+ country: "US",
106
+ ghcnh_id: "USW00013874",
107
+ icao: "KATL",
108
+ latitude: 33.6407,
109
+ longitude: -84.4277,
110
+ name: "Hartsfield-Jackson Atlanta International",
111
+ tz: "America/New_York"
112
+ },
113
+ {
114
+ code: "AUS",
115
+ country: "US",
116
+ ghcnh_id: "USW00013904",
117
+ icao: "KAUS",
118
+ latitude: 30.1975,
119
+ longitude: -97.6664,
120
+ name: "Austin-Bergstrom International",
121
+ tz: "America/Chicago"
122
+ },
123
+ {
124
+ code: "BOS",
125
+ country: "US",
126
+ ghcnh_id: "USW00014739",
127
+ icao: "KBOS",
128
+ latitude: 42.3656,
129
+ longitude: -71.0096,
130
+ name: "Boston Logan International",
131
+ tz: "America/New_York"
132
+ },
133
+ {
134
+ code: "DCA",
135
+ country: "US",
136
+ ghcnh_id: "USW00013743",
137
+ icao: "KDCA",
138
+ latitude: 38.8512,
139
+ longitude: -77.0402,
140
+ name: "Washington Reagan National",
141
+ tz: "America/New_York"
142
+ },
143
+ {
144
+ code: "DEN",
145
+ country: "US",
146
+ ghcnh_id: "USW00003017",
147
+ icao: "KDEN",
148
+ latitude: 39.8561,
149
+ longitude: -104.6737,
150
+ name: "Denver International",
151
+ tz: "America/Denver"
152
+ },
153
+ {
154
+ code: "DFW",
155
+ country: "US",
156
+ ghcnh_id: "USW00003927",
157
+ icao: "KDFW",
158
+ latitude: 32.8998,
159
+ longitude: -97.0403,
160
+ name: "Dallas-Fort Worth International",
161
+ tz: "America/Chicago"
162
+ },
163
+ {
164
+ code: "HOU",
165
+ country: "US",
166
+ ghcnh_id: "USW00012918",
167
+ icao: "KHOU",
168
+ latitude: 29.6454,
169
+ longitude: -95.2789,
170
+ name: "Houston Hobby",
171
+ tz: "America/Chicago"
172
+ },
173
+ {
174
+ code: "LAS",
175
+ country: "US",
176
+ ghcnh_id: "USW00023169",
177
+ icao: "KLAS",
178
+ latitude: 36.084,
179
+ longitude: -115.1537,
180
+ name: "Harry Reid (McCarran) International",
181
+ tz: "America/Los_Angeles"
182
+ },
183
+ {
184
+ code: "LAX",
185
+ country: "US",
186
+ ghcnh_id: "USW00023174",
187
+ icao: "KLAX",
188
+ latitude: 33.9425,
189
+ longitude: -118.4081,
190
+ name: "Los Angeles International",
191
+ tz: "America/Los_Angeles"
192
+ },
193
+ {
194
+ code: "MDW",
195
+ country: "US",
196
+ ghcnh_id: "USW00014819",
197
+ icao: "KMDW",
198
+ latitude: 41.7868,
199
+ longitude: -87.7522,
200
+ name: "Chicago Midway International",
201
+ tz: "America/Chicago"
202
+ },
203
+ {
204
+ code: "MIA",
205
+ country: "US",
206
+ ghcnh_id: "USW00012839",
207
+ icao: "KMIA",
208
+ latitude: 25.7959,
209
+ longitude: -80.287,
210
+ name: "Miami International",
211
+ tz: "America/New_York"
212
+ },
213
+ {
214
+ code: "MSP",
215
+ country: "US",
216
+ ghcnh_id: "USW00014922",
217
+ icao: "KMSP",
218
+ latitude: 44.8848,
219
+ longitude: -93.2223,
220
+ name: "Minneapolis-St Paul International",
221
+ tz: "America/Chicago"
222
+ },
223
+ {
224
+ code: "MSY",
225
+ country: "US",
226
+ ghcnh_id: "USW00012916",
227
+ icao: "KMSY",
228
+ latitude: 29.9934,
229
+ longitude: -90.258,
230
+ name: "New Orleans Louis Armstrong International",
231
+ tz: "America/Chicago"
232
+ },
233
+ {
234
+ code: "NYC",
235
+ country: "US",
236
+ ghcnh_id: "USW00094728",
237
+ icao: "KNYC",
238
+ latitude: 40.7789,
239
+ longitude: -73.9692,
240
+ name: "Central Park, New York",
241
+ tz: "America/New_York"
242
+ },
243
+ {
244
+ code: "OKC",
245
+ country: "US",
246
+ ghcnh_id: "USW00013967",
247
+ icao: "KOKC",
248
+ latitude: 35.3931,
249
+ longitude: -97.6007,
250
+ name: "Oklahoma City Will Rogers World",
251
+ tz: "America/Chicago"
252
+ },
253
+ {
254
+ code: "PHL",
255
+ country: "US",
256
+ ghcnh_id: "USW00013739",
257
+ icao: "KPHL",
258
+ latitude: 39.8721,
259
+ longitude: -75.2411,
260
+ name: "Philadelphia International",
261
+ tz: "America/New_York"
262
+ },
263
+ {
264
+ code: "PHX",
265
+ country: "US",
266
+ ghcnh_id: "USW00023183",
267
+ icao: "KPHX",
268
+ latitude: 33.4373,
269
+ longitude: -112.0078,
270
+ name: "Phoenix Sky Harbor International",
271
+ tz: "America/Phoenix"
272
+ },
273
+ {
274
+ code: "SAT",
275
+ country: "US",
276
+ ghcnh_id: "USW00012921",
277
+ icao: "KSAT",
278
+ latitude: 29.5337,
279
+ longitude: -98.4698,
280
+ name: "San Antonio International",
281
+ tz: "America/Chicago"
282
+ },
283
+ {
284
+ code: "SEA",
285
+ country: "US",
286
+ ghcnh_id: "USW00024233",
287
+ icao: "KSEA",
288
+ latitude: 47.4502,
289
+ longitude: -122.3088,
290
+ name: "Seattle-Tacoma International",
291
+ tz: "America/Los_Angeles"
292
+ },
293
+ {
294
+ code: "SFO",
295
+ country: "US",
296
+ ghcnh_id: "USW00023234",
297
+ icao: "KSFO",
298
+ latitude: 37.6213,
299
+ longitude: -122.379,
300
+ name: "San Francisco International",
301
+ tz: "America/Los_Angeles"
302
+ },
303
+ {
304
+ code: "LEBL",
305
+ country: "ES",
306
+ ghcnh_id: null,
307
+ icao: "LEBL",
308
+ latitude: 41.2974,
309
+ longitude: 2.0833,
310
+ name: "Barcelona El Prat",
311
+ tz: "Europe/Madrid"
312
+ },
313
+ {
314
+ code: "LEMD",
315
+ country: "ES",
316
+ ghcnh_id: null,
317
+ icao: "LEMD",
318
+ latitude: 40.4719,
319
+ longitude: -3.5626,
320
+ name: "Madrid Barajas",
321
+ tz: "Europe/Madrid"
322
+ },
323
+ {
324
+ code: "LFPB",
325
+ country: "FR",
326
+ ghcnh_id: null,
327
+ icao: "LFPB",
328
+ latitude: 48.9694,
329
+ longitude: 2.4414,
330
+ name: "Paris Le Bourget",
331
+ tz: "Europe/Paris"
332
+ },
333
+ {
334
+ code: "LFPG",
335
+ country: "FR",
336
+ ghcnh_id: null,
337
+ icao: "LFPG",
338
+ latitude: 49.0097,
339
+ longitude: 2.5479,
340
+ name: "Paris Charles de Gaulle",
341
+ tz: "Europe/Paris"
342
+ },
343
+ {
344
+ code: "LFPO",
345
+ country: "FR",
346
+ ghcnh_id: null,
347
+ icao: "LFPO",
348
+ latitude: 48.7233,
349
+ longitude: 2.3794,
350
+ name: "Paris Orly",
351
+ tz: "Europe/Paris"
352
+ },
353
+ {
354
+ code: "LIMC",
355
+ country: "IT",
356
+ ghcnh_id: null,
357
+ icao: "LIMC",
358
+ latitude: 45.6306,
359
+ longitude: 8.7281,
360
+ name: "Milan Malpensa",
361
+ tz: "Europe/Rome"
362
+ },
363
+ {
364
+ code: "LIRF",
365
+ country: "IT",
366
+ ghcnh_id: null,
367
+ icao: "LIRF",
368
+ latitude: 41.8003,
369
+ longitude: 12.2389,
370
+ name: "Rome Fiumicino",
371
+ tz: "Europe/Rome"
372
+ },
373
+ {
374
+ code: "LOWW",
375
+ country: "AT",
376
+ ghcnh_id: null,
377
+ icao: "LOWW",
378
+ latitude: 48.1103,
379
+ longitude: 16.5697,
380
+ name: "Vienna International",
381
+ tz: "Europe/Vienna"
382
+ },
383
+ {
384
+ code: "LSZH",
385
+ country: "CH",
386
+ ghcnh_id: null,
387
+ icao: "LSZH",
388
+ latitude: 47.4647,
389
+ longitude: 8.5492,
390
+ name: "Zurich",
391
+ tz: "Europe/Zurich"
392
+ },
393
+ {
394
+ code: "NZAA",
395
+ country: "NZ",
396
+ ghcnh_id: null,
397
+ icao: "NZAA",
398
+ latitude: -37.0081,
399
+ longitude: 174.7917,
400
+ name: "Auckland",
401
+ tz: "Pacific/Auckland"
402
+ },
403
+ {
404
+ code: "NZWN",
405
+ country: "NZ",
406
+ ghcnh_id: null,
407
+ icao: "NZWN",
408
+ latitude: -41.3272,
409
+ longitude: 174.8053,
410
+ name: "Wellington",
411
+ tz: "Pacific/Auckland"
412
+ },
413
+ {
414
+ code: "OERK",
415
+ country: "SA",
416
+ ghcnh_id: null,
417
+ icao: "OERK",
418
+ latitude: 24.9576,
419
+ longitude: 46.6988,
420
+ name: "Riyadh King Khalid International",
421
+ tz: "Asia/Riyadh"
422
+ },
423
+ {
424
+ code: "OMDB",
425
+ country: "AE",
426
+ ghcnh_id: null,
427
+ icao: "OMDB",
428
+ latitude: 25.2532,
429
+ longitude: 55.3657,
430
+ name: "Dubai International",
431
+ tz: "Asia/Dubai"
432
+ },
433
+ {
434
+ code: "OTHH",
435
+ country: "QA",
436
+ ghcnh_id: null,
437
+ icao: "OTHH",
438
+ latitude: 25.2731,
439
+ longitude: 51.608,
440
+ name: "Doha Hamad International",
441
+ tz: "Asia/Qatar"
442
+ },
443
+ {
444
+ code: "RCTP",
445
+ country: "TW",
446
+ ghcnh_id: null,
447
+ icao: "RCTP",
448
+ latitude: 25.0777,
449
+ longitude: 121.2328,
450
+ name: "Taipei Taoyuan",
451
+ tz: "Asia/Taipei"
452
+ },
453
+ {
454
+ code: "RJAA",
455
+ country: "JP",
456
+ ghcnh_id: null,
457
+ icao: "RJAA",
458
+ latitude: 35.7647,
459
+ longitude: 140.3864,
460
+ name: "Tokyo Narita",
461
+ tz: "Asia/Tokyo"
462
+ },
463
+ {
464
+ code: "RJTT",
465
+ country: "JP",
466
+ ghcnh_id: null,
467
+ icao: "RJTT",
468
+ latitude: 35.5522,
469
+ longitude: 139.78,
470
+ name: "Tokyo Haneda",
471
+ tz: "Asia/Tokyo"
472
+ },
473
+ {
474
+ code: "RKSI",
475
+ country: "KR",
476
+ ghcnh_id: null,
477
+ icao: "RKSI",
478
+ latitude: 37.4691,
479
+ longitude: 126.4505,
480
+ name: "Seoul Incheon",
481
+ tz: "Asia/Seoul"
482
+ },
483
+ {
484
+ code: "SAEZ",
485
+ country: "AR",
486
+ ghcnh_id: null,
487
+ icao: "SAEZ",
488
+ latitude: -34.8222,
489
+ longitude: -58.5358,
490
+ name: "Buenos Aires Ezeiza",
491
+ tz: "America/Argentina/Buenos_Aires"
492
+ },
493
+ {
494
+ code: "SBGR",
495
+ country: "BR",
496
+ ghcnh_id: null,
497
+ icao: "SBGR",
498
+ latitude: -23.4356,
499
+ longitude: -46.4731,
500
+ name: "S\xE3o Paulo Guarulhos",
501
+ tz: "America/Sao_Paulo"
502
+ },
503
+ {
504
+ code: "UUEE",
505
+ country: "RU",
506
+ ghcnh_id: null,
507
+ icao: "UUEE",
508
+ latitude: 55.9728,
509
+ longitude: 37.4147,
510
+ name: "Moscow Sheremetyevo",
511
+ tz: "Europe/Moscow"
512
+ },
513
+ {
514
+ code: "VABB",
515
+ country: "IN",
516
+ ghcnh_id: null,
517
+ icao: "VABB",
518
+ latitude: 19.0887,
519
+ longitude: 72.8679,
520
+ name: "Mumbai Chhatrapati Shivaji",
521
+ tz: "Asia/Kolkata"
522
+ },
523
+ {
524
+ code: "VHHH",
525
+ country: "HK",
526
+ ghcnh_id: null,
527
+ icao: "VHHH",
528
+ latitude: 22.308,
529
+ longitude: 113.9185,
530
+ name: "Hong Kong International",
531
+ tz: "Asia/Hong_Kong"
532
+ },
533
+ {
534
+ code: "VIDP",
535
+ country: "IN",
536
+ ghcnh_id: null,
537
+ icao: "VIDP",
538
+ latitude: 28.5562,
539
+ longitude: 77.1,
540
+ name: "Delhi Indira Gandhi",
541
+ tz: "Asia/Kolkata"
542
+ },
543
+ {
544
+ code: "VTBS",
545
+ country: "TH",
546
+ ghcnh_id: null,
547
+ icao: "VTBS",
548
+ latitude: 13.69,
549
+ longitude: 100.7501,
550
+ name: "Bangkok Suvarnabhumi",
551
+ tz: "Asia/Bangkok"
552
+ },
553
+ {
554
+ code: "WSSS",
555
+ country: "SG",
556
+ ghcnh_id: null,
557
+ icao: "WSSS",
558
+ latitude: 1.3644,
559
+ longitude: 103.9915,
560
+ name: "Singapore Changi",
561
+ tz: "Asia/Singapore"
562
+ },
563
+ {
564
+ code: "YBBN",
565
+ country: "AU",
566
+ ghcnh_id: null,
567
+ icao: "YBBN",
568
+ latitude: -27.3842,
569
+ longitude: 153.1175,
570
+ name: "Brisbane",
571
+ tz: "Australia/Brisbane"
572
+ },
573
+ {
574
+ code: "YMML",
575
+ country: "AU",
576
+ ghcnh_id: null,
577
+ icao: "YMML",
578
+ latitude: -37.6733,
579
+ longitude: 144.8433,
580
+ name: "Melbourne Tullamarine",
581
+ tz: "Australia/Melbourne"
582
+ },
583
+ {
584
+ code: "YSSY",
585
+ country: "AU",
586
+ ghcnh_id: null,
587
+ icao: "YSSY",
588
+ latitude: -33.9461,
589
+ longitude: 151.1772,
590
+ name: "Sydney Kingsford Smith",
591
+ tz: "Australia/Sydney"
592
+ },
593
+ {
594
+ code: "ZBAA",
595
+ country: "CN",
596
+ ghcnh_id: null,
597
+ icao: "ZBAA",
598
+ latitude: 40.0801,
599
+ longitude: 116.5846,
600
+ name: "Beijing Capital",
601
+ tz: "Asia/Shanghai"
602
+ },
603
+ {
604
+ code: "ZSPD",
605
+ country: "CN",
606
+ ghcnh_id: null,
607
+ icao: "ZSPD",
608
+ latitude: 31.1443,
609
+ longitude: 121.8083,
610
+ name: "Shanghai Pudong",
611
+ tz: "Asia/Shanghai"
612
+ }
613
+ ];
614
+ var STATION_BY_CODE = /* @__PURE__ */ new Map([
615
+ ["ATL", STATIONS[10]],
616
+ ["AUS", STATIONS[11]],
617
+ ["BOS", STATIONS[12]],
618
+ ["DCA", STATIONS[13]],
619
+ ["DEN", STATIONS[14]],
620
+ ["DFW", STATIONS[15]],
621
+ ["EDDB", STATIONS[0]],
622
+ ["EDDF", STATIONS[1]],
623
+ ["EDDM", STATIONS[2]],
624
+ ["EFHK", STATIONS[3]],
625
+ ["EGKK", STATIONS[4]],
626
+ ["EGLL", STATIONS[5]],
627
+ ["EHAM", STATIONS[6]],
628
+ ["EKCH", STATIONS[7]],
629
+ ["EPWA", STATIONS[8]],
630
+ ["ESSA", STATIONS[9]],
631
+ ["HOU", STATIONS[16]],
632
+ ["LAS", STATIONS[17]],
633
+ ["LAX", STATIONS[18]],
634
+ ["LEBL", STATIONS[30]],
635
+ ["LEMD", STATIONS[31]],
636
+ ["LFPB", STATIONS[32]],
637
+ ["LFPG", STATIONS[33]],
638
+ ["LFPO", STATIONS[34]],
639
+ ["LIMC", STATIONS[35]],
640
+ ["LIRF", STATIONS[36]],
641
+ ["LOWW", STATIONS[37]],
642
+ ["LSZH", STATIONS[38]],
643
+ ["MDW", STATIONS[19]],
644
+ ["MIA", STATIONS[20]],
645
+ ["MSP", STATIONS[21]],
646
+ ["MSY", STATIONS[22]],
647
+ ["NYC", STATIONS[23]],
648
+ ["NZAA", STATIONS[39]],
649
+ ["NZWN", STATIONS[40]],
650
+ ["OERK", STATIONS[41]],
651
+ ["OKC", STATIONS[24]],
652
+ ["OMDB", STATIONS[42]],
653
+ ["OTHH", STATIONS[43]],
654
+ ["PHL", STATIONS[25]],
655
+ ["PHX", STATIONS[26]],
656
+ ["RCTP", STATIONS[44]],
657
+ ["RJAA", STATIONS[45]],
658
+ ["RJTT", STATIONS[46]],
659
+ ["RKSI", STATIONS[47]],
660
+ ["SAEZ", STATIONS[48]],
661
+ ["SAT", STATIONS[27]],
662
+ ["SBGR", STATIONS[49]],
663
+ ["SEA", STATIONS[28]],
664
+ ["SFO", STATIONS[29]],
665
+ ["UUEE", STATIONS[50]],
666
+ ["VABB", STATIONS[51]],
667
+ ["VHHH", STATIONS[52]],
668
+ ["VIDP", STATIONS[53]],
669
+ ["VTBS", STATIONS[54]],
670
+ ["WSSS", STATIONS[55]],
671
+ ["YBBN", STATIONS[56]],
672
+ ["YMML", STATIONS[57]],
673
+ ["YSSY", STATIONS[58]],
674
+ ["ZBAA", STATIONS[59]],
675
+ ["ZSPD", STATIONS[60]]
676
+ ]);
677
+ var STATION_BY_ICAO = /* @__PURE__ */ new Map([
678
+ ["EDDB", STATIONS[0]],
679
+ ["EDDF", STATIONS[1]],
680
+ ["EDDM", STATIONS[2]],
681
+ ["EFHK", STATIONS[3]],
682
+ ["EGKK", STATIONS[4]],
683
+ ["EGLL", STATIONS[5]],
684
+ ["EHAM", STATIONS[6]],
685
+ ["EKCH", STATIONS[7]],
686
+ ["EPWA", STATIONS[8]],
687
+ ["ESSA", STATIONS[9]],
688
+ ["KATL", STATIONS[10]],
689
+ ["KAUS", STATIONS[11]],
690
+ ["KBOS", STATIONS[12]],
691
+ ["KDCA", STATIONS[13]],
692
+ ["KDEN", STATIONS[14]],
693
+ ["KDFW", STATIONS[15]],
694
+ ["KHOU", STATIONS[16]],
695
+ ["KLAS", STATIONS[17]],
696
+ ["KLAX", STATIONS[18]],
697
+ ["KMDW", STATIONS[19]],
698
+ ["KMIA", STATIONS[20]],
699
+ ["KMSP", STATIONS[21]],
700
+ ["KMSY", STATIONS[22]],
701
+ ["KNYC", STATIONS[23]],
702
+ ["KOKC", STATIONS[24]],
703
+ ["KPHL", STATIONS[25]],
704
+ ["KPHX", STATIONS[26]],
705
+ ["KSAT", STATIONS[27]],
706
+ ["KSEA", STATIONS[28]],
707
+ ["KSFO", STATIONS[29]],
708
+ ["LEBL", STATIONS[30]],
709
+ ["LEMD", STATIONS[31]],
710
+ ["LFPB", STATIONS[32]],
711
+ ["LFPG", STATIONS[33]],
712
+ ["LFPO", STATIONS[34]],
713
+ ["LIMC", STATIONS[35]],
714
+ ["LIRF", STATIONS[36]],
715
+ ["LOWW", STATIONS[37]],
716
+ ["LSZH", STATIONS[38]],
717
+ ["NZAA", STATIONS[39]],
718
+ ["NZWN", STATIONS[40]],
719
+ ["OERK", STATIONS[41]],
720
+ ["OMDB", STATIONS[42]],
721
+ ["OTHH", STATIONS[43]],
722
+ ["RCTP", STATIONS[44]],
723
+ ["RJAA", STATIONS[45]],
724
+ ["RJTT", STATIONS[46]],
725
+ ["RKSI", STATIONS[47]],
726
+ ["SAEZ", STATIONS[48]],
727
+ ["SBGR", STATIONS[49]],
728
+ ["UUEE", STATIONS[50]],
729
+ ["VABB", STATIONS[51]],
730
+ ["VHHH", STATIONS[52]],
731
+ ["VIDP", STATIONS[53]],
732
+ ["VTBS", STATIONS[54]],
733
+ ["WSSS", STATIONS[55]],
734
+ ["YBBN", STATIONS[56]],
735
+ ["YMML", STATIONS[57]],
736
+ ["YSSY", STATIONS[58]],
737
+ ["ZBAA", STATIONS[59]],
738
+ ["ZSPD", STATIONS[60]]
739
+ ]);
740
+
741
+ // src/discovery/availability.ts
742
+ function hasListKeys(store) {
743
+ return typeof store.listKeys === "function";
744
+ }
745
+ var STATION_RE = /^[A-Z0-9]{3,5}$/;
746
+ function normalizeStation(station) {
747
+ const upper = station.toUpperCase();
748
+ if (!STATION_RE.test(upper)) {
749
+ throw new RangeError(
750
+ `availability: station must be a 3-5 char alphanumeric code; got ${JSON.stringify(station)}`
751
+ );
752
+ }
753
+ const byIcao = STATION_BY_ICAO.get(upper);
754
+ if (byIcao !== void 0) {
755
+ return byIcao.code ?? byIcao.icao;
756
+ }
757
+ const byCode = STATION_BY_CODE.get(upper);
758
+ if (byCode !== void 0) {
759
+ return byCode.code ?? byCode.icao;
760
+ }
761
+ return upper;
762
+ }
763
+ var OBS_KEY_RE = /^mostlyright:v1:observations:([A-Z0-9]+):(\d{4}):(\d{2})(?::[a-z0-9_-]+)?$/;
764
+ var CLIMATE_KEY_RE = /^mostlyright:v1:climate:([A-Z0-9]+):(\d{4})$/;
765
+ async function availability(station, cache, opts = {}) {
766
+ const stationCode = normalizeStation(station);
767
+ const empty = Object.freeze({
768
+ station: stationCode,
769
+ monthsCached: 0,
770
+ firstMonth: null,
771
+ lastMonth: null,
772
+ climateYears: 0,
773
+ firstClimateYear: null,
774
+ lastClimateYear: null
775
+ });
776
+ if (!hasListKeys(cache)) {
777
+ return empty;
778
+ }
779
+ const upperInput = station.toUpperCase();
780
+ const scanCodes = upperInput === stationCode ? [stationCode] : [stationCode, upperInput];
781
+ const obsPrefixes = scanCodes.map((c) => `mostlyright:v1:observations:${c}:`);
782
+ const climatePrefixes = scanCodes.map((c) => `mostlyright:v1:climate:${c}:`);
783
+ const obsKeySets = await Promise.all(obsPrefixes.map((p) => cache.listKeys(p)));
784
+ const climateKeySets = await Promise.all(climatePrefixes.map((p) => cache.listKeys(p)));
785
+ const obsKeys = obsKeySets.flat();
786
+ const climateKeys = climateKeySets.flat();
787
+ const monthCandidates = /* @__PURE__ */ new Map();
788
+ for (const key of obsKeys) {
789
+ const m = OBS_KEY_RE.exec(key);
790
+ if (m === null) continue;
791
+ const keyStation = m[1];
792
+ if (!scanCodes.includes(keyStation)) continue;
793
+ const ym = `${m[2]}-${m[3]}`;
794
+ const arr = monthCandidates.get(ym) ?? [];
795
+ arr.push(key);
796
+ monthCandidates.set(ym, arr);
797
+ }
798
+ const yearCandidates = /* @__PURE__ */ new Map();
799
+ for (const key of climateKeys) {
800
+ const m = CLIMATE_KEY_RE.exec(key);
801
+ if (m === null) continue;
802
+ const keyStation = m[1];
803
+ if (!scanCodes.includes(keyStation)) continue;
804
+ const y = m[2];
805
+ const arr = yearCandidates.get(y) ?? [];
806
+ arr.push(key);
807
+ yearCandidates.set(y, arr);
808
+ }
809
+ let months;
810
+ let years;
811
+ if (opts.validate === true) {
812
+ const monthChecks = await Promise.all(
813
+ [...monthCandidates.entries()].map(async ([ym, keys]) => {
814
+ for (const k of keys) {
815
+ if (await cache.get(k) !== null) return ym;
816
+ }
817
+ return null;
818
+ })
819
+ );
820
+ months = monthChecks.filter((v) => v !== null).sort();
821
+ const yearChecks = await Promise.all(
822
+ [...yearCandidates.entries()].map(async ([y, keys]) => {
823
+ for (const k of keys) {
824
+ if (await cache.get(k) !== null) return y;
825
+ }
826
+ return null;
827
+ })
828
+ );
829
+ years = yearChecks.filter((v) => v !== null).sort();
830
+ } else {
831
+ months = [...monthCandidates.keys()].sort();
832
+ years = [...yearCandidates.keys()].sort();
833
+ }
834
+ return Object.freeze({
835
+ station: stationCode,
836
+ monthsCached: months.length,
837
+ firstMonth: months[0] ?? null,
838
+ lastMonth: months.at(-1) ?? null,
839
+ climateYears: years.length,
840
+ firstClimateYear: years[0] ?? null,
841
+ lastClimateYear: years.at(-1) ?? null
842
+ });
843
+ }
844
+
845
+ // src/discovery/international.ts
846
+ var LOW_COVERAGE_THRESHOLD = 12;
847
+ var PARTS_CACHE = /* @__PURE__ */ new Map();
848
+ function getDateFormatter(tz) {
849
+ let f = PARTS_CACHE.get(tz);
850
+ if (f === void 0) {
851
+ f = new Intl.DateTimeFormat("en-US", {
852
+ timeZone: tz,
853
+ year: "numeric",
854
+ month: "2-digit",
855
+ day: "2-digit"
856
+ });
857
+ PARTS_CACHE.set(tz, f);
858
+ }
859
+ return f;
860
+ }
861
+ function localDateFor(instant, tz) {
862
+ const parts = getDateFormatter(tz).formatToParts(instant);
863
+ let y = "";
864
+ let m = "";
865
+ let d = "";
866
+ for (const p of parts) {
867
+ if (p.type === "year") y = p.value;
868
+ else if (p.type === "month") m = p.value;
869
+ else if (p.type === "day") d = p.value;
870
+ }
871
+ return `${y}-${m}-${d}`;
872
+ }
873
+ function parseInstant(observed) {
874
+ if (observed === void 0 || observed === null || observed.length === 0) {
875
+ return null;
876
+ }
877
+ const ms = Date.parse(observed);
878
+ if (Number.isNaN(ms)) return null;
879
+ return new Date(ms);
880
+ }
881
+ function roundHalfUp(value, places) {
882
+ if (!Number.isFinite(value)) return value;
883
+ const scale = 10 ** places;
884
+ const sign = value < 0 ? -1 : 1;
885
+ const abs = Math.abs(value);
886
+ const rounded = Math.floor(abs * scale + 0.5 + abs * 1e-12) / scale;
887
+ return sign * rounded;
888
+ }
889
+ function cToF(c) {
890
+ return c * 1.8 + 32;
891
+ }
892
+ function internationalDailyExtremes(rows, opts) {
893
+ const tz = opts.stationTz;
894
+ if (typeof tz !== "string" || tz.length === 0) {
895
+ throw new RangeError("internationalDailyExtremes: stationTz is required (non-empty string)");
896
+ }
897
+ const precision = opts.precision ?? 0;
898
+ const minObs = opts.minObs ?? LOW_COVERAGE_THRESHOLD;
899
+ try {
900
+ getDateFormatter(tz);
901
+ } catch (e) {
902
+ throw new RangeError(
903
+ `internationalDailyExtremes: invalid stationTz ${JSON.stringify(tz)}: ${e.message}`
904
+ );
905
+ }
906
+ const byLocalDate = /* @__PURE__ */ new Map();
907
+ for (const row of rows) {
908
+ const instant = parseInstant(row.observed_at);
909
+ if (instant === null) continue;
910
+ const localDate = localDateFor(instant, tz);
911
+ let bucket = byLocalDate.get(localDate);
912
+ if (bucket === void 0) {
913
+ bucket = { temps: [], precipMm: 0 };
914
+ byLocalDate.set(localDate, bucket);
915
+ }
916
+ const t = row.temp_c;
917
+ if (typeof t === "number" && Number.isFinite(t)) {
918
+ bucket.temps.push({ value: t, source: row.source ?? null });
919
+ }
920
+ const p = row.precip_mm_1h;
921
+ if (typeof p === "number" && Number.isFinite(p)) {
922
+ bucket.precipMm += p;
923
+ }
924
+ }
925
+ const out = [];
926
+ const sortedDates = [...byLocalDate.keys()].sort();
927
+ for (const localDate of sortedDates) {
928
+ const bucket = byLocalDate.get(localDate);
929
+ if (bucket === void 0) continue;
930
+ const nObs = bucket.temps.length;
931
+ let tempMinC = null;
932
+ let tempMaxC = null;
933
+ let tempMeanC = null;
934
+ let sourceTmin = null;
935
+ let sourceTmax = null;
936
+ if (nObs > 0 && nObs >= minObs) {
937
+ let minIdx = 0;
938
+ let maxIdx = 0;
939
+ let sum = 0;
940
+ for (let i = 0; i < bucket.temps.length; i += 1) {
941
+ const v = bucket.temps[i];
942
+ sum += v.value;
943
+ const minRow2 = bucket.temps[minIdx];
944
+ const maxRow2 = bucket.temps[maxIdx];
945
+ if (v.value < minRow2.value) minIdx = i;
946
+ if (v.value > maxRow2.value) maxIdx = i;
947
+ }
948
+ const mean = sum / nObs;
949
+ const minRow = bucket.temps[minIdx];
950
+ const maxRow = bucket.temps[maxIdx];
951
+ tempMinC = roundHalfUp(minRow.value, precision);
952
+ tempMaxC = roundHalfUp(maxRow.value, precision);
953
+ tempMeanC = roundHalfUp(mean, precision);
954
+ sourceTmin = minRow.source;
955
+ sourceTmax = maxRow.source;
956
+ }
957
+ out.push(
958
+ Object.freeze({
959
+ localDate,
960
+ nObs,
961
+ tempMinC,
962
+ tempMaxC,
963
+ tempMeanC,
964
+ tempMinF: tempMinC === null ? null : roundHalfUp(cToF(tempMinC), precision),
965
+ tempMaxF: tempMaxC === null ? null : roundHalfUp(cToF(tempMaxC), precision),
966
+ precipMm: roundHalfUp(bucket.precipMm, 4),
967
+ sourceTmin,
968
+ sourceTmax
969
+ })
970
+ );
971
+ }
972
+ return out;
973
+ }
974
+
975
+ // src/exceptions/index.ts
976
+ function toJsonSafe(value, seen) {
977
+ const visited = seen ?? /* @__PURE__ */ new WeakSet();
978
+ if (value === null || value === void 0) {
979
+ return null;
980
+ }
981
+ if (typeof value === "boolean") {
982
+ return value;
983
+ }
984
+ if (typeof value === "string") {
985
+ return value;
986
+ }
987
+ if (typeof value === "number") {
988
+ return Number.isFinite(value) ? value : null;
989
+ }
990
+ if (typeof value === "bigint") {
991
+ if (value >= BigInt(Number.MIN_SAFE_INTEGER) && value <= BigInt(Number.MAX_SAFE_INTEGER)) {
992
+ return Number(value);
993
+ }
994
+ return { _repr_only: true, value: value.toString() };
995
+ }
996
+ if (value instanceof Date) {
997
+ if (Number.isNaN(value.getTime())) {
998
+ return null;
999
+ }
1000
+ return value.toISOString();
1001
+ }
1002
+ if (Array.isArray(value)) {
1003
+ if (visited.has(value)) {
1004
+ return { _cycle: true, value: String(value) };
1005
+ }
1006
+ visited.add(value);
1007
+ try {
1008
+ return value.map((item) => toJsonSafe(item, visited));
1009
+ } finally {
1010
+ visited.delete(value);
1011
+ }
1012
+ }
1013
+ if (typeof value === "object") {
1014
+ if (visited.has(value)) {
1015
+ return { _cycle: true, value: String(value) };
1016
+ }
1017
+ visited.add(value);
1018
+ try {
1019
+ const out = {};
1020
+ for (const key of Object.keys(value)) {
1021
+ if (typeof key !== "string") {
1022
+ throw new TypeError(`toJsonSafe dict keys must be string; got ${typeof key}`);
1023
+ }
1024
+ out[key] = toJsonSafe(value[key], visited);
1025
+ }
1026
+ return out;
1027
+ } finally {
1028
+ visited.delete(value);
1029
+ }
1030
+ }
1031
+ return { _repr_only: true, value: String(value) };
1032
+ }
1033
+ var TradewindsError = class extends Error {
1034
+ /** Subclass override — the stable string enum surfaced via `errorCode`. */
1035
+ static defaultErrorCode = "TRADEWINDS_ERROR";
1036
+ errorCode;
1037
+ source;
1038
+ requestId;
1039
+ constructor(message = "", options = {}) {
1040
+ super(message);
1041
+ this.name = new.target.name;
1042
+ const ctor = this.constructor;
1043
+ this.errorCode = options.errorCode ?? ctor.defaultErrorCode;
1044
+ this.source = options.source ?? null;
1045
+ this.requestId = options.requestId ?? null;
1046
+ Object.setPrototypeOf(this, new.target.prototype);
1047
+ }
1048
+ /**
1049
+ * Subclass hook returning the structured attributes for `toDict`.
1050
+ * Values are passed through `toJsonSafe` by `toDict()`, so subclasses
1051
+ * don't need to coerce values themselves.
1052
+ */
1053
+ payload() {
1054
+ return {
1055
+ error_code: this.errorCode,
1056
+ message: this.message,
1057
+ source: this.source,
1058
+ request_id: this.requestId
1059
+ };
1060
+ }
1061
+ /** Return a JSON-safe dict suitable for MCP `error.data`. */
1062
+ toDict() {
1063
+ const safe = toJsonSafe(this.payload());
1064
+ return safe;
1065
+ }
1066
+ };
1067
+
1068
+ // src/formats/toon.ts
1069
+ var SAFE_KEY_RE = /^[A-Za-z_][A-Za-z0-9_.]*$/;
1070
+ var NUMERIC_LIKE_RE = /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?$/;
1071
+ var NEEDS_QUOTE_CHARS_RE = /[:\\\"'\[\]{}\x00-\x1f\x7f\x85\u2028\u2029]/;
1072
+ var UNSUPPORTED_CTRL_RE = /[\x00-\x08\x0b\x0c\x0e-\x1f\x7f\x85\u2028\u2029]/g;
1073
+ function formatNumber(n) {
1074
+ if (!Number.isFinite(n)) return "null";
1075
+ if (n === 0) return "0";
1076
+ if (Number.isInteger(n) && Math.abs(n) <= 2 ** 53) return String(n);
1077
+ let s = String(n);
1078
+ if (/[eE]/.test(s)) {
1079
+ s = expandExponent(s);
1080
+ }
1081
+ return s;
1082
+ }
1083
+ function expandExponent(s) {
1084
+ const m = /^(-?)(\d+(?:\.\d+)?)[eE]([+-]?\d+)$/.exec(s);
1085
+ if (!m) return s;
1086
+ const sign = m[1] ?? "";
1087
+ const mantissa = m[2] ?? "";
1088
+ const exp = Number(m[3]);
1089
+ const [intPart, fracPart = ""] = mantissa.split(".");
1090
+ const digits = (intPart ?? "") + fracPart;
1091
+ const pointPos = (intPart ?? "").length + exp;
1092
+ let out;
1093
+ if (pointPos <= 0) {
1094
+ out = `0.${"0".repeat(-pointPos)}${digits}`.replace(/0+$/, "");
1095
+ if (out.endsWith(".")) out = out.slice(0, -1);
1096
+ } else if (pointPos >= digits.length) {
1097
+ out = digits + "0".repeat(pointPos - digits.length);
1098
+ } else {
1099
+ out = `${digits.slice(0, pointPos)}.${digits.slice(pointPos)}`.replace(/0+$/, "");
1100
+ if (out.endsWith(".")) out = out.slice(0, -1);
1101
+ }
1102
+ return sign + out;
1103
+ }
1104
+ function needsQuoting(s, delimiter) {
1105
+ if (s.length === 0) return true;
1106
+ const first = s.charAt(0);
1107
+ const last = s.charAt(s.length - 1);
1108
+ if (first === " " || first === " ") return true;
1109
+ if (last === " " || last === " ") return true;
1110
+ if (s === "true" || s === "false" || s === "null") return true;
1111
+ if (first === "-" || first === "+") return true;
1112
+ if (first >= "0" && first <= "9") return true;
1113
+ if (NUMERIC_LIKE_RE.test(s)) return true;
1114
+ if (s.includes(delimiter)) return true;
1115
+ if (NEEDS_QUOTE_CHARS_RE.test(s)) return true;
1116
+ return false;
1117
+ }
1118
+ function quoteString(s) {
1119
+ let out = s.replace(UNSUPPORTED_CTRL_RE, "");
1120
+ out = out.replace(/\\/g, "\\\\");
1121
+ out = out.replace(/"/g, '\\"');
1122
+ out = out.replace(/\n/g, "\\n");
1123
+ out = out.replace(/\r/g, "\\r");
1124
+ out = out.replace(/\t/g, "\\t");
1125
+ return `"${out}"`;
1126
+ }
1127
+ function formatKey(key) {
1128
+ if (typeof key !== "string") {
1129
+ throw new TypeError(`TOON keys must be strings; got ${typeof key}`);
1130
+ }
1131
+ if (SAFE_KEY_RE.test(key)) return key;
1132
+ return quoteString(key);
1133
+ }
1134
+ function encodeScalar(value, delimiter) {
1135
+ if (value === null || value === void 0) return "null";
1136
+ if (typeof value === "boolean") return value ? "true" : "false";
1137
+ if (typeof value === "number") return formatNumber(value);
1138
+ if (typeof value === "string") {
1139
+ if (needsQuoting(value, delimiter)) return quoteString(value);
1140
+ return value;
1141
+ }
1142
+ if (typeof value === "object") {
1143
+ if (Array.isArray(value)) {
1144
+ return quoteString(JSON.stringify(value));
1145
+ }
1146
+ const sorted = sortedJson(value);
1147
+ return quoteString(sorted);
1148
+ }
1149
+ return quoteString(String(value));
1150
+ }
1151
+ function sortedJson(obj) {
1152
+ const keys = Object.keys(obj).sort();
1153
+ const parts = keys.map((k) => `${JSON.stringify(k)}:${JSON.stringify(obj[k])}`);
1154
+ return `{${parts.join(",")}}`;
1155
+ }
1156
+ var ToonTabularError = class extends RangeError {
1157
+ name = "ToonTabularError";
1158
+ };
1159
+ function isToonPrimitive(v) {
1160
+ if (v === null || v === void 0) return true;
1161
+ const t = typeof v;
1162
+ return t === "string" || t === "number" || t === "boolean";
1163
+ }
1164
+ function assertTabular(rows) {
1165
+ if (rows.length === 0) return;
1166
+ const first = rows[0];
1167
+ const expectedKeys = Object.keys(first);
1168
+ if (expectedKeys.length === 0) {
1169
+ throw new ToonTabularError(
1170
+ "toonDumps requires non-empty rows; first row has no keys (Python parity: encode_tabular rejects empty key set)"
1171
+ );
1172
+ }
1173
+ const expectedKeySet = new Set(expectedKeys);
1174
+ for (let i = 0; i < rows.length; i++) {
1175
+ const row = rows[i];
1176
+ const rowKeys = Object.keys(row);
1177
+ if (rowKeys.length !== expectedKeySet.size) {
1178
+ throw new ToonTabularError(
1179
+ `toonDumps requires uniform rows; row ${i} has ${rowKeys.length} key(s) vs row 0's ${expectedKeySet.size}. Python encode_tabular rejects rows whose key sets differ.`
1180
+ );
1181
+ }
1182
+ for (const k of rowKeys) {
1183
+ if (!expectedKeySet.has(k)) {
1184
+ throw new ToonTabularError(
1185
+ `toonDumps requires uniform rows; row ${i} has key ${JSON.stringify(k)} not present in row 0. Python encode_tabular rejects rows whose key sets differ.`
1186
+ );
1187
+ }
1188
+ }
1189
+ for (const k of expectedKeys) {
1190
+ const v = row[k];
1191
+ if (!isToonPrimitive(v)) {
1192
+ throw new ToonTabularError(
1193
+ `toonDumps requires primitive cell values; row ${i} column ${JSON.stringify(k)} has non-primitive value of type ${typeof v}. Python encode_tabular rejects nested objects/arrays at the cell level.`
1194
+ );
1195
+ }
1196
+ }
1197
+ }
1198
+ }
1199
+ function toonDumps(rows, columns) {
1200
+ if (rows.length === 0) {
1201
+ if (columns !== void 0) {
1202
+ const cols2 = columns.map((c) => formatKey(String(c))).join(",");
1203
+ return `rows[0]{${cols2}}:`;
1204
+ }
1205
+ return "rows[0]:";
1206
+ }
1207
+ assertTabular(rows);
1208
+ const cols = Object.keys(rows[0]);
1209
+ const colHeader = cols.map((c) => formatKey(c)).join(",");
1210
+ const header = `rows[${rows.length}]{${colHeader}}:`;
1211
+ const dataLines = rows.map((r) => {
1212
+ const vals = cols.map((c) => encodeScalar(r[c], ","));
1213
+ return ` ${vals.join(",")}`;
1214
+ });
1215
+ return `${header}
1216
+ ${dataLines.join("\n")}`;
1217
+ }
1218
+
1219
+ // src/discovery/snapshot.ts
1220
+ function normalizeKnowledgeTime(value) {
1221
+ if (value === void 0) {
1222
+ return (/* @__PURE__ */ new Date()).toISOString();
1223
+ }
1224
+ if (value instanceof Date) {
1225
+ if (Number.isNaN(value.getTime())) {
1226
+ throw new RangeError("buildSnapshot: knowledgeTime is an invalid Date");
1227
+ }
1228
+ return value.toISOString();
1229
+ }
1230
+ const ms = Date.parse(value);
1231
+ if (Number.isNaN(ms)) {
1232
+ throw new RangeError(
1233
+ `buildSnapshot: knowledgeTime ${JSON.stringify(value)} is not a parseable ISO 8601 timestamp`
1234
+ );
1235
+ }
1236
+ return new Date(ms).toISOString();
1237
+ }
1238
+ function freezeRows(rows) {
1239
+ const out = [];
1240
+ for (const r of rows) {
1241
+ out.push(Object.freeze({ ...r }));
1242
+ }
1243
+ return Object.freeze(out);
1244
+ }
1245
+ function buildSnapshot(opts) {
1246
+ if (typeof opts.schemaId !== "string" || opts.schemaId.length === 0) {
1247
+ throw new RangeError("buildSnapshot: schemaId must be a non-empty string");
1248
+ }
1249
+ if (typeof opts.source !== "string" || opts.source.length === 0) {
1250
+ throw new RangeError("buildSnapshot: source must be a non-empty string");
1251
+ }
1252
+ if (!Array.isArray(opts.rows)) {
1253
+ throw new RangeError("buildSnapshot: rows must be an array");
1254
+ }
1255
+ const knowledgeTime = normalizeKnowledgeTime(opts.knowledgeTime);
1256
+ const schemaId = opts.schemaId;
1257
+ const source = opts.source;
1258
+ const rows = freezeRows(opts.rows);
1259
+ const dataVersion = opts.dataVersion ?? null;
1260
+ const metadata = Object.freeze({ ...opts.metadata ?? {} });
1261
+ const snapshot = {
1262
+ knowledgeTime,
1263
+ schemaId,
1264
+ source,
1265
+ rows,
1266
+ dataVersion,
1267
+ metadata,
1268
+ toDict() {
1269
+ return toJsonSafe({
1270
+ knowledge_time: knowledgeTime,
1271
+ schema_id: schemaId,
1272
+ source,
1273
+ rows,
1274
+ data_version: dataVersion,
1275
+ metadata
1276
+ });
1277
+ },
1278
+ toToon() {
1279
+ return toonDumps(rows);
1280
+ }
1281
+ };
1282
+ return Object.freeze(snapshot);
1283
+ }
1284
+
1285
+ // src/discovery/data-version.ts
1286
+ var HEX = "0123456789abcdef";
1287
+ function bytesToHex(bytes) {
1288
+ let out = "";
1289
+ for (let i = 0; i < bytes.length; i += 1) {
1290
+ const b = bytes[i];
1291
+ out += HEX[b >> 4 & 15];
1292
+ out += HEX[b & 15];
1293
+ }
1294
+ return out;
1295
+ }
1296
+ async function dataVersionFromComponents(components) {
1297
+ const sortedSchemaIds = [...components.schemaIds].sort();
1298
+ const sortedSources = [...components.sources].sort();
1299
+ const canonical = [
1300
+ components.sdkVersion,
1301
+ sortedSchemaIds.join(","),
1302
+ sortedSources.join(","),
1303
+ components.codeSha,
1304
+ components.dataSha
1305
+ ].join("|");
1306
+ const encoded = new TextEncoder().encode(canonical);
1307
+ const digest = await crypto.subtle.digest("SHA-256", encoded);
1308
+ const token = bytesToHex(new Uint8Array(digest));
1309
+ return Object.freeze({
1310
+ sdkVersion: components.sdkVersion,
1311
+ schemaIds: Object.freeze([...components.schemaIds]),
1312
+ sources: Object.freeze([...components.sources]),
1313
+ codeSha: components.codeSha,
1314
+ dataSha: components.dataSha,
1315
+ token
1316
+ });
1317
+ }
1318
+ async function dataVersionForResearch(args) {
1319
+ return dataVersionFromComponents({
1320
+ sdkVersion: args.sdkVersion,
1321
+ schemaIds: ["schema.observation.v1", "schema.forecast.iem_mos.v1", "schema.settlement.cli.v1"],
1322
+ sources: ["iem.archive", "iem.live", "awc.live", "ghcnh", "nws.cli"],
1323
+ codeSha: `research:${args.station}:${args.fromDate}:${args.toDate}`,
1324
+ dataSha: args.dataSha
1325
+ });
1326
+ }
1327
+
1328
+ // src/discovery/describe.ts
1329
+ var BUILT_IN_SCHEMAS = Object.freeze([
1330
+ {
1331
+ id: "schema.observation.v1",
1332
+ title: "schema.observation.v1",
1333
+ columnCount: 20,
1334
+ columns: [
1335
+ { name: "dew_point_c", description: "units: celsius \u2014 bounded", nullable: true },
1336
+ { name: "event_time", description: "observation valid time", nullable: false },
1337
+ {
1338
+ name: "metar_raw",
1339
+ description: "raw METAR text if source has it; null for AWC JSON (structured-only)",
1340
+ nullable: true
1341
+ },
1342
+ {
1343
+ name: "observation_type",
1344
+ description: "METAR | SPECI; defaults METAR when source can't distinguish (e.g. AWC JSON)",
1345
+ nullable: false
1346
+ },
1347
+ {
1348
+ name: "precip_mm_1h",
1349
+ description: "units: mm \u2014 hourly precip (METAR p01i, converted from inches)",
1350
+ nullable: true
1351
+ },
1352
+ {
1353
+ name: "sky_base_1_m",
1354
+ description: "units: meters \u2014 first cloud layer base height (converted from feet)",
1355
+ nullable: true
1356
+ },
1357
+ { name: "sky_base_2_m", description: "units: meters", nullable: true },
1358
+ { name: "sky_base_3_m", description: "units: meters", nullable: true },
1359
+ { name: "sky_base_4_m", description: "units: meters", nullable: true },
1360
+ { name: "sky_cover_1", description: "first cloud layer cover code", nullable: true },
1361
+ { name: "sky_cover_2", description: "second layer; null if not present", nullable: true },
1362
+ { name: "sky_cover_3", description: "third layer; null if not present", nullable: true },
1363
+ { name: "sky_cover_4", description: "fourth layer; null if not present", nullable: true },
1364
+ {
1365
+ name: "slp_hpa",
1366
+ description: "units: hPa \u2014 sea-level pressure (canonical aviation unit, not converted across modes)",
1367
+ nullable: true
1368
+ },
1369
+ { name: "station", description: "ICAO/ASOS station ID (e.g. KORD)", nullable: false },
1370
+ {
1371
+ name: "temp_c",
1372
+ description: "units: celsius \u2014 bounded TEMP_MIN_C..TEMP_MAX_C",
1373
+ nullable: true
1374
+ },
1375
+ {
1376
+ name: "visibility_m",
1377
+ description: "units: meters \u2014 converted from statute miles",
1378
+ nullable: true
1379
+ },
1380
+ {
1381
+ name: "wind_dir_deg",
1382
+ description: "units: degrees \u2014 0-360, bounded",
1383
+ nullable: true
1384
+ },
1385
+ { name: "wind_gust_ms", description: "units: m/s \u2014 converted from kt", nullable: true },
1386
+ { name: "wind_speed_ms", description: "units: m/s \u2014 converted from kt", nullable: true }
1387
+ ]
1388
+ },
1389
+ {
1390
+ id: "schema.forecast.iem_mos.v1",
1391
+ title: "schema.forecast.iem_mos.v1",
1392
+ columnCount: 11,
1393
+ columns: [
1394
+ { name: "dew_point_c", description: "units: celsius", nullable: true },
1395
+ {
1396
+ name: "forecast_hour",
1397
+ description: "units: hours \u2014 (valid_at - issued_at).total_seconds() / 3600",
1398
+ nullable: false
1399
+ },
1400
+ {
1401
+ name: "issued_at",
1402
+ description: "model run time (from source `runtime` field)",
1403
+ nullable: false
1404
+ },
1405
+ { name: "model", description: "e.g. NBE, GFS, LAV, MET", nullable: false },
1406
+ {
1407
+ name: "precip_probability",
1408
+ description: "units: probability \u2014 bounded [0, 1]",
1409
+ nullable: true
1410
+ },
1411
+ {
1412
+ name: "sky_cover_pct",
1413
+ description: "units: percent \u2014 bounded [0, 100]",
1414
+ nullable: true
1415
+ },
1416
+ { name: "station", description: "", nullable: false },
1417
+ { name: "temp_c", description: "units: celsius", nullable: true },
1418
+ {
1419
+ name: "valid_at",
1420
+ description: "forecast target time (from source `ftime`)",
1421
+ nullable: false
1422
+ },
1423
+ { name: "wind_dir_deg", description: "units: degrees", nullable: true },
1424
+ { name: "wind_speed_ms", description: "units: m/s", nullable: true }
1425
+ ]
1426
+ },
1427
+ {
1428
+ id: "schema.settlement.cli.v1",
1429
+ title: "schema.settlement.cli.v1",
1430
+ columnCount: 12,
1431
+ columns: [
1432
+ {
1433
+ name: "cli_data_quality",
1434
+ description: "NWS CLI data-quality marker (Pitfall 6/16). Allows downstream code to filter or weight settlement rows by issuer quality without re-parsing the product header.",
1435
+ nullable: false
1436
+ },
1437
+ {
1438
+ name: "event_time",
1439
+ description: "00:00 local time on observation_date converted to UTC; for sort/join only",
1440
+ nullable: false
1441
+ },
1442
+ {
1443
+ name: "observation_date",
1444
+ description: "local climate day per NWS convention (no timezone applied to the date itself)",
1445
+ nullable: false
1446
+ },
1447
+ { name: "precipitation_in", description: "units: inches", nullable: true },
1448
+ {
1449
+ name: "product_release_time",
1450
+ description: "parsed from CLI product header (_climate.py::_parse_product_timestamp)",
1451
+ nullable: false
1452
+ },
1453
+ {
1454
+ name: "report_type",
1455
+ description: "preliminary | final | correction; dedup priority preliminary < final < correction",
1456
+ nullable: false
1457
+ },
1458
+ {
1459
+ name: "settlement_finality",
1460
+ description: "provisional | final | superseded. Kalshi NHIGH/NLOW settlement contractually requires 'final'; 'provisional' values are kept for early-look research only.",
1461
+ nullable: false
1462
+ },
1463
+ { name: "snowfall_in", description: "units: inches", nullable: true },
1464
+ { name: "station", description: "ICAO/ASOS station ID", nullable: false },
1465
+ {
1466
+ name: "station_tz",
1467
+ description: "IANA timezone for the station (e.g. America/Chicago for KORD). Required for local-climate-day semantics; see \xA7U.",
1468
+ nullable: false
1469
+ },
1470
+ {
1471
+ name: "temp_max_F",
1472
+ description: "units: fahrenheit \u2014 daily high (uppercase F for consistency with obs imperial mode)",
1473
+ nullable: true
1474
+ },
1475
+ { name: "temp_min_F", description: "units: fahrenheit \u2014 daily low", nullable: true }
1476
+ ]
1477
+ },
1478
+ {
1479
+ id: "schema.observation_ledger.v1",
1480
+ title: "schema.observation_ledger.v1",
1481
+ columnCount: 15,
1482
+ columns: [
1483
+ { name: "as_of_time", description: "", nullable: true },
1484
+ { name: "dewpoint_c", description: "units: celsius", nullable: true },
1485
+ { name: "ingestion_id", description: "", nullable: true },
1486
+ { name: "observation_kind", description: "", nullable: true },
1487
+ {
1488
+ name: "observation_quality",
1489
+ description: "Lineage row-quality flag per LINEAGE-01; distinct from qc_status enum slot AND distinct from the obs_qc_status bitmask column per QC-05.",
1490
+ nullable: true
1491
+ },
1492
+ { name: "observation_type", description: "", nullable: false },
1493
+ { name: "observed_at", description: "", nullable: false },
1494
+ { name: "parser_name", description: "", nullable: true },
1495
+ { name: "parser_version", description: "", nullable: true },
1496
+ { name: "provenance", description: "", nullable: true },
1497
+ { name: "qc_status", description: "", nullable: true },
1498
+ {
1499
+ name: "source",
1500
+ description: "ncei reserved per D-2.1-09; never written in v0.1.0.",
1501
+ nullable: false
1502
+ },
1503
+ { name: "source_received_at", description: "", nullable: true },
1504
+ { name: "station_code", description: "", nullable: false },
1505
+ { name: "temp_c", description: "units: celsius", nullable: true }
1506
+ ]
1507
+ },
1508
+ {
1509
+ id: "schema.observation_qc.v1",
1510
+ title: "schema.observation_qc.v1",
1511
+ columnCount: 13,
1512
+ columns: [
1513
+ { name: "as_of_time", description: "", nullable: true },
1514
+ {
1515
+ name: "detector_metadata",
1516
+ description: "JSON-serialized detector payload; shape per qc_system.",
1517
+ nullable: true
1518
+ },
1519
+ {
1520
+ name: "field",
1521
+ description: "Observation column the rule evaluated (e.g. temp_c).",
1522
+ nullable: false
1523
+ },
1524
+ { name: "flag", description: "", nullable: false },
1525
+ { name: "ingestion_id", description: "", nullable: true },
1526
+ { name: "observation_kind", description: "", nullable: true },
1527
+ { name: "observed_at", description: "", nullable: false },
1528
+ { name: "parser_name", description: "", nullable: true },
1529
+ { name: "qc_system", description: "", nullable: false },
1530
+ { name: "qc_version", description: "", nullable: false },
1531
+ { name: "rule_id", description: "", nullable: false },
1532
+ { name: "source", description: "", nullable: false },
1533
+ { name: "station_code", description: "", nullable: false }
1534
+ ]
1535
+ }
1536
+ ]);
1537
+ function deepFreezeSchema(info) {
1538
+ const frozenCols = Object.freeze(info.columns.map((c) => Object.freeze({ ...c })));
1539
+ return Object.freeze({ ...info, columns: frozenCols });
1540
+ }
1541
+ var REGISTRY = new Map(
1542
+ BUILT_IN_SCHEMAS.map((info) => [info.id, deepFreezeSchema(info)])
1543
+ );
1544
+ function registerSchema(info) {
1545
+ REGISTRY.set(info.id, deepFreezeSchema(info));
1546
+ }
1547
+ function describe(schemaId) {
1548
+ const info = REGISTRY.get(schemaId);
1549
+ if (info === void 0) {
1550
+ const known = [...REGISTRY.keys()].sort();
1551
+ throw new UnknownSchemaError(
1552
+ `Unknown schemaId ${JSON.stringify(schemaId)}; registered: ${known.length === 0 ? "<none>" : known.join(", ")}`
1553
+ );
1554
+ }
1555
+ const lines = [`Schema: ${info.id}`, ` Title: ${info.title}`, ` Columns: ${info.columnCount}`];
1556
+ for (const col of info.columns) {
1557
+ const nullable = col.nullable ? "?" : "";
1558
+ const desc = col.description.length === 0 ? "" : ` \u2014 ${col.description}`;
1559
+ lines.push(` - ${col.name}${nullable}${desc}`);
1560
+ }
1561
+ return lines.join("\n");
1562
+ }
1563
+ var UnknownSchemaError = class extends TradewindsError {
1564
+ constructor(message) {
1565
+ super(message);
1566
+ this.name = "UnknownSchemaError";
1567
+ }
1568
+ static defaultErrorCode = "UNKNOWN_SCHEMA";
1569
+ };
1570
+ var FEATURE_NAMES = Object.freeze([
1571
+ "calendarFeatures",
1572
+ "clipOutliers",
1573
+ "diff",
1574
+ "diff2",
1575
+ "heatIndex",
1576
+ "lag",
1577
+ "rolling",
1578
+ "spread",
1579
+ "windChill"
1580
+ ]);
1581
+ function featureCatalog() {
1582
+ return FEATURE_NAMES;
1583
+ }
1584
+ function climateGaps(_station, _fromDate, _toDate) {
1585
+ throw new ClimateGapsNotImplementedError(
1586
+ "climateGaps is Python-only in v0.1.0; the TS climate cache lands in v0.2"
1587
+ );
1588
+ }
1589
+ var ClimateGapsNotImplementedError = class extends TradewindsError {
1590
+ constructor(message) {
1591
+ super(message);
1592
+ this.name = "ClimateGapsNotImplementedError";
1593
+ }
1594
+ static defaultErrorCode = "NOT_IMPLEMENTED";
1595
+ };
1596
+ export {
1597
+ ClimateGapsNotImplementedError,
1598
+ UnknownSchemaError,
1599
+ availability,
1600
+ buildSnapshot,
1601
+ climateGaps,
1602
+ dataVersionForResearch,
1603
+ dataVersionFromComponents,
1604
+ describe,
1605
+ featureCatalog,
1606
+ internationalDailyExtremes,
1607
+ registerSchema
1608
+ };
1609
+ //# sourceMappingURL=index.mjs.map