@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,266 @@
1
+ /**
2
+ * Geographic utility functions for location detection and classification
3
+ */
4
+ /**
5
+ * Great Lakes bounding boxes (approximate)
6
+ * Source: NOAA Great Lakes Environmental Research Laboratory
7
+ */
8
+ const GREAT_LAKES_REGIONS = [
9
+ {
10
+ name: 'Lake Superior',
11
+ bbox: {
12
+ minLat: 46.4,
13
+ maxLat: 49.0,
14
+ minLon: -92.2,
15
+ maxLon: -84.3
16
+ },
17
+ description: 'Largest Great Lake by surface area'
18
+ },
19
+ {
20
+ name: 'Lake Michigan',
21
+ bbox: {
22
+ minLat: 41.6,
23
+ maxLat: 46.0,
24
+ minLon: -87.8,
25
+ maxLon: -84.8
26
+ },
27
+ description: 'Third largest Great Lake, only one entirely in US'
28
+ },
29
+ {
30
+ name: 'Lake Huron',
31
+ bbox: {
32
+ minLat: 43.0,
33
+ maxLat: 46.5,
34
+ minLon: -84.8,
35
+ maxLon: -79.8
36
+ },
37
+ description: 'Second largest Great Lake by surface area'
38
+ },
39
+ {
40
+ name: 'Lake Erie',
41
+ bbox: {
42
+ minLat: 41.3,
43
+ maxLat: 42.9,
44
+ minLon: -83.5,
45
+ maxLon: -78.9
46
+ },
47
+ description: 'Shallowest of the Great Lakes'
48
+ },
49
+ {
50
+ name: 'Lake Ontario',
51
+ bbox: {
52
+ minLat: 43.2,
53
+ maxLat: 44.3,
54
+ minLon: -79.8,
55
+ maxLon: -76.1
56
+ },
57
+ description: 'Smallest Great Lake by surface area'
58
+ }
59
+ ];
60
+ /**
61
+ * Major US coastal bays and large inland lakes with NOAA marine forecasts
62
+ * These locations have NOAA marine zone forecasts available
63
+ */
64
+ const MAJOR_COASTAL_BAYS = [
65
+ {
66
+ name: 'Chesapeake Bay',
67
+ bbox: {
68
+ minLat: 36.9,
69
+ maxLat: 39.6,
70
+ minLon: -76.6,
71
+ maxLon: -75.9
72
+ },
73
+ description: 'Largest estuary in the United States'
74
+ },
75
+ {
76
+ name: 'San Francisco Bay',
77
+ bbox: {
78
+ minLat: 37.4,
79
+ maxLat: 38.2,
80
+ minLon: -122.6,
81
+ maxLon: -121.8
82
+ },
83
+ description: 'West Coast major bay area'
84
+ },
85
+ {
86
+ name: 'Tampa Bay',
87
+ bbox: {
88
+ minLat: 27.5,
89
+ maxLat: 28.0,
90
+ minLon: -82.8,
91
+ maxLon: -82.4
92
+ },
93
+ description: 'Gulf Coast major bay'
94
+ },
95
+ {
96
+ name: 'Puget Sound',
97
+ bbox: {
98
+ minLat: 47.0,
99
+ maxLat: 48.5,
100
+ minLon: -122.9,
101
+ maxLon: -122.2
102
+ },
103
+ description: 'Pacific Northwest inland sea'
104
+ },
105
+ {
106
+ name: 'Lake Okeechobee',
107
+ bbox: {
108
+ minLat: 26.7,
109
+ maxLat: 27.2,
110
+ minLon: -81.0,
111
+ maxLon: -80.6
112
+ },
113
+ description: 'Largest freshwater lake in Florida'
114
+ }
115
+ ];
116
+ /**
117
+ * Check if a point is within a bounding box
118
+ */
119
+ function isInBoundingBox(lat, lon, bbox) {
120
+ return (lat >= bbox.minLat &&
121
+ lat <= bbox.maxLat &&
122
+ lon >= bbox.minLon &&
123
+ lon <= bbox.maxLon);
124
+ }
125
+ /**
126
+ * Check if coordinates are within the Great Lakes region
127
+ * @param latitude Latitude coordinate
128
+ * @param longitude Longitude coordinate
129
+ * @returns The Great Lake name if in region, null otherwise
130
+ */
131
+ export function getGreatLakeRegion(latitude, longitude) {
132
+ for (const region of GREAT_LAKES_REGIONS) {
133
+ if (isInBoundingBox(latitude, longitude, region.bbox)) {
134
+ return region.name;
135
+ }
136
+ }
137
+ return null;
138
+ }
139
+ /**
140
+ * Check if coordinates are within a major US coastal bay or large inland lake
141
+ * @param latitude Latitude coordinate
142
+ * @param longitude Longitude coordinate
143
+ * @returns The bay/lake name if in region, null otherwise
144
+ */
145
+ export function getMajorCoastalBayRegion(latitude, longitude) {
146
+ for (const region of MAJOR_COASTAL_BAYS) {
147
+ if (isInBoundingBox(latitude, longitude, region.bbox)) {
148
+ return region.name;
149
+ }
150
+ }
151
+ return null;
152
+ }
153
+ /**
154
+ * Check if coordinates should use NOAA marine data (Great Lakes or major coastal bays)
155
+ * @param latitude Latitude coordinate
156
+ * @param longitude Longitude coordinate
157
+ * @returns Object with detection results
158
+ */
159
+ export function shouldUseNOAAMarine(latitude, longitude) {
160
+ // Check Great Lakes first
161
+ const greatLake = getGreatLakeRegion(latitude, longitude);
162
+ if (greatLake) {
163
+ return {
164
+ useNOAA: true,
165
+ region: greatLake,
166
+ source: 'great-lakes'
167
+ };
168
+ }
169
+ // Check major coastal bays
170
+ const coastalBay = getMajorCoastalBayRegion(latitude, longitude);
171
+ if (coastalBay) {
172
+ return {
173
+ useNOAA: true,
174
+ region: coastalBay,
175
+ source: 'coastal-bay'
176
+ };
177
+ }
178
+ // Default to Open-Meteo for oceans and other locations
179
+ return {
180
+ useNOAA: false,
181
+ region: null,
182
+ source: 'ocean'
183
+ };
184
+ }
185
+ /**
186
+ * Get a human-readable description of the marine region
187
+ * @param latitude Latitude coordinate
188
+ * @param longitude Longitude coordinate
189
+ * @returns Description string
190
+ */
191
+ export function getMarineRegionDescription(latitude, longitude) {
192
+ const detection = shouldUseNOAAMarine(latitude, longitude);
193
+ if (detection.region) {
194
+ return `${detection.region} (${detection.source === 'great-lakes' ? 'Great Lakes' : 'Coastal Bay'})`;
195
+ }
196
+ return 'Open ocean or coastal waters';
197
+ }
198
+ /**
199
+ * Get all Great Lakes regions (for testing and documentation)
200
+ */
201
+ export function getGreatLakesRegions() {
202
+ return GREAT_LAKES_REGIONS;
203
+ }
204
+ /**
205
+ * Get all major coastal bay regions (for testing and documentation)
206
+ */
207
+ export function getMajorCoastalBayRegions() {
208
+ return MAJOR_COASTAL_BAYS;
209
+ }
210
+ /**
211
+ * Approximate country/region detection from coordinates
212
+ * PRIVACY: Intentionally vague - only major regions for privacy
213
+ * ACCURACY: This is a ROUGH approximation with known inaccuracies:
214
+ * - Mexico, Caribbean, Central America -> OTHER
215
+ * - Some border regions may be misclassified
216
+ * - Alaska and Hawaii have special handling
217
+ *
218
+ * This is called OUTSIDE the analytics module to ensure coordinates
219
+ * never enter the analytics boundary. Trade-off: Privacy (no reverse geocoding)
220
+ * vs Accuracy (bounding boxes)
221
+ *
222
+ * @param lat Latitude (-90 to 90)
223
+ * @param lon Longitude (-180 to 180)
224
+ * @returns ISO 3166-1 alpha-2 region code (US, CA, EU, AP, SA, AF, OC, OTHER)
225
+ */
226
+ export function getCountryFromCoordinates(lat, lon) {
227
+ // Handle Alaska (49°N+, west of 130°W)
228
+ if (lat >= 49 && lon <= -130 && lon >= -180) {
229
+ return 'US';
230
+ }
231
+ // Handle Hawaii (18-23°N, 154-162°W)
232
+ if (lat >= 18 && lat <= 23 && lon >= -162 && lon <= -154) {
233
+ return 'US';
234
+ }
235
+ // Continental US: Approximately 25-49°N, 125-66°W
236
+ if (lat >= 24 && lat <= 50 && lon >= -125 && lon <= -66) {
237
+ return 'US';
238
+ }
239
+ // Canada: Approximately 42-83°N, 141-52°W
240
+ if (lat >= 41 && lat <= 84 && lon >= -142 && lon <= -52) {
241
+ return 'CA';
242
+ }
243
+ // Europe: Approximately 35-71°N, 10°W-40°E
244
+ if (lat >= 35 && lat <= 72 && lon >= -11 && lon <= 41) {
245
+ return 'EU';
246
+ }
247
+ // Asia-Pacific: Rough approximation
248
+ if (lat >= -10 && lat <= 55 && lon >= 60 && lon <= 180) {
249
+ return 'AP';
250
+ }
251
+ // South America: Approximate
252
+ if (lat >= -56 && lat <= 13 && lon >= -82 && lon <= -34) {
253
+ return 'SA';
254
+ }
255
+ // Africa: Approximate
256
+ if (lat >= -35 && lat <= 38 && lon >= -18 && lon <= 52) {
257
+ return 'AF';
258
+ }
259
+ // Australia/Oceania: Approximate
260
+ if (lat >= -48 && lat <= -10 && lon >= 112 && lon <= 180) {
261
+ return 'OC';
262
+ }
263
+ // Default to OTHER for privacy (intentionally vague)
264
+ return 'OTHER';
265
+ }
266
+ //# sourceMappingURL=geography.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"geography.js","sourceRoot":"","sources":["../../src/utils/geography.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Geohash utilities for lightning strike location filtering
3
+ * Based on the homeassistant-blitzortung implementation
4
+ */
5
+ /**
6
+ * Bounding box for geographic area
7
+ */
8
+ export interface BoundingBox {
9
+ minLat: number;
10
+ minLon: number;
11
+ maxLat: number;
12
+ maxLon: number;
13
+ }
14
+ /**
15
+ * Calculate bounding box around a point given a radius in kilometers
16
+ * @param lat Latitude
17
+ * @param lon Longitude
18
+ * @param radiusKm Radius in kilometers
19
+ * @returns Bounding box
20
+ */
21
+ export declare function calculateBoundingBox(lat: number, lon: number, radiusKm: number): BoundingBox;
22
+ /**
23
+ * Get all geohash neighbors for a given geohash
24
+ * @param hash Geohash string
25
+ * @returns Array of neighbor geohashes (up to 8 neighbors)
26
+ */
27
+ export declare function getGeohashNeighbors(hash: string): string[];
28
+ /**
29
+ * Compute geohash tiles that overlap a circular search area
30
+ * Uses breadth-first search to find all geohashes within the bounding box
31
+ * @param lat Center latitude
32
+ * @param lon Center longitude
33
+ * @param radiusKm Search radius in kilometers
34
+ * @param precision Geohash precision (1-12)
35
+ * @returns Set of geohash strings that overlap the search area
36
+ */
37
+ export declare function computeGeohashTiles(lat: number, lon: number, radiusKm: number, precision: number): Set<string>;
38
+ /**
39
+ * Calculate optimal geohash tiles for MQTT subscription
40
+ * Selects the coarsest precision that keeps the tile count at or below maxTiles
41
+ * This balances spatial granularity against subscription overhead
42
+ *
43
+ * @param lat Center latitude
44
+ * @param lon Center longitude
45
+ * @param radiusKm Search radius in kilometers
46
+ * @param maxTiles Maximum number of tiles (default 9, as used by homeassistant-blitzortung)
47
+ * @returns Set of geohash strings to subscribe to
48
+ */
49
+ export declare function calculateGeohashSubscriptions(lat: number, lon: number, radiusKm: number, maxTiles?: number): Set<string>;
50
+ /**
51
+ * Check if a point is within a radius of a center point
52
+ * Uses Haversine formula for great-circle distance
53
+ *
54
+ * @param centerLat Center latitude
55
+ * @param centerLon Center longitude
56
+ * @param pointLat Point latitude
57
+ * @param pointLon Point longitude
58
+ * @param radiusKm Radius in kilometers
59
+ * @returns true if point is within radius
60
+ */
61
+ export declare function isWithinRadius(centerLat: number, centerLon: number, pointLat: number, pointLon: number, radiusKm: number): boolean;
62
+ //# sourceMappingURL=geohash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"geohash.d.ts","sourceRoot":"","sources":["../../src/utils/geohash.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,WAAW,CAW5F;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAmB1D;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAChB,GAAG,CAAC,MAAM,CAAC,CA0Cb;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,6BAA6B,CAC3C,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,QAAQ,GAAE,MAAU,GACnB,GAAG,CAAC,MAAM,CAAC,CAsBb;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,OAAO,CAgBT"}
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Geohash utilities for lightning strike location filtering
3
+ * Based on the homeassistant-blitzortung implementation
4
+ */
5
+ import geohash from 'ngeohash';
6
+ /**
7
+ * Calculate bounding box around a point given a radius in kilometers
8
+ * @param lat Latitude
9
+ * @param lon Longitude
10
+ * @param radiusKm Radius in kilometers
11
+ * @returns Bounding box
12
+ */
13
+ export function calculateBoundingBox(lat, lon, radiusKm) {
14
+ // Earth's circumference at equator: ~40,000 km
15
+ const latDelta = (radiusKm * 360) / 40000;
16
+ const lonDelta = latDelta / Math.cos((lat * Math.PI) / 180);
17
+ return {
18
+ minLat: Math.max(-90, lat - latDelta),
19
+ minLon: Math.max(-180, lon - lonDelta),
20
+ maxLat: Math.min(90, lat + latDelta),
21
+ maxLon: Math.min(180, lon + lonDelta)
22
+ };
23
+ }
24
+ /**
25
+ * Get all geohash neighbors for a given geohash
26
+ * @param hash Geohash string
27
+ * @returns Array of neighbor geohashes (up to 8 neighbors)
28
+ */
29
+ export function getGeohashNeighbors(hash) {
30
+ const neighbors = [];
31
+ try {
32
+ // Get all 8 neighbors (N, S, E, W, NE, NW, SE, SW)
33
+ neighbors.push(geohash.neighbor(hash, [0, 1])); // N
34
+ neighbors.push(geohash.neighbor(hash, [0, -1])); // S
35
+ neighbors.push(geohash.neighbor(hash, [1, 0])); // E
36
+ neighbors.push(geohash.neighbor(hash, [-1, 0])); // W
37
+ neighbors.push(geohash.neighbor(hash, [1, 1])); // NE
38
+ neighbors.push(geohash.neighbor(hash, [-1, 1])); // NW
39
+ neighbors.push(geohash.neighbor(hash, [1, -1])); // SE
40
+ neighbors.push(geohash.neighbor(hash, [-1, -1])); // SW
41
+ }
42
+ catch (error) {
43
+ // If neighbor calculation fails, return empty array
44
+ // This can happen at edge cases (poles, date line)
45
+ }
46
+ return neighbors;
47
+ }
48
+ /**
49
+ * Compute geohash tiles that overlap a circular search area
50
+ * Uses breadth-first search to find all geohashes within the bounding box
51
+ * @param lat Center latitude
52
+ * @param lon Center longitude
53
+ * @param radiusKm Search radius in kilometers
54
+ * @param precision Geohash precision (1-12)
55
+ * @returns Set of geohash strings that overlap the search area
56
+ */
57
+ export function computeGeohashTiles(lat, lon, radiusKm, precision) {
58
+ const bbox = calculateBoundingBox(lat, lon, radiusKm);
59
+ const tiles = new Set();
60
+ const queue = [];
61
+ const MAX_TILES = 10000; // Safety limit to prevent memory exhaustion
62
+ // Start with the center point's geohash
63
+ const centerHash = geohash.encode(lat, lon, precision);
64
+ queue.push(centerHash);
65
+ tiles.add(centerHash);
66
+ // Breadth-first search to find all tiles within bounding box
67
+ while (queue.length > 0) {
68
+ const currentHash = queue.shift();
69
+ const neighbors = getGeohashNeighbors(currentHash);
70
+ for (const neighbor of neighbors) {
71
+ if (tiles.has(neighbor)) {
72
+ continue; // Already visited
73
+ }
74
+ // Safety check: prevent unbounded growth
75
+ if (tiles.size >= MAX_TILES) {
76
+ return tiles;
77
+ }
78
+ // Decode neighbor to check if it's within bounding box
79
+ const decoded = geohash.decode(neighbor);
80
+ if (decoded.latitude >= bbox.minLat &&
81
+ decoded.latitude <= bbox.maxLat &&
82
+ decoded.longitude >= bbox.minLon &&
83
+ decoded.longitude <= bbox.maxLon) {
84
+ tiles.add(neighbor);
85
+ queue.push(neighbor);
86
+ }
87
+ }
88
+ }
89
+ return tiles;
90
+ }
91
+ /**
92
+ * Calculate optimal geohash tiles for MQTT subscription
93
+ * Selects the coarsest precision that keeps the tile count at or below maxTiles
94
+ * This balances spatial granularity against subscription overhead
95
+ *
96
+ * @param lat Center latitude
97
+ * @param lon Center longitude
98
+ * @param radiusKm Search radius in kilometers
99
+ * @param maxTiles Maximum number of tiles (default 9, as used by homeassistant-blitzortung)
100
+ * @returns Set of geohash strings to subscribe to
101
+ */
102
+ export function calculateGeohashSubscriptions(lat, lon, radiusKm, maxTiles = 9) {
103
+ let result = new Set();
104
+ // Iterate through precision levels 1-12
105
+ // Start with coarse precision and increase until we exceed maxTiles
106
+ for (let precision = 1; precision <= 12; precision++) {
107
+ const tiles = computeGeohashTiles(lat, lon, radiusKm, precision);
108
+ if (tiles.size <= maxTiles) {
109
+ result = tiles;
110
+ }
111
+ else {
112
+ // Exceeded maxTiles, use previous precision
113
+ break;
114
+ }
115
+ }
116
+ // If result is empty (shouldn't happen), fall back to center point at precision 4
117
+ if (result.size === 0) {
118
+ result.add(geohash.encode(lat, lon, 4));
119
+ }
120
+ return result;
121
+ }
122
+ /**
123
+ * Check if a point is within a radius of a center point
124
+ * Uses Haversine formula for great-circle distance
125
+ *
126
+ * @param centerLat Center latitude
127
+ * @param centerLon Center longitude
128
+ * @param pointLat Point latitude
129
+ * @param pointLon Point longitude
130
+ * @param radiusKm Radius in kilometers
131
+ * @returns true if point is within radius
132
+ */
133
+ export function isWithinRadius(centerLat, centerLon, pointLat, pointLon, radiusKm) {
134
+ const R = 6371; // Earth's radius in km
135
+ const dLat = ((pointLat - centerLat) * Math.PI) / 180;
136
+ const dLon = ((pointLon - centerLon) * Math.PI) / 180;
137
+ const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
138
+ Math.cos((centerLat * Math.PI) / 180) *
139
+ Math.cos((pointLat * Math.PI) / 180) *
140
+ Math.sin(dLon / 2) *
141
+ Math.sin(dLon / 2);
142
+ const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
143
+ const distance = R * c;
144
+ return distance <= radiusKm;
145
+ }
146
+ //# sourceMappingURL=geohash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"geohash.js","sourceRoot":"","sources":["../../src/utils/geohash.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Utility for resolving location coordinates from various input formats
3
+ */
4
+ import type { GeocodingService } from '../services/geocoding.js';
5
+ import { LocationStore } from '../services/locationStore.js';
6
+ export interface LocationInput {
7
+ latitude?: number;
8
+ longitude?: number;
9
+ location_name?: string;
10
+ city_name?: string;
11
+ }
12
+ export interface ResolvedLocation {
13
+ latitude: number;
14
+ longitude: number;
15
+ source: 'coordinates' | 'saved_location' | 'geocoded';
16
+ location_name?: string;
17
+ display_name?: string;
18
+ }
19
+ /**
20
+ * Resolve location coordinates from either direct coordinates or a saved location name
21
+ *
22
+ * @param args - Arguments containing either (latitude + longitude) OR location_name
23
+ * @param locationStore - Location store instance
24
+ * @returns Resolved coordinates and metadata
25
+ * @throws Error if neither coordinates nor location_name provided, or if validation fails
26
+ */
27
+ export declare function resolveLocation(args: LocationInput, locationStore: LocationStore): ResolvedLocation;
28
+ /**
29
+ * Resolve location coordinates from coordinates, saved location name, or city name (geocoded)
30
+ *
31
+ * Priority: coordinates > location_name > city_name
32
+ */
33
+ export declare function resolveLocationAsync(args: LocationInput, locationStore: LocationStore, geocodingService: GeocodingService): Promise<ResolvedLocation>;
34
+ //# sourceMappingURL=locationResolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locationResolver.d.ts","sourceRoot":"","sources":["../../src/utils/locationResolver.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAG7D,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,aAAa,GAAG,gBAAgB,GAAG,UAAU,CAAC;IACtD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAwDD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,aAAa,EACnB,aAAa,EAAE,aAAa,GAC3B,gBAAgB,CAgClB;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,aAAa,EACnB,aAAa,EAAE,aAAa,EAC5B,gBAAgB,EAAE,gBAAgB,GACjC,OAAO,CAAC,gBAAgB,CAAC,CA6C3B"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Utility for resolving location coordinates from various input formats
3
+ */
4
+ import { validateLatitude, validateLongitude } from './validation.js';
5
+ function hasCoordinates(args) {
6
+ return typeof args.latitude === 'number' && typeof args.longitude === 'number';
7
+ }
8
+ function hasLocationName(args) {
9
+ return typeof args.location_name === 'string' && args.location_name.trim().length > 0;
10
+ }
11
+ function resolveSavedLocation(locationName, locationStore) {
12
+ const normalizedName = locationName.toLowerCase().trim();
13
+ let savedLocation = locationStore.get(normalizedName);
14
+ let matchedAlias = normalizedName;
15
+ if (!savedLocation) {
16
+ const allLocations = locationStore.getAll();
17
+ for (const [alias, location] of Object.entries(allLocations)) {
18
+ if (location.alternateNames && location.alternateNames.length > 0) {
19
+ const normalizedAlternates = location.alternateNames.map(name => name.toLowerCase().trim());
20
+ if (normalizedAlternates.includes(normalizedName)) {
21
+ savedLocation = location;
22
+ matchedAlias = alias;
23
+ break;
24
+ }
25
+ }
26
+ }
27
+ }
28
+ if (!savedLocation) {
29
+ const available = Object.keys(locationStore.getAll());
30
+ throw new Error(`Saved location "${normalizedName}" not found.\n\n` +
31
+ (available.length > 0
32
+ ? `Available locations: ${available.join(', ')}\n\n`
33
+ : 'No saved locations yet. Use save_location to create one.\n\n') +
34
+ `Use list_saved_locations to see all saved locations.`);
35
+ }
36
+ return {
37
+ latitude: savedLocation.latitude,
38
+ longitude: savedLocation.longitude,
39
+ source: 'saved_location',
40
+ location_name: matchedAlias
41
+ };
42
+ }
43
+ /**
44
+ * Resolve location coordinates from either direct coordinates or a saved location name
45
+ *
46
+ * @param args - Arguments containing either (latitude + longitude) OR location_name
47
+ * @param locationStore - Location store instance
48
+ * @returns Resolved coordinates and metadata
49
+ * @throws Error if neither coordinates nor location_name provided, or if validation fails
50
+ */
51
+ export function resolveLocation(args, locationStore) {
52
+ // Check if location_name is provided
53
+ if (args.location_name && typeof args.location_name === 'string') {
54
+ const locationName = args.location_name.toLowerCase().trim();
55
+ if (locationName.length === 0) {
56
+ throw new Error('location_name cannot be empty');
57
+ }
58
+ return resolveSavedLocation(locationName, locationStore);
59
+ }
60
+ // Check if direct coordinates are provided
61
+ if (hasCoordinates(args)) {
62
+ validateLatitude(args.latitude);
63
+ validateLongitude(args.longitude);
64
+ return {
65
+ latitude: args.latitude,
66
+ longitude: args.longitude,
67
+ source: 'coordinates'
68
+ };
69
+ }
70
+ // Neither location_name nor coordinates provided
71
+ throw new Error('Either location_name OR (latitude + longitude) must be provided.\n\n' +
72
+ 'Examples:\n' +
73
+ ' - Using coordinates: latitude=47.6062, longitude=-122.3321\n' +
74
+ ' - Using saved location: location_name="home"\n\n' +
75
+ 'Use save_location to save frequently used locations.');
76
+ }
77
+ /**
78
+ * Resolve location coordinates from coordinates, saved location name, or city name (geocoded)
79
+ *
80
+ * Priority: coordinates > location_name > city_name
81
+ */
82
+ export async function resolveLocationAsync(args, locationStore, geocodingService) {
83
+ if (hasCoordinates(args)) {
84
+ validateLatitude(args.latitude);
85
+ validateLongitude(args.longitude);
86
+ return {
87
+ latitude: args.latitude,
88
+ longitude: args.longitude,
89
+ source: 'coordinates'
90
+ };
91
+ }
92
+ if (hasLocationName(args)) {
93
+ const locationName = args.location_name.trim();
94
+ if (locationName.length === 0) {
95
+ throw new Error('location_name cannot be empty');
96
+ }
97
+ return resolveSavedLocation(locationName, locationStore);
98
+ }
99
+ if (typeof args.city_name === 'string') {
100
+ const cityName = args.city_name.trim();
101
+ if (cityName.length === 0) {
102
+ throw new Error('city_name cannot be empty');
103
+ }
104
+ const results = await geocodingService.geocode(cityName, 1);
105
+ const match = results[0];
106
+ return {
107
+ latitude: match.latitude,
108
+ longitude: match.longitude,
109
+ source: 'geocoded',
110
+ display_name: match.display_name || match.name
111
+ };
112
+ }
113
+ throw new Error('Either city_name, location_name, OR (latitude + longitude) must be provided.\n\n' +
114
+ 'Examples:\n' +
115
+ ' - Using city name: city_name="Seattle, WA"\n' +
116
+ ' - Using coordinates: latitude=47.6062, longitude=-122.3321\n' +
117
+ ' - Using saved location: location_name="home"\n\n' +
118
+ 'Use save_location to save frequently used locations.');
119
+ }
120
+ //# sourceMappingURL=locationResolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locationResolver.js","sourceRoot":"","sources":["../../src/utils/locationResolver.ts"],"names":[],"mappings":"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"}