@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.
- package/LICENSE +21 -0
- package/README.md +1319 -0
- package/dist/analytics/anonymizer.d.ts +37 -0
- package/dist/analytics/anonymizer.d.ts.map +1 -0
- package/dist/analytics/anonymizer.js +112 -0
- package/dist/analytics/anonymizer.js.map +1 -0
- package/dist/analytics/collector.d.ts +72 -0
- package/dist/analytics/collector.d.ts.map +1 -0
- package/dist/analytics/collector.js +282 -0
- package/dist/analytics/collector.js.map +1 -0
- package/dist/analytics/config.d.ts +15 -0
- package/dist/analytics/config.d.ts.map +1 -0
- package/dist/analytics/config.js +172 -0
- package/dist/analytics/config.js.map +1 -0
- package/dist/analytics/index.d.ts +8 -0
- package/dist/analytics/index.d.ts.map +1 -0
- package/dist/analytics/index.js +7 -0
- package/dist/analytics/index.js.map +1 -0
- package/dist/analytics/middleware.d.ts +33 -0
- package/dist/analytics/middleware.d.ts.map +1 -0
- package/dist/analytics/middleware.js +99 -0
- package/dist/analytics/middleware.js.map +1 -0
- package/dist/analytics/transport.d.ts +11 -0
- package/dist/analytics/transport.d.ts.map +1 -0
- package/dist/analytics/transport.js +92 -0
- package/dist/analytics/transport.js.map +1 -0
- package/dist/analytics/types.d.ts +74 -0
- package/dist/analytics/types.d.ts.map +1 -0
- package/dist/analytics/types.js +6 -0
- package/dist/analytics/types.js.map +1 -0
- package/dist/config/api.d.ts +30 -0
- package/dist/config/api.d.ts.map +1 -0
- package/dist/config/api.js +32 -0
- package/dist/config/api.js.map +1 -0
- package/dist/config/cache.d.ts +31 -0
- package/dist/config/cache.d.ts.map +1 -0
- package/dist/config/cache.js +108 -0
- package/dist/config/cache.js.map +1 -0
- 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/config/tools.d.ts +44 -0
- package/dist/config/tools.d.ts.map +1 -0
- package/dist/config/tools.js +269 -0
- package/dist/config/tools.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 +171 -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 +98 -0
- package/dist/handlers/alertsHandler.js.map +1 -0
- package/dist/handlers/currentConditionsHandler.d.ts +13 -0
- package/dist/handlers/currentConditionsHandler.d.ts.map +1 -0
- package/dist/handlers/currentConditionsHandler.js +296 -0
- package/dist/handlers/currentConditionsHandler.js.map +1 -0
- package/dist/handlers/forecastHandler.d.ts +16 -0
- package/dist/handlers/forecastHandler.d.ts.map +1 -0
- package/dist/handlers/forecastHandler.js +454 -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/lightningHandler.d.ts +14 -0
- package/dist/handlers/lightningHandler.d.ts.map +1 -0
- package/dist/handlers/lightningHandler.js +258 -0
- package/dist/handlers/lightningHandler.js.map +1 -0
- package/dist/handlers/locationHandler.d.ts +12 -0
- package/dist/handlers/locationHandler.d.ts.map +1 -0
- package/dist/handlers/locationHandler.js +149 -0
- package/dist/handlers/locationHandler.js.map +1 -0
- package/dist/handlers/marineConditionsHandler.d.ts +13 -0
- package/dist/handlers/marineConditionsHandler.d.ts.map +1 -0
- package/dist/handlers/marineConditionsHandler.js +270 -0
- package/dist/handlers/marineConditionsHandler.js.map +1 -0
- package/dist/handlers/riverConditionsHandler.d.ts +11 -0
- package/dist/handlers/riverConditionsHandler.d.ts.map +1 -0
- package/dist/handlers/riverConditionsHandler.js +176 -0
- package/dist/handlers/riverConditionsHandler.js.map +1 -0
- package/dist/handlers/savedLocationsHandler.d.ts +50 -0
- package/dist/handlers/savedLocationsHandler.d.ts.map +1 -0
- package/dist/handlers/savedLocationsHandler.js +397 -0
- package/dist/handlers/savedLocationsHandler.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 +115 -0
- package/dist/handlers/statusHandler.js.map +1 -0
- package/dist/handlers/weatherImageryHandler.d.ts +14 -0
- package/dist/handlers/weatherImageryHandler.d.ts.map +1 -0
- package/dist/handlers/weatherImageryHandler.js +143 -0
- package/dist/handlers/weatherImageryHandler.js.map +1 -0
- package/dist/handlers/wildfireHandler.d.ts +11 -0
- package/dist/handlers/wildfireHandler.d.ts.map +1 -0
- package/dist/handlers/wildfireHandler.js +186 -0
- package/dist/handlers/wildfireHandler.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +735 -0
- package/dist/index.js.map +1 -0
- package/dist/services/blitzortung.d.ts +67 -0
- package/dist/services/blitzortung.d.ts.map +1 -0
- package/dist/services/blitzortung.js +475 -0
- package/dist/services/blitzortung.js.map +1 -0
- package/dist/services/geocoding.d.ts +57 -0
- package/dist/services/geocoding.d.ts.map +1 -0
- package/dist/services/geocoding.js +393 -0
- package/dist/services/geocoding.js.map +1 -0
- package/dist/services/locationStore.d.ts +62 -0
- package/dist/services/locationStore.d.ts.map +1 -0
- package/dist/services/locationStore.js +201 -0
- package/dist/services/locationStore.js.map +1 -0
- package/dist/services/ncei.d.ts +61 -0
- package/dist/services/ncei.d.ts.map +1 -0
- package/dist/services/ncei.js +126 -0
- package/dist/services/ncei.js.map +1 -0
- package/dist/services/nifc.d.ts +44 -0
- package/dist/services/nifc.d.ts.map +1 -0
- package/dist/services/nifc.js +159 -0
- package/dist/services/nifc.js.map +1 -0
- package/dist/services/noaa.d.ts +161 -0
- package/dist/services/noaa.d.ts.map +1 -0
- package/dist/services/noaa.js +681 -0
- package/dist/services/noaa.js.map +1 -0
- package/dist/services/nominatim.d.ts +62 -0
- package/dist/services/nominatim.d.ts.map +1 -0
- package/dist/services/nominatim.js +254 -0
- package/dist/services/nominatim.js.map +1 -0
- package/dist/services/openmeteo.d.ts +189 -0
- package/dist/services/openmeteo.d.ts.map +1 -0
- package/dist/services/openmeteo.js +936 -0
- package/dist/services/openmeteo.js.map +1 -0
- package/dist/services/rainviewer.d.ts +37 -0
- package/dist/services/rainviewer.d.ts.map +1 -0
- package/dist/services/rainviewer.js +115 -0
- package/dist/services/rainviewer.js.map +1 -0
- package/dist/types/imagery.d.ts +82 -0
- package/dist/types/imagery.d.ts.map +1 -0
- package/dist/types/imagery.js +6 -0
- package/dist/types/imagery.js.map +1 -0
- package/dist/types/lightning.d.ts +89 -0
- package/dist/types/lightning.d.ts.map +1 -0
- package/dist/types/lightning.js +6 -0
- package/dist/types/lightning.js.map +1 -0
- package/dist/types/noaa.d.ts +535 -0
- package/dist/types/noaa.d.ts.map +1 -0
- package/dist/types/noaa.js +5 -0
- package/dist/types/noaa.js.map +1 -0
- package/dist/types/nominatim.d.ts +72 -0
- package/dist/types/nominatim.d.ts.map +1 -0
- package/dist/types/nominatim.js +6 -0
- package/dist/types/nominatim.js.map +1 -0
- package/dist/types/openmeteo.d.ts +583 -0
- package/dist/types/openmeteo.d.ts.map +1 -0
- package/dist/types/openmeteo.js +6 -0
- package/dist/types/openmeteo.js.map +1 -0
- package/dist/types/savedLocations.d.ts +58 -0
- package/dist/types/savedLocations.d.ts.map +1 -0
- package/dist/types/savedLocations.js +5 -0
- package/dist/types/savedLocations.js.map +1 -0
- package/dist/types/wildfire.d.ts +83 -0
- package/dist/types/wildfire.d.ts.map +1 -0
- package/dist/types/wildfire.js +5 -0
- package/dist/types/wildfire.js.map +1 -0
- 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 +69 -0
- package/dist/utils/cache.d.ts.map +1 -0
- package/dist/utils/cache.js +164 -0
- package/dist/utils/cache.js.map +1 -0
- package/dist/utils/distance.d.ts +25 -0
- package/dist/utils/distance.d.ts.map +1 -0
- package/dist/utils/distance.js +40 -0
- package/dist/utils/distance.js.map +1 -0
- package/dist/utils/fireWeather.d.ts +76 -0
- package/dist/utils/fireWeather.d.ts.map +1 -0
- package/dist/utils/fireWeather.js +243 -0
- package/dist/utils/fireWeather.js.map +1 -0
- package/dist/utils/geography.d.ts +79 -0
- package/dist/utils/geography.d.ts.map +1 -0
- package/dist/utils/geography.js +266 -0
- package/dist/utils/geography.js.map +1 -0
- package/dist/utils/geohash.d.ts +62 -0
- package/dist/utils/geohash.d.ts.map +1 -0
- package/dist/utils/geohash.js +146 -0
- package/dist/utils/geohash.js.map +1 -0
- package/dist/utils/locationResolver.d.ts +34 -0
- package/dist/utils/locationResolver.d.ts.map +1 -0
- package/dist/utils/locationResolver.js +120 -0
- package/dist/utils/locationResolver.js.map +1 -0
- package/dist/utils/logger.d.ts +75 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +153 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/marine.d.ts +59 -0
- package/dist/utils/marine.d.ts.map +1 -0
- package/dist/utils/marine.js +215 -0
- package/dist/utils/marine.js.map +1 -0
- package/dist/utils/normals.d.ts +86 -0
- package/dist/utils/normals.d.ts.map +1 -0
- package/dist/utils/normals.js +223 -0
- package/dist/utils/normals.js.map +1 -0
- package/dist/utils/snow.d.ts +45 -0
- package/dist/utils/snow.d.ts.map +1 -0
- package/dist/utils/snow.js +144 -0
- package/dist/utils/snow.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/timezone.d.ts +56 -0
- package/dist/utils/timezone.d.ts.map +1 -0
- package/dist/utils/timezone.js +167 -0
- package/dist/utils/timezone.js.map +1 -0
- package/dist/utils/units.d.ts +69 -0
- package/dist/utils/units.d.ts.map +1 -0
- package/dist/utils/units.js +158 -0
- package/dist/utils/units.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/dist/utils/version.d.ts +15 -0
- package/dist/utils/version.d.ts.map +1 -0
- package/dist/utils/version.js +24 -0
- package/dist/utils/version.js.map +1 -0
- package/package.json +74 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured logging utility for MCP server
|
|
3
|
+
*
|
|
4
|
+
* IMPORTANT: MCP servers use stdio for communication, so all logging MUST go to stderr
|
|
5
|
+
* (console.error) to avoid interfering with the MCP protocol on stdout.
|
|
6
|
+
*/
|
|
7
|
+
export declare enum LogLevel {
|
|
8
|
+
DEBUG = 0,
|
|
9
|
+
INFO = 1,
|
|
10
|
+
WARN = 2,
|
|
11
|
+
ERROR = 3
|
|
12
|
+
}
|
|
13
|
+
export declare class Logger {
|
|
14
|
+
private level;
|
|
15
|
+
private context?;
|
|
16
|
+
constructor(level?: LogLevel, context?: string);
|
|
17
|
+
/**
|
|
18
|
+
* Create a child logger with a specific context
|
|
19
|
+
*/
|
|
20
|
+
child(context: string): Logger;
|
|
21
|
+
/**
|
|
22
|
+
* Set the logging level
|
|
23
|
+
*/
|
|
24
|
+
setLevel(level: LogLevel): void;
|
|
25
|
+
/**
|
|
26
|
+
* Internal logging method
|
|
27
|
+
*/
|
|
28
|
+
private log;
|
|
29
|
+
/**
|
|
30
|
+
* Log debug message (detailed information for diagnosing problems)
|
|
31
|
+
*/
|
|
32
|
+
debug(message: string, metadata?: Record<string, any>): void;
|
|
33
|
+
/**
|
|
34
|
+
* Log info message (general informational messages)
|
|
35
|
+
*/
|
|
36
|
+
info(message: string, metadata?: Record<string, any>): void;
|
|
37
|
+
/**
|
|
38
|
+
* Log warning message (warning messages for potentially harmful situations)
|
|
39
|
+
*/
|
|
40
|
+
warn(message: string, metadata?: Record<string, any>): void;
|
|
41
|
+
/**
|
|
42
|
+
* Log error message (error events that might still allow the application to continue)
|
|
43
|
+
*/
|
|
44
|
+
error(message: string, error?: Error, metadata?: Record<string, any>): void;
|
|
45
|
+
/**
|
|
46
|
+
* Log API request
|
|
47
|
+
*/
|
|
48
|
+
logApiRequest(service: string, endpoint: string, metadata?: Record<string, any>): void;
|
|
49
|
+
/**
|
|
50
|
+
* Log API response
|
|
51
|
+
*/
|
|
52
|
+
logApiResponse(service: string, endpoint: string, success: boolean, duration?: number): void;
|
|
53
|
+
/**
|
|
54
|
+
* Log cache operation
|
|
55
|
+
*/
|
|
56
|
+
logCacheOperation(operation: 'hit' | 'miss' | 'set' | 'evict', key: string): void;
|
|
57
|
+
}
|
|
58
|
+
export declare const logger: Logger;
|
|
59
|
+
/**
|
|
60
|
+
* Round coordinates for logging to protect user privacy
|
|
61
|
+
* Reduces precision to ~1.1km accuracy (2 decimal places)
|
|
62
|
+
* Set LOG_PII=true environment variable to log full precision (not recommended for production)
|
|
63
|
+
*
|
|
64
|
+
* Privacy rationale: Precise coordinates can reveal sensitive locations (homes, workplaces).
|
|
65
|
+
* Rounded coordinates provide sufficient context for debugging while protecting user privacy.
|
|
66
|
+
*
|
|
67
|
+
* @param latitude - Original latitude
|
|
68
|
+
* @param longitude - Original longitude
|
|
69
|
+
* @returns Rounded coordinates object
|
|
70
|
+
*/
|
|
71
|
+
export declare function redactCoordinatesForLogging(latitude: number, longitude: number): {
|
|
72
|
+
lat: number;
|
|
73
|
+
lon: number;
|
|
74
|
+
};
|
|
75
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,oBAAY,QAAQ;IAClB,KAAK,IAAI;IACT,IAAI,IAAI;IACR,IAAI,IAAI;IACR,KAAK,IAAI;CACV;AAeD,qBAAa,MAAM;IACjB,OAAO,CAAC,KAAK,CAAW;IACxB,OAAO,CAAC,OAAO,CAAC,CAAS;gBAEb,KAAK,GAAE,QAAwB,EAAE,OAAO,CAAC,EAAE,MAAM;IAK7D;;OAEG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAI9B;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI;IAI/B;;OAEG;IACH,OAAO,CAAC,GAAG;IA8BX;;OAEG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IAI5D;;OAEG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IAI3D;;OAEG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IAI3D;;OAEG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IAI3E;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IAQtF;;OAEG;IACH,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI;IAU5F;;OAEG;IACH,iBAAiB,CAAC,SAAS,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;CAGlF;AAkBD,eAAO,MAAM,MAAM,QAAwB,CAAC;AAE5C;;;;;;;;;;;GAWG;AACH,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAc7G"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured logging utility for MCP server
|
|
3
|
+
*
|
|
4
|
+
* IMPORTANT: MCP servers use stdio for communication, so all logging MUST go to stderr
|
|
5
|
+
* (console.error) to avoid interfering with the MCP protocol on stdout.
|
|
6
|
+
*/
|
|
7
|
+
export var LogLevel;
|
|
8
|
+
(function (LogLevel) {
|
|
9
|
+
LogLevel[LogLevel["DEBUG"] = 0] = "DEBUG";
|
|
10
|
+
LogLevel[LogLevel["INFO"] = 1] = "INFO";
|
|
11
|
+
LogLevel[LogLevel["WARN"] = 2] = "WARN";
|
|
12
|
+
LogLevel[LogLevel["ERROR"] = 3] = "ERROR";
|
|
13
|
+
})(LogLevel || (LogLevel = {}));
|
|
14
|
+
export class Logger {
|
|
15
|
+
level;
|
|
16
|
+
context;
|
|
17
|
+
constructor(level = LogLevel.INFO, context) {
|
|
18
|
+
this.level = level;
|
|
19
|
+
this.context = context;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Create a child logger with a specific context
|
|
23
|
+
*/
|
|
24
|
+
child(context) {
|
|
25
|
+
return new Logger(this.level, context);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Set the logging level
|
|
29
|
+
*/
|
|
30
|
+
setLevel(level) {
|
|
31
|
+
this.level = level;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Internal logging method
|
|
35
|
+
*/
|
|
36
|
+
log(level, message, metadata, error) {
|
|
37
|
+
// Skip if below current log level
|
|
38
|
+
if (level < this.level)
|
|
39
|
+
return;
|
|
40
|
+
const entry = {
|
|
41
|
+
timestamp: new Date().toISOString(),
|
|
42
|
+
level: LogLevel[level],
|
|
43
|
+
message,
|
|
44
|
+
};
|
|
45
|
+
if (this.context) {
|
|
46
|
+
entry.context = this.context;
|
|
47
|
+
}
|
|
48
|
+
if (error) {
|
|
49
|
+
entry.error = {
|
|
50
|
+
message: error.message,
|
|
51
|
+
stack: error.stack,
|
|
52
|
+
code: error.code,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
if (metadata) {
|
|
56
|
+
entry.metadata = metadata;
|
|
57
|
+
}
|
|
58
|
+
// Output to stderr for MCP compatibility
|
|
59
|
+
console.error(JSON.stringify(entry));
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Log debug message (detailed information for diagnosing problems)
|
|
63
|
+
*/
|
|
64
|
+
debug(message, metadata) {
|
|
65
|
+
this.log(LogLevel.DEBUG, message, metadata);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Log info message (general informational messages)
|
|
69
|
+
*/
|
|
70
|
+
info(message, metadata) {
|
|
71
|
+
this.log(LogLevel.INFO, message, metadata);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Log warning message (warning messages for potentially harmful situations)
|
|
75
|
+
*/
|
|
76
|
+
warn(message, metadata) {
|
|
77
|
+
this.log(LogLevel.WARN, message, metadata);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Log error message (error events that might still allow the application to continue)
|
|
81
|
+
*/
|
|
82
|
+
error(message, error, metadata) {
|
|
83
|
+
this.log(LogLevel.ERROR, message, metadata, error);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Log API request
|
|
87
|
+
*/
|
|
88
|
+
logApiRequest(service, endpoint, metadata) {
|
|
89
|
+
this.debug(`API request to ${service}`, {
|
|
90
|
+
service,
|
|
91
|
+
endpoint,
|
|
92
|
+
...metadata,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Log API response
|
|
97
|
+
*/
|
|
98
|
+
logApiResponse(service, endpoint, success, duration) {
|
|
99
|
+
const level = success ? LogLevel.DEBUG : LogLevel.WARN;
|
|
100
|
+
this.log(level, `API response from ${service}`, {
|
|
101
|
+
service,
|
|
102
|
+
endpoint,
|
|
103
|
+
success,
|
|
104
|
+
duration,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Log cache operation
|
|
109
|
+
*/
|
|
110
|
+
logCacheOperation(operation, key) {
|
|
111
|
+
this.debug(`Cache ${operation}`, { operation, key });
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Create the default logger instance
|
|
116
|
+
* Level is controlled by LOG_LEVEL environment variable
|
|
117
|
+
*/
|
|
118
|
+
function createDefaultLogger() {
|
|
119
|
+
const levelStr = process.env.LOG_LEVEL?.toUpperCase();
|
|
120
|
+
let level = LogLevel.INFO; // Default to INFO
|
|
121
|
+
if (levelStr && levelStr in LogLevel) {
|
|
122
|
+
level = LogLevel[levelStr];
|
|
123
|
+
}
|
|
124
|
+
return new Logger(level);
|
|
125
|
+
}
|
|
126
|
+
// Export singleton instance
|
|
127
|
+
export const logger = createDefaultLogger();
|
|
128
|
+
/**
|
|
129
|
+
* Round coordinates for logging to protect user privacy
|
|
130
|
+
* Reduces precision to ~1.1km accuracy (2 decimal places)
|
|
131
|
+
* Set LOG_PII=true environment variable to log full precision (not recommended for production)
|
|
132
|
+
*
|
|
133
|
+
* Privacy rationale: Precise coordinates can reveal sensitive locations (homes, workplaces).
|
|
134
|
+
* Rounded coordinates provide sufficient context for debugging while protecting user privacy.
|
|
135
|
+
*
|
|
136
|
+
* @param latitude - Original latitude
|
|
137
|
+
* @param longitude - Original longitude
|
|
138
|
+
* @returns Rounded coordinates object
|
|
139
|
+
*/
|
|
140
|
+
export function redactCoordinatesForLogging(latitude, longitude) {
|
|
141
|
+
// Check if PII logging is explicitly enabled (not recommended)
|
|
142
|
+
const logPII = process.env.LOG_PII === 'true';
|
|
143
|
+
if (logPII) {
|
|
144
|
+
return { lat: latitude, lon: longitude };
|
|
145
|
+
}
|
|
146
|
+
// Round to 2 decimal places (~1.1km precision at equator)
|
|
147
|
+
// This balances GDPR/CPRA data minimization with operational observability
|
|
148
|
+
return {
|
|
149
|
+
lat: Math.round(latitude * 100) / 100,
|
|
150
|
+
lon: Math.round(longitude * 100) / 100
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for marine conditions data formatting and interpretation
|
|
3
|
+
*/
|
|
4
|
+
import type { GridpointResponse } from '../types/noaa.js';
|
|
5
|
+
/**
|
|
6
|
+
* NOAA Marine Conditions extracted from gridpoint data
|
|
7
|
+
*/
|
|
8
|
+
export interface NOAAMarineConditions {
|
|
9
|
+
waveHeight?: number;
|
|
10
|
+
wavePeriod?: number;
|
|
11
|
+
waveDirection?: number;
|
|
12
|
+
windSpeed?: number;
|
|
13
|
+
windDirection?: number;
|
|
14
|
+
windGust?: number;
|
|
15
|
+
timestamp: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Extract marine conditions from NOAA gridpoint response
|
|
19
|
+
*/
|
|
20
|
+
export declare function extractNOAAMarineConditions(gridpoint: GridpointResponse): NOAAMarineConditions | null;
|
|
21
|
+
/**
|
|
22
|
+
* Format wave height with appropriate units and precision
|
|
23
|
+
*/
|
|
24
|
+
export declare function formatWaveHeight(meters: number | undefined): string;
|
|
25
|
+
/**
|
|
26
|
+
* Format wave period with units
|
|
27
|
+
*/
|
|
28
|
+
export declare function formatWavePeriod(seconds: number | undefined): string;
|
|
29
|
+
/**
|
|
30
|
+
* Format wind speed with units (converts km/h to knots for marine)
|
|
31
|
+
*/
|
|
32
|
+
export declare function formatWindSpeed(kmh: number | undefined): string;
|
|
33
|
+
/**
|
|
34
|
+
* Format ocean current velocity
|
|
35
|
+
*/
|
|
36
|
+
export declare function formatCurrentVelocity(metersPerSecond: number | undefined): string;
|
|
37
|
+
/**
|
|
38
|
+
* Convert degrees to cardinal/ordinal direction
|
|
39
|
+
*/
|
|
40
|
+
export declare function formatDirection(degrees: number | undefined): string;
|
|
41
|
+
/**
|
|
42
|
+
* Categorize wave height
|
|
43
|
+
*/
|
|
44
|
+
export interface WaveHeightCategory {
|
|
45
|
+
description: string;
|
|
46
|
+
level: string;
|
|
47
|
+
recommendation: string;
|
|
48
|
+
}
|
|
49
|
+
export declare function getWaveHeightCategory(meters: number | undefined): WaveHeightCategory;
|
|
50
|
+
/**
|
|
51
|
+
* Overall safety assessment based on multiple factors
|
|
52
|
+
*/
|
|
53
|
+
export interface SafetyAssessment {
|
|
54
|
+
level: string;
|
|
55
|
+
description: string;
|
|
56
|
+
recommendation: string;
|
|
57
|
+
}
|
|
58
|
+
export declare function getSafetyAssessment(totalWaveHeight: number | undefined, windWaveHeight: number | undefined, swellHeight: number | undefined, wavePeriod: number | undefined): SafetyAssessment;
|
|
59
|
+
//# sourceMappingURL=marine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"marine.d.ts","sourceRoot":"","sources":["../../src/utils/marine.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAuB,MAAM,kBAAkB,CAAC;AAE/E;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAqBD;;GAEG;AACH,wBAAgB,2BAA2B,CAAC,SAAS,EAAE,iBAAiB,GAAG,oBAAoB,GAAG,IAAI,CAyBrG;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAOnE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAMpE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAQ/D;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,eAAe,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAQjF;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAmBnE;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,kBAAkB,CAiEpF;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,mBAAmB,CACjC,eAAe,EAAE,MAAM,GAAG,SAAS,EACnC,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,UAAU,EAAE,MAAM,GAAG,SAAS,GAC7B,gBAAgB,CAoClB"}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for marine conditions data formatting and interpretation
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Extract current value from a gridpoint data series
|
|
6
|
+
*/
|
|
7
|
+
function extractCurrentValue(series) {
|
|
8
|
+
if (!series || !series.values || series.values.length === 0) {
|
|
9
|
+
return undefined;
|
|
10
|
+
}
|
|
11
|
+
// Find the first valid value (gridpoint data is time-ordered)
|
|
12
|
+
for (const entry of series.values) {
|
|
13
|
+
const value = entry.value;
|
|
14
|
+
if (value !== null && value !== undefined) {
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Extract marine conditions from NOAA gridpoint response
|
|
22
|
+
*/
|
|
23
|
+
export function extractNOAAMarineConditions(gridpoint) {
|
|
24
|
+
const props = gridpoint.properties;
|
|
25
|
+
// Extract marine data
|
|
26
|
+
const waveHeight = extractCurrentValue(props.waveHeight);
|
|
27
|
+
const wavePeriod = extractCurrentValue(props.wavePeriod);
|
|
28
|
+
const waveDirection = extractCurrentValue(props.waveDirection);
|
|
29
|
+
const windSpeed = extractCurrentValue(props.windSpeed);
|
|
30
|
+
const windDirection = extractCurrentValue(props.windDirection);
|
|
31
|
+
const windGust = extractCurrentValue(props.windGust);
|
|
32
|
+
// Check if we have any marine data
|
|
33
|
+
if (waveHeight === undefined && wavePeriod === undefined && waveDirection === undefined) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
waveHeight,
|
|
38
|
+
wavePeriod,
|
|
39
|
+
waveDirection,
|
|
40
|
+
windSpeed,
|
|
41
|
+
windDirection,
|
|
42
|
+
windGust,
|
|
43
|
+
timestamp: props.updateTime
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Format wave height with appropriate units and precision
|
|
48
|
+
*/
|
|
49
|
+
export function formatWaveHeight(meters) {
|
|
50
|
+
if (meters === undefined || meters === null) {
|
|
51
|
+
return 'N/A';
|
|
52
|
+
}
|
|
53
|
+
const feet = meters * 3.28084;
|
|
54
|
+
return `${meters.toFixed(1)}m (${feet.toFixed(1)}ft)`;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Format wave period with units
|
|
58
|
+
*/
|
|
59
|
+
export function formatWavePeriod(seconds) {
|
|
60
|
+
if (seconds === undefined || seconds === null) {
|
|
61
|
+
return 'N/A';
|
|
62
|
+
}
|
|
63
|
+
return `${seconds.toFixed(1)}s`;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Format wind speed with units (converts km/h to knots for marine)
|
|
67
|
+
*/
|
|
68
|
+
export function formatWindSpeed(kmh) {
|
|
69
|
+
if (kmh === undefined || kmh === null) {
|
|
70
|
+
return 'N/A';
|
|
71
|
+
}
|
|
72
|
+
// Convert km/h to knots (1 km/h = 0.539957 knots)
|
|
73
|
+
const knots = kmh * 0.539957;
|
|
74
|
+
return `${knots.toFixed(1)} knots (${kmh.toFixed(1)} km/h)`;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Format ocean current velocity
|
|
78
|
+
*/
|
|
79
|
+
export function formatCurrentVelocity(metersPerSecond) {
|
|
80
|
+
if (metersPerSecond === undefined || metersPerSecond === null) {
|
|
81
|
+
return 'N/A';
|
|
82
|
+
}
|
|
83
|
+
// Convert m/s to knots (1 m/s = 1.94384 knots)
|
|
84
|
+
const knots = metersPerSecond * 1.94384;
|
|
85
|
+
return `${metersPerSecond.toFixed(2)} m/s (${knots.toFixed(2)} knots)`;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Convert degrees to cardinal/ordinal direction
|
|
89
|
+
*/
|
|
90
|
+
export function formatDirection(degrees) {
|
|
91
|
+
if (degrees === undefined || degrees === null) {
|
|
92
|
+
return 'N/A';
|
|
93
|
+
}
|
|
94
|
+
const directions = [
|
|
95
|
+
'N', 'NNE', 'NE', 'ENE',
|
|
96
|
+
'E', 'ESE', 'SE', 'SSE',
|
|
97
|
+
'S', 'SSW', 'SW', 'WSW',
|
|
98
|
+
'W', 'WNW', 'NW', 'NNW'
|
|
99
|
+
];
|
|
100
|
+
// Normalize to 0-360
|
|
101
|
+
const normalized = ((degrees % 360) + 360) % 360;
|
|
102
|
+
// Calculate index (16 directions, each 22.5 degrees)
|
|
103
|
+
const index = Math.round(normalized / 22.5) % 16;
|
|
104
|
+
return `${directions[index]} (${Math.round(normalized)}°)`;
|
|
105
|
+
}
|
|
106
|
+
export function getWaveHeightCategory(meters) {
|
|
107
|
+
if (meters === undefined || meters === null) {
|
|
108
|
+
return {
|
|
109
|
+
description: 'Unknown',
|
|
110
|
+
level: 'Unknown',
|
|
111
|
+
recommendation: 'No data available'
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
// Based on WMO Sea State Code and Douglas Sea Scale
|
|
115
|
+
if (meters < 0.1) {
|
|
116
|
+
return {
|
|
117
|
+
description: 'Calm (glassy)',
|
|
118
|
+
level: 'Calm',
|
|
119
|
+
recommendation: 'Ideal for all water activities'
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
else if (meters < 0.5) {
|
|
123
|
+
return {
|
|
124
|
+
description: 'Calm (rippled)',
|
|
125
|
+
level: 'Calm',
|
|
126
|
+
recommendation: 'Excellent conditions for all vessels'
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
else if (meters < 1.25) {
|
|
130
|
+
return {
|
|
131
|
+
description: 'Smooth',
|
|
132
|
+
level: 'Slight',
|
|
133
|
+
recommendation: 'Good conditions for most activities'
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
else if (meters < 2.5) {
|
|
137
|
+
return {
|
|
138
|
+
description: 'Slight',
|
|
139
|
+
level: 'Moderate',
|
|
140
|
+
recommendation: 'Safe for experienced boaters'
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
else if (meters < 4.0) {
|
|
144
|
+
return {
|
|
145
|
+
description: 'Moderate',
|
|
146
|
+
level: 'Moderate',
|
|
147
|
+
recommendation: 'Use caution, especially for small craft'
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
else if (meters < 6.0) {
|
|
151
|
+
return {
|
|
152
|
+
description: 'Rough',
|
|
153
|
+
level: 'Rough',
|
|
154
|
+
recommendation: 'Hazardous for small vessels, secure all gear'
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
else if (meters < 9.0) {
|
|
158
|
+
return {
|
|
159
|
+
description: 'Very Rough',
|
|
160
|
+
level: 'Very Rough',
|
|
161
|
+
recommendation: 'Dangerous conditions, avoid non-essential travel'
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
else if (meters < 14.0) {
|
|
165
|
+
return {
|
|
166
|
+
description: 'High',
|
|
167
|
+
level: 'High',
|
|
168
|
+
recommendation: 'Very dangerous, only experienced vessels should be out'
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
return {
|
|
173
|
+
description: 'Very High',
|
|
174
|
+
level: 'Extreme',
|
|
175
|
+
recommendation: 'Extremely dangerous, all vessels should seek shelter'
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
export function getSafetyAssessment(totalWaveHeight, windWaveHeight, swellHeight, wavePeriod) {
|
|
180
|
+
if (totalWaveHeight === undefined || totalWaveHeight === null) {
|
|
181
|
+
return {
|
|
182
|
+
level: 'Unknown',
|
|
183
|
+
description: 'Marine conditions data not available',
|
|
184
|
+
recommendation: 'Consult local marine forecast'
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
const waveCategory = getWaveHeightCategory(totalWaveHeight);
|
|
188
|
+
// Adjust based on wave period (short period = choppy/uncomfortable)
|
|
189
|
+
let adjustedDescription = waveCategory.description;
|
|
190
|
+
if (wavePeriod !== undefined && wavePeriod < 6 && totalWaveHeight > 1.0) {
|
|
191
|
+
adjustedDescription += ' and choppy (short period)';
|
|
192
|
+
}
|
|
193
|
+
else if (wavePeriod !== undefined && wavePeriod > 12 && totalWaveHeight > 2.0) {
|
|
194
|
+
adjustedDescription += ' with long-period swell (powerful)';
|
|
195
|
+
}
|
|
196
|
+
// Add context about wind vs swell
|
|
197
|
+
let context = '';
|
|
198
|
+
if (windWaveHeight !== undefined && swellHeight !== undefined) {
|
|
199
|
+
if (windWaveHeight > swellHeight * 1.5) {
|
|
200
|
+
context = ' Conditions dominated by local wind waves.';
|
|
201
|
+
}
|
|
202
|
+
else if (swellHeight > windWaveHeight * 1.5) {
|
|
203
|
+
context = ' Conditions dominated by swell from distant systems.';
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
context = ' Mixed wind and swell conditions.';
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return {
|
|
210
|
+
level: waveCategory.level,
|
|
211
|
+
description: adjustedDescription + context,
|
|
212
|
+
recommendation: waveCategory.recommendation
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=marine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"marine.js","sourceRoot":"","sources":["../../src/utils/marine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for computing climate normals from historical data
|
|
3
|
+
*
|
|
4
|
+
* Climate normals are 30-year averages (1991-2020) used to provide
|
|
5
|
+
* context for current weather conditions.
|
|
6
|
+
*
|
|
7
|
+
* Hybrid Strategy:
|
|
8
|
+
* 1. Try NCEI (US only, requires token) for official normals
|
|
9
|
+
* 2. Fall back to Open-Meteo (global, no token) computed normals
|
|
10
|
+
*/
|
|
11
|
+
import type { OpenMeteoHistoricalResponse, ClimateNormals } from '../types/openmeteo.js';
|
|
12
|
+
import type { OpenMeteoService } from '../services/openmeteo.js';
|
|
13
|
+
import type { NCEIService } from '../services/ncei.js';
|
|
14
|
+
/**
|
|
15
|
+
* Compute climate normals from 30 years of historical data
|
|
16
|
+
*
|
|
17
|
+
* @param historicalData - 30 years of daily historical weather data from Open-Meteo
|
|
18
|
+
* @param targetMonth - Month (1-12) to compute normals for
|
|
19
|
+
* @param targetDay - Day of month (1-31) to compute normals for
|
|
20
|
+
* @returns Climate normals (30-year averages) for the specified date
|
|
21
|
+
*/
|
|
22
|
+
export declare function computeNormalsFrom30YearData(historicalData: OpenMeteoHistoricalResponse, targetMonth: number, targetDay: number): ClimateNormals;
|
|
23
|
+
/**
|
|
24
|
+
* Generate a cache key for climate normals
|
|
25
|
+
*
|
|
26
|
+
* @param latitude - Latitude (rounded to 2 decimals)
|
|
27
|
+
* @param longitude - Longitude (rounded to 2 decimals)
|
|
28
|
+
* @param month - Month (1-12)
|
|
29
|
+
* @param day - Day of month (1-31)
|
|
30
|
+
* @returns Cache key string
|
|
31
|
+
*/
|
|
32
|
+
export declare function getNormalsCacheKey(latitude: number, longitude: number, month: number, day: number): string;
|
|
33
|
+
/**
|
|
34
|
+
* Calculate departure from normal
|
|
35
|
+
*
|
|
36
|
+
* @param actual - Actual temperature value
|
|
37
|
+
* @param normal - Normal (average) temperature value
|
|
38
|
+
* @returns Departure with sign (e.g., +10, -5)
|
|
39
|
+
*/
|
|
40
|
+
export declare function calculateDeparture(actual: number, normal: number): string;
|
|
41
|
+
/**
|
|
42
|
+
* Format climate normals for display
|
|
43
|
+
*
|
|
44
|
+
* @param normals - Climate normals data
|
|
45
|
+
* @param currentTemp - Optional current temperature for comparison
|
|
46
|
+
* @returns Formatted markdown string
|
|
47
|
+
*/
|
|
48
|
+
export declare function formatNormals(normals: ClimateNormals, currentTemp?: {
|
|
49
|
+
high?: number;
|
|
50
|
+
low?: number;
|
|
51
|
+
}): string;
|
|
52
|
+
/**
|
|
53
|
+
* Get date components from Date object or ISO string
|
|
54
|
+
*
|
|
55
|
+
* @param date - Date object or ISO string
|
|
56
|
+
* @returns Object with month (1-12) and day (1-31)
|
|
57
|
+
*/
|
|
58
|
+
export declare function getDateComponents(date: Date | string): {
|
|
59
|
+
month: number;
|
|
60
|
+
day: number;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Check if coordinates are within the contiguous United States
|
|
64
|
+
*
|
|
65
|
+
* @param latitude - Latitude
|
|
66
|
+
* @param longitude - Longitude
|
|
67
|
+
* @returns true if location is in contiguous US
|
|
68
|
+
*/
|
|
69
|
+
export declare function isLocationInUS(latitude: number, longitude: number): boolean;
|
|
70
|
+
/**
|
|
71
|
+
* Get climate normals using hybrid strategy
|
|
72
|
+
*
|
|
73
|
+
* Strategy:
|
|
74
|
+
* 1. If location is in US and NCEI token available, try NCEI first
|
|
75
|
+
* 2. Fall back to Open-Meteo computed normals (always works)
|
|
76
|
+
*
|
|
77
|
+
* @param openMeteoService - Open-Meteo service instance
|
|
78
|
+
* @param nceiService - NCEI service instance (optional)
|
|
79
|
+
* @param latitude - Latitude
|
|
80
|
+
* @param longitude - Longitude
|
|
81
|
+
* @param month - Month (1-12)
|
|
82
|
+
* @param day - Day of month (1-31)
|
|
83
|
+
* @returns Climate normals with source indication
|
|
84
|
+
*/
|
|
85
|
+
export declare function getClimateNormals(openMeteoService: OpenMeteoService, nceiService: NCEIService | undefined, latitude: number, longitude: number, month: number, day: number): Promise<ClimateNormals>;
|
|
86
|
+
//# sourceMappingURL=normals.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normals.d.ts","sourceRoot":"","sources":["../../src/utils/normals.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,2BAA2B,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEzF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAUvD;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAC1C,cAAc,EAAE,2BAA2B,EAC3C,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,cAAc,CAsDhB;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,GACV,MAAM,CAKR;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAGzE;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,cAAc,EACvB,WAAW,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAC5C,MAAM,CAkCR;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAMrF;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAU3E;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,iBAAiB,CACrC,gBAAgB,EAAE,gBAAgB,EAClC,WAAW,EAAE,WAAW,GAAG,SAAS,EACpC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,cAAc,CAAC,CA8CzB"}
|