@jablum/weather-mcp 1.7.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.
Files changed (235) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1319 -0
  3. package/dist/analytics/anonymizer.d.ts +37 -0
  4. package/dist/analytics/anonymizer.d.ts.map +1 -0
  5. package/dist/analytics/anonymizer.js +112 -0
  6. package/dist/analytics/anonymizer.js.map +1 -0
  7. package/dist/analytics/collector.d.ts +72 -0
  8. package/dist/analytics/collector.d.ts.map +1 -0
  9. package/dist/analytics/collector.js +282 -0
  10. package/dist/analytics/collector.js.map +1 -0
  11. package/dist/analytics/config.d.ts +15 -0
  12. package/dist/analytics/config.d.ts.map +1 -0
  13. package/dist/analytics/config.js +172 -0
  14. package/dist/analytics/config.js.map +1 -0
  15. package/dist/analytics/index.d.ts +8 -0
  16. package/dist/analytics/index.d.ts.map +1 -0
  17. package/dist/analytics/index.js +7 -0
  18. package/dist/analytics/index.js.map +1 -0
  19. package/dist/analytics/middleware.d.ts +33 -0
  20. package/dist/analytics/middleware.d.ts.map +1 -0
  21. package/dist/analytics/middleware.js +99 -0
  22. package/dist/analytics/middleware.js.map +1 -0
  23. package/dist/analytics/transport.d.ts +11 -0
  24. package/dist/analytics/transport.d.ts.map +1 -0
  25. package/dist/analytics/transport.js +92 -0
  26. package/dist/analytics/transport.js.map +1 -0
  27. package/dist/analytics/types.d.ts +74 -0
  28. package/dist/analytics/types.d.ts.map +1 -0
  29. package/dist/analytics/types.js +6 -0
  30. package/dist/analytics/types.js.map +1 -0
  31. package/dist/config/api.d.ts +30 -0
  32. package/dist/config/api.d.ts.map +1 -0
  33. package/dist/config/api.js +32 -0
  34. package/dist/config/api.js.map +1 -0
  35. package/dist/config/cache.d.ts +31 -0
  36. package/dist/config/cache.d.ts.map +1 -0
  37. package/dist/config/cache.js +108 -0
  38. package/dist/config/cache.js.map +1 -0
  39. package/dist/config/displayThresholds.d.ts +83 -0
  40. package/dist/config/displayThresholds.d.ts.map +1 -0
  41. package/dist/config/displayThresholds.js +83 -0
  42. package/dist/config/displayThresholds.js.map +1 -0
  43. package/dist/config/tools.d.ts +44 -0
  44. package/dist/config/tools.d.ts.map +1 -0
  45. package/dist/config/tools.js +269 -0
  46. package/dist/config/tools.js.map +1 -0
  47. package/dist/errors/ApiError.d.ts +62 -0
  48. package/dist/errors/ApiError.d.ts.map +1 -0
  49. package/dist/errors/ApiError.js +171 -0
  50. package/dist/errors/ApiError.js.map +1 -0
  51. package/dist/handlers/airQualityHandler.d.ts +11 -0
  52. package/dist/handlers/airQualityHandler.d.ts.map +1 -0
  53. package/dist/handlers/airQualityHandler.js +154 -0
  54. package/dist/handlers/airQualityHandler.js.map +1 -0
  55. package/dist/handlers/alertsHandler.d.ts +11 -0
  56. package/dist/handlers/alertsHandler.d.ts.map +1 -0
  57. package/dist/handlers/alertsHandler.js +98 -0
  58. package/dist/handlers/alertsHandler.js.map +1 -0
  59. package/dist/handlers/currentConditionsHandler.d.ts +13 -0
  60. package/dist/handlers/currentConditionsHandler.d.ts.map +1 -0
  61. package/dist/handlers/currentConditionsHandler.js +296 -0
  62. package/dist/handlers/currentConditionsHandler.js.map +1 -0
  63. package/dist/handlers/forecastHandler.d.ts +16 -0
  64. package/dist/handlers/forecastHandler.d.ts.map +1 -0
  65. package/dist/handlers/forecastHandler.js +454 -0
  66. package/dist/handlers/forecastHandler.js.map +1 -0
  67. package/dist/handlers/historicalWeatherHandler.d.ts +12 -0
  68. package/dist/handlers/historicalWeatherHandler.d.ts.map +1 -0
  69. package/dist/handlers/historicalWeatherHandler.js +188 -0
  70. package/dist/handlers/historicalWeatherHandler.js.map +1 -0
  71. package/dist/handlers/lightningHandler.d.ts +14 -0
  72. package/dist/handlers/lightningHandler.d.ts.map +1 -0
  73. package/dist/handlers/lightningHandler.js +258 -0
  74. package/dist/handlers/lightningHandler.js.map +1 -0
  75. package/dist/handlers/locationHandler.d.ts +12 -0
  76. package/dist/handlers/locationHandler.d.ts.map +1 -0
  77. package/dist/handlers/locationHandler.js +149 -0
  78. package/dist/handlers/locationHandler.js.map +1 -0
  79. package/dist/handlers/marineConditionsHandler.d.ts +13 -0
  80. package/dist/handlers/marineConditionsHandler.d.ts.map +1 -0
  81. package/dist/handlers/marineConditionsHandler.js +270 -0
  82. package/dist/handlers/marineConditionsHandler.js.map +1 -0
  83. package/dist/handlers/riverConditionsHandler.d.ts +11 -0
  84. package/dist/handlers/riverConditionsHandler.d.ts.map +1 -0
  85. package/dist/handlers/riverConditionsHandler.js +176 -0
  86. package/dist/handlers/riverConditionsHandler.js.map +1 -0
  87. package/dist/handlers/savedLocationsHandler.d.ts +50 -0
  88. package/dist/handlers/savedLocationsHandler.d.ts.map +1 -0
  89. package/dist/handlers/savedLocationsHandler.js +397 -0
  90. package/dist/handlers/savedLocationsHandler.js.map +1 -0
  91. package/dist/handlers/statusHandler.d.ts +12 -0
  92. package/dist/handlers/statusHandler.d.ts.map +1 -0
  93. package/dist/handlers/statusHandler.js +115 -0
  94. package/dist/handlers/statusHandler.js.map +1 -0
  95. package/dist/handlers/weatherImageryHandler.d.ts +14 -0
  96. package/dist/handlers/weatherImageryHandler.d.ts.map +1 -0
  97. package/dist/handlers/weatherImageryHandler.js +143 -0
  98. package/dist/handlers/weatherImageryHandler.js.map +1 -0
  99. package/dist/handlers/wildfireHandler.d.ts +11 -0
  100. package/dist/handlers/wildfireHandler.d.ts.map +1 -0
  101. package/dist/handlers/wildfireHandler.js +186 -0
  102. package/dist/handlers/wildfireHandler.js.map +1 -0
  103. package/dist/index.d.ts +7 -0
  104. package/dist/index.d.ts.map +1 -0
  105. package/dist/index.js +735 -0
  106. package/dist/index.js.map +1 -0
  107. package/dist/services/blitzortung.d.ts +67 -0
  108. package/dist/services/blitzortung.d.ts.map +1 -0
  109. package/dist/services/blitzortung.js +475 -0
  110. package/dist/services/blitzortung.js.map +1 -0
  111. package/dist/services/geocoding.d.ts +57 -0
  112. package/dist/services/geocoding.d.ts.map +1 -0
  113. package/dist/services/geocoding.js +393 -0
  114. package/dist/services/geocoding.js.map +1 -0
  115. package/dist/services/locationStore.d.ts +62 -0
  116. package/dist/services/locationStore.d.ts.map +1 -0
  117. package/dist/services/locationStore.js +201 -0
  118. package/dist/services/locationStore.js.map +1 -0
  119. package/dist/services/ncei.d.ts +61 -0
  120. package/dist/services/ncei.d.ts.map +1 -0
  121. package/dist/services/ncei.js +126 -0
  122. package/dist/services/ncei.js.map +1 -0
  123. package/dist/services/nifc.d.ts +44 -0
  124. package/dist/services/nifc.d.ts.map +1 -0
  125. package/dist/services/nifc.js +159 -0
  126. package/dist/services/nifc.js.map +1 -0
  127. package/dist/services/noaa.d.ts +161 -0
  128. package/dist/services/noaa.d.ts.map +1 -0
  129. package/dist/services/noaa.js +681 -0
  130. package/dist/services/noaa.js.map +1 -0
  131. package/dist/services/nominatim.d.ts +62 -0
  132. package/dist/services/nominatim.d.ts.map +1 -0
  133. package/dist/services/nominatim.js +254 -0
  134. package/dist/services/nominatim.js.map +1 -0
  135. package/dist/services/openmeteo.d.ts +189 -0
  136. package/dist/services/openmeteo.d.ts.map +1 -0
  137. package/dist/services/openmeteo.js +936 -0
  138. package/dist/services/openmeteo.js.map +1 -0
  139. package/dist/services/rainviewer.d.ts +37 -0
  140. package/dist/services/rainviewer.d.ts.map +1 -0
  141. package/dist/services/rainviewer.js +115 -0
  142. package/dist/services/rainviewer.js.map +1 -0
  143. package/dist/types/imagery.d.ts +82 -0
  144. package/dist/types/imagery.d.ts.map +1 -0
  145. package/dist/types/imagery.js +6 -0
  146. package/dist/types/imagery.js.map +1 -0
  147. package/dist/types/lightning.d.ts +89 -0
  148. package/dist/types/lightning.d.ts.map +1 -0
  149. package/dist/types/lightning.js +6 -0
  150. package/dist/types/lightning.js.map +1 -0
  151. package/dist/types/noaa.d.ts +535 -0
  152. package/dist/types/noaa.d.ts.map +1 -0
  153. package/dist/types/noaa.js +5 -0
  154. package/dist/types/noaa.js.map +1 -0
  155. package/dist/types/nominatim.d.ts +72 -0
  156. package/dist/types/nominatim.d.ts.map +1 -0
  157. package/dist/types/nominatim.js +6 -0
  158. package/dist/types/nominatim.js.map +1 -0
  159. package/dist/types/openmeteo.d.ts +583 -0
  160. package/dist/types/openmeteo.d.ts.map +1 -0
  161. package/dist/types/openmeteo.js +6 -0
  162. package/dist/types/openmeteo.js.map +1 -0
  163. package/dist/types/savedLocations.d.ts +58 -0
  164. package/dist/types/savedLocations.d.ts.map +1 -0
  165. package/dist/types/savedLocations.js +5 -0
  166. package/dist/types/savedLocations.js.map +1 -0
  167. package/dist/types/wildfire.d.ts +83 -0
  168. package/dist/types/wildfire.d.ts.map +1 -0
  169. package/dist/types/wildfire.js +5 -0
  170. package/dist/types/wildfire.js.map +1 -0
  171. package/dist/utils/airQuality.d.ts +54 -0
  172. package/dist/utils/airQuality.d.ts.map +1 -0
  173. package/dist/utils/airQuality.js +251 -0
  174. package/dist/utils/airQuality.js.map +1 -0
  175. package/dist/utils/cache.d.ts +69 -0
  176. package/dist/utils/cache.d.ts.map +1 -0
  177. package/dist/utils/cache.js +164 -0
  178. package/dist/utils/cache.js.map +1 -0
  179. package/dist/utils/distance.d.ts +25 -0
  180. package/dist/utils/distance.d.ts.map +1 -0
  181. package/dist/utils/distance.js +40 -0
  182. package/dist/utils/distance.js.map +1 -0
  183. package/dist/utils/fireWeather.d.ts +76 -0
  184. package/dist/utils/fireWeather.d.ts.map +1 -0
  185. package/dist/utils/fireWeather.js +243 -0
  186. package/dist/utils/fireWeather.js.map +1 -0
  187. package/dist/utils/geography.d.ts +79 -0
  188. package/dist/utils/geography.d.ts.map +1 -0
  189. package/dist/utils/geography.js +266 -0
  190. package/dist/utils/geography.js.map +1 -0
  191. package/dist/utils/geohash.d.ts +62 -0
  192. package/dist/utils/geohash.d.ts.map +1 -0
  193. package/dist/utils/geohash.js +146 -0
  194. package/dist/utils/geohash.js.map +1 -0
  195. package/dist/utils/locationResolver.d.ts +34 -0
  196. package/dist/utils/locationResolver.d.ts.map +1 -0
  197. package/dist/utils/locationResolver.js +120 -0
  198. package/dist/utils/locationResolver.js.map +1 -0
  199. package/dist/utils/logger.d.ts +75 -0
  200. package/dist/utils/logger.d.ts.map +1 -0
  201. package/dist/utils/logger.js +153 -0
  202. package/dist/utils/logger.js.map +1 -0
  203. package/dist/utils/marine.d.ts +59 -0
  204. package/dist/utils/marine.d.ts.map +1 -0
  205. package/dist/utils/marine.js +215 -0
  206. package/dist/utils/marine.js.map +1 -0
  207. package/dist/utils/normals.d.ts +86 -0
  208. package/dist/utils/normals.d.ts.map +1 -0
  209. package/dist/utils/normals.js +223 -0
  210. package/dist/utils/normals.js.map +1 -0
  211. package/dist/utils/snow.d.ts +45 -0
  212. package/dist/utils/snow.d.ts.map +1 -0
  213. package/dist/utils/snow.js +144 -0
  214. package/dist/utils/snow.js.map +1 -0
  215. package/dist/utils/temperatureConversion.d.ts +12 -0
  216. package/dist/utils/temperatureConversion.d.ts.map +1 -0
  217. package/dist/utils/temperatureConversion.js +17 -0
  218. package/dist/utils/temperatureConversion.js.map +1 -0
  219. package/dist/utils/timezone.d.ts +56 -0
  220. package/dist/utils/timezone.d.ts.map +1 -0
  221. package/dist/utils/timezone.js +167 -0
  222. package/dist/utils/timezone.js.map +1 -0
  223. package/dist/utils/units.d.ts +69 -0
  224. package/dist/utils/units.d.ts.map +1 -0
  225. package/dist/utils/units.js +158 -0
  226. package/dist/utils/units.js.map +1 -0
  227. package/dist/utils/validation.d.ts +89 -0
  228. package/dist/utils/validation.d.ts.map +1 -0
  229. package/dist/utils/validation.js +177 -0
  230. package/dist/utils/validation.js.map +1 -0
  231. package/dist/utils/version.d.ts +15 -0
  232. package/dist/utils/version.d.ts.map +1 -0
  233. package/dist/utils/version.js +24 -0
  234. package/dist/utils/version.js.map +1 -0
  235. package/package.json +74 -0
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Multi-Service Geocoding Service
3
+ * Implements automatic fallback strategy across multiple geocoding providers
4
+ * for maximum reliability and coverage
5
+ */
6
+ /**
7
+ * Geocoding result with standardized format across all providers
8
+ */
9
+ export interface GeocodingResult {
10
+ name: string;
11
+ display_name: string;
12
+ latitude: number;
13
+ longitude: number;
14
+ country?: string;
15
+ country_code?: string;
16
+ admin1?: string;
17
+ admin2?: string;
18
+ timezone?: string;
19
+ elevation?: number;
20
+ population?: number;
21
+ feature_code?: string;
22
+ confidence: 'high' | 'medium' | 'low';
23
+ source: 'census' | 'nominatim' | 'openmeteo';
24
+ }
25
+ /**
26
+ * Multi-Service Geocoding Service
27
+ * Automatically tries multiple providers in order with intelligent fallback
28
+ */
29
+ export declare class GeocodingService {
30
+ private census;
31
+ private nominatim;
32
+ private openmeteo;
33
+ constructor();
34
+ /**
35
+ * Detect if query is likely a US location
36
+ * Helps optimize provider selection
37
+ */
38
+ private isLikelyUSLocation;
39
+ /**
40
+ * Geocode a location query with automatic multi-service fallback
41
+ *
42
+ * Strategy:
43
+ * 1. If likely US: Try Census.gov first (fast, authoritative)
44
+ * 2. Try Nominatim (worldwide, good natural language support)
45
+ * 3. Fallback to Open-Meteo (reliable, detailed metadata)
46
+ *
47
+ * @param query - Location search query (e.g., "Seattle, WA", "Paris, France")
48
+ * @param limit - Maximum number of results to return
49
+ * @returns Array of geocoding results from first successful provider
50
+ */
51
+ geocode(query: string, limit?: number): Promise<GeocodingResult[]>;
52
+ /**
53
+ * Get service information for debugging
54
+ */
55
+ getServiceInfo(): string;
56
+ }
57
+ //# sourceMappingURL=geocoding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"geocoding.d.ts","sourceRoot":"","sources":["../../src/services/geocoding.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACtC,MAAM,EAAE,QAAQ,GAAG,WAAW,GAAG,WAAW,CAAC;CAC9C;AAkTD;;;GAGG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,SAAS,CAAoB;IACrC,OAAO,CAAC,SAAS,CAAoB;;IAQrC;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IA0C1B;;;;;;;;;;;OAWG;IACG,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,GAAE,MAAU,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IA0D3E;;OAEG;IACH,cAAc,IAAI,MAAM;CAOzB"}
@@ -0,0 +1,393 @@
1
+ /**
2
+ * Multi-Service Geocoding Service
3
+ * Implements automatic fallback strategy across multiple geocoding providers
4
+ * for maximum reliability and coverage
5
+ */
6
+ import axios from 'axios';
7
+ import { DataNotFoundError, RateLimitError, ServiceUnavailableError } from '../errors/ApiError.js';
8
+ import { logger } from '../utils/logger.js';
9
+ /**
10
+ * Rate limiter for controlling request frequency per provider
11
+ */
12
+ class RateLimiter {
13
+ lastRequestTime = 0;
14
+ minInterval; // milliseconds between requests
15
+ constructor(requestsPerSecond) {
16
+ this.minInterval = 1000 / requestsPerSecond;
17
+ }
18
+ async throttle() {
19
+ const now = Date.now();
20
+ const timeSinceLastRequest = now - this.lastRequestTime;
21
+ if (timeSinceLastRequest < this.minInterval) {
22
+ const delay = this.minInterval - timeSinceLastRequest;
23
+ await new Promise(resolve => setTimeout(resolve, delay));
24
+ }
25
+ this.lastRequestTime = Date.now();
26
+ }
27
+ }
28
+ /**
29
+ * Census.gov Geocoding Provider
30
+ * Best for: US locations (cities, states, addresses)
31
+ * Coverage: United States only
32
+ * Rate limit: No strict limit (but we throttle to be respectful)
33
+ */
34
+ class CensusGovProvider {
35
+ name = 'Census.gov';
36
+ client;
37
+ rateLimiter;
38
+ constructor() {
39
+ this.client = axios.create({
40
+ baseURL: 'https://geocoding.geo.census.gov/geocoder',
41
+ timeout: 10000,
42
+ headers: {
43
+ 'Accept': 'application/json'
44
+ }
45
+ });
46
+ // Rate limit to 5 requests/second to be respectful
47
+ this.rateLimiter = new RateLimiter(5);
48
+ }
49
+ async geocode(query, limit) {
50
+ await this.rateLimiter.throttle();
51
+ try {
52
+ logger.debug(`Census.gov geocode: "${query}"`);
53
+ const response = await this.client.get('/locations/onelineaddress', {
54
+ params: {
55
+ address: query,
56
+ benchmark: 'Public_AR_Current',
57
+ format: 'json'
58
+ }
59
+ });
60
+ if (!response.data?.result?.addressMatches || response.data.result.addressMatches.length === 0) {
61
+ logger.debug('Census.gov: No results found');
62
+ return [];
63
+ }
64
+ const matches = response.data.result.addressMatches;
65
+ const results = [];
66
+ for (let i = 0; i < Math.min(matches.length, limit); i++) {
67
+ const match = matches[i];
68
+ const coords = match.coordinates;
69
+ if (!coords || coords.x === undefined || coords.y === undefined) {
70
+ continue;
71
+ }
72
+ // Census.gov uses longitude, latitude (x, y) order
73
+ const result = {
74
+ name: match.matchedAddress || query,
75
+ display_name: match.matchedAddress || query,
76
+ latitude: coords.y,
77
+ longitude: coords.x,
78
+ country: 'United States',
79
+ country_code: 'US',
80
+ admin1: match.addressComponents?.state,
81
+ admin2: match.addressComponents?.county,
82
+ confidence: 'high', // Census.gov is authoritative for US locations
83
+ source: 'census'
84
+ };
85
+ results.push(result);
86
+ }
87
+ logger.debug(`Census.gov: Found ${results.length} result(s)`);
88
+ return results;
89
+ }
90
+ catch (error) {
91
+ if (axios.isAxiosError(error)) {
92
+ if (error.code === 'ECONNABORTED') {
93
+ throw new ServiceUnavailableError('OpenMeteo', 'Census.gov geocoding service timed out');
94
+ }
95
+ if (error.response?.status === 429) {
96
+ throw new RateLimitError('OpenMeteo', 'Census.gov geocoding rate limit exceeded');
97
+ }
98
+ }
99
+ logger.debug(`Census.gov error: ${error instanceof Error ? error.message : 'Unknown'}`);
100
+ return []; // Return empty array for fallback
101
+ }
102
+ }
103
+ }
104
+ /**
105
+ * Nominatim (OpenStreetMap) Provider
106
+ * Best for: Worldwide locations, landmarks, natural language queries
107
+ * Coverage: Global
108
+ * Rate limit: 1 request/second (strictly enforced)
109
+ */
110
+ class NominatimProvider {
111
+ name = 'Nominatim';
112
+ client;
113
+ rateLimiter;
114
+ constructor() {
115
+ this.client = axios.create({
116
+ baseURL: 'https://nominatim.openstreetmap.org',
117
+ timeout: 10000,
118
+ headers: {
119
+ 'User-Agent': '(weather-mcp, github.com/weather-mcp/weather-mcp)',
120
+ 'Accept': 'application/json'
121
+ }
122
+ });
123
+ // Strict 1 request/second rate limit as per Nominatim usage policy
124
+ this.rateLimiter = new RateLimiter(1);
125
+ }
126
+ async geocode(query, limit) {
127
+ await this.rateLimiter.throttle();
128
+ try {
129
+ logger.debug(`Nominatim geocode: "${query}"`);
130
+ const response = await this.client.get('/search', {
131
+ params: {
132
+ q: query,
133
+ format: 'json',
134
+ addressdetails: 1,
135
+ limit: Math.min(limit, 50), // Nominatim max is 50
136
+ 'accept-language': 'en'
137
+ }
138
+ });
139
+ if (!response.data || response.data.length === 0) {
140
+ logger.debug('Nominatim: No results found');
141
+ return [];
142
+ }
143
+ const results = response.data.map((item) => {
144
+ const address = item.address || {};
145
+ // Determine confidence based on importance and type
146
+ let confidence = 'medium';
147
+ if (item.importance > 0.6)
148
+ confidence = 'high';
149
+ else if (item.importance < 0.3)
150
+ confidence = 'low';
151
+ return {
152
+ name: item.name || item.display_name,
153
+ display_name: item.display_name,
154
+ latitude: parseFloat(item.lat),
155
+ longitude: parseFloat(item.lon),
156
+ country: address.country,
157
+ country_code: address.country_code?.toUpperCase(),
158
+ admin1: address.state || address.region,
159
+ admin2: address.county,
160
+ feature_code: this.mapTypeToFeatureCode(item.type),
161
+ confidence,
162
+ source: 'nominatim'
163
+ };
164
+ });
165
+ logger.debug(`Nominatim: Found ${results.length} result(s)`);
166
+ return results;
167
+ }
168
+ catch (error) {
169
+ if (axios.isAxiosError(error)) {
170
+ if (error.code === 'ECONNABORTED') {
171
+ throw new ServiceUnavailableError('OpenMeteo', 'Nominatim geocoding service timed out');
172
+ }
173
+ if (error.response?.status === 429) {
174
+ throw new RateLimitError('OpenMeteo', 'Nominatim geocoding rate limit exceeded (1 req/sec limit)');
175
+ }
176
+ }
177
+ logger.debug(`Nominatim error: ${error instanceof Error ? error.message : 'Unknown'}`);
178
+ return []; // Return empty array for fallback
179
+ }
180
+ }
181
+ /**
182
+ * Map Nominatim type to GeoNames-style feature code
183
+ */
184
+ mapTypeToFeatureCode(type) {
185
+ const typeMap = {
186
+ 'city': 'PPL',
187
+ 'town': 'PPL',
188
+ 'village': 'PPL',
189
+ 'administrative': 'ADM1',
190
+ 'country': 'PCLI',
191
+ 'state': 'ADM1',
192
+ 'county': 'ADM2',
193
+ 'island': 'ISL',
194
+ 'airport': 'AIRP',
195
+ 'park': 'PRK',
196
+ 'lake': 'LAKE'
197
+ };
198
+ return typeMap[type.toLowerCase()] || type.toUpperCase();
199
+ }
200
+ }
201
+ /**
202
+ * Open-Meteo Geocoding Provider (existing implementation as fallback)
203
+ * Best for: Reliable global coverage with detailed metadata
204
+ * Coverage: Global
205
+ * Rate limit: Part of 10,000 requests/day shared limit
206
+ */
207
+ class OpenMeteoProvider {
208
+ name = 'Open-Meteo';
209
+ client;
210
+ constructor() {
211
+ this.client = axios.create({
212
+ baseURL: 'https://geocoding-api.open-meteo.com/v1',
213
+ timeout: 10000,
214
+ headers: {
215
+ 'Accept': 'application/json'
216
+ }
217
+ });
218
+ }
219
+ async geocode(query, limit) {
220
+ try {
221
+ logger.debug(`Open-Meteo geocode: "${query}"`);
222
+ const response = await this.client.get('/search', {
223
+ params: {
224
+ name: query,
225
+ count: Math.min(limit, 100),
226
+ language: 'en',
227
+ format: 'json'
228
+ }
229
+ });
230
+ if (!response.data?.results || response.data.results.length === 0) {
231
+ logger.debug('Open-Meteo: No results found');
232
+ return [];
233
+ }
234
+ const results = response.data.results.map((item) => ({
235
+ name: item.name,
236
+ display_name: [item.name, item.admin1, item.admin2, item.country]
237
+ .filter(Boolean)
238
+ .join(', '),
239
+ latitude: item.latitude,
240
+ longitude: item.longitude,
241
+ country: item.country,
242
+ country_code: item.country_code,
243
+ admin1: item.admin1,
244
+ admin2: item.admin2,
245
+ timezone: item.timezone,
246
+ elevation: item.elevation,
247
+ population: item.population,
248
+ feature_code: item.feature_code,
249
+ confidence: 'medium', // Open-Meteo is reliable but not authoritative
250
+ source: 'openmeteo'
251
+ }));
252
+ logger.debug(`Open-Meteo: Found ${results.length} result(s)`);
253
+ return results;
254
+ }
255
+ catch (error) {
256
+ if (axios.isAxiosError(error)) {
257
+ if (error.code === 'ECONNABORTED') {
258
+ throw new ServiceUnavailableError('OpenMeteo', 'Open-Meteo geocoding service timed out');
259
+ }
260
+ if (error.response?.status === 429) {
261
+ throw new RateLimitError('OpenMeteo', 'Open-Meteo geocoding rate limit exceeded');
262
+ }
263
+ }
264
+ logger.debug(`Open-Meteo error: ${error instanceof Error ? error.message : 'Unknown'}`);
265
+ return []; // Return empty array for fallback
266
+ }
267
+ }
268
+ }
269
+ /**
270
+ * Multi-Service Geocoding Service
271
+ * Automatically tries multiple providers in order with intelligent fallback
272
+ */
273
+ export class GeocodingService {
274
+ census;
275
+ nominatim;
276
+ openmeteo;
277
+ constructor() {
278
+ this.census = new CensusGovProvider();
279
+ this.nominatim = new NominatimProvider();
280
+ this.openmeteo = new OpenMeteoProvider();
281
+ }
282
+ /**
283
+ * Detect if query is likely a US location
284
+ * Helps optimize provider selection
285
+ */
286
+ isLikelyUSLocation(query) {
287
+ const lowerQuery = query.toLowerCase();
288
+ // State abbreviations
289
+ const stateAbbreviations = [
290
+ 'al', 'ak', 'az', 'ar', 'ca', 'co', 'ct', 'de', 'fl', 'ga',
291
+ 'hi', 'id', 'il', 'in', 'ia', 'ks', 'ky', 'la', 'me', 'md',
292
+ 'ma', 'mi', 'mn', 'ms', 'mo', 'mt', 'ne', 'nv', 'nh', 'nj',
293
+ 'nm', 'ny', 'nc', 'nd', 'oh', 'ok', 'or', 'pa', 'ri', 'sc',
294
+ 'sd', 'tn', 'tx', 'ut', 'vt', 'va', 'wa', 'wv', 'wi', 'wy'
295
+ ];
296
+ // Check for state abbreviations (e.g., "Seattle, WA")
297
+ for (const state of stateAbbreviations) {
298
+ if (lowerQuery.includes(`, ${state}`) || lowerQuery.endsWith(` ${state}`)) {
299
+ return true;
300
+ }
301
+ }
302
+ // Check for explicit country mentions (US or USA)
303
+ if (lowerQuery.includes('usa') ||
304
+ lowerQuery.includes('u.s.a') ||
305
+ lowerQuery.includes('united states')) {
306
+ return true;
307
+ }
308
+ // Check for explicit non-US country mentions
309
+ const nonUSKeywords = [
310
+ 'france', 'germany', 'japan', 'china', 'uk', 'england',
311
+ 'canada', 'mexico', 'australia', 'india', 'brazil'
312
+ ];
313
+ for (const keyword of nonUSKeywords) {
314
+ if (lowerQuery.includes(keyword)) {
315
+ return false;
316
+ }
317
+ }
318
+ // Default: Assume might be US (we'll try Census.gov first, then fallback)
319
+ return null; // null means "uncertain"
320
+ }
321
+ /**
322
+ * Geocode a location query with automatic multi-service fallback
323
+ *
324
+ * Strategy:
325
+ * 1. If likely US: Try Census.gov first (fast, authoritative)
326
+ * 2. Try Nominatim (worldwide, good natural language support)
327
+ * 3. Fallback to Open-Meteo (reliable, detailed metadata)
328
+ *
329
+ * @param query - Location search query (e.g., "Seattle, WA", "Paris, France")
330
+ * @param limit - Maximum number of results to return
331
+ * @returns Array of geocoding results from first successful provider
332
+ */
333
+ async geocode(query, limit = 5) {
334
+ const isLikelyUS = this.isLikelyUSLocation(query);
335
+ const providers = [];
336
+ // Build provider order based on query characteristics
337
+ if (isLikelyUS === true) {
338
+ // Definitely US - try Census.gov first
339
+ providers.push(this.census, this.nominatim, this.openmeteo);
340
+ logger.debug('Provider strategy: US-optimized (Census → Nominatim → Open-Meteo)');
341
+ }
342
+ else if (isLikelyUS === false) {
343
+ // Definitely non-US - skip Census.gov
344
+ providers.push(this.nominatim, this.openmeteo);
345
+ logger.debug('Provider strategy: International (Nominatim → Open-Meteo)');
346
+ }
347
+ else {
348
+ // Uncertain - try all providers
349
+ providers.push(this.census, this.nominatim, this.openmeteo);
350
+ logger.debug('Provider strategy: Uncertain (Census → Nominatim → Open-Meteo)');
351
+ }
352
+ const errors = [];
353
+ // Try each provider in order
354
+ for (const provider of providers) {
355
+ try {
356
+ logger.debug(`Trying provider: ${provider.name}`);
357
+ const results = await provider.geocode(query, limit);
358
+ if (results.length > 0) {
359
+ logger.info(`Geocoding successful via ${provider.name}: ${results.length} result(s)`);
360
+ return results;
361
+ }
362
+ logger.debug(`${provider.name}: No results found`);
363
+ errors.push(`${provider.name}: No results found`);
364
+ }
365
+ catch (error) {
366
+ const errorMsg = error instanceof Error ? error.message : 'Unknown error';
367
+ logger.debug(`${provider.name} failed: ${errorMsg}`);
368
+ errors.push(`${provider.name}: ${errorMsg}`);
369
+ // Continue to next provider
370
+ continue;
371
+ }
372
+ }
373
+ // All providers failed or returned no results
374
+ throw new DataNotFoundError('OpenMeteo', `No locations found matching "${query}".\n\n` +
375
+ `Tried ${providers.length} provider(s): ${errors.join('; ')}\n\n` +
376
+ `Suggestions:\n` +
377
+ `- Add more detail (e.g., "Paris, France" instead of "Paris")\n` +
378
+ `- Check spelling\n` +
379
+ `- Use a nearby major city\n` +
380
+ `- Try providing coordinates directly (latitude, longitude)`);
381
+ }
382
+ /**
383
+ * Get service information for debugging
384
+ */
385
+ getServiceInfo() {
386
+ return `Multi-Service Geocoding:\n` +
387
+ `- Census.gov (US locations, high accuracy)\n` +
388
+ `- Nominatim/OpenStreetMap (worldwide, 1 req/sec limit)\n` +
389
+ `- Open-Meteo (worldwide fallback)\n` +
390
+ `Automatic fallback strategy based on query characteristics`;
391
+ }
392
+ }
393
+ //# sourceMappingURL=geocoding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"geocoding.js","sourceRoot":"","sources":["../../src/services/geocoding.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Service for managing saved/favorite locations
3
+ * Stores locations in ~/.weather-mcp/locations.json
4
+ */
5
+ import type { SavedLocation, SavedLocationsStore } from '../types/savedLocations.js';
6
+ export declare class LocationStore {
7
+ private readonly storePath;
8
+ private readonly storeDir;
9
+ private cache;
10
+ constructor(customPath?: string);
11
+ /**
12
+ * Ensure the storage directory exists
13
+ * @private
14
+ */
15
+ private ensureDirectoryExists;
16
+ /**
17
+ * Load all saved locations from disk
18
+ */
19
+ load(): SavedLocationsStore;
20
+ /**
21
+ * Save all locations to disk
22
+ * @private
23
+ */
24
+ private save;
25
+ /**
26
+ * Get a saved location by alias
27
+ */
28
+ get(alias: string): SavedLocation | undefined;
29
+ /**
30
+ * Get all saved locations
31
+ */
32
+ getAll(): SavedLocationsStore;
33
+ /**
34
+ * Save or update a location
35
+ */
36
+ set(alias: string, location: Omit<SavedLocation, 'saved_at' | 'updated_at'>): SavedLocation;
37
+ /**
38
+ * Remove a saved location
39
+ */
40
+ remove(alias: string): boolean;
41
+ /**
42
+ * Check if a location exists
43
+ */
44
+ has(alias: string): boolean;
45
+ /**
46
+ * Get the number of saved locations
47
+ */
48
+ count(): number;
49
+ /**
50
+ * Clear all saved locations
51
+ */
52
+ clear(): void;
53
+ /**
54
+ * Get the storage file path
55
+ */
56
+ getStorePath(): string;
57
+ /**
58
+ * Invalidate the cache, forcing reload on next access
59
+ */
60
+ invalidateCache(): void;
61
+ }
62
+ //# sourceMappingURL=locationStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locationStore.d.ts","sourceRoot":"","sources":["../../src/services/locationStore.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAIrF,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,KAAK,CAAoC;gBAErC,UAAU,CAAC,EAAE,MAAM;IAU/B;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAc7B;;OAEG;IACH,IAAI,IAAI,mBAAmB;IA6C3B;;;OAGG;IACH,OAAO,CAAC,IAAI;IAmBZ;;OAEG;IACH,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAM7C;;OAEG;IACH,MAAM,IAAI,mBAAmB;IAI7B;;OAEG;IACH,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,aAAa,EAAE,UAAU,GAAG,YAAY,CAAC,GAAG,aAAa;IAoC3F;;OAEG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAe9B;;OAEG;IACH,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAM3B;;OAEG;IACH,KAAK,IAAI,MAAM;IAKf;;OAEG;IACH,KAAK,IAAI,IAAI;IAKb;;OAEG;IACH,YAAY,IAAI,MAAM;IAItB;;OAEG;IACH,eAAe,IAAI,IAAI;CAGxB"}