@dangahagan/weather-mcp 1.31.4 → 1.32.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 +6 -6
- package/dist/config/tools.d.ts +3 -2
- package/dist/config/tools.d.ts.map +1 -1
- package/dist/config/tools.js +5 -4
- package/dist/config/tools.js.map +1 -1
- package/dist/handlers/locationHandler.d.ts.map +1 -1
- package/dist/handlers/locationHandler.js +5 -1
- package/dist/handlers/locationHandler.js.map +1 -1
- package/dist/handlers/weatherSummaryHandler.d.ts.map +1 -1
- package/dist/handlers/weatherSummaryHandler.js +62 -16
- package/dist/handlers/weatherSummaryHandler.js.map +1 -1
- package/dist/index.js +15 -45
- package/dist/index.js.map +1 -1
- package/dist/server/lightningPrewarm.d.ts +45 -0
- package/dist/server/lightningPrewarm.d.ts.map +1 -0
- package/dist/server/lightningPrewarm.js +104 -0
- package/dist/server/lightningPrewarm.js.map +1 -0
- package/dist/server/weatherServer.d.ts +8 -2
- package/dist/server/weatherServer.d.ts.map +1 -1
- package/dist/server/weatherServer.js +8 -2
- package/dist/server/weatherServer.js.map +1 -1
- package/dist/services/blitzortung.d.ts +25 -4
- package/dist/services/blitzortung.d.ts.map +1 -1
- package/dist/services/blitzortung.js +79 -24
- package/dist/services/blitzortung.js.map +1 -1
- package/dist/services/openmeteo.d.ts +8 -6
- package/dist/services/openmeteo.d.ts.map +1 -1
- package/dist/services/openmeteo.js +8 -6
- package/dist/services/openmeteo.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@dangahagan/weather-mcp)
|
|
4
4
|
[](https://registry.modelcontextprotocol.io/v0/servers?search=io.github.dgahagan/weather-mcp)
|
|
5
5
|
[](https://opensource.org/licenses/MIT)
|
|
6
|
-
[](./docs/testing/TEST_SUITE_README.md)
|
|
7
7
|
[](https://nodejs.org)
|
|
8
8
|
|
|
9
9
|
**Give your AI assistant real weather data — 17 tools, zero API keys, zero signup, zero cost.**
|
|
@@ -58,7 +58,7 @@ Choose this one if you want:
|
|
|
58
58
|
|
|
59
59
|
- **Genuinely free** — every data source is a free public API. No trial that expires, no credit card, no rate-limited "free tier" bait.
|
|
60
60
|
- **No API keys** — install to first forecast in under a minute. Nothing to configure, nothing to leak into a repo. ([Three optional keys](#optional-api-keys) add extras if you want them; the default configuration needs none.)
|
|
61
|
-
- **Fully open source** — MIT licensed, readable TypeScript, 3,
|
|
61
|
+
- **Fully open source** — MIT licensed, readable TypeScript, 3,644 tests. Audit it, fork it, fix it.
|
|
62
62
|
- **Privacy-respecting** — your queries go directly from your machine to public weather APIs. No middleman server, no telemetry.
|
|
63
63
|
- **Breadth** — 17 tools covering weather, safety hazards (lightning, floods, wildfires), marine conditions, air quality, and historical data back to 1940. Most weather MCPs stop at forecasts.
|
|
64
64
|
|
|
@@ -231,8 +231,8 @@ Control which tools are exposed to reduce context overhead:
|
|
|
231
231
|
|
|
232
232
|
**Context cost.** Every MCP client puts the `tools/list` result into model context on
|
|
233
233
|
every turn, so the preset you choose is a standing cost on every request. Measured on
|
|
234
|
-
the built server: `basic` **
|
|
235
|
-
`full`/`all` **
|
|
234
|
+
the built server: `basic` **13,212 bytes** (~3.3k tokens), `standard` **21,186** (~5.3k),
|
|
235
|
+
`full`/`all` **31,055** (~7.8k). It scales with the number of **tools**, not the number of
|
|
236
236
|
data sources — adding Japan and India as alert authorities added zero tools and zero bytes.
|
|
237
237
|
|
|
238
238
|
```bash
|
|
@@ -273,7 +273,7 @@ Supported on `get_forecast`, `get_current_conditions`, and `get_historical_weath
|
|
|
273
273
|
| `CACHE_ENABLED` | `true` | Enable/disable response caching |
|
|
274
274
|
| `CACHE_MAX_SIZE` | `1000` | Max cache entries (100–10000) |
|
|
275
275
|
| `API_TIMEOUT_MS` | `30000` | Upstream API timeout (5000–120000) |
|
|
276
|
-
| `WEATHER_LIGHTNING_PREWARM` | `true` | Subscribe saved locations' geohashes at startup so
|
|
276
|
+
| `WEATHER_LIGHTNING_PREWARM` | `true` | Subscribe saved locations' geohashes at startup so lightning has coverage before the first query, and keep them subscribed for as long as they stay saved. The saved list is re-read every 30 minutes: a location saved from another client is picked up, and a removed one stops being watched within about an hour, with no restart. Follows the lightning tool (`get_lightning_activity`), not `get_weather_summary`: no effect when the lightning tool is disabled, as it is in the default `basic` preset — use `ENABLED_TOOLS=basic,+lightning` to opt in. A saved location that does not fit the 50-subscription limit is skipped rather than displacing an area you queried. Set `false` to skip pre-warm and the persistent MQTT connection it opens. |
|
|
277
277
|
| `LOG_LEVEL` | `1` | `0`/`DEBUG`, `1`/`INFO`, `2`/`WARN`, `3`/`ERROR` — number or name, names case-insensitive. An unrecognized value warns on stderr and falls back to `INFO`. Logs go to stderr |
|
|
278
278
|
| `NCEI_API_TOKEN` | — | Optional [free NCEI token](https://www.ncdc.noaa.gov/cdo-web/token) for official NOAA climate normals (US); falls back to Open-Meteo automatically. See [Optional API keys](#optional-api-keys) |
|
|
279
279
|
| `FIRMS_MAP_KEY` | — | Optional [free FIRMS key](https://firms.modaps.eosdis.nasa.gov/api/map_key/) for targeted wildfire queries and up to 5 days of detection history. See [Optional API keys](#optional-api-keys) |
|
|
@@ -390,7 +390,7 @@ Being honest about what free public data can and can't do:
|
|
|
390
390
|
```bash
|
|
391
391
|
npm run build # Compile TypeScript
|
|
392
392
|
npm run dev # Run in development mode
|
|
393
|
-
npm test # Run all 3,
|
|
393
|
+
npm test # Run all 3,644 tests
|
|
394
394
|
npm run test:coverage # Coverage report
|
|
395
395
|
npm run audit # Dependency vulnerability scan
|
|
396
396
|
```
|
package/dist/config/tools.d.ts
CHANGED
|
@@ -46,9 +46,10 @@ export declare const ALIASES: Record<string, "check_service_status" | "get_air_q
|
|
|
46
46
|
* Every MCP client puts this payload into model context on every turn, so it is
|
|
47
47
|
* a standing context cost. Each value is the measured payload rounded up to the
|
|
48
48
|
* next 1,000 bytes, so growth past it is a deliberate edit of this file rather
|
|
49
|
-
* than a description that quietly grew. Measured 2026-09-
|
|
49
|
+
* than a description that quietly grew. Measured 2026-09-23 in UTF-8 bytes
|
|
50
50
|
* (Buffer.byteLength, not String.length — the descriptions carry em-dashes, and
|
|
51
|
-
* a code-unit count under-reports): basic
|
|
51
|
+
* a code-unit count under-reports): basic 13,212, full 31,055. Raised from
|
|
52
|
+
* 13,000 / 31,000 on purpose, for get_weather_summary's declared `source`.
|
|
52
53
|
*/
|
|
53
54
|
export declare const TOOLS_LIST_BYTE_BUDGET: Record<'basic' | 'full', number>;
|
|
54
55
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/config/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;;GAEG;AAKH,eAAO,MAAM,UAAU,YACrB,cAAc,EACd,wBAAwB,EACxB,YAAY,EACZ,wBAAwB,EACxB,qBAAqB,EACrB,sBAAsB,EACtB,iBAAiB,EACjB,iBAAiB,EACjB,uBAAuB,EACvB,qBAAqB,EACrB,wBAAwB,EACxB,sBAAsB,EACtB,mBAAmB,EACnB,eAAe,EACf,sBAAsB,EACtB,oBAAoB,EACpB,uBAAuB,CACf,CAAC;AAEX,MAAM,MAAM,QAAQ,GAAG,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC;AAmOjD;;GAEG;AACH,cAAM,UAAU;IACd,OAAO,CAAC,YAAY,CAAgB;IAEpC,cASC;IAED;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAEjC;IAED;;OAEG;IACH,eAAe,IAAI,QAAQ,EAAE,CAE5B;IAED;;OAEG;IACH,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,CAE9C;IAED;;OAEG;IACH,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAE5C;CACF;AAGD,eAAO,MAAM,UAAU,YAAmB,CAAC;AAG3C,eAAO,MAAM,OAAO,0ZAAe,CAAC;AACpC,eAAO,MAAM,OAAO,sZAAe,CAAC;AAEpC
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/config/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;;GAEG;AAKH,eAAO,MAAM,UAAU,YACrB,cAAc,EACd,wBAAwB,EACxB,YAAY,EACZ,wBAAwB,EACxB,qBAAqB,EACrB,sBAAsB,EACtB,iBAAiB,EACjB,iBAAiB,EACjB,uBAAuB,EACvB,qBAAqB,EACrB,wBAAwB,EACxB,sBAAsB,EACtB,mBAAmB,EACnB,eAAe,EACf,sBAAsB,EACtB,oBAAoB,EACpB,uBAAuB,CACf,CAAC;AAEX,MAAM,MAAM,QAAQ,GAAG,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC;AAmOjD;;GAEG;AACH,cAAM,UAAU;IACd,OAAO,CAAC,YAAY,CAAgB;IAEpC,cASC;IAED;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAEjC;IAED;;OAEG;IACH,eAAe,IAAI,QAAQ,EAAE,CAE5B;IAED;;OAEG;IACH,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,CAE9C;IAED;;OAEG;IACH,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAE5C;CACF;AAGD,eAAO,MAAM,UAAU,YAAmB,CAAC;AAG3C,eAAO,MAAM,OAAO,0ZAAe,CAAC;AACpC,eAAO,MAAM,OAAO,sZAAe,CAAC;AAEpC;;;;;;;;;GASG;AACH,eAAO,MAAM,sBAAsB,EAAE,MAAM,CAAC,OAAO,GAAG,MAAM,EAAE,MAAM,CAGnE,CAAC"}
|
package/dist/config/tools.js
CHANGED
|
@@ -299,12 +299,13 @@ export const ALIASES = TOOL_ALIASES;
|
|
|
299
299
|
* Every MCP client puts this payload into model context on every turn, so it is
|
|
300
300
|
* a standing context cost. Each value is the measured payload rounded up to the
|
|
301
301
|
* next 1,000 bytes, so growth past it is a deliberate edit of this file rather
|
|
302
|
-
* than a description that quietly grew. Measured 2026-09-
|
|
302
|
+
* than a description that quietly grew. Measured 2026-09-23 in UTF-8 bytes
|
|
303
303
|
* (Buffer.byteLength, not String.length — the descriptions carry em-dashes, and
|
|
304
|
-
* a code-unit count under-reports): basic
|
|
304
|
+
* a code-unit count under-reports): basic 13,212, full 31,055. Raised from
|
|
305
|
+
* 13,000 / 31,000 on purpose, for get_weather_summary's declared `source`.
|
|
305
306
|
*/
|
|
306
307
|
export const TOOLS_LIST_BYTE_BUDGET = {
|
|
307
|
-
basic:
|
|
308
|
-
full:
|
|
308
|
+
basic: 14000,
|
|
309
|
+
full: 32000,
|
|
309
310
|
};
|
|
310
311
|
//# sourceMappingURL=tools.js.map
|
package/dist/config/tools.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/config/tools.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/config/tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"locationHandler.d.ts","sourceRoot":"","sources":["../../src/handlers/locationHandler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAiC5D,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,OAAO,EACb,gBAAgB,EAAE,gBAAgB,GACjC,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"locationHandler.d.ts","sourceRoot":"","sources":["../../src/handlers/locationHandler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAiC5D,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,OAAO,EACb,gBAAgB,EAAE,gBAAgB,GACjC,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC,CAmG7D"}
|
|
@@ -40,8 +40,12 @@ export async function handleSearchLocation(args, geocodingService) {
|
|
|
40
40
|
// clamps to the same number independently, so raising one means raising all
|
|
41
41
|
// three. Out-of-range values are clamped, never rejected — the same tolerant
|
|
42
42
|
// clamping contract wildfireHandler.ts and riverConditionsHandler.ts follow.
|
|
43
|
+
// A fractional value (the schema declares `limit` as `integer`, but nothing
|
|
44
|
+
// stops a caller from sending a float) is truncated with Math.floor before
|
|
45
|
+
// the clamp, never rejected, which keeps the tolerant contract — so the
|
|
46
|
+
// geocoders only ever receive integers.
|
|
43
47
|
const limit = typeof locationArgs.limit === 'number' ?
|
|
44
|
-
Math.min(Math.max(1, locationArgs.limit), 50) : 5; // Nominatim max is 50
|
|
48
|
+
Math.min(Math.max(1, Math.floor(locationArgs.limit)), 50) : 5; // Nominatim max is 50
|
|
45
49
|
// Search for locations using multi-service geocoding
|
|
46
50
|
const results = await geocodingService.geocode(query, limit);
|
|
47
51
|
// Format the results for display
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"locationHandler.js","sourceRoot":"","sources":["../../src/handlers/locationHandler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AASH;;;;;GAKG;AACH,SAAS,cAAc,CAAC,IAAY;IAClC,8DAA8D;IAC9D,OAAO,IAAI;SACR,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAI,4BAA4B;SACtD,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAM,yBAAyB;SACpD,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAO,2BAA2B;SACtD,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAM,uBAAuB;SAClD,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAM,wBAAwB;SACnD,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAM,qBAAqB;SAChD,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAM,sBAAsB;SACjD,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAM,6BAA6B;SACxD,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAM,gCAAgC;SAC3D,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAO,kBAAkB;SAC7C,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAO,wBAAwB;SACnD,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAO,iBAAiB;SAC5C,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAO,uBAAuB;SAClD,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAQ,mDAAmD;SAC9E,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAQ,0BAA0B;AAC1D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,IAAa,EACb,gBAAkC;IAElC,4BAA4B;IAC5B,MAAM,YAAY,GAAG,IAAoB,CAAC;IAE1C,IAAI,CAAC,YAAY,CAAC,KAAK,IAAI,OAAO,YAAY,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QAClE,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;IACtE,CAAC;IAED,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;IACxC,yEAAyE;IACzE,8EAA8E;IAC9E,6EAA6E;IAC7E,4EAA4E;IAC5E,6EAA6E;IAC7E,6EAA6E;IAC7E,MAAM,KAAK,GAAG,OAAO,YAAY,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC;QACpD,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,YAAY,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,sBAAsB;
|
|
1
|
+
{"version":3,"file":"locationHandler.js","sourceRoot":"","sources":["../../src/handlers/locationHandler.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"weatherSummaryHandler.d.ts","sourceRoot":"","sources":["../../src/handlers/weatherSummaryHandler.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"weatherSummaryHandler.d.ts","sourceRoot":"","sources":["../../src/handlers/weatherSummaryHandler.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAQhE,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAMpD;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,UAAU,GAAG,QAAQ,GAAG,aAAa,GAAG,WAAW,CAAC;AAqG7F,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,OAAO,EACb,WAAW,EAAE,WAAW,EACxB,gBAAgB,EAAE,gBAAgB,EAClC,WAAW,EAAE,WAAW,EACxB,aAAa,EAAE,aAAa,EAC5B,gBAAgB,EAAE,gBAAgB,EAClC,iBAAiB,CAAC,EAAE,iBAAiB,EACrC,aAAa,CAAC,EAAE,aAAa,EAC7B,gBAAgB,CAAC,EAAE,gBAAgB,EACnC,oBAAoB,CAAC,EAAE,oBAAoB,EAC3C,kBAAkB,CAAC,EAAE,kBAAkB,EASvC,UAAU,CAAC,EAAE,UAAU,EAgBvB,mBAAmB,CAAC,EAAE,OAAO,EAO7B,YAAY,CAAC,EAAE,YAAY,GAC1B,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC,CAoI7D"}
|
|
@@ -19,6 +19,23 @@ import { resolveCriticalAlertBanner } from './criticalAlertBanner.js';
|
|
|
19
19
|
import { guessTimezoneFromCoords } from '../utils/timezone.js';
|
|
20
20
|
const VALID_SECTIONS = ['current', 'forecast', 'alerts', 'air_quality', 'lightning'];
|
|
21
21
|
const DEFAULT_SECTIONS = ['current', 'forecast', 'alerts'];
|
|
22
|
+
const VALID_SOURCES = ['auto', 'noaa', 'openmeteo'];
|
|
23
|
+
/**
|
|
24
|
+
* The unit keys the summary declares and forwards. They mirror
|
|
25
|
+
* `UNIT_SCHEMA_PROPERTIES` in `src/server/weatherServer.ts`, which this module
|
|
26
|
+
* cannot import (that file imports this handler, so the import would be a
|
|
27
|
+
* cycle). `tests/unit/weather-summary-allowlist.test.ts` derives its expected
|
|
28
|
+
* key set from the declared schema, so the two cannot drift apart unnoticed.
|
|
29
|
+
*/
|
|
30
|
+
const SUMMARY_UNIT_KEYS = [
|
|
31
|
+
'units',
|
|
32
|
+
'temperature_unit',
|
|
33
|
+
'wind_speed_unit',
|
|
34
|
+
'precipitation_unit',
|
|
35
|
+
'pressure_unit',
|
|
36
|
+
'distance_unit',
|
|
37
|
+
'time_format'
|
|
38
|
+
];
|
|
22
39
|
/**
|
|
23
40
|
* Validate and normalize the `include` array.
|
|
24
41
|
* Defaults to current + forecast + alerts; unknown entries are rejected.
|
|
@@ -42,6 +59,21 @@ function validateInclude(value) {
|
|
|
42
59
|
// Empty array falls back to the default set rather than producing an empty report
|
|
43
60
|
return sections.length > 0 ? sections : DEFAULT_SECTIONS;
|
|
44
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Validate the optional `source`. Absent stays absent (not `'auto'`): both
|
|
64
|
+
* sub-handlers apply their own `|| 'auto'`, so forwarding nothing keeps the
|
|
65
|
+
* default path identical by construction. `metar` and any other value are
|
|
66
|
+
* refused before any upstream call.
|
|
67
|
+
*/
|
|
68
|
+
function validateSummarySource(value) {
|
|
69
|
+
if (value === undefined) {
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
if (typeof value === 'string' && VALID_SOURCES.includes(value)) {
|
|
73
|
+
return value;
|
|
74
|
+
}
|
|
75
|
+
throw new Error(`Invalid source "${String(value)}". Valid sources for get_weather_summary: ${VALID_SOURCES.join(', ')}.`);
|
|
76
|
+
}
|
|
45
77
|
/**
|
|
46
78
|
* Extract the text payload from a sub-handler result.
|
|
47
79
|
*/
|
|
@@ -70,10 +102,10 @@ jmaService,
|
|
|
70
102
|
// safety element people stop reading.
|
|
71
103
|
//
|
|
72
104
|
// The summary therefore resolves the banner **once, here**, and prepends it to
|
|
73
|
-
// its own assembled body. Two facts already keep the sub-handlers quiet:
|
|
74
|
-
// calls below pass
|
|
75
|
-
//
|
|
76
|
-
// parameter and not
|
|
105
|
+
// its own assembled body. Two facts already keep the sub-handlers quiet: the
|
|
106
|
+
// two calls below never pass the banner flag positionally; and `subArgs` is
|
|
107
|
+
// built from a fixed allowlist of declared keys, while this is a function
|
|
108
|
+
// parameter and not on that list. Neither survives a future edit
|
|
77
109
|
// unnoticed, which is why `tests/unit/critical-alert-summary.test.ts` counts
|
|
78
110
|
// the banner's occurrences rather than merely asserting it is present.
|
|
79
111
|
criticalAlertBanner,
|
|
@@ -85,29 +117,43 @@ criticalAlertBanner,
|
|
|
85
117
|
// exact assumption G19 exists to refuse.
|
|
86
118
|
metnoService) {
|
|
87
119
|
const typedArgs = (args ?? {});
|
|
120
|
+
// First, before resolveLocationAsync: a `city_name` is geocoded there, which
|
|
121
|
+
// is itself an upstream call, and a refused source must cost none.
|
|
122
|
+
const source = validateSummarySource(typedArgs.source);
|
|
88
123
|
// Resolve location once; sub-handlers receive the resolved coordinates so they
|
|
89
124
|
// never re-geocode (coordinates take precedence in resolveLocationAsync).
|
|
90
125
|
const resolved = await resolveLocationAsync(typedArgs, locationStore, geocodingService);
|
|
91
126
|
const include = validateInclude(typedArgs.include);
|
|
92
127
|
const detail = validateDetail(typedArgs.detail, 'summary');
|
|
93
128
|
const days = validateForecastDays(typedArgs);
|
|
94
|
-
//
|
|
95
|
-
//
|
|
129
|
+
// The invariant: the summary forwards only what it declares. A sub-tool
|
|
130
|
+
// parameter reaches a section only if it is declared on get_weather_summary
|
|
131
|
+
// (G85). This is an allowlist, not a spread, so a parameter added to a
|
|
132
|
+
// sub-handler later does not leak through by default.
|
|
133
|
+
//
|
|
134
|
+
// - Resolved coordinates, so no sub-handler re-geocodes. `location_name` and
|
|
135
|
+
// `city_name` are consumed here and never copied.
|
|
136
|
+
// - `detail`, as validated for the summary.
|
|
137
|
+
// - The declared unit keys and `source`, each copied only when the caller
|
|
138
|
+
// sent it, so no key arrives with an `undefined` value.
|
|
139
|
+
//
|
|
140
|
+
// Deliberately not forwarded: `granularity` (an hourly table is the wrong
|
|
141
|
+
// shape inside a one-call overview; use get_forecast), and `compare_models` /
|
|
142
|
+
// `ensemble_spread` (D9: a comparison or spread view is the wrong shape inside
|
|
143
|
+
// a summary). `days` goes to the forecast section only, below.
|
|
96
144
|
const subArgs = {
|
|
97
|
-
...(typeof args === 'object' && args !== null ? args : {}),
|
|
98
145
|
latitude: resolved.latitude,
|
|
99
146
|
longitude: resolved.longitude,
|
|
100
|
-
location_name: undefined,
|
|
101
|
-
city_name: undefined,
|
|
102
|
-
// A comparison block is the wrong shape inside a summary; users wanting
|
|
103
|
-
// a comparison call get_forecast directly.
|
|
104
|
-
compare_models: undefined,
|
|
105
|
-
// Same reasoning as compare_models (D9): the summary's forecast section is
|
|
106
|
-
// a plain forecast, and a spread view would replace that section with a
|
|
107
|
-
// different product rather than compose with the summary's other sections.
|
|
108
|
-
ensemble_spread: undefined,
|
|
109
147
|
detail
|
|
110
148
|
};
|
|
149
|
+
for (const key of SUMMARY_UNIT_KEYS) {
|
|
150
|
+
if (typedArgs[key] !== undefined) {
|
|
151
|
+
subArgs[key] = typedArgs[key];
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (source !== undefined) {
|
|
155
|
+
subArgs.source = source;
|
|
156
|
+
}
|
|
111
157
|
// Resolved once for the whole summary and prepended outermost, so the reader
|
|
112
158
|
// meets the warning before the heading. The summary builds a string rather
|
|
113
159
|
// than mutating `content[0].text`, so this is plain concatenation and
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"weatherSummaryHandler.js","sourceRoot":"","sources":["../../src/handlers/weatherSummaryHandler.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAYH,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AACxF,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAe,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"weatherSummaryHandler.js","sourceRoot":"","sources":["../../src/handlers/weatherSummaryHandler.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -13,6 +13,7 @@ import { toolConfig } from './config/tools.js';
|
|
|
13
13
|
import { logger, LogLevel } from './utils/logger.js';
|
|
14
14
|
import { analytics } from './analytics/index.js';
|
|
15
15
|
import { createWeatherServer, SERVER_VERSION, clearServiceCaches } from './server/weatherServer.js';
|
|
16
|
+
import { startLightningPrewarm } from './server/lightningPrewarm.js';
|
|
16
17
|
/**
|
|
17
18
|
* Initialize the LocationStore for managing saved/favorite locations
|
|
18
19
|
* Stores locations in ~/.weather-mcp/locations.json
|
|
@@ -20,49 +21,10 @@ import { createWeatherServer, SERVER_VERSION, clearServiceCaches } from './serve
|
|
|
20
21
|
*/
|
|
21
22
|
const locationStore = new LocationStore();
|
|
22
23
|
const server = createWeatherServer({ locationStore });
|
|
24
|
+
let lightningPrewarm;
|
|
23
25
|
/**
|
|
24
26
|
* Start the server
|
|
25
27
|
*/
|
|
26
|
-
/**
|
|
27
|
-
* Pre-warm live lightning monitoring for saved locations at startup.
|
|
28
|
-
*
|
|
29
|
-
* The Blitzortung feed only buffers strikes for an area once it is subscribed, so the
|
|
30
|
-
* first query to a location otherwise reports zero monitoring coverage. Subscribing
|
|
31
|
-
* saved locations at startup lets their coverage accumulate before the user asks.
|
|
32
|
-
* Best-effort and fully non-blocking: it opens a persistent MQTT connection, so it is
|
|
33
|
-
* skipped when the lightning tool is disabled or when WEATHER_LIGHTNING_PREWARM=false.
|
|
34
|
-
* The saved-locations read is guarded too: an unreadable locations file must not stop
|
|
35
|
-
* the server from booting.
|
|
36
|
-
*/
|
|
37
|
-
function prewarmLightningMonitoring() {
|
|
38
|
-
if (process.env.WEATHER_LIGHTNING_PREWARM === 'false') {
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
if (!toolConfig.isEnabled('get_lightning_activity')) {
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
let savedLocations;
|
|
45
|
-
try {
|
|
46
|
-
savedLocations = Object.values(locationStore.getAll());
|
|
47
|
-
}
|
|
48
|
-
catch (error) {
|
|
49
|
-
logger.warn('Skipping lightning pre-warm: saved locations could not be read', {
|
|
50
|
-
error: error instanceof Error ? error.message : String(error)
|
|
51
|
-
});
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
if (savedLocations.length === 0) {
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
logger.info('Pre-warming lightning monitoring for saved locations', {
|
|
58
|
-
count: savedLocations.length
|
|
59
|
-
});
|
|
60
|
-
// Fire-and-forget: prewarmLocation swallows its own errors and must never block
|
|
61
|
-
// startup or the stdio transport.
|
|
62
|
-
for (const location of savedLocations) {
|
|
63
|
-
void blitzortungService.prewarmLocation(location.latitude, location.longitude);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
28
|
async function main() {
|
|
67
29
|
const transport = new StdioServerTransport();
|
|
68
30
|
// Set up graceful shutdown handlers
|
|
@@ -72,10 +34,12 @@ async function main() {
|
|
|
72
34
|
// 1. Flush analytics first (fast)
|
|
73
35
|
await analytics.shutdown();
|
|
74
36
|
logger.info('Analytics flushed');
|
|
75
|
-
// 2.
|
|
37
|
+
// 2. Stop the lightning pre-warm refresh
|
|
38
|
+
lightningPrewarm?.stop();
|
|
39
|
+
// 3. Clean up resources
|
|
76
40
|
clearServiceCaches();
|
|
77
41
|
logger.info('Cache cleared');
|
|
78
|
-
//
|
|
42
|
+
// 4. Close server connection
|
|
79
43
|
await server.close();
|
|
80
44
|
logger.info('Server closed');
|
|
81
45
|
process.exit(0);
|
|
@@ -96,9 +60,15 @@ async function main() {
|
|
|
96
60
|
enabledTools: toolConfig.getEnabledTools().length,
|
|
97
61
|
toolList: toolConfig.getEnabledTools().join(', ')
|
|
98
62
|
});
|
|
99
|
-
// Begin buffering lightning strikes for saved locations so their coverage
|
|
100
|
-
//
|
|
101
|
-
|
|
63
|
+
// Begin buffering lightning strikes for saved locations so their coverage accumulates
|
|
64
|
+
// before the first query, and keep it subscribed while it stays saved (non-blocking,
|
|
65
|
+
// best-effort).
|
|
66
|
+
lightningPrewarm = startLightningPrewarm({
|
|
67
|
+
toolEnabled: toolConfig.isEnabled('get_lightning_activity'),
|
|
68
|
+
optOutValue: process.env.WEATHER_LIGHTNING_PREWARM,
|
|
69
|
+
readSavedLocations: () => Object.values(locationStore.getAll()),
|
|
70
|
+
prewarmLocation: (lat, lon, r, o) => blitzortungService.prewarmLocation(lat, lon, r, o)
|
|
71
|
+
});
|
|
102
72
|
// Inform users about version and upgrade options
|
|
103
73
|
logger.info('Version check', {
|
|
104
74
|
installedVersion: SERVER_VERSION,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;GAGG;AAEH,oEAAoE;AACpE,OAAO,eAAe,CAAC;AAEvB,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,kBAAkB,EACnB,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;GAGG;AAEH,oEAAoE;AACpE,OAAO,eAAe,CAAC;AAEvB,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,kBAAkB,EACnB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,qBAAqB,EAA+B,MAAM,8BAA8B,CAAC;AAElG;;;;GAIG;AACH,MAAM,aAAa,GAAG,IAAI,aAAa,EAAE,CAAC;AAE1C,MAAM,MAAM,GAAG,mBAAmB,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC;AAEtD,IAAI,gBAAoD,CAAC;AAEzD;;GAEG;AACH,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAE7C,oCAAoC;IACpC,MAAM,QAAQ,GAAG,KAAK,EAAE,MAAc,EAAE,EAAE;QACxC,MAAM,CAAC,IAAI,CAAC,YAAY,MAAM,+BAA+B,CAAC,CAAC;QAE/D,IAAI,CAAC;YACH,kCAAkC;YAClC,MAAM,SAAS,CAAC,QAAQ,EAAE,CAAC;YAC3B,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;YAEjC,yCAAyC;YACzC,gBAAgB,EAAE,IAAI,EAAE,CAAC;YAEzB,wBAAwB;YACxB,kBAAkB,EAAE,CAAC;YACrB,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;YAE7B,6BAA6B;YAC7B,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;YACrB,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;YAE7B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,uBAAuB,EAAE,KAAc,CAAC,CAAC;YACtD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;IACjD,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;IAE/C,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAChC,MAAM,CAAC,IAAI,CAAC,4BAA4B,EAAE;YACxC,OAAO,EAAE,cAAc;YACvB,YAAY,EAAE,WAAW,CAAC,OAAO;YACjC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;YACrC,YAAY,EAAE,UAAU,CAAC,eAAe,EAAE,CAAC,MAAM;YACjD,QAAQ,EAAE,UAAU,CAAC,eAAe,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;SAClD,CAAC,CAAC;QAEH,sFAAsF;QACtF,qFAAqF;QACrF,gBAAgB;QAChB,gBAAgB,GAAG,qBAAqB,CAAC;YACvC,WAAW,EAAE,UAAU,CAAC,SAAS,CAAC,wBAAwB,CAAC;YAC3D,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,yBAAyB;YAClD,kBAAkB,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC;YAC/D,eAAe,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;SACxF,CAAC,CAAC;QAEH,iDAAiD;QACjD,MAAM,CAAC,IAAI,CAAC,eAAe,EAAE;YAC3B,gBAAgB,EAAE,cAAc;YAChC,aAAa,EAAE,4DAA4D;YAC3E,mBAAmB,EAAE,wEAAwE;YAC7F,aAAa,EAAE,+EAA+E;SAC/F,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,KAAK,CAAC,wBAAwB,EAAE,KAAc,CAAC,CAAC;QACvD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,MAAM,CAAC,KAAK,CAAC,uBAAuB,EAAE,KAAK,CAAC,CAAC;IAE7C,sCAAsC;IACtC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC;QAC3B,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,KAAK,EAAE,OAAO;QACd,OAAO,EAAE,6BAA6B;QACtC,KAAK,EAAE;YACL,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;YAC/D,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;SACxD;KACF,CAAC,CAAC,CAAC;IAEJ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Saved-location lightning pre-warm: subscribe saved locations at startup and keep them
|
|
3
|
+
* subscribed for as long as they stay saved.
|
|
4
|
+
*
|
|
5
|
+
* The Blitzortung feed only buffers strikes for an area while it is subscribed, and the
|
|
6
|
+
* service prunes any subscription idle for longer than `SUBSCRIPTION_IDLE_THRESHOLD_MS`.
|
|
7
|
+
* A single startup pre-warm therefore lapsed after about an hour. This module re-warms
|
|
8
|
+
* every saved location on an interval derived from that threshold, so a saved location's
|
|
9
|
+
* access stamp never ages past it. A location removed from the store is simply not
|
|
10
|
+
* re-warmed, and the ordinary prune drops it.
|
|
11
|
+
*
|
|
12
|
+
* - The timer starts whenever the gate passes, even with an empty or unreadable store, so
|
|
13
|
+
* a location saved (or a file repaired) later is picked up on the next tick. An empty
|
|
14
|
+
* store opens no connection: nothing connects until the first `prewarmLocation` call.
|
|
15
|
+
* - The store read is guarded, and only the read: an unreadable file must not stop the
|
|
16
|
+
* server booting, and a fault anywhere else must not be hidden behind the same catch.
|
|
17
|
+
* On an unreadable tick nothing is re-warmed, so subscriptions age out rather than being
|
|
18
|
+
* extended from data that could not be read.
|
|
19
|
+
* - Pre-warm never evicts. The service skips a saved location that does not fit instead of
|
|
20
|
+
* displacing another subscription; this module reports the skipped count when it changes.
|
|
21
|
+
*/
|
|
22
|
+
import { type PrewarmOutcome } from '../services/blitzortung.js';
|
|
23
|
+
export interface PrewarmScheduler {
|
|
24
|
+
setInterval(fn: () => void, ms: number): ReturnType<typeof setInterval>;
|
|
25
|
+
clearInterval(handle: ReturnType<typeof setInterval>): void;
|
|
26
|
+
}
|
|
27
|
+
export interface LightningPrewarmDeps {
|
|
28
|
+
/** `toolConfig.isEnabled('get_lightning_activity')`. */
|
|
29
|
+
toolEnabled: boolean;
|
|
30
|
+
/** The raw `WEATHER_LIGHTNING_PREWARM` value; `'false'` opts out. */
|
|
31
|
+
optOutValue: string | undefined;
|
|
32
|
+
/** Synchronous store read. May throw when the file is unreadable. */
|
|
33
|
+
readSavedLocations: () => Array<{
|
|
34
|
+
latitude: number;
|
|
35
|
+
longitude: number;
|
|
36
|
+
}>;
|
|
37
|
+
prewarmLocation: (latitude: number, longitude: number, radiusKm?: number, outcome?: PrewarmOutcome) => Promise<void>;
|
|
38
|
+
scheduler?: PrewarmScheduler;
|
|
39
|
+
intervalMs?: number;
|
|
40
|
+
}
|
|
41
|
+
export interface LightningPrewarmHandle {
|
|
42
|
+
stop(): void;
|
|
43
|
+
}
|
|
44
|
+
export declare function startLightningPrewarm(deps: LightningPrewarmDeps): LightningPrewarmHandle;
|
|
45
|
+
//# sourceMappingURL=lightningPrewarm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lightningPrewarm.d.ts","sourceRoot":"","sources":["../../src/server/lightningPrewarm.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAEL,KAAK,cAAc,EACpB,MAAM,4BAA4B,CAAC;AAGpC,MAAM,WAAW,gBAAgB;IAC/B,WAAW,CAAC,EAAE,EAAE,MAAM,IAAI,EAAE,EAAE,EAAE,MAAM,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;IACxE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,GAAG,IAAI,CAAC;CAC7D;AAED,MAAM,WAAW,oBAAoB;IACnC,wDAAwD;IACxD,WAAW,EAAE,OAAO,CAAC;IACrB,qEAAqE;IACrE,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,qEAAqE;IACrE,kBAAkB,EAAE,MAAM,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACzE,eAAe,EAAE,CACf,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,cAAc,KACrB,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,IAAI,IAAI,CAAC;CACd;AAOD,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,oBAAoB,GAAG,sBAAsB,CA+ExF"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Saved-location lightning pre-warm: subscribe saved locations at startup and keep them
|
|
3
|
+
* subscribed for as long as they stay saved.
|
|
4
|
+
*
|
|
5
|
+
* The Blitzortung feed only buffers strikes for an area while it is subscribed, and the
|
|
6
|
+
* service prunes any subscription idle for longer than `SUBSCRIPTION_IDLE_THRESHOLD_MS`.
|
|
7
|
+
* A single startup pre-warm therefore lapsed after about an hour. This module re-warms
|
|
8
|
+
* every saved location on an interval derived from that threshold, so a saved location's
|
|
9
|
+
* access stamp never ages past it. A location removed from the store is simply not
|
|
10
|
+
* re-warmed, and the ordinary prune drops it.
|
|
11
|
+
*
|
|
12
|
+
* - The timer starts whenever the gate passes, even with an empty or unreadable store, so
|
|
13
|
+
* a location saved (or a file repaired) later is picked up on the next tick. An empty
|
|
14
|
+
* store opens no connection: nothing connects until the first `prewarmLocation` call.
|
|
15
|
+
* - The store read is guarded, and only the read: an unreadable file must not stop the
|
|
16
|
+
* server booting, and a fault anywhere else must not be hidden behind the same catch.
|
|
17
|
+
* On an unreadable tick nothing is re-warmed, so subscriptions age out rather than being
|
|
18
|
+
* extended from data that could not be read.
|
|
19
|
+
* - Pre-warm never evicts. The service skips a saved location that does not fit instead of
|
|
20
|
+
* displacing another subscription; this module reports the skipped count when it changes.
|
|
21
|
+
*/
|
|
22
|
+
import { PREWARM_REFRESH_INTERVAL_MS } from '../services/blitzortung.js';
|
|
23
|
+
import { logger } from '../utils/logger.js';
|
|
24
|
+
const defaultScheduler = {
|
|
25
|
+
setInterval: (fn, ms) => setInterval(fn, ms),
|
|
26
|
+
clearInterval: (handle) => clearInterval(handle)
|
|
27
|
+
};
|
|
28
|
+
export function startLightningPrewarm(deps) {
|
|
29
|
+
if (deps.optOutValue === 'false' || !deps.toolEnabled) {
|
|
30
|
+
return { stop: () => { } };
|
|
31
|
+
}
|
|
32
|
+
const scheduler = deps.scheduler ?? defaultScheduler;
|
|
33
|
+
const intervalMs = deps.intervalMs ?? PREWARM_REFRESH_INTERVAL_MS;
|
|
34
|
+
let unreadable = false;
|
|
35
|
+
let lastSkipped = 0;
|
|
36
|
+
// Not `async`: a synchronous throw from `prewarmLocation` must leave this function as a
|
|
37
|
+
// throw, not be converted into a rejected promise nobody reads.
|
|
38
|
+
const runOnce = (startup) => {
|
|
39
|
+
let savedLocations;
|
|
40
|
+
try {
|
|
41
|
+
savedLocations = deps.readSavedLocations();
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
if (!unreadable) {
|
|
45
|
+
logger.warn('Skipping lightning pre-warm: saved locations could not be read', {
|
|
46
|
+
error: error instanceof Error ? error.message : String(error)
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
unreadable = true;
|
|
50
|
+
return Promise.resolve();
|
|
51
|
+
}
|
|
52
|
+
unreadable = false;
|
|
53
|
+
if (startup && savedLocations.length > 0) {
|
|
54
|
+
logger.info('Pre-warming lightning monitoring for saved locations', {
|
|
55
|
+
count: savedLocations.length
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
else if (!startup) {
|
|
59
|
+
logger.debug('Refreshing lightning pre-warm for saved locations', {
|
|
60
|
+
count: savedLocations.length
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
// No await between the read and this loop, and every call is started before any is
|
|
64
|
+
// awaited: the service's single-flight import and `isConnecting` guard are built for
|
|
65
|
+
// concurrent entry. Each call gets its own outcome object.
|
|
66
|
+
const outcomes = [];
|
|
67
|
+
const pending = [];
|
|
68
|
+
for (const location of savedLocations) {
|
|
69
|
+
const outcome = {};
|
|
70
|
+
outcomes.push(outcome);
|
|
71
|
+
pending.push(deps.prewarmLocation(location.latitude, location.longitude, undefined, outcome));
|
|
72
|
+
}
|
|
73
|
+
return Promise.all(pending).then(() => {
|
|
74
|
+
const skipped = outcomes.filter((o) => o.status === 'skipped-capacity').length;
|
|
75
|
+
if (skipped !== lastSkipped) {
|
|
76
|
+
if (skipped > 0) {
|
|
77
|
+
logger.warn('Lightning pre-warm skipped saved locations: subscription limit reached', {
|
|
78
|
+
skipped,
|
|
79
|
+
total: outcomes.length
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
logger.debug('Lightning pre-warm no longer skipping saved locations');
|
|
84
|
+
}
|
|
85
|
+
lastSkipped = skipped;
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
};
|
|
89
|
+
void runOnce(true);
|
|
90
|
+
const handle = scheduler.setInterval(() => {
|
|
91
|
+
void runOnce(false);
|
|
92
|
+
}, intervalMs);
|
|
93
|
+
let stopped = false;
|
|
94
|
+
return {
|
|
95
|
+
stop: () => {
|
|
96
|
+
if (stopped) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
stopped = true;
|
|
100
|
+
scheduler.clearInterval(handle);
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=lightningPrewarm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lightningPrewarm.js","sourceRoot":"","sources":["../../src/server/lightningPrewarm.ts"],"names":[],"mappings":"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"}
|