@dangahagan/weather-mcp 0.2.0 → 1.0.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 +372 -53
- package/dist/config/cache.d.ts +2 -0
- package/dist/config/cache.d.ts.map +1 -1
- package/dist/config/cache.js +48 -2
- package/dist/config/cache.js.map +1 -1
- package/dist/config/displayThresholds.d.ts +83 -0
- package/dist/config/displayThresholds.d.ts.map +1 -0
- package/dist/config/displayThresholds.js +83 -0
- package/dist/config/displayThresholds.js.map +1 -0
- package/dist/errors/ApiError.d.ts +62 -0
- package/dist/errors/ApiError.d.ts.map +1 -0
- package/dist/errors/ApiError.js +147 -0
- package/dist/errors/ApiError.js.map +1 -0
- package/dist/handlers/airQualityHandler.d.ts +11 -0
- package/dist/handlers/airQualityHandler.d.ts.map +1 -0
- package/dist/handlers/airQualityHandler.js +154 -0
- package/dist/handlers/airQualityHandler.js.map +1 -0
- package/dist/handlers/alertsHandler.d.ts +11 -0
- package/dist/handlers/alertsHandler.d.ts.map +1 -0
- package/dist/handlers/alertsHandler.js +82 -0
- package/dist/handlers/alertsHandler.js.map +1 -0
- package/dist/handlers/currentConditionsHandler.d.ts +11 -0
- package/dist/handlers/currentConditionsHandler.d.ts.map +1 -0
- package/dist/handlers/currentConditionsHandler.js +231 -0
- package/dist/handlers/currentConditionsHandler.js.map +1 -0
- package/dist/handlers/forecastHandler.d.ts +13 -0
- package/dist/handlers/forecastHandler.d.ts.map +1 -0
- package/dist/handlers/forecastHandler.js +337 -0
- package/dist/handlers/forecastHandler.js.map +1 -0
- package/dist/handlers/historicalWeatherHandler.d.ts +12 -0
- package/dist/handlers/historicalWeatherHandler.d.ts.map +1 -0
- package/dist/handlers/historicalWeatherHandler.js +188 -0
- package/dist/handlers/historicalWeatherHandler.js.map +1 -0
- package/dist/handlers/locationHandler.d.ts +11 -0
- package/dist/handlers/locationHandler.d.ts.map +1 -0
- package/dist/handlers/locationHandler.js +113 -0
- package/dist/handlers/locationHandler.js.map +1 -0
- package/dist/handlers/marineConditionsHandler.d.ts +11 -0
- package/dist/handlers/marineConditionsHandler.d.ts.map +1 -0
- package/dist/handlers/marineConditionsHandler.js +154 -0
- package/dist/handlers/marineConditionsHandler.js.map +1 -0
- package/dist/handlers/statusHandler.d.ts +12 -0
- package/dist/handlers/statusHandler.d.ts.map +1 -0
- package/dist/handlers/statusHandler.js +106 -0
- package/dist/handlers/statusHandler.js.map +1 -0
- package/dist/index.js +219 -377
- package/dist/index.js.map +1 -1
- package/dist/services/noaa.d.ts +24 -1
- package/dist/services/noaa.d.ts.map +1 -1
- package/dist/services/noaa.js +116 -43
- package/dist/services/noaa.js.map +1 -1
- package/dist/services/openmeteo.d.ts +110 -3
- package/dist/services/openmeteo.d.ts.map +1 -1
- package/dist/services/openmeteo.js +568 -112
- package/dist/services/openmeteo.js.map +1 -1
- package/dist/types/noaa.d.ts +158 -12
- package/dist/types/noaa.d.ts.map +1 -1
- package/dist/types/openmeteo.d.ts +448 -0
- package/dist/types/openmeteo.d.ts.map +1 -1
- package/dist/utils/airQuality.d.ts +54 -0
- package/dist/utils/airQuality.d.ts.map +1 -0
- package/dist/utils/airQuality.js +251 -0
- package/dist/utils/airQuality.js.map +1 -0
- package/dist/utils/cache.d.ts +11 -4
- package/dist/utils/cache.d.ts.map +1 -1
- package/dist/utils/cache.js +33 -4
- package/dist/utils/cache.js.map +1 -1
- package/dist/utils/fireWeather.d.ts +62 -0
- package/dist/utils/fireWeather.d.ts.map +1 -0
- package/dist/utils/fireWeather.js +168 -0
- package/dist/utils/fireWeather.js.map +1 -0
- package/dist/utils/logger.d.ts +59 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +128 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/marine.d.ts +38 -0
- package/dist/utils/marine.d.ts.map +1 -0
- package/dist/utils/marine.js +162 -0
- package/dist/utils/marine.js.map +1 -0
- package/dist/utils/temperatureConversion.d.ts +12 -0
- package/dist/utils/temperatureConversion.d.ts.map +1 -0
- package/dist/utils/temperatureConversion.js +17 -0
- package/dist/utils/temperatureConversion.js.map +1 -0
- package/dist/utils/validation.d.ts +89 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +177 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +10 -3
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Display thresholds and constants for weather data formatting
|
|
3
|
+
*
|
|
4
|
+
* These values determine when certain weather metrics are shown or highlighted
|
|
5
|
+
*/
|
|
6
|
+
export declare const DisplayThresholds: {
|
|
7
|
+
/**
|
|
8
|
+
* Temperature thresholds (in Fahrenheit)
|
|
9
|
+
*/
|
|
10
|
+
readonly temperature: {
|
|
11
|
+
/** Show heat index when temperature is above this value */
|
|
12
|
+
readonly showHeatIndex: 80;
|
|
13
|
+
/** Show wind chill when temperature is below this value */
|
|
14
|
+
readonly showWindChill: 50;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Wind thresholds
|
|
18
|
+
*/
|
|
19
|
+
readonly wind: {
|
|
20
|
+
/** Show gusts if they are this ratio higher than sustained wind speed (1.2 = 20% higher) */
|
|
21
|
+
readonly gustSignificanceRatio: 1.2;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Visibility thresholds (in miles)
|
|
25
|
+
*/
|
|
26
|
+
readonly visibility: {
|
|
27
|
+
/** Dense fog */
|
|
28
|
+
readonly denseFog: 0.25;
|
|
29
|
+
/** Fog */
|
|
30
|
+
readonly fog: 1;
|
|
31
|
+
/** Haze or mist */
|
|
32
|
+
readonly hazeMist: 3;
|
|
33
|
+
/** Clear visibility */
|
|
34
|
+
readonly clear: 10;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Precipitation thresholds
|
|
38
|
+
*/
|
|
39
|
+
readonly precipitation: {
|
|
40
|
+
/** Light precipitation (inches per hour) */
|
|
41
|
+
readonly light: 0.1;
|
|
42
|
+
/** Moderate precipitation (inches per hour) */
|
|
43
|
+
readonly moderate: 0.3;
|
|
44
|
+
/** Heavy precipitation (inches per hour) */
|
|
45
|
+
readonly heavy: 0.5;
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* API-related constants
|
|
50
|
+
*/
|
|
51
|
+
export declare const ApiConstants: {
|
|
52
|
+
/**
|
|
53
|
+
* Historical data threshold (in days)
|
|
54
|
+
* Data older than this uses archival API instead of recent observations
|
|
55
|
+
*/
|
|
56
|
+
readonly historicalDataThresholdDays: 7;
|
|
57
|
+
/**
|
|
58
|
+
* Maximum date range for hourly historical data (in days)
|
|
59
|
+
*/
|
|
60
|
+
readonly maxHourlyHistoricalDays: 31;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Formatting constants
|
|
64
|
+
*/
|
|
65
|
+
export declare const FormatConstants: {
|
|
66
|
+
/**
|
|
67
|
+
* Default forecast periods to show
|
|
68
|
+
*/
|
|
69
|
+
readonly defaultForecastDays: 7;
|
|
70
|
+
/**
|
|
71
|
+
* Maximum forecast days (Open-Meteo supports up to 16 days)
|
|
72
|
+
*/
|
|
73
|
+
readonly maxForecastDays: 16;
|
|
74
|
+
/**
|
|
75
|
+
* Default observation limit for historical data
|
|
76
|
+
*/
|
|
77
|
+
readonly defaultHistoricalLimit: 168;
|
|
78
|
+
/**
|
|
79
|
+
* Maximum observations to return
|
|
80
|
+
*/
|
|
81
|
+
readonly maxHistoricalLimit: 500;
|
|
82
|
+
};
|
|
83
|
+
//# sourceMappingURL=displayThresholds.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"displayThresholds.d.ts","sourceRoot":"","sources":["../../src/config/displayThresholds.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,eAAO,MAAM,iBAAiB;IAC5B;;OAEG;;QAED,2DAA2D;;QAE3D,2DAA2D;;;IAI7D;;OAEG;;QAED,4FAA4F;;;IAI9F;;OAEG;;QAED,gBAAgB;;QAEhB,UAAU;;QAEV,mBAAmB;;QAEnB,uBAAuB;;;IAIzB;;OAEG;;QAED,4CAA4C;;QAE5C,+CAA+C;;QAE/C,4CAA4C;;;CAGtC,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,YAAY;IACvB;;;OAGG;;IAGH;;OAEG;;CAEK,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,eAAe;IAC1B;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;CAEK,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Display thresholds and constants for weather data formatting
|
|
3
|
+
*
|
|
4
|
+
* These values determine when certain weather metrics are shown or highlighted
|
|
5
|
+
*/
|
|
6
|
+
export const DisplayThresholds = {
|
|
7
|
+
/**
|
|
8
|
+
* Temperature thresholds (in Fahrenheit)
|
|
9
|
+
*/
|
|
10
|
+
temperature: {
|
|
11
|
+
/** Show heat index when temperature is above this value */
|
|
12
|
+
showHeatIndex: 80,
|
|
13
|
+
/** Show wind chill when temperature is below this value */
|
|
14
|
+
showWindChill: 50,
|
|
15
|
+
},
|
|
16
|
+
/**
|
|
17
|
+
* Wind thresholds
|
|
18
|
+
*/
|
|
19
|
+
wind: {
|
|
20
|
+
/** Show gusts if they are this ratio higher than sustained wind speed (1.2 = 20% higher) */
|
|
21
|
+
gustSignificanceRatio: 1.2,
|
|
22
|
+
},
|
|
23
|
+
/**
|
|
24
|
+
* Visibility thresholds (in miles)
|
|
25
|
+
*/
|
|
26
|
+
visibility: {
|
|
27
|
+
/** Dense fog */
|
|
28
|
+
denseFog: 0.25,
|
|
29
|
+
/** Fog */
|
|
30
|
+
fog: 1.0,
|
|
31
|
+
/** Haze or mist */
|
|
32
|
+
hazeMist: 3.0,
|
|
33
|
+
/** Clear visibility */
|
|
34
|
+
clear: 10.0,
|
|
35
|
+
},
|
|
36
|
+
/**
|
|
37
|
+
* Precipitation thresholds
|
|
38
|
+
*/
|
|
39
|
+
precipitation: {
|
|
40
|
+
/** Light precipitation (inches per hour) */
|
|
41
|
+
light: 0.1,
|
|
42
|
+
/** Moderate precipitation (inches per hour) */
|
|
43
|
+
moderate: 0.3,
|
|
44
|
+
/** Heavy precipitation (inches per hour) */
|
|
45
|
+
heavy: 0.5,
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* API-related constants
|
|
50
|
+
*/
|
|
51
|
+
export const ApiConstants = {
|
|
52
|
+
/**
|
|
53
|
+
* Historical data threshold (in days)
|
|
54
|
+
* Data older than this uses archival API instead of recent observations
|
|
55
|
+
*/
|
|
56
|
+
historicalDataThresholdDays: 7,
|
|
57
|
+
/**
|
|
58
|
+
* Maximum date range for hourly historical data (in days)
|
|
59
|
+
*/
|
|
60
|
+
maxHourlyHistoricalDays: 31,
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Formatting constants
|
|
64
|
+
*/
|
|
65
|
+
export const FormatConstants = {
|
|
66
|
+
/**
|
|
67
|
+
* Default forecast periods to show
|
|
68
|
+
*/
|
|
69
|
+
defaultForecastDays: 7,
|
|
70
|
+
/**
|
|
71
|
+
* Maximum forecast days (Open-Meteo supports up to 16 days)
|
|
72
|
+
*/
|
|
73
|
+
maxForecastDays: 16,
|
|
74
|
+
/**
|
|
75
|
+
* Default observation limit for historical data
|
|
76
|
+
*/
|
|
77
|
+
defaultHistoricalLimit: 168, // One week of hourly data
|
|
78
|
+
/**
|
|
79
|
+
* Maximum observations to return
|
|
80
|
+
*/
|
|
81
|
+
maxHistoricalLimit: 500,
|
|
82
|
+
};
|
|
83
|
+
//# sourceMappingURL=displayThresholds.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"displayThresholds.js","sourceRoot":"","sources":["../../src/config/displayThresholds.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B;;OAEG;IACH,WAAW,EAAE;QACX,2DAA2D;QAC3D,aAAa,EAAE,EAAE;QACjB,2DAA2D;QAC3D,aAAa,EAAE,EAAE;KAClB;IAED;;OAEG;IACH,IAAI,EAAE;QACJ,4FAA4F;QAC5F,qBAAqB,EAAE,GAAG;KAC3B;IAED;;OAEG;IACH,UAAU,EAAE;QACV,gBAAgB;QAChB,QAAQ,EAAE,IAAI;QACd,UAAU;QACV,GAAG,EAAE,GAAG;QACR,mBAAmB;QACnB,QAAQ,EAAE,GAAG;QACb,uBAAuB;QACvB,KAAK,EAAE,IAAI;KACZ;IAED;;OAEG;IACH,aAAa,EAAE;QACb,4CAA4C;QAC5C,KAAK,EAAE,GAAG;QACV,+CAA+C;QAC/C,QAAQ,EAAE,GAAG;QACb,4CAA4C;QAC5C,KAAK,EAAE,GAAG;KACX;CACO,CAAC;AAEX;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B;;;OAGG;IACH,2BAA2B,EAAE,CAAC;IAE9B;;OAEG;IACH,uBAAuB,EAAE,EAAE;CACnB,CAAC;AAEX;;GAEG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B;;OAEG;IACH,mBAAmB,EAAE,CAAC;IAEtB;;OAEG;IACH,eAAe,EAAE,EAAE;IAEnB;;OAEG;IACH,sBAAsB,EAAE,GAAG,EAAE,0BAA0B;IAEvD;;OAEG;IACH,kBAAkB,EAAE,GAAG;CACf,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom error classes for better error handling and logging
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Base error class for API-related errors
|
|
6
|
+
*/
|
|
7
|
+
export declare class ApiError extends Error {
|
|
8
|
+
readonly statusCode: number;
|
|
9
|
+
readonly service: 'NOAA' | 'OpenMeteo';
|
|
10
|
+
readonly userMessage: string;
|
|
11
|
+
readonly helpLinks: string[];
|
|
12
|
+
readonly isRetryable: boolean;
|
|
13
|
+
constructor(message: string, statusCode: number, service: 'NOAA' | 'OpenMeteo', userMessage: string, helpLinks?: string[], isRetryable?: boolean);
|
|
14
|
+
/**
|
|
15
|
+
* Format error for display to user
|
|
16
|
+
*/
|
|
17
|
+
toUserMessage(): string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Rate limit error - too many requests
|
|
21
|
+
*/
|
|
22
|
+
export declare class RateLimitError extends ApiError {
|
|
23
|
+
readonly retryAfter?: number;
|
|
24
|
+
constructor(service: 'NOAA' | 'OpenMeteo', retryAfter?: number);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Service unavailable error - API is down or timing out
|
|
28
|
+
*/
|
|
29
|
+
export declare class ServiceUnavailableError extends ApiError {
|
|
30
|
+
constructor(service: 'NOAA' | 'OpenMeteo', originalError?: Error);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Invalid location error - coordinates not supported or out of range
|
|
34
|
+
*/
|
|
35
|
+
export declare class InvalidLocationError extends ApiError {
|
|
36
|
+
readonly latitude?: number;
|
|
37
|
+
readonly longitude?: number;
|
|
38
|
+
constructor(service: 'NOAA' | 'OpenMeteo', message: string, latitude?: number, longitude?: number);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Data not found error - requested data doesn't exist
|
|
42
|
+
*/
|
|
43
|
+
export declare class DataNotFoundError extends ApiError {
|
|
44
|
+
constructor(service: 'NOAA' | 'OpenMeteo', message: string);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Validation error - invalid input parameters
|
|
48
|
+
*/
|
|
49
|
+
export declare class ValidationError extends Error {
|
|
50
|
+
readonly field?: string;
|
|
51
|
+
readonly value?: any;
|
|
52
|
+
constructor(message: string, field?: string, value?: any);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Check if an error is retryable
|
|
56
|
+
*/
|
|
57
|
+
export declare function isRetryableError(error: Error): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Format error for user display
|
|
60
|
+
*/
|
|
61
|
+
export declare function formatErrorForUser(error: Error): string;
|
|
62
|
+
//# sourceMappingURL=ApiError.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ApiError.d.ts","sourceRoot":"","sources":["../../src/errors/ApiError.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,qBAAa,QAAS,SAAQ,KAAK;IACjC,SAAgB,UAAU,EAAE,MAAM,CAAC;IACnC,SAAgB,OAAO,EAAE,MAAM,GAAG,WAAW,CAAC;IAC9C,SAAgB,WAAW,EAAE,MAAM,CAAC;IACpC,SAAgB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpC,SAAgB,WAAW,EAAE,OAAO,CAAC;gBAGnC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,GAAG,WAAW,EAC7B,WAAW,EAAE,MAAM,EACnB,SAAS,GAAE,MAAM,EAAO,EACxB,WAAW,GAAE,OAAe;IAgB9B;;OAEG;IACH,aAAa,IAAI,MAAM;CAYxB;AAED;;GAEG;AACH,qBAAa,cAAe,SAAQ,QAAQ;IAC1C,SAAgB,UAAU,CAAC,EAAE,MAAM,CAAC;gBAExB,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE,UAAU,CAAC,EAAE,MAAM;CAoB/D;AAED;;GAEG;AACH,qBAAa,uBAAwB,SAAQ,QAAQ;gBACvC,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE,aAAa,CAAC,EAAE,KAAK;CAoBjE;AAED;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,QAAQ;IAChD,SAAgB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClC,SAAgB,SAAS,CAAC,EAAE,MAAM,CAAC;gBAGjC,OAAO,EAAE,MAAM,GAAG,WAAW,EAC7B,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,MAAM;CAerB;AAED;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,QAAQ;gBACjC,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE,OAAO,EAAE,MAAM;CAY3D;AAED;;GAEG;AACH,qBAAa,eAAgB,SAAQ,KAAK;IACxC,SAAgB,KAAK,CAAC,EAAE,MAAM,CAAC;IAC/B,SAAgB,KAAK,CAAC,EAAE,GAAG,CAAC;gBAEhB,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,GAAG;CAUzD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAetD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAgBvD"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom error classes for better error handling and logging
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Base error class for API-related errors
|
|
6
|
+
*/
|
|
7
|
+
export class ApiError extends Error {
|
|
8
|
+
statusCode;
|
|
9
|
+
service;
|
|
10
|
+
userMessage;
|
|
11
|
+
helpLinks;
|
|
12
|
+
isRetryable;
|
|
13
|
+
constructor(message, statusCode, service, userMessage, helpLinks = [], isRetryable = false) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = 'ApiError';
|
|
16
|
+
this.statusCode = statusCode;
|
|
17
|
+
this.service = service;
|
|
18
|
+
this.userMessage = userMessage;
|
|
19
|
+
this.helpLinks = helpLinks;
|
|
20
|
+
this.isRetryable = isRetryable;
|
|
21
|
+
// Maintains proper stack trace for where our error was thrown (only available on V8)
|
|
22
|
+
if (Error.captureStackTrace) {
|
|
23
|
+
Error.captureStackTrace(this, this.constructor);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Format error for display to user
|
|
28
|
+
*/
|
|
29
|
+
toUserMessage() {
|
|
30
|
+
let message = `${this.service} API Error: ${this.userMessage}`;
|
|
31
|
+
if (this.helpLinks.length > 0) {
|
|
32
|
+
message += '\n\nFor more information:\n';
|
|
33
|
+
this.helpLinks.forEach(link => {
|
|
34
|
+
message += `- ${link}\n`;
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
return message;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Rate limit error - too many requests
|
|
42
|
+
*/
|
|
43
|
+
export class RateLimitError extends ApiError {
|
|
44
|
+
retryAfter;
|
|
45
|
+
constructor(service, retryAfter) {
|
|
46
|
+
const userMessage = retryAfter
|
|
47
|
+
? `Rate limit exceeded. Please retry after ${retryAfter} seconds.`
|
|
48
|
+
: 'Rate limit exceeded. Please retry in a few seconds.';
|
|
49
|
+
super(`Rate limit exceeded for ${service}`, 429, service, userMessage, [
|
|
50
|
+
'https://weather.gov/documentation/services-web-api',
|
|
51
|
+
'https://open-meteo.com/en/features#api-documentation',
|
|
52
|
+
], true // Retryable after waiting
|
|
53
|
+
);
|
|
54
|
+
this.name = 'RateLimitError';
|
|
55
|
+
this.retryAfter = retryAfter;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Service unavailable error - API is down or timing out
|
|
60
|
+
*/
|
|
61
|
+
export class ServiceUnavailableError extends ApiError {
|
|
62
|
+
constructor(service, originalError) {
|
|
63
|
+
super(`${service} API is currently unavailable`, 503, service, `The ${service} weather service is temporarily unavailable. Please try again in a few minutes.`, [
|
|
64
|
+
service === 'NOAA'
|
|
65
|
+
? 'https://www.weather.gov/'
|
|
66
|
+
: 'https://open-meteo.com/',
|
|
67
|
+
], true // Retryable
|
|
68
|
+
);
|
|
69
|
+
this.name = 'ServiceUnavailableError';
|
|
70
|
+
if (originalError && originalError.stack) {
|
|
71
|
+
this.stack = `${this.stack}\nCaused by: ${originalError.stack}`;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Invalid location error - coordinates not supported or out of range
|
|
77
|
+
*/
|
|
78
|
+
export class InvalidLocationError extends ApiError {
|
|
79
|
+
latitude;
|
|
80
|
+
longitude;
|
|
81
|
+
constructor(service, message, latitude, longitude) {
|
|
82
|
+
super(message, 400, service, message, [], false // Not retryable
|
|
83
|
+
);
|
|
84
|
+
this.name = 'InvalidLocationError';
|
|
85
|
+
this.latitude = latitude;
|
|
86
|
+
this.longitude = longitude;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Data not found error - requested data doesn't exist
|
|
91
|
+
*/
|
|
92
|
+
export class DataNotFoundError extends ApiError {
|
|
93
|
+
constructor(service, message) {
|
|
94
|
+
super(message, 404, service, message, [], false // Not retryable
|
|
95
|
+
);
|
|
96
|
+
this.name = 'DataNotFoundError';
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Validation error - invalid input parameters
|
|
101
|
+
*/
|
|
102
|
+
export class ValidationError extends Error {
|
|
103
|
+
field;
|
|
104
|
+
value;
|
|
105
|
+
constructor(message, field, value) {
|
|
106
|
+
super(message);
|
|
107
|
+
this.name = 'ValidationError';
|
|
108
|
+
this.field = field;
|
|
109
|
+
this.value = value;
|
|
110
|
+
if (Error.captureStackTrace) {
|
|
111
|
+
Error.captureStackTrace(this, this.constructor);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Check if an error is retryable
|
|
117
|
+
*/
|
|
118
|
+
export function isRetryableError(error) {
|
|
119
|
+
if (error instanceof ApiError) {
|
|
120
|
+
return error.isRetryable;
|
|
121
|
+
}
|
|
122
|
+
// Network errors are generally retryable
|
|
123
|
+
if (error.message.includes('ECONNREFUSED') ||
|
|
124
|
+
error.message.includes('ETIMEDOUT') ||
|
|
125
|
+
error.message.includes('ENOTFOUND')) {
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Format error for user display
|
|
132
|
+
*/
|
|
133
|
+
export function formatErrorForUser(error) {
|
|
134
|
+
if (error instanceof ApiError) {
|
|
135
|
+
return error.toUserMessage();
|
|
136
|
+
}
|
|
137
|
+
if (error instanceof ValidationError) {
|
|
138
|
+
return `Validation Error: ${error.message}`;
|
|
139
|
+
}
|
|
140
|
+
// Sanitize generic errors to avoid leaking sensitive information
|
|
141
|
+
const sanitizedMessage = error.message
|
|
142
|
+
.replace(/ECONNREFUSED/, 'Connection refused')
|
|
143
|
+
.replace(/ETIMEDOUT/, 'Connection timed out')
|
|
144
|
+
.replace(/ENOTFOUND/, 'Service not found');
|
|
145
|
+
return `Error: ${sanitizedMessage}`;
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=ApiError.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ApiError.js","sourceRoot":"","sources":["../../src/errors/ApiError.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Handler for get_air_quality tool
|
|
3
|
+
*/
|
|
4
|
+
import { OpenMeteoService } from '../services/openmeteo.js';
|
|
5
|
+
export declare function handleGetAirQuality(args: unknown, openMeteoService: OpenMeteoService): Promise<{
|
|
6
|
+
content: Array<{
|
|
7
|
+
type: string;
|
|
8
|
+
text: string;
|
|
9
|
+
}>;
|
|
10
|
+
}>;
|
|
11
|
+
//# sourceMappingURL=airQualityHandler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"airQualityHandler.d.ts","sourceRoot":"","sources":["../../src/handlers/airQualityHandler.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAkB5D,wBAAsB,mBAAmB,CACvC,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,CA4B7D"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Handler for get_air_quality tool
|
|
3
|
+
*/
|
|
4
|
+
import { validateCoordinates, validateOptionalBoolean } from '../utils/validation.js';
|
|
5
|
+
import { getUSAQICategory, getEuropeanAQICategory, getUVIndexCategory, getPollutantInfo, formatPollutantConcentration, shouldUseUSAQI } from '../utils/airQuality.js';
|
|
6
|
+
export async function handleGetAirQuality(args, openMeteoService) {
|
|
7
|
+
// Validate input parameters with runtime checks
|
|
8
|
+
const { latitude, longitude } = validateCoordinates(args);
|
|
9
|
+
const forecast = validateOptionalBoolean(args?.forecast, 'forecast', false);
|
|
10
|
+
// Get air quality data
|
|
11
|
+
const airQualityData = await openMeteoService.getAirQuality(latitude, longitude, forecast, 5 // Default 5-day forecast
|
|
12
|
+
);
|
|
13
|
+
// Format the air quality data for display
|
|
14
|
+
const output = formatAirQuality(airQualityData, latitude, longitude, forecast);
|
|
15
|
+
return {
|
|
16
|
+
content: [
|
|
17
|
+
{
|
|
18
|
+
type: 'text',
|
|
19
|
+
text: output
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Format air quality data as markdown
|
|
26
|
+
*/
|
|
27
|
+
function formatAirQuality(data, latitude, longitude, includeForecast) {
|
|
28
|
+
let output = `# Air Quality Report\n\n`;
|
|
29
|
+
output += `**Location:** ${latitude.toFixed(4)}, ${longitude.toFixed(4)}\n`;
|
|
30
|
+
output += `**Timezone:** ${data.timezone}\n`;
|
|
31
|
+
output += `**Elevation:** ${Math.round(data.elevation)}m\n`;
|
|
32
|
+
output += `\n`;
|
|
33
|
+
// Determine which AQI to show primarily based on location
|
|
34
|
+
const useUSAQI = shouldUseUSAQI(latitude, longitude);
|
|
35
|
+
if (!data.current) {
|
|
36
|
+
output += `⚠️ **No current air quality data available for this location.**\n`;
|
|
37
|
+
return output;
|
|
38
|
+
}
|
|
39
|
+
const current = data.current;
|
|
40
|
+
const currentTime = new Date(current.time);
|
|
41
|
+
output += `**Observation Time:** ${currentTime.toLocaleString()}\n\n`;
|
|
42
|
+
// Display primary AQI with health information
|
|
43
|
+
if (useUSAQI && current.us_aqi !== undefined) {
|
|
44
|
+
const category = getUSAQICategory(current.us_aqi);
|
|
45
|
+
const emoji = category.level === 'Good' ? '🟢' :
|
|
46
|
+
category.level === 'Moderate' ? '🟡' :
|
|
47
|
+
category.level === 'Unhealthy for Sensitive Groups' ? '🟠' :
|
|
48
|
+
category.level === 'Unhealthy' ? '🔴' :
|
|
49
|
+
category.level === 'Very Unhealthy' ? '🟣' : '🟤';
|
|
50
|
+
output += `## ${emoji} US Air Quality Index: ${Math.round(current.us_aqi)}\n\n`;
|
|
51
|
+
output += `**Category:** ${category.level} (${category.color})\n`;
|
|
52
|
+
output += `**Description:** ${category.description}\n\n`;
|
|
53
|
+
output += `**Health Implications:**\n${category.healthImplications}\n\n`;
|
|
54
|
+
if (category.cautionaryStatement !== 'None') {
|
|
55
|
+
output += `⚠️ **Caution:** ${category.cautionaryStatement}\n\n`;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
else if (current.european_aqi !== undefined) {
|
|
59
|
+
const category = getEuropeanAQICategory(current.european_aqi);
|
|
60
|
+
const emoji = category.level === 'Good' ? '🟢' :
|
|
61
|
+
category.level === 'Fair' ? '🟢' :
|
|
62
|
+
category.level === 'Moderate' ? '🟡' :
|
|
63
|
+
category.level === 'Poor' ? '🟠' :
|
|
64
|
+
category.level === 'Very Poor' ? '🔴' : '🟣';
|
|
65
|
+
output += `## ${emoji} European Air Quality Index: ${Math.round(current.european_aqi)}\n\n`;
|
|
66
|
+
output += `**Category:** ${category.level} (${category.color})\n`;
|
|
67
|
+
output += `**Description:** ${category.description}\n\n`;
|
|
68
|
+
output += `**Health Implications:**\n${category.healthImplications}\n\n`;
|
|
69
|
+
if (category.cautionaryStatement !== 'None') {
|
|
70
|
+
output += `⚠️ **Caution:** ${category.cautionaryStatement}\n\n`;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// UV Index
|
|
74
|
+
if (current.uv_index !== undefined) {
|
|
75
|
+
const uvCategory = getUVIndexCategory(current.uv_index);
|
|
76
|
+
const uvEmoji = uvCategory.level === 'Low' ? '🟢' :
|
|
77
|
+
uvCategory.level === 'Moderate' ? '🟡' :
|
|
78
|
+
uvCategory.level === 'High' ? '🟠' :
|
|
79
|
+
uvCategory.level === 'Very High' ? '🔴' : '🟣';
|
|
80
|
+
output += `## ${uvEmoji} UV Index: ${current.uv_index.toFixed(1)}\n\n`;
|
|
81
|
+
output += `**Level:** ${uvCategory.level}\n`;
|
|
82
|
+
output += `**Description:** ${uvCategory.description}\n`;
|
|
83
|
+
output += `**Recommendation:** ${uvCategory.recommendation}\n\n`;
|
|
84
|
+
if (current.uv_index_clear_sky !== undefined && Math.abs(current.uv_index_clear_sky - current.uv_index) > 1) {
|
|
85
|
+
output += `*Note: UV index under clear sky would be ${current.uv_index_clear_sky.toFixed(1)}*\n\n`;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// Pollutant Concentrations
|
|
89
|
+
output += `## Pollutant Concentrations\n\n`;
|
|
90
|
+
const pollutants = [
|
|
91
|
+
{ key: 'pm2_5', value: current.pm2_5, units: data.current_units?.pm2_5 },
|
|
92
|
+
{ key: 'pm10', value: current.pm10, units: data.current_units?.pm10 },
|
|
93
|
+
{ key: 'ozone', value: current.ozone, units: data.current_units?.ozone },
|
|
94
|
+
{ key: 'nitrogen_dioxide', value: current.nitrogen_dioxide, units: data.current_units?.nitrogen_dioxide },
|
|
95
|
+
{ key: 'sulphur_dioxide', value: current.sulphur_dioxide, units: data.current_units?.sulphur_dioxide },
|
|
96
|
+
{ key: 'carbon_monoxide', value: current.carbon_monoxide, units: data.current_units?.carbon_monoxide }
|
|
97
|
+
];
|
|
98
|
+
for (const pollutant of pollutants) {
|
|
99
|
+
if (pollutant.value !== undefined) {
|
|
100
|
+
const info = getPollutantInfo(pollutant.key);
|
|
101
|
+
const concentration = formatPollutantConcentration(pollutant.value, pollutant.units);
|
|
102
|
+
output += `**${info.name}:** ${concentration}\n`;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (current.ammonia !== undefined && data.current_units?.ammonia) {
|
|
106
|
+
const info = getPollutantInfo('ammonia');
|
|
107
|
+
const concentration = formatPollutantConcentration(current.ammonia, data.current_units.ammonia);
|
|
108
|
+
output += `**${info.name}:** ${concentration}\n`;
|
|
109
|
+
}
|
|
110
|
+
if (current.aerosol_optical_depth !== undefined) {
|
|
111
|
+
output += `**Aerosol Optical Depth:** ${current.aerosol_optical_depth.toFixed(3)} (atmospheric haze indicator)\n`;
|
|
112
|
+
}
|
|
113
|
+
output += `\n`;
|
|
114
|
+
// Show secondary AQI for reference
|
|
115
|
+
if (useUSAQI && current.european_aqi !== undefined) {
|
|
116
|
+
output += `*European AQI: ${Math.round(current.european_aqi)} (${getEuropeanAQICategory(current.european_aqi).level})*\n\n`;
|
|
117
|
+
}
|
|
118
|
+
else if (!useUSAQI && current.us_aqi !== undefined) {
|
|
119
|
+
output += `*US AQI: ${Math.round(current.us_aqi)} (${getUSAQICategory(current.us_aqi).level})*\n\n`;
|
|
120
|
+
}
|
|
121
|
+
// Add forecast summary if requested
|
|
122
|
+
if (includeForecast && data.hourly && data.hourly.time && data.hourly.time.length > 0) {
|
|
123
|
+
output += `---\n\n`;
|
|
124
|
+
output += `## Air Quality Forecast\n\n`;
|
|
125
|
+
// Show next 24 hours
|
|
126
|
+
const hoursToShow = Math.min(24, data.hourly.time.length);
|
|
127
|
+
output += `**Next ${hoursToShow} hours:**\n\n`;
|
|
128
|
+
// Group by 6-hour periods for readability
|
|
129
|
+
const periods = Math.ceil(hoursToShow / 6);
|
|
130
|
+
for (let i = 0; i < periods; i++) {
|
|
131
|
+
const startIdx = i * 6;
|
|
132
|
+
const endIdx = Math.min(startIdx + 6, hoursToShow);
|
|
133
|
+
const startTime = new Date(data.hourly.time[startIdx]);
|
|
134
|
+
const endTime = new Date(data.hourly.time[endIdx - 1]);
|
|
135
|
+
// Get AQI range for this period
|
|
136
|
+
let minAQI = Infinity;
|
|
137
|
+
let maxAQI = -Infinity;
|
|
138
|
+
for (let j = startIdx; j < endIdx; j++) {
|
|
139
|
+
const aqiValue = useUSAQI ? data.hourly.us_aqi?.[j] : data.hourly.european_aqi?.[j];
|
|
140
|
+
if (aqiValue !== undefined) {
|
|
141
|
+
minAQI = Math.min(minAQI, aqiValue);
|
|
142
|
+
maxAQI = Math.max(maxAQI, aqiValue);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
const avgAQI = (minAQI + maxAQI) / 2;
|
|
146
|
+
const aqiCategory = useUSAQI ? getUSAQICategory(avgAQI) : getEuropeanAQICategory(avgAQI);
|
|
147
|
+
output += `**${startTime.toLocaleTimeString()} - ${endTime.toLocaleTimeString()}:** `;
|
|
148
|
+
output += `${useUSAQI ? 'US' : 'EU'} AQI ${Math.round(minAQI)}-${Math.round(maxAQI)} (${aqiCategory.level})\n`;
|
|
149
|
+
}
|
|
150
|
+
output += `\n*Forecast includes ${data.hourly.time.length} hours of data*\n`;
|
|
151
|
+
}
|
|
152
|
+
return output;
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=airQualityHandler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"airQualityHandler.js","sourceRoot":"","sources":["../../src/handlers/airQualityHandler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Handler for get_alerts tool
|
|
3
|
+
*/
|
|
4
|
+
import { NOAAService } from '../services/noaa.js';
|
|
5
|
+
export declare function handleGetAlerts(args: unknown, noaaService: NOAAService): Promise<{
|
|
6
|
+
content: Array<{
|
|
7
|
+
type: string;
|
|
8
|
+
text: string;
|
|
9
|
+
}>;
|
|
10
|
+
}>;
|
|
11
|
+
//# sourceMappingURL=alertsHandler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alertsHandler.d.ts","sourceRoot":"","sources":["../../src/handlers/alertsHandler.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AASlD,wBAAsB,eAAe,CACnC,IAAI,EAAE,OAAO,EACb,WAAW,EAAE,WAAW,GACvB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC,CAmG7D"}
|