weather-for-grown-ups 0.2.2 → 0.3.0
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/README.md +122 -217
- package/dist/{cache/file-access-policy.d.ts → access/access-policy.d.ts} +5 -1
- package/dist/{cache/file-access-policy.js → access/access-policy.js} +16 -49
- package/dist/access/access-policy.js.map +1 -0
- package/dist/access/http-fetch.d.ts +13 -0
- package/dist/access/http-fetch.js +21 -0
- package/dist/access/http-fetch.js.map +1 -0
- package/dist/{sources → access}/http-retry.d.ts +9 -0
- package/dist/{sources → access}/http-retry.js +38 -0
- package/dist/access/http-retry.js.map +1 -0
- package/dist/cache/gefs-reforecast-s3-subset-cache.d.ts +30 -0
- package/dist/cache/gefs-reforecast-s3-subset-cache.js +182 -0
- package/dist/cache/gefs-reforecast-s3-subset-cache.js.map +1 -0
- package/dist/cache/gefs-s3-subset-cache.d.ts +1 -1
- package/dist/cache/gefs-s3-subset-cache.js +24 -57
- package/dist/cache/gefs-s3-subset-cache.js.map +1 -1
- package/dist/cache/ifs-open-data-cache.d.ts +1 -1
- package/dist/cache/ifs-open-data-cache.js +1 -1
- package/dist/cache/ifs-open-data-cache.js.map +1 -1
- package/dist/cache/nomads-cache.d.ts +6 -3
- package/dist/cache/nomads-cache.js +42 -12
- package/dist/cache/nomads-cache.js.map +1 -1
- package/dist/cache/s3-subset-cache.d.ts +1 -1
- package/dist/cache/s3-subset-cache.js +24 -57
- package/dist/cache/s3-subset-cache.js.map +1 -1
- package/dist/catalog/gefs-reforecast.d.ts +12 -0
- package/dist/catalog/gefs-reforecast.js +49 -0
- package/dist/catalog/gefs-reforecast.js.map +1 -0
- package/dist/catalog/unified-search.js +43 -4
- package/dist/catalog/unified-search.js.map +1 -1
- package/dist/cli/program.js +1 -1
- package/dist/cli/program.js.map +1 -1
- package/dist/cli/unified-atmosphere-command.d.ts +2 -0
- package/dist/cli/unified-atmosphere-command.js +78 -38
- package/dist/cli/unified-atmosphere-command.js.map +1 -1
- package/dist/cli/unified-catalog-command.js +2 -0
- package/dist/cli/unified-catalog-command.js.map +1 -1
- package/dist/core/archived-gfs-query.d.ts +4 -1
- package/dist/core/archived-gfs-query.js +9 -4
- package/dist/core/archived-gfs-query.js.map +1 -1
- package/dist/core/area-summary.d.ts +2 -1
- package/dist/core/area-summary.js +4 -3
- package/dist/core/area-summary.js.map +1 -1
- package/dist/core/diagnostic-adapters/gefs.d.ts +19 -0
- package/dist/core/diagnostic-adapters/gefs.js +102 -0
- package/dist/core/diagnostic-adapters/gefs.js.map +1 -0
- package/dist/core/diagnostic-adapters/gfs-analysis.d.ts +9 -0
- package/dist/core/diagnostic-adapters/gfs-analysis.js +33 -0
- package/dist/core/diagnostic-adapters/gfs-analysis.js.map +1 -0
- package/dist/core/diagnostic-adapters/gfs.d.ts +15 -0
- package/dist/core/diagnostic-adapters/gfs.js +43 -0
- package/dist/core/diagnostic-adapters/gfs.js.map +1 -0
- package/dist/core/diagnostic-adapters/helpers.d.ts +45 -0
- package/dist/core/diagnostic-adapters/helpers.js +45 -0
- package/dist/core/diagnostic-adapters/helpers.js.map +1 -0
- package/dist/core/diagnostic-adapters/ifs-ens.d.ts +16 -0
- package/dist/core/diagnostic-adapters/ifs-ens.js +55 -0
- package/dist/core/diagnostic-adapters/ifs-ens.js.map +1 -0
- package/dist/core/diagnostic-adapters/ifs.d.ts +9 -0
- package/dist/core/diagnostic-adapters/ifs.js +30 -0
- package/dist/core/diagnostic-adapters/ifs.js.map +1 -0
- package/dist/core/diagnostic-adapters/registry.d.ts +12 -0
- package/dist/core/diagnostic-adapters/registry.js +19 -0
- package/dist/core/diagnostic-adapters/registry.js.map +1 -0
- package/dist/core/diagnostic-adapters/types.d.ts +5 -0
- package/dist/core/diagnostic-adapters/types.js +2 -0
- package/dist/core/diagnostic-adapters/types.js.map +1 -0
- package/dist/core/gefs-reforecast-diagnostics.d.ts +34 -0
- package/dist/core/gefs-reforecast-diagnostics.js +306 -0
- package/dist/core/gefs-reforecast-diagnostics.js.map +1 -0
- package/dist/core/gefs-reforecast-mixed.d.ts +48 -0
- package/dist/core/gefs-reforecast-mixed.js +388 -0
- package/dist/core/gefs-reforecast-mixed.js.map +1 -0
- package/dist/core/gefs-reforecast-points-timeseries.d.ts +13 -0
- package/dist/core/gefs-reforecast-points-timeseries.js +206 -0
- package/dist/core/gefs-reforecast-points-timeseries.js.map +1 -0
- package/dist/core/gefs-reforecast-points.d.ts +16 -0
- package/dist/core/gefs-reforecast-points.js +169 -0
- package/dist/core/gefs-reforecast-points.js.map +1 -0
- package/dist/core/gefs-reforecast-profile.d.ts +17 -0
- package/dist/core/gefs-reforecast-profile.js +161 -0
- package/dist/core/gefs-reforecast-profile.js.map +1 -0
- package/dist/core/gefs-reforecast-timeseries.d.ts +16 -0
- package/dist/core/gefs-reforecast-timeseries.js +165 -0
- package/dist/core/gefs-reforecast-timeseries.js.map +1 -0
- package/dist/core/gefs-reforecast.d.ts +23 -0
- package/dist/core/gefs-reforecast.js +92 -0
- package/dist/core/gefs-reforecast.js.map +1 -0
- package/dist/core/history-area-summary.d.ts +2 -1
- package/dist/core/history-area-summary.js +4 -3
- package/dist/core/history-area-summary.js.map +1 -1
- package/dist/core/history-fields.d.ts +2 -1
- package/dist/core/history-fields.js +4 -3
- package/dist/core/history-fields.js.map +1 -1
- package/dist/core/history-forecast.d.ts +3 -1
- package/dist/core/history-forecast.js +5 -3
- package/dist/core/history-forecast.js.map +1 -1
- package/dist/core/history.d.ts +2 -1
- package/dist/core/history.js +4 -3
- package/dist/core/history.js.map +1 -1
- package/dist/core/ifs-ens-latest-run.js +1 -1
- package/dist/core/ifs-ens-latest-run.js.map +1 -1
- package/dist/core/ifs-ifs-ens-aligned-run.d.ts +20 -0
- package/dist/core/ifs-ifs-ens-aligned-run.js +51 -0
- package/dist/core/ifs-ifs-ens-aligned-run.js.map +1 -0
- package/dist/core/ifs-ifs-ens-comparison.d.ts +22 -0
- package/dist/core/ifs-ifs-ens-comparison.js +172 -0
- package/dist/core/ifs-ifs-ens-comparison.js.map +1 -0
- package/dist/core/ifs-latest-run.js +1 -1
- package/dist/core/ifs-latest-run.js.map +1 -1
- package/dist/core/igra-observation.d.ts +2 -1
- package/dist/core/igra-observation.js +4 -3
- package/dist/core/igra-observation.js.map +1 -1
- package/dist/core/profile.d.ts +2 -1
- package/dist/core/profile.js +5 -3
- package/dist/core/profile.js.map +1 -1
- package/dist/core/query-adapters/gefs.d.ts +56 -0
- package/dist/core/query-adapters/gefs.js +315 -0
- package/dist/core/query-adapters/gefs.js.map +1 -0
- package/dist/core/query-adapters/gfs-analysis.d.ts +38 -0
- package/dist/core/query-adapters/gfs-analysis.js +152 -0
- package/dist/core/query-adapters/gfs-analysis.js.map +1 -0
- package/dist/core/query-adapters/gfs.d.ts +39 -0
- package/dist/core/query-adapters/gfs.js +141 -0
- package/dist/core/query-adapters/gfs.js.map +1 -0
- package/dist/core/query-adapters/helpers.d.ts +33 -0
- package/dist/core/query-adapters/helpers.js +48 -0
- package/dist/core/query-adapters/helpers.js.map +1 -0
- package/dist/core/query-adapters/ifs-ens.d.ts +31 -0
- package/dist/core/query-adapters/ifs-ens.js +145 -0
- package/dist/core/query-adapters/ifs-ens.js.map +1 -0
- package/dist/core/query-adapters/ifs.d.ts +29 -0
- package/dist/core/query-adapters/ifs.js +119 -0
- package/dist/core/query-adapters/ifs.js.map +1 -0
- package/dist/core/query-adapters/registry.d.ts +12 -0
- package/dist/core/query-adapters/registry.js +19 -0
- package/dist/core/query-adapters/registry.js.map +1 -0
- package/dist/core/query-adapters/types.d.ts +5 -0
- package/dist/core/query-adapters/types.js +2 -0
- package/dist/core/query-adapters/types.js.map +1 -0
- package/dist/core/specialized-adapters/analogs.d.ts +8 -0
- package/dist/core/specialized-adapters/analogs.js +21 -0
- package/dist/core/specialized-adapters/analogs.js.map +1 -0
- package/dist/core/specialized-adapters/dataset-comparison.d.ts +26 -0
- package/dist/core/specialized-adapters/dataset-comparison.js +99 -0
- package/dist/core/specialized-adapters/dataset-comparison.js.map +1 -0
- package/dist/core/specialized-adapters/registry.d.ts +5 -0
- package/dist/core/specialized-adapters/registry.js +36 -0
- package/dist/core/specialized-adapters/registry.js.map +1 -0
- package/dist/core/specialized-adapters/run-comparison.d.ts +26 -0
- package/dist/core/specialized-adapters/run-comparison.js +111 -0
- package/dist/core/specialized-adapters/run-comparison.js.map +1 -0
- package/dist/core/specialized-adapters/types.d.ts +23 -0
- package/dist/core/specialized-adapters/types.js +4 -0
- package/dist/core/specialized-adapters/types.js.map +1 -0
- package/dist/core/specialized-adapters/verification.d.ts +18 -0
- package/dist/core/specialized-adapters/verification.js +91 -0
- package/dist/core/specialized-adapters/verification.js.map +1 -0
- package/dist/core/transect.d.ts +3 -1
- package/dist/core/transect.js +7 -4
- package/dist/core/transect.js.map +1 -1
- package/dist/core/unified-atmosphere-api.d.ts +3 -144
- package/dist/core/unified-atmosphere-api.js +3 -812
- package/dist/core/unified-atmosphere-api.js.map +1 -1
- package/dist/core/unified-atmosphere-diagnostics.d.ts +10 -0
- package/dist/core/unified-atmosphere-diagnostics.js +17 -0
- package/dist/core/unified-atmosphere-diagnostics.js.map +1 -0
- package/dist/core/unified-atmosphere-query.d.ts +12 -0
- package/dist/core/unified-atmosphere-query.js +18 -0
- package/dist/core/unified-atmosphere-query.js.map +1 -0
- package/dist/core/unified-atmosphere-result.d.ts +2 -0
- package/dist/core/unified-atmosphere-result.js +44 -0
- package/dist/core/unified-atmosphere-result.js.map +1 -0
- package/dist/core/unified-specialized-api.d.ts +21 -28
- package/dist/core/unified-specialized-api.js +23 -224
- package/dist/core/unified-specialized-api.js.map +1 -1
- package/dist/grib/index.d.ts +2 -0
- package/dist/grib/index.js +49 -0
- package/dist/grib/index.js.map +1 -1
- package/dist/mcp-server.js +2 -2
- package/dist/mcp-server.js.map +1 -1
- package/dist/mcp-unified-tool.js +3 -4
- package/dist/mcp-unified-tool.js.map +1 -1
- package/dist/schema/gefs-reforecast-diagnostics.d.ts +802 -0
- package/dist/schema/gefs-reforecast-diagnostics.js +311 -0
- package/dist/schema/gefs-reforecast-diagnostics.js.map +1 -0
- package/dist/schema/gefs-reforecast-mixed.d.ts +1033 -0
- package/dist/schema/gefs-reforecast-mixed.js +221 -0
- package/dist/schema/gefs-reforecast-mixed.js.map +1 -0
- package/dist/schema/gefs-reforecast.d.ts +1298 -0
- package/dist/schema/gefs-reforecast.js +605 -0
- package/dist/schema/gefs-reforecast.js.map +1 -0
- package/dist/schema/ifs-ifs-ens-comparison.d.ts +253 -0
- package/dist/schema/ifs-ifs-ens-comparison.js +110 -0
- package/dist/schema/ifs-ifs-ens-comparison.js.map +1 -0
- package/dist/schema/transect-result.d.ts +298 -1
- package/dist/schema/transect-result.js +25 -5
- package/dist/schema/transect-result.js.map +1 -1
- package/dist/schema/transect.d.ts +69 -3
- package/dist/schema/transect.js +21 -3
- package/dist/schema/transect.js.map +1 -1
- package/dist/schema/unified-api.d.ts +14 -1
- package/dist/schema/unified-api.js +92 -0
- package/dist/schema/unified-api.js.map +1 -1
- package/dist/schema/unified-catalog.d.ts +8 -0
- package/dist/schema/unified-catalog.js +9 -0
- package/dist/schema/unified-catalog.js.map +1 -1
- package/dist/schema/unified-specialized.d.ts +179 -0
- package/dist/schema/unified-specialized.js +39 -0
- package/dist/schema/unified-specialized.js.map +1 -1
- package/dist/sources/gefs-reforecast-s3.d.ts +23 -0
- package/dist/sources/gefs-reforecast-s3.js +138 -0
- package/dist/sources/gefs-reforecast-s3.js.map +1 -0
- package/dist/{cache → sources}/ifs-open-data-access-policy.d.ts +2 -2
- package/dist/{cache → sources}/ifs-open-data-access-policy.js +2 -2
- package/dist/sources/ifs-open-data-access-policy.js.map +1 -0
- package/dist/sources/ifs-open-data.js +6 -12
- package/dist/sources/ifs-open-data.js.map +1 -1
- package/dist/sources/ncei-gfs-forecast-history.d.ts +1 -1
- package/dist/sources/ncei-gfs-forecast-history.js +40 -50
- package/dist/sources/ncei-gfs-forecast-history.js.map +1 -1
- package/dist/sources/ncei-gfs-history.d.ts +1 -1
- package/dist/sources/ncei-gfs-history.js +40 -50
- package/dist/sources/ncei-gfs-history.js.map +1 -1
- package/dist/sources/ncei-igra.d.ts +11 -3
- package/dist/sources/ncei-igra.js +65 -77
- package/dist/sources/ncei-igra.js.map +1 -1
- package/dist/sources/rda-gfs-forecast-history.d.ts +1 -1
- package/dist/sources/rda-gfs-forecast-history.js +64 -85
- package/dist/sources/rda-gfs-forecast-history.js.map +1 -1
- package/docs/ARCHITECTURE.md +18 -0
- package/docs/GEFS_ENSEMBLE.md +89 -0
- package/docs/IFS_IFS_ENS_COMPARISON.md +71 -0
- package/docs/INSTALL.md +6 -12
- package/docs/README.md +56 -35
- package/docs/RELEASES.md +64 -0
- package/docs/UNIFIED_API.md +53 -7
- package/package.json +4 -3
- package/dist/cache/file-access-policy.js.map +0 -1
- package/dist/cache/file-rate-limiter.d.ts +0 -7
- package/dist/cache/file-rate-limiter.js +0 -17
- package/dist/cache/file-rate-limiter.js.map +0 -1
- package/dist/cache/ifs-open-data-access-policy.js.map +0 -1
- package/dist/sources/http-retry.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,288 +1,193 @@
|
|
|
1
1
|
# Weather for Grown Ups
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**Weather is the hello-world of agent tools. This is the version for when “temperature tomorrow” stops being enough.**
|
|
4
4
|
|
|
5
|
-
Weather
|
|
5
|
+
Weather for Grown Ups (WFG) gives agents direct, structured access to numerical weather prediction: NOAA **GFS**, **GEFS** and historical GFS data, plus ECMWF **IFS** and **IFS ENS**.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
The central idea is deliberately simple:
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
> **One query language over weather datasets. Native model semantics stay intact.**
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Ask for a point, a time range, several locations, a transect, an area, a pressure profile or a meteorological diagnostic. Change the dataset without learning another API. WFG handles source selection, GRIB message access, decoding, caching and shared physics; the result keeps the model's real cadence, grid, run, member and provenance semantics.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
No weather API key. No model-specific public namespaces. No need to teach the agent GRIB first.
|
|
14
|
+
|
|
15
|
+
## 30-second start
|
|
16
|
+
|
|
17
|
+
Node.js 20+ is enough. The npm package includes its GRIB2 decoder.
|
|
14
18
|
|
|
15
19
|
```bash
|
|
16
20
|
npx weather-for-grown-ups --help
|
|
17
|
-
npx weather-for-grown-ups catalog --dataset
|
|
21
|
+
npx weather-for-grown-ups catalog --dataset all --search wind --json
|
|
18
22
|
```
|
|
19
23
|
|
|
20
|
-
|
|
24
|
+
Run the same core as MCP:
|
|
21
25
|
|
|
22
26
|
```bash
|
|
23
27
|
npx weather-for-grown-ups mcp
|
|
28
|
+
# or
|
|
24
29
|
npx weather-for-grown-ups mcp-http
|
|
25
30
|
```
|
|
26
31
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
## What can an agent do with it?
|
|
30
|
-
|
|
31
|
-
WFG is deliberately a **tool**, not a forecast persona. It returns structured model data, diagnostics, provenance, and explicit ensemble semantics. The consuming agent decides what those data mean for the user's question.
|
|
32
|
+
For global npm, Docker and hosted MCP setup, see [Installation](docs/INSTALL.md).
|
|
32
33
|
|
|
33
|
-
The
|
|
34
|
+
## The query model
|
|
34
35
|
|
|
35
|
-
|
|
36
|
+
Normal atmospheric access is expressed as four orthogonal choices:
|
|
36
37
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
```text
|
|
39
|
+
dataset × geometry × time × selection
|
|
40
|
+
```
|
|
40
41
|
|
|
41
|
-
|
|
42
|
+
For example:
|
|
43
|
+
|
|
44
|
+
```json
|
|
45
|
+
{
|
|
46
|
+
"dataset": "gefs",
|
|
47
|
+
"geometry": {
|
|
48
|
+
"type": "point",
|
|
49
|
+
"latitude": 50.08,
|
|
50
|
+
"longitude": 14.43
|
|
51
|
+
},
|
|
52
|
+
"time": {
|
|
53
|
+
"at": "2026-08-30T12:00:00Z"
|
|
54
|
+
},
|
|
55
|
+
"selection": {
|
|
56
|
+
"variables": ["temperature", "wind"],
|
|
57
|
+
"pressureLevelsHpa": [850, 700, 500],
|
|
58
|
+
"fields": ["temperature_2m", "wind_10m"]
|
|
59
|
+
},
|
|
60
|
+
"ensemble": {
|
|
61
|
+
"quantiles": [0.1, 0.5, 0.9]
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
```
|
|
42
65
|
|
|
43
|
-
|
|
66
|
+
The same vocabulary is used for deterministic forecasts, ensembles, archived forecasts and historical analyses. Capability differences are explicit: unsupported combinations fail rather than being coerced into fake symmetry.
|
|
44
67
|
|
|
45
|
-
|
|
68
|
+
The full contract lives in [Unified atmospheric API](docs/UNIFIED_API.md).
|
|
46
69
|
|
|
47
|
-
|
|
70
|
+
## What can an agent ask?
|
|
48
71
|
|
|
49
|
-
|
|
72
|
+
WFG is intentionally a **tool**, not a forecast persona. It supplies atmospheric evidence; the consuming agent supplies interpretation.
|
|
50
73
|
|
|
51
|
-
|
|
74
|
+
### Synoptic and profile meteorology
|
|
52
75
|
|
|
53
|
-
>
|
|
76
|
+
> A cold front is crossing Prague. How does the vertical structure change, and how confident is the ensemble about the timing?
|
|
54
77
|
|
|
55
|
-
|
|
78
|
+
An agent can combine GFS/GEFS pressure profiles, inversion and lapse-rate diagnostics, ensemble distributions and run-to-run changes. The useful answer is no longer just a surface temperature—it can reason about the structure and timing of the air-mass transition.
|
|
56
79
|
|
|
57
|
-
|
|
80
|
+
### Aviation and paragliding
|
|
58
81
|
|
|
59
|
-
|
|
82
|
+
> What does the Bassano profile say about tomorrow's usable convective window, and what is most likely to shut it down?
|
|
60
83
|
|
|
61
|
-
|
|
84
|
+
An agent can inspect parcel diagnostics, CAPE/CIN, freezing levels, wind shear and the member-by-member GEFS distribution through time. WFG deliberately does not turn those into a “go flying” score; activity-specific judgment stays outside the core.
|
|
62
85
|
|
|
63
86
|
*Slightly more information than “Bassano: 21 °C, sunny.”*
|
|
64
87
|
|
|
65
|
-
###
|
|
66
|
-
|
|
67
|
-
**You ask**
|
|
68
|
-
|
|
69
|
-
> I'm considering a Grossglockner summit attempt tomorrow morning. What conditions should I expect near summit altitude, and when does the weather start deteriorating?
|
|
70
|
-
|
|
71
|
-
**The agent might use WFG**
|
|
72
|
-
|
|
73
|
-
`query_atmosphere` on `gfs` → `query_atmosphere` on `gefs` → `diagnose_atmosphere` on `gefs`
|
|
74
|
-
|
|
75
|
-
**Example agent interpretation**
|
|
76
|
-
|
|
77
|
-
> The valley-level forecast understates the change aloft. Near the pressure levels representative of the upper mountain, temperatures remain well below freezing while winds strengthen through the morning. Moisture also increases higher in the column later in the period, raising the risk of cloud around the high terrain. Ensemble agreement is tighter on the wind increase than on the moisture timing, making stronger summit-level flow the more robust deterioration signal.
|
|
88
|
+
### Wind energy
|
|
78
89
|
|
|
79
|
-
|
|
90
|
+
> Is tomorrow afternoon's wind ramp near Esbjerg a local grid-point feature or a regional change, and how uncertain is the timing?
|
|
80
91
|
|
|
81
|
-
|
|
92
|
+
An agent can combine multi-point queries, transects, area statistics and ensemble evolution to distinguish a spatially coherent flow change from a local signal.
|
|
82
93
|
|
|
83
|
-
|
|
94
|
+
### Forecast verification
|
|
84
95
|
|
|
85
|
-
>
|
|
96
|
+
> What did the 48-hour GFS forecast predict for this event, and how wrong was it?
|
|
86
97
|
|
|
87
|
-
|
|
98
|
+
Old GFS initializations stay `dataset: "gfs"` and route to the matching archive. WFG can compare them with later GFS analysis or NOAA IGRA radiosondes, and can summarize bias, MAE and RMSE over bounded samples.
|
|
88
99
|
|
|
89
|
-
|
|
100
|
+
## Datasets
|
|
90
101
|
|
|
91
|
-
|
|
102
|
+
| Public dataset | Meaning | Key semantics |
|
|
103
|
+
| --- | --- | --- |
|
|
104
|
+
| `gfs` | NOAA deterministic GFS | 0.25° default / 0.5° optional; operational data and archived forecasts share one public identity |
|
|
105
|
+
| `gefs` | NOAA GEFS | member-first operational ensemble; explicit `forecast.kind: "reforecast"` selects the GEFSv12 retrospective population |
|
|
106
|
+
| `ifs` | ECMWF deterministic IFS | 0.25° Open Data forecast with native ECMWF run/cadence semantics |
|
|
107
|
+
| `ifs-ens` | ECMWF IFS ENS | 50 perturbations `p01`–`p50`; deterministic IFS is the Cycle-50r1 unperturbed control |
|
|
108
|
+
| `gfs-analysis` | historical GFS Grid 4 analysis | deterministic analyzed state with analysis-time rather than forecast-lead semantics |
|
|
92
109
|
|
|
93
|
-
|
|
110
|
+
NOAA IGRA is available as a **verification reference**, not as a fake gridded model dataset.
|
|
94
111
|
|
|
95
|
-
|
|
112
|
+
For source inventories, cadence, member sets and archive details, start with [the documentation index](docs/README.md).
|
|
96
113
|
|
|
97
|
-
##
|
|
114
|
+
## One core, two equal surfaces
|
|
98
115
|
|
|
99
|
-
|
|
116
|
+
CLI and MCP are adapters over the same schemas and application services. Surface equivalence is tested explicitly.
|
|
100
117
|
|
|
101
|
-
| Operation |
|
|
102
|
-
| --- | --- | --- |
|
|
103
|
-
|
|
|
104
|
-
|
|
|
105
|
-
|
|
|
106
|
-
|
|
|
107
|
-
|
|
|
108
|
-
|
|
|
109
|
-
|
|
|
110
|
-
| Diagnostic time series | ✅ layer/profile/parcel | ✅ layer/profile/parcel | ✅ layer/profile/parcel | ✅ compact member-first |
|
|
111
|
-
| Multi-point queries | ✅ | ✅ | ✅ | ✅ member distributions |
|
|
112
|
-
| Multi-point time series | ✅ | ✅ | ✅ | ✅ native 3h/6h cadence |
|
|
113
|
-
| Transects | ✅ deterministic | ✅ ensemble-native mixed fields | ✅ deterministic mixed fields | ✅ member-first mixed fields |
|
|
114
|
-
| Area statistics | ✅ deterministic | ✅ member-first spatial statistics | ✅ deterministic raw scalar | ✅ member-first spatial statistics |
|
|
115
|
-
| Run-to-run comparison | ✅ deterministic deltas | ✅ distribution shifts | ✅ deterministic deltas | ✅ distribution shifts, 6h/12h stride |
|
|
116
|
-
| Scalar ensemble distribution | — | ✅ | — | ✅ 50 perturbations |
|
|
117
|
-
| Aligned GFS-vs-GEFS comparison | ✅ | ✅ | — | — |
|
|
118
|
-
| Aligned GFS-vs-IFS comparison | ✅ deterministic deltas | — | ✅ deterministic deltas | — |
|
|
119
|
-
| Aligned GEFS-vs-IFS ENS comparison | — | ✅ distribution shifts | — | ✅ distribution shifts |
|
|
118
|
+
| Operation | CLI | MCP |
|
|
119
|
+
| --- | --- | --- |
|
|
120
|
+
| Discover capabilities | `catalog` | `search_catalog` |
|
|
121
|
+
| Query atmospheric state | `query` | `query_atmosphere` |
|
|
122
|
+
| Derive meteorology | `diagnose` | `diagnose_atmosphere` |
|
|
123
|
+
| Compare forecast cycles | `compare-runs` | `compare_runs` |
|
|
124
|
+
| Compare datasets | `compare-datasets` | `compare_datasets` |
|
|
125
|
+
| Verify forecasts | `verify` | `verify_forecast` |
|
|
126
|
+
| Search historical analogs | `analogs` | `find_analogs` |
|
|
120
127
|
|
|
121
|
-
|
|
128
|
+
Administrative index build/backfill remains CLI-only on purpose; it is not part of the normal weather-query surface.
|
|
122
129
|
|
|
123
|
-
|
|
130
|
+
## What the engine covers
|
|
124
131
|
|
|
125
|
-
|
|
132
|
+
The common language composes a fairly broad atmospheric surface:
|
|
126
133
|
|
|
127
|
-
|
|
134
|
+
- pressure profiles and mixed pressure/non-isobaric fields;
|
|
135
|
+
- native-cadence time ranges;
|
|
136
|
+
- multi-point queries and multi-point ranges;
|
|
137
|
+
- great-circle transects;
|
|
138
|
+
- bounded area statistics;
|
|
139
|
+
- layer diagnostics such as lapse rate, wind shear and potential-temperature gradient;
|
|
140
|
+
- whole-profile freezing-level and inversion diagnostics;
|
|
141
|
+
- parcel/LCL/LFC/EL/CAPE/CIN diagnostics where the source fields support them;
|
|
142
|
+
- deterministic run deltas and ensemble distribution shifts;
|
|
143
|
+
- aligned GFS↔GEFS, GFS↔IFS, GEFS↔IFS ENS and IFS↔IFS ENS comparisons;
|
|
144
|
+
- historical analog search and archived-forecast verification.
|
|
128
145
|
|
|
129
|
-
|
|
146
|
+
Not every dataset implements every line. `catalog` / `search_catalog` is the source of truth for what a particular dataset and forecast population supports.
|
|
130
147
|
|
|
131
|
-
|
|
148
|
+
## Semantics are part of the API
|
|
132
149
|
|
|
133
|
-
|
|
150
|
+
WFG is opinionated about a few things that are easy to get subtly wrong:
|
|
134
151
|
|
|
135
|
-
|
|
152
|
+
- **Ensemble physics is member-first.** Nonlinear diagnostics are computed inside each GEFS/IFS ENS member before aggregation.
|
|
153
|
+
- **Spread is not calibrated uncertainty.** Member fractions and ensemble spread are reported as raw model evidence unless a dedicated calibrated layer says otherwise.
|
|
154
|
+
- **History is not relabeled as “current”.** Archived GFS forecasts retain their old initialization and lead; GFS analysis retains analysis-time semantics; GEFSv12 reforecasts are explicitly retrospective forecasts, not archived operational GEFS.
|
|
155
|
+
- **Provenance stays visible.** Results keep run, valid time, sampled grid, source product and archive/backend information.
|
|
156
|
+
- **Unsupported means unsupported.** The engine fails at capability boundaries instead of silently substituting another model, grid or physical meaning.
|
|
136
157
|
|
|
137
|
-
|
|
158
|
+
The deeper reasoning is documented in [Architecture](docs/ARCHITECTURE.md).
|
|
138
159
|
|
|
139
|
-
|
|
160
|
+
## Data access without the plumbing leaking into the query
|
|
140
161
|
|
|
141
|
-
|
|
162
|
+
WFG selects only the upstream messages needed for a request, caches immutable slices and decodes locally.
|
|
142
163
|
|
|
143
|
-
-
|
|
144
|
-
- member fractions and spread are labeled as raw ensemble evidence, not calibrated probability or uncertainty;
|
|
145
|
-
- pressure levels, temporal semantics, valid times, cycles, sampling and provenance stay explicit;
|
|
146
|
-
- unsupported combinations fail explicitly rather than being guessed;
|
|
147
|
-
- WFG does not own activity-specific scores or safety judgments.
|
|
164
|
+
Operational point/profile access favors indexed byte-range reads from NOAA AWS Open Data and ECMWF Open Data. Bounded GFS areas use NOMADS geographic subsetting where that is materially better. Historical products route to NCEI or NCAR/GDEX as appropriate.
|
|
148
165
|
|
|
149
|
-
|
|
166
|
+
Provider etiquette is also source-specific: NOMADS retains its courtesy pacing, while AWS, ECMWF, NCEI, GDEX and IGRA use independent bounded-concurrency policies with transient retry/backoff. A slow provider does not impose its policy on unrelated sources.
|
|
150
167
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
WFG exposes the dataset-oriented query vocabulary documented in [UNIFIED_API.md](docs/UNIFIED_API.md).
|
|
154
|
-
|
|
155
|
-
Normal atmospheric access is expressed as:
|
|
156
|
-
|
|
157
|
-
```text
|
|
158
|
-
dataset × geometry × time × selection
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
with short dataset IDs `gfs`, `gefs`, `ifs`, `ifs-ens`, and `gfs-analysis`. The same query structure therefore works for a deterministic forecast, an ensemble forecast, an archived GFS forecast, or an archived analysis while each result preserves its native deterministic/ensemble and forecast/analysis semantics. An archived forecast remains `gfs`; the explicit old `forecast.run` selects the historical state.
|
|
162
|
-
|
|
163
|
-
The MCP vocabulary is intentionally small:
|
|
164
|
-
|
|
165
|
-
- `search_catalog`
|
|
166
|
-
- `query_atmosphere`
|
|
167
|
-
- `diagnose_atmosphere`
|
|
168
|
-
- `compare_runs`
|
|
169
|
-
- `compare_datasets`
|
|
170
|
-
- `verify_forecast`
|
|
171
|
-
- `find_analogs`
|
|
172
|
-
|
|
173
|
-
The CLI mirrors the same concepts with `catalog --dataset ...`, `query`, `diagnose`, `compare-runs`, `compare-datasets`, `verify`, and `analogs`.
|
|
174
|
-
|
|
175
|
-
## CLI
|
|
176
|
-
|
|
177
|
-
The CLI mirrors the same operation vocabulary. Dataset choice is always explicit through `--dataset`.
|
|
178
|
-
|
|
179
|
-
A deterministic GFS profile:
|
|
180
|
-
|
|
181
|
-
```bash
|
|
182
|
-
wfg query \
|
|
183
|
-
--dataset gfs \
|
|
184
|
-
--lat 50.08 --lon 14.43 \
|
|
185
|
-
--at 2026-08-24T12:00:00Z \
|
|
186
|
-
--vars temperature,relative_humidity,wind \
|
|
187
|
-
--levels 1000,925,850,700,500 \
|
|
188
|
-
--json
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
An old forecast keeps `gfs` and selects the historical initialization:
|
|
192
|
-
|
|
193
|
-
```bash
|
|
194
|
-
wfg query \
|
|
195
|
-
--dataset gfs \
|
|
196
|
-
--grid 0p25 \
|
|
197
|
-
--run 2019-12-24T12:00:00Z \
|
|
198
|
-
--lat 50.08 --lon 14.43 \
|
|
199
|
-
--at 2019-12-26T18:00:00Z \
|
|
200
|
-
--vars temperature,relative_humidity,wind \
|
|
201
|
-
--levels 1000,925,850,700,500 \
|
|
202
|
-
--json
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
The same query against historical analysis only changes the dataset and time:
|
|
206
|
-
|
|
207
|
-
```bash
|
|
208
|
-
wfg query \
|
|
209
|
-
--dataset gfs-analysis \
|
|
210
|
-
--lat 50.08 --lon 14.43 \
|
|
211
|
-
--at 2019-12-26T18:00:00Z \
|
|
212
|
-
--vars temperature,relative_humidity,wind \
|
|
213
|
-
--levels 1000,925,850,700,500 \
|
|
214
|
-
--json
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
An ensemble parcel diagnostic:
|
|
218
|
-
|
|
219
|
-
```bash
|
|
220
|
-
wfg diagnose \
|
|
221
|
-
--dataset gefs \
|
|
222
|
-
--lat 45.80 --lon 11.77 \
|
|
223
|
-
--at 2026-08-24T12:00:00Z \
|
|
224
|
-
--kind parcel \
|
|
225
|
-
--parcel surface_2m \
|
|
226
|
-
--levels 1000,925,850,700,500,250,200 \
|
|
227
|
-
--quantiles 0.1,0.5,0.9 \
|
|
228
|
-
--json
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
Local analog-index maintenance is intentionally separate from weather queries:
|
|
232
|
-
|
|
233
|
-
```bash
|
|
234
|
-
wfg index build --dataset gfs-analysis ...
|
|
235
|
-
wfg index backfill --dataset gfs-analysis ...
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
Run `wfg --help` or `npx weather-for-grown-ups --help` for the complete command surface.
|
|
239
|
-
|
|
240
|
-
## MCP
|
|
241
|
-
|
|
242
|
-
MCP exposes exactly seven atmospheric tools:
|
|
243
|
-
|
|
244
|
-
- `search_catalog`
|
|
245
|
-
- `query_atmosphere`
|
|
246
|
-
- `diagnose_atmosphere`
|
|
247
|
-
- `compare_runs`
|
|
248
|
-
- `compare_datasets`
|
|
249
|
-
- `verify_forecast`
|
|
250
|
-
- `find_analogs`
|
|
251
|
-
|
|
252
|
-
Both transports expose exactly the same tool set:
|
|
253
|
-
|
|
254
|
-
- **stdio** — `npx weather-for-grown-ups mcp`
|
|
255
|
-
- **Streamable HTTP** — `npx weather-for-grown-ups mcp-http`
|
|
256
|
-
|
|
257
|
-
The HTTP server defaults to `127.0.0.1:3000`, serves MCP at `/mcp`, and exposes `/healthz`. Read [INSTALL.md](docs/INSTALL.md) before exposing it remotely.
|
|
258
|
-
|
|
259
|
-
## Data access
|
|
260
|
-
|
|
261
|
-
WFG selects only the GRIB messages needed for a query, caches immutable upstream slices, decodes locally, and performs physical transforms and aggregation in the TypeScript core.
|
|
262
|
-
|
|
263
|
-
- GFS source routing is automatic by default: point/profile, time-series, multi-point, transect, and run-comparison access uses NOAA AWS Open Data selected-message byte ranges; bounded area queries use NOAA NOMADS geographic subsetting. `--source` remains an explicit override where that geometry supports it, and result provenance reports the resolved backend.
|
|
264
|
-
- GEFS uses NOAA AWS Open Data `.idx` inventories and byte-range access per member. Pressure/mixed selections use `pgrb2a` 0.5°; eligible field-only selections use `pgrb2s` 0.25° through `f240`.
|
|
265
|
-
- The npm package ships with a GRIB2 decoder; native `wgrib2` remains an optional compatibility/debug path.
|
|
266
|
-
- Historical GFS analysis uses NOAA NCEI THREDDS/NCSS: grid-as-point for point/profile operations and native bbox/grid subsets for area statistics.
|
|
267
|
-
- Historical GFS forecasts keep the public `gfs` identity and route by grid: 0.25° uses NCAR/GDEX d084001 through THREDDS/NCSS, while 0.5° uses NOAA NCEI Grid 4 through THREDDS/NCSS. Direct online availability varies; older Grid 4 files may require NCEI HAS retrieval.
|
|
268
|
-
- Upstream etiquette is provider-specific: NOMADS keeps an 11-second cross-process courtesy interval, NCEI THREDDS/NCSS is bounded to 2 concurrent requests, NCAR/GDEX to 4, and IGRA downloads to 4. NOAA AWS and ECMWF cloud/direct access are bounded separately without inheriting the NOMADS delay. Transient 429/5xx responses use exponential backoff with jitter and honor `Retry-After`.
|
|
168
|
+
Those are implementation and provenance concerns—not new public query dimensions.
|
|
269
169
|
|
|
270
170
|
## Documentation
|
|
271
171
|
|
|
272
|
-
The
|
|
172
|
+
The root README is the product overview. Detailed reference material lives under [`docs/`](docs/README.md).
|
|
273
173
|
|
|
274
|
-
Start
|
|
174
|
+
Start here:
|
|
275
175
|
|
|
276
|
-
- [Installation and
|
|
176
|
+
- [Installation and deployment](docs/INSTALL.md)
|
|
177
|
+
- [Unified atmospheric API](docs/UNIFIED_API.md)
|
|
277
178
|
- [Architecture](docs/ARCHITECTURE.md)
|
|
278
|
-
- [GEFS
|
|
279
|
-
- [ECMWF IFS
|
|
280
|
-
- [
|
|
281
|
-
- [Testing](docs/TESTING.md)
|
|
282
|
-
- [
|
|
179
|
+
- [GEFS and GEFSv12 reforecast semantics](docs/GEFS_ENSEMBLE.md)
|
|
180
|
+
- [ECMWF IFS / IFS ENS semantics](docs/IFS.md)
|
|
181
|
+
- [Historical GFS, archives and verification](docs/HISTORY.md)
|
|
182
|
+
- [Testing](docs/TESTING.md) and [meteorology validation](docs/METEOROLOGY_VALIDATION.md)
|
|
183
|
+
- [Release notes](docs/RELEASES.md)
|
|
184
|
+
|
|
185
|
+
## Scope
|
|
186
|
+
|
|
187
|
+
WFG exposes numerical-model evidence and meteorological diagnostics. It does **not** own activity-specific scores, turbine power curves, route decisions, flight/summit safety judgments or calibrated probabilities unless such a layer is explicitly designed and validated.
|
|
283
188
|
|
|
284
|
-
|
|
189
|
+
That separation is intentional: the tool should be reusable by many agents and applications without smuggling one application's judgment into the weather core.
|
|
285
190
|
|
|
286
191
|
## License
|
|
287
192
|
|
|
288
|
-
MIT.
|
|
193
|
+
MIT. See [LICENSE](LICENSE).
|
|
@@ -8,6 +8,11 @@ export interface UpstreamAccessPolicyDefinition {
|
|
|
8
8
|
minIntervalMs: number;
|
|
9
9
|
staleLockMs?: number;
|
|
10
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* Provider etiquette and concurrency limits live here, independently of cache
|
|
13
|
+
* implementation. A source/cache client may reuse these policies, but it must
|
|
14
|
+
* not invent provider pacing of its own.
|
|
15
|
+
*/
|
|
11
16
|
export declare const UPSTREAM_ACCESS_POLICIES: {
|
|
12
17
|
readonly nomads: {
|
|
13
18
|
readonly id: "nomads";
|
|
@@ -58,4 +63,3 @@ export declare class FileAccessPolicy implements UpstreamAccessPolicy {
|
|
|
58
63
|
private statePath;
|
|
59
64
|
private readState;
|
|
60
65
|
}
|
|
61
|
-
export declare function withLegacyCooldown(definition: UpstreamAccessPolicyDefinition, cooldownMs: number | undefined): UpstreamAccessPolicyDefinition;
|
|
@@ -3,42 +3,19 @@ import { join } from "node:path";
|
|
|
3
3
|
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
4
4
|
export const DEFAULT_ACCESS_POLICY_STALE_LOCK_MS = 120_000;
|
|
5
5
|
const DEFAULT_POLL_MS = 100;
|
|
6
|
+
/**
|
|
7
|
+
* Provider etiquette and concurrency limits live here, independently of cache
|
|
8
|
+
* implementation. A source/cache client may reuse these policies, but it must
|
|
9
|
+
* not invent provider pacing of its own.
|
|
10
|
+
*/
|
|
6
11
|
export const UPSTREAM_ACCESS_POLICIES = {
|
|
7
|
-
nomads: {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
},
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
maxConcurrency: 8,
|
|
15
|
-
minIntervalMs: 0,
|
|
16
|
-
},
|
|
17
|
-
ecmwfCloud: {
|
|
18
|
-
id: "ecmwf-cloud",
|
|
19
|
-
maxConcurrency: 8,
|
|
20
|
-
minIntervalMs: 0,
|
|
21
|
-
},
|
|
22
|
-
ecmwfDirect: {
|
|
23
|
-
id: "ecmwf-direct",
|
|
24
|
-
maxConcurrency: 4,
|
|
25
|
-
minIntervalMs: 0,
|
|
26
|
-
},
|
|
27
|
-
nceiThredds: {
|
|
28
|
-
id: "ncei-thredds",
|
|
29
|
-
maxConcurrency: 2,
|
|
30
|
-
minIntervalMs: 0,
|
|
31
|
-
},
|
|
32
|
-
gdex: {
|
|
33
|
-
id: "gdex",
|
|
34
|
-
maxConcurrency: 4,
|
|
35
|
-
minIntervalMs: 0,
|
|
36
|
-
},
|
|
37
|
-
nceiIgra: {
|
|
38
|
-
id: "ncei-igra",
|
|
39
|
-
maxConcurrency: 4,
|
|
40
|
-
minIntervalMs: 0,
|
|
41
|
-
},
|
|
12
|
+
nomads: { id: "nomads", maxConcurrency: 1, minIntervalMs: 11_000 },
|
|
13
|
+
noaaAws: { id: "noaa-aws", maxConcurrency: 8, minIntervalMs: 0 },
|
|
14
|
+
ecmwfCloud: { id: "ecmwf-cloud", maxConcurrency: 8, minIntervalMs: 0 },
|
|
15
|
+
ecmwfDirect: { id: "ecmwf-direct", maxConcurrency: 4, minIntervalMs: 0 },
|
|
16
|
+
nceiThredds: { id: "ncei-thredds", maxConcurrency: 2, minIntervalMs: 0 },
|
|
17
|
+
gdex: { id: "gdex", maxConcurrency: 4, minIntervalMs: 0 },
|
|
18
|
+
nceiIgra: { id: "ncei-igra", maxConcurrency: 4, minIntervalMs: 0 },
|
|
42
19
|
};
|
|
43
20
|
export class FileAccessPolicy {
|
|
44
21
|
rootDir;
|
|
@@ -124,10 +101,9 @@ export class FileAccessPolicy {
|
|
|
124
101
|
}
|
|
125
102
|
}
|
|
126
103
|
slotPath(slot) {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
return join(this.rootDir, `${this.definition.id}.slot-${slot}.lock`);
|
|
104
|
+
return this.definition.maxConcurrency === 1
|
|
105
|
+
? join(this.rootDir, `${this.definition.id}.lock`)
|
|
106
|
+
: join(this.rootDir, `${this.definition.id}.slot-${slot}.lock`);
|
|
131
107
|
}
|
|
132
108
|
statePath() {
|
|
133
109
|
return join(this.rootDir, `${this.definition.id}-state.json`);
|
|
@@ -141,16 +117,7 @@ export class FileAccessPolicy {
|
|
|
141
117
|
}
|
|
142
118
|
}
|
|
143
119
|
}
|
|
144
|
-
export function withLegacyCooldown(definition, cooldownMs) {
|
|
145
|
-
if (cooldownMs === undefined)
|
|
146
|
-
return definition;
|
|
147
|
-
return {
|
|
148
|
-
...definition,
|
|
149
|
-
maxConcurrency: 1,
|
|
150
|
-
minIntervalMs: cooldownMs,
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
120
|
function isAlreadyExists(error) {
|
|
154
121
|
return error instanceof Error && "code" in error && error.code === "EEXIST";
|
|
155
122
|
}
|
|
156
|
-
//# sourceMappingURL=
|
|
123
|
+
//# sourceMappingURL=access-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"access-policy.js","sourceRoot":"","sources":["../../src/access/access-policy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { UpstreamAccessPolicy } from "./access-policy.js";
|
|
2
|
+
import { type HttpRetryExecutionOptions } from "./http-retry.js";
|
|
3
|
+
export interface RetryableFetchOptions extends HttpRetryExecutionOptions {
|
|
4
|
+
fetchFn?: typeof fetch;
|
|
5
|
+
accessPolicy?: UpstreamAccessPolicy;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Shared HTTP execution policy: provider concurrency/pacing is applied to every
|
|
9
|
+
* attempt, then transient HTTP/transport failures use the common retry policy.
|
|
10
|
+
* Callers retain responsibility for provider-specific success validation and
|
|
11
|
+
* response decoding.
|
|
12
|
+
*/
|
|
13
|
+
export declare function fetchWithRetry(input: string | URL, init: RequestInit | undefined, options?: RetryableFetchOptions): Promise<Response>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { runWithHttpRetry, } from "./http-retry.js";
|
|
2
|
+
/**
|
|
3
|
+
* Shared HTTP execution policy: provider concurrency/pacing is applied to every
|
|
4
|
+
* attempt, then transient HTTP/transport failures use the common retry policy.
|
|
5
|
+
* Callers retain responsibility for provider-specific success validation and
|
|
6
|
+
* response decoding.
|
|
7
|
+
*/
|
|
8
|
+
export async function fetchWithRetry(input, init, options = {}) {
|
|
9
|
+
const fetchFn = options.fetchFn ?? globalThis.fetch;
|
|
10
|
+
const run = (operation) => options.accessPolicy?.run(operation) ?? operation();
|
|
11
|
+
const result = await runWithHttpRetry(async () => {
|
|
12
|
+
const response = await run(() => fetchFn(input, init));
|
|
13
|
+
return {
|
|
14
|
+
status: response.status,
|
|
15
|
+
retryAfter: response.headers.get("retry-after"),
|
|
16
|
+
response,
|
|
17
|
+
};
|
|
18
|
+
}, options);
|
|
19
|
+
return result.response;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=http-fetch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-fetch.js","sourceRoot":"","sources":["../../src/access/http-fetch.ts"],"names":[],"mappings":"AACA,OAAO,EACL,gBAAgB,GAEjB,MAAM,iBAAiB,CAAC;AAOzB;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,KAAmB,EACnB,IAA6B,EAC7B,UAAiC,EAAE;IAEnC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,UAAU,CAAC,KAAK,CAAC;IACpD,MAAM,GAAG,GAAG,CAAI,SAA2B,EAAE,EAAE,CAC7C,OAAO,CAAC,YAAY,EAAE,GAAG,CAAC,SAAS,CAAC,IAAI,SAAS,EAAE,CAAC;IAEtD,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,KAAK,IAAI,EAAE;QAC/C,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;QACvD,OAAO;YACL,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,UAAU,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;YAC/C,QAAQ;SACT,CAAC;IACJ,CAAC,EAAE,OAAO,CAAC,CAAC;IAEZ,OAAO,MAAM,CAAC,QAAQ,CAAC;AACzB,CAAC"}
|
|
@@ -2,6 +2,13 @@ export declare const DEFAULT_HTTP_RETRY_BASE_DELAY_MS = 500;
|
|
|
2
2
|
export declare const DEFAULT_HTTP_RETRY_MAX_DELAY_MS = 10000;
|
|
3
3
|
export declare const DEFAULT_HTTP_RETRY_MAX_ATTEMPTS = 3;
|
|
4
4
|
export declare const DEFAULT_HTTP_RETRY_JITTER_RATIO = 0.2;
|
|
5
|
+
export interface HttpRetryAttemptResult {
|
|
6
|
+
status: number;
|
|
7
|
+
retryAfter: string | null;
|
|
8
|
+
}
|
|
9
|
+
export interface HttpRetryExecutionOptions extends HttpRetryWaitOptions {
|
|
10
|
+
maxAttempts?: number;
|
|
11
|
+
}
|
|
5
12
|
export interface HttpRetryWaitOptions {
|
|
6
13
|
baseDelayMs?: number;
|
|
7
14
|
maxDelayMs?: number;
|
|
@@ -10,6 +17,8 @@ export interface HttpRetryWaitOptions {
|
|
|
10
17
|
randomFn?: () => number;
|
|
11
18
|
}
|
|
12
19
|
export declare function isRetryableHttpStatus(status: number): boolean;
|
|
20
|
+
export declare function isRetryableHttpTransportError(error: unknown): boolean;
|
|
13
21
|
export declare function retryAfterMilliseconds(value: string | null, now?: number): number | undefined;
|
|
14
22
|
export declare function exponentialBackoffMilliseconds(attempt: number, options?: Omit<HttpRetryWaitOptions, "sleepFn">): number;
|
|
23
|
+
export declare function runWithHttpRetry<T extends HttpRetryAttemptResult>(operation: () => Promise<T>, options?: HttpRetryExecutionOptions): Promise<T>;
|
|
15
24
|
export declare function waitBeforeHttpRetry(attempt: number, retryAfterHeader: string | null, options?: HttpRetryWaitOptions): Promise<void>;
|