@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,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Data anonymization utilities for privacy-first analytics
|
|
3
|
+
* Ensures no PII is collected as per docs/ANALYTICS_MCP_PLAN.md
|
|
4
|
+
*/
|
|
5
|
+
import { AnalyticsEvent, AnalyticsLevel } from './types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Raw event data before anonymization
|
|
8
|
+
* Includes all possible fields that might be collected
|
|
9
|
+
*/
|
|
10
|
+
interface RawEventData {
|
|
11
|
+
version: string;
|
|
12
|
+
tool: string;
|
|
13
|
+
status: 'success' | 'error';
|
|
14
|
+
timestamp_hour: string;
|
|
15
|
+
analytics_level?: AnalyticsLevel;
|
|
16
|
+
error_type?: string;
|
|
17
|
+
response_time_ms?: number;
|
|
18
|
+
service?: string;
|
|
19
|
+
cache_hit?: boolean;
|
|
20
|
+
retry_count?: number;
|
|
21
|
+
country?: string;
|
|
22
|
+
parameters?: Record<string, unknown>;
|
|
23
|
+
session_id?: string;
|
|
24
|
+
sequence_number?: number;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Anonymize event data based on analytics level
|
|
28
|
+
* Strips sensitive information and ensures privacy compliance
|
|
29
|
+
*/
|
|
30
|
+
export declare function anonymizeEvent(rawData: RawEventData, level: AnalyticsLevel, salt?: string): AnalyticsEvent;
|
|
31
|
+
/**
|
|
32
|
+
* Round timestamp to nearest hour for privacy
|
|
33
|
+
* Prevents precise user tracking
|
|
34
|
+
*/
|
|
35
|
+
export declare function roundToHour(date: Date): string;
|
|
36
|
+
export {};
|
|
37
|
+
//# sourceMappingURL=anonymizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anonymizer.d.ts","sourceRoot":"","sources":["../../src/analytics/anonymizer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5D;;;GAGG;AACH,UAAU,YAAY;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,cAAc,CAAC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,YAAY,EACrB,KAAK,EAAE,cAAc,EACrB,IAAI,CAAC,EAAE,MAAM,GACZ,cAAc,CA0ChB;AAiED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAI9C"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Data anonymization utilities for privacy-first analytics
|
|
3
|
+
* Ensures no PII is collected as per docs/ANALYTICS_MCP_PLAN.md
|
|
4
|
+
*/
|
|
5
|
+
import crypto from 'crypto';
|
|
6
|
+
/**
|
|
7
|
+
* Anonymize event data based on analytics level
|
|
8
|
+
* Strips sensitive information and ensures privacy compliance
|
|
9
|
+
*/
|
|
10
|
+
export function anonymizeEvent(rawData, level, salt) {
|
|
11
|
+
// Base event (minimal level) - always included
|
|
12
|
+
const baseEvent = {
|
|
13
|
+
version: rawData.version,
|
|
14
|
+
tool: rawData.tool,
|
|
15
|
+
status: rawData.status,
|
|
16
|
+
timestamp_hour: rawData.timestamp_hour,
|
|
17
|
+
analytics_level: 'minimal',
|
|
18
|
+
...(rawData.status === 'error' && rawData.error_type ? { error_type: rawData.error_type } : {}),
|
|
19
|
+
};
|
|
20
|
+
// Return minimal level (no additional data)
|
|
21
|
+
if (level === 'minimal') {
|
|
22
|
+
return baseEvent;
|
|
23
|
+
}
|
|
24
|
+
// Standard level - add performance metrics
|
|
25
|
+
const standardEvent = {
|
|
26
|
+
...baseEvent,
|
|
27
|
+
analytics_level: 'standard',
|
|
28
|
+
...(rawData.response_time_ms !== undefined && { response_time_ms: rawData.response_time_ms }),
|
|
29
|
+
...(rawData.service && { service: rawData.service }),
|
|
30
|
+
...(rawData.cache_hit !== undefined && { cache_hit: rawData.cache_hit }),
|
|
31
|
+
...(rawData.retry_count !== undefined && { retry_count: rawData.retry_count }),
|
|
32
|
+
...(rawData.country && { country: rawData.country }),
|
|
33
|
+
};
|
|
34
|
+
// Return standard level
|
|
35
|
+
if (level === 'standard') {
|
|
36
|
+
return standardEvent;
|
|
37
|
+
}
|
|
38
|
+
// Detailed level - add anonymized workflow data
|
|
39
|
+
const detailedEvent = {
|
|
40
|
+
...standardEvent,
|
|
41
|
+
analytics_level: 'detailed',
|
|
42
|
+
...(rawData.parameters && { parameters: sanitizeParameters(rawData.parameters) }),
|
|
43
|
+
...(rawData.session_id && { session_id: hashSessionId(rawData.session_id, salt) }),
|
|
44
|
+
...(rawData.sequence_number !== undefined && { sequence_number: rawData.sequence_number }),
|
|
45
|
+
};
|
|
46
|
+
return detailedEvent;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Sanitize tool parameters - ONLY keep safe, non-identifying values
|
|
50
|
+
* NEVER include: coordinates, location names, user input
|
|
51
|
+
*/
|
|
52
|
+
function sanitizeParameters(params) {
|
|
53
|
+
const safe = {};
|
|
54
|
+
// Allowlist of safe parameters that don't contain PII
|
|
55
|
+
const allowedParams = [
|
|
56
|
+
'days',
|
|
57
|
+
'granularity',
|
|
58
|
+
'source',
|
|
59
|
+
'forecast_type',
|
|
60
|
+
'include_normals',
|
|
61
|
+
'include_fire_weather',
|
|
62
|
+
'include_severe_weather',
|
|
63
|
+
'active_only',
|
|
64
|
+
'limit',
|
|
65
|
+
'radius',
|
|
66
|
+
'units',
|
|
67
|
+
'hourly',
|
|
68
|
+
'daily',
|
|
69
|
+
];
|
|
70
|
+
for (const key of allowedParams) {
|
|
71
|
+
if (params[key] !== undefined) {
|
|
72
|
+
// Only include primitive values (no objects/arrays that might contain PII)
|
|
73
|
+
const value = params[key];
|
|
74
|
+
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
|
|
75
|
+
safe[key] = value;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// NEVER include these (blocklist for extra safety):
|
|
80
|
+
// - latitude, longitude, lat, lon
|
|
81
|
+
// - location, address, city, state, zip, postal_code
|
|
82
|
+
// - user, name, email, phone
|
|
83
|
+
// - any user-provided strings
|
|
84
|
+
return safe;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Create one-way hash of session ID
|
|
88
|
+
* Cannot be reversed to identify users
|
|
89
|
+
*/
|
|
90
|
+
function hashSessionId(sessionId, salt) {
|
|
91
|
+
// Salt should always be provided by config (auto-generated)
|
|
92
|
+
// Fallback to environment variable if somehow not provided
|
|
93
|
+
const sessionSalt = salt || process.env.ANALYTICS_SALT || '';
|
|
94
|
+
if (!sessionSalt) {
|
|
95
|
+
throw new Error('Analytics salt must be provided for session ID hashing');
|
|
96
|
+
}
|
|
97
|
+
return crypto
|
|
98
|
+
.createHash('sha256')
|
|
99
|
+
.update(sessionId + sessionSalt)
|
|
100
|
+
.digest('hex')
|
|
101
|
+
.substring(0, 16); // Shortened for storage efficiency
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Round timestamp to nearest hour for privacy
|
|
105
|
+
* Prevents precise user tracking
|
|
106
|
+
*/
|
|
107
|
+
export function roundToHour(date) {
|
|
108
|
+
const rounded = new Date(date);
|
|
109
|
+
rounded.setMinutes(0, 0, 0);
|
|
110
|
+
return rounded.toISOString();
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=anonymizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anonymizer.js","sourceRoot":"","sources":["../../src/analytics/anonymizer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analytics event collector and batch manager
|
|
3
|
+
* Buffers events in memory and periodically flushes to analytics server
|
|
4
|
+
*/
|
|
5
|
+
import { AnalyticsConfig, ToolExecutionMetadata } from './types.js';
|
|
6
|
+
/**
|
|
7
|
+
* AnalyticsCollector - Manages event buffering and batch sending
|
|
8
|
+
* Implements privacy-first analytics with automatic flushing
|
|
9
|
+
*/
|
|
10
|
+
export declare class AnalyticsCollector {
|
|
11
|
+
private buffer;
|
|
12
|
+
private config;
|
|
13
|
+
private flushTimer;
|
|
14
|
+
private sessionId;
|
|
15
|
+
private sequenceNumber;
|
|
16
|
+
private isShuttingDown;
|
|
17
|
+
private consecutiveFailures;
|
|
18
|
+
private circuitOpen;
|
|
19
|
+
private circuitOpenUntil;
|
|
20
|
+
private readonly MAX_CONSECUTIVE_FAILURES;
|
|
21
|
+
private readonly CIRCUIT_BREAKER_RESET_MS;
|
|
22
|
+
private errorCount;
|
|
23
|
+
private successCount;
|
|
24
|
+
private readonly ERROR_THRESHOLD;
|
|
25
|
+
private lastFlushTime;
|
|
26
|
+
private flushCount;
|
|
27
|
+
private readonly MIN_FLUSH_INTERVAL_MS;
|
|
28
|
+
private readonly MAX_FLUSHES_PER_HOUR;
|
|
29
|
+
private readonly MAX_EVENTS_PER_MINUTE;
|
|
30
|
+
private recentEventTimestamps;
|
|
31
|
+
private readonly MAX_BUFFER_SIZE;
|
|
32
|
+
private readonly FLUSH_INTERVAL_MS;
|
|
33
|
+
constructor(config: AnalyticsConfig);
|
|
34
|
+
/**
|
|
35
|
+
* Track a tool execution event
|
|
36
|
+
* Fails silently - analytics should never break the application
|
|
37
|
+
*/
|
|
38
|
+
trackToolCall(tool: string, status: 'success' | 'error', metadata?: ToolExecutionMetadata): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Flush buffered events to analytics server
|
|
41
|
+
* Called automatically on timer or when buffer is full
|
|
42
|
+
* Implements circuit breaker pattern (3.7)
|
|
43
|
+
*/
|
|
44
|
+
flush(): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* Start periodic flush timer
|
|
47
|
+
*/
|
|
48
|
+
private startFlushTimer;
|
|
49
|
+
/**
|
|
50
|
+
* Stop flush timer
|
|
51
|
+
*/
|
|
52
|
+
private stopFlushTimer;
|
|
53
|
+
/**
|
|
54
|
+
* Generate unique session ID
|
|
55
|
+
* Used for tracking tool call sequences in detailed mode
|
|
56
|
+
*/
|
|
57
|
+
private generateSessionId;
|
|
58
|
+
/**
|
|
59
|
+
* Public shutdown method called by main shutdown handler
|
|
60
|
+
* Ensures buffered events are sent before process exits
|
|
61
|
+
*/
|
|
62
|
+
shutdown(): Promise<void>;
|
|
63
|
+
/**
|
|
64
|
+
* Get current buffer size (for testing)
|
|
65
|
+
*/
|
|
66
|
+
getBufferSize(): number;
|
|
67
|
+
/**
|
|
68
|
+
* Get session ID (for testing)
|
|
69
|
+
*/
|
|
70
|
+
getSessionId(): string;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=collector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collector.d.ts","sourceRoot":"","sources":["../../src/analytics/collector.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,EAAE,eAAe,EAAkB,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAEpF;;;GAGG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,UAAU,CAA+B;IACjD,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,cAAc,CAAS;IAG/B,OAAO,CAAC,mBAAmB,CAAK;IAChC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,gBAAgB,CAAqB;IAC7C,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAK;IAC9C,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAiB;IAG1D,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAM;IAGtC,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAS;IAC/C,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAM;IAC3C,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAM;IAC5C,OAAO,CAAC,qBAAqB,CAAgB;IAE7C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAO;IACvC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAiB;gBAEvC,MAAM,EAAE,eAAe;IAanC;;;OAGG;IACU,aAAa,CACxB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,SAAS,GAAG,OAAO,EAC3B,QAAQ,GAAE,qBAA0B,GACnC,OAAO,CAAC,IAAI,CAAC;IA+GhB;;;;OAIG;IACU,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA6EnC;;OAEG;IACH,OAAO,CAAC,eAAe;IAavB;;OAEG;IACH,OAAO,CAAC,cAAc;IAOtB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAIzB;;;OAGG;IACU,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAmBtC;;OAEG;IACI,aAAa,IAAI,MAAM;IAI9B;;OAEG;IACI,YAAY,IAAI,MAAM;CAG9B"}
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analytics event collector and batch manager
|
|
3
|
+
* Buffers events in memory and periodically flushes to analytics server
|
|
4
|
+
*/
|
|
5
|
+
import crypto from 'crypto';
|
|
6
|
+
import { logger } from '../utils/logger.js';
|
|
7
|
+
import { anonymizeEvent, roundToHour } from './anonymizer.js';
|
|
8
|
+
import { sendBatch } from './transport.js';
|
|
9
|
+
/**
|
|
10
|
+
* AnalyticsCollector - Manages event buffering and batch sending
|
|
11
|
+
* Implements privacy-first analytics with automatic flushing
|
|
12
|
+
*/
|
|
13
|
+
export class AnalyticsCollector {
|
|
14
|
+
buffer = [];
|
|
15
|
+
config;
|
|
16
|
+
flushTimer = null;
|
|
17
|
+
sessionId;
|
|
18
|
+
sequenceNumber = 0;
|
|
19
|
+
isShuttingDown = false;
|
|
20
|
+
// Rate limiting state
|
|
21
|
+
consecutiveFailures = 0;
|
|
22
|
+
circuitOpen = false;
|
|
23
|
+
circuitOpenUntil = null;
|
|
24
|
+
MAX_CONSECUTIVE_FAILURES = 5;
|
|
25
|
+
CIRCUIT_BREAKER_RESET_MS = 5 * 60 * 1000; // 5 minutes
|
|
26
|
+
// Error tracking for health monitoring
|
|
27
|
+
errorCount = 0;
|
|
28
|
+
successCount = 0;
|
|
29
|
+
ERROR_THRESHOLD = 10; // Alert after 10 consecutive failures
|
|
30
|
+
// Rate limiting for event collection
|
|
31
|
+
lastFlushTime = 0;
|
|
32
|
+
flushCount = 0;
|
|
33
|
+
MIN_FLUSH_INTERVAL_MS = 30000; // 30 seconds minimum between flushes
|
|
34
|
+
MAX_FLUSHES_PER_HOUR = 20;
|
|
35
|
+
MAX_EVENTS_PER_MINUTE = 60;
|
|
36
|
+
recentEventTimestamps = [];
|
|
37
|
+
MAX_BUFFER_SIZE = 100;
|
|
38
|
+
FLUSH_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes
|
|
39
|
+
constructor(config) {
|
|
40
|
+
this.config = config;
|
|
41
|
+
this.sessionId = this.generateSessionId();
|
|
42
|
+
if (this.config.enabled) {
|
|
43
|
+
this.startFlushTimer();
|
|
44
|
+
logger.debug('Analytics collector initialized', {
|
|
45
|
+
level: this.config.level,
|
|
46
|
+
endpoint: this.config.endpoint,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Track a tool execution event
|
|
52
|
+
* Fails silently - analytics should never break the application
|
|
53
|
+
*/
|
|
54
|
+
async trackToolCall(tool, status, metadata = {}) {
|
|
55
|
+
if (!this.config.enabled || this.isShuttingDown) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
// SECURITY: Rate limit event collection (M-3)
|
|
60
|
+
const now = Date.now();
|
|
61
|
+
this.recentEventTimestamps.push(now);
|
|
62
|
+
// Remove timestamps older than 1 minute
|
|
63
|
+
this.recentEventTimestamps = this.recentEventTimestamps.filter(ts => now - ts < 60000);
|
|
64
|
+
// Check rate limit
|
|
65
|
+
if (this.recentEventTimestamps.length > this.MAX_EVENTS_PER_MINUTE) {
|
|
66
|
+
logger.warn('Analytics rate limit exceeded, dropping event', {
|
|
67
|
+
tool,
|
|
68
|
+
eventsPerMinute: this.recentEventTimestamps.length,
|
|
69
|
+
securityEvent: true
|
|
70
|
+
});
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
// Increment sequence number for detailed level
|
|
74
|
+
if (this.config.level === 'detailed') {
|
|
75
|
+
this.sequenceNumber++;
|
|
76
|
+
}
|
|
77
|
+
// Build raw event data
|
|
78
|
+
const rawData = {
|
|
79
|
+
version: this.config.version,
|
|
80
|
+
tool,
|
|
81
|
+
status,
|
|
82
|
+
timestamp_hour: roundToHour(new Date()),
|
|
83
|
+
analytics_level: this.config.level,
|
|
84
|
+
error_type: metadata.error_type,
|
|
85
|
+
response_time_ms: metadata.response_time_ms,
|
|
86
|
+
service: metadata.service,
|
|
87
|
+
cache_hit: metadata.cache_hit,
|
|
88
|
+
retry_count: metadata.retry_count,
|
|
89
|
+
country: metadata.country,
|
|
90
|
+
parameters: metadata.parameters,
|
|
91
|
+
session_id: undefined,
|
|
92
|
+
sequence_number: undefined,
|
|
93
|
+
};
|
|
94
|
+
// Add session tracking for detailed level
|
|
95
|
+
if (this.config.level === 'detailed') {
|
|
96
|
+
rawData.session_id = this.sessionId;
|
|
97
|
+
rawData.sequence_number = this.sequenceNumber;
|
|
98
|
+
}
|
|
99
|
+
// Anonymize event based on configured level (pass salt for session hashing)
|
|
100
|
+
const event = anonymizeEvent(rawData, this.config.level, this.config.salt);
|
|
101
|
+
// Add to buffer
|
|
102
|
+
this.buffer.push(event);
|
|
103
|
+
this.successCount++;
|
|
104
|
+
this.errorCount = 0; // Reset on success (L-2)
|
|
105
|
+
logger.debug('Analytics event tracked', {
|
|
106
|
+
tool,
|
|
107
|
+
status,
|
|
108
|
+
bufferSize: this.buffer.length,
|
|
109
|
+
});
|
|
110
|
+
// Flush if buffer is full (with rate limiting)
|
|
111
|
+
// Flush asynchronously to avoid blocking tool requests
|
|
112
|
+
if (this.buffer.length >= this.MAX_BUFFER_SIZE) {
|
|
113
|
+
const timeSinceLastFlush = now - this.lastFlushTime;
|
|
114
|
+
if (timeSinceLastFlush < this.MIN_FLUSH_INTERVAL_MS) {
|
|
115
|
+
logger.warn('Analytics flush rate limit hit, delaying', {
|
|
116
|
+
timeSinceLastFlush,
|
|
117
|
+
bufferSize: this.buffer.length,
|
|
118
|
+
securityEvent: true
|
|
119
|
+
});
|
|
120
|
+
return; // Don't flush, will be picked up by timer
|
|
121
|
+
}
|
|
122
|
+
// Schedule flush asynchronously to not block the tool request
|
|
123
|
+
setImmediate(() => {
|
|
124
|
+
this.flush().catch((err) => {
|
|
125
|
+
logger.warn('Async analytics flush error', {
|
|
126
|
+
error: err instanceof Error ? err.message : 'Unknown error',
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
// Fail silently - analytics should never break the application
|
|
134
|
+
this.errorCount++;
|
|
135
|
+
logger.warn('Analytics tracking error', {
|
|
136
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
137
|
+
tool,
|
|
138
|
+
consecutiveErrors: this.errorCount
|
|
139
|
+
});
|
|
140
|
+
// MONITORING: Alert on persistent failures (L-2)
|
|
141
|
+
if (this.errorCount >= this.ERROR_THRESHOLD) {
|
|
142
|
+
logger.error('Analytics system appears to be failing consistently', undefined, {
|
|
143
|
+
consecutiveErrors: this.errorCount,
|
|
144
|
+
successCount: this.successCount,
|
|
145
|
+
securityEvent: true
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Flush buffered events to analytics server
|
|
152
|
+
* Called automatically on timer or when buffer is full
|
|
153
|
+
* Implements circuit breaker pattern (3.7)
|
|
154
|
+
*/
|
|
155
|
+
async flush() {
|
|
156
|
+
if (!this.config.enabled || this.buffer.length === 0) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
// Check circuit breaker (3.7)
|
|
160
|
+
if (this.circuitOpen) {
|
|
161
|
+
if (this.circuitOpenUntil && new Date() < this.circuitOpenUntil) {
|
|
162
|
+
logger.debug('Analytics circuit breaker open, skipping flush', {
|
|
163
|
+
resetAt: this.circuitOpenUntil.toISOString(),
|
|
164
|
+
});
|
|
165
|
+
this.buffer = []; // Drop buffered events to prevent memory leak
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
// Try to close circuit
|
|
170
|
+
logger.info('Analytics circuit breaker attempting reset');
|
|
171
|
+
this.circuitOpen = false;
|
|
172
|
+
this.circuitOpenUntil = null;
|
|
173
|
+
this.consecutiveFailures = 0;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
const eventsToSend = [...this.buffer];
|
|
177
|
+
this.buffer = [];
|
|
178
|
+
// Track flush for rate limiting (M-3)
|
|
179
|
+
const now = Date.now();
|
|
180
|
+
this.lastFlushTime = now;
|
|
181
|
+
this.flushCount++;
|
|
182
|
+
// Reset counter every hour
|
|
183
|
+
if (this.flushCount > this.MAX_FLUSHES_PER_HOUR) {
|
|
184
|
+
logger.warn('Analytics flush count exceeded hourly limit', {
|
|
185
|
+
flushCount: this.flushCount,
|
|
186
|
+
securityEvent: true
|
|
187
|
+
});
|
|
188
|
+
// Continue but log for monitoring
|
|
189
|
+
}
|
|
190
|
+
try {
|
|
191
|
+
logger.debug('Flushing analytics batch', {
|
|
192
|
+
count: eventsToSend.length,
|
|
193
|
+
});
|
|
194
|
+
await sendBatch(eventsToSend, this.config.endpoint, this.config.version);
|
|
195
|
+
logger.debug('Analytics batch sent successfully', {
|
|
196
|
+
count: eventsToSend.length,
|
|
197
|
+
});
|
|
198
|
+
// Reset failure counter on success (3.7)
|
|
199
|
+
this.consecutiveFailures = 0;
|
|
200
|
+
}
|
|
201
|
+
catch (error) {
|
|
202
|
+
this.consecutiveFailures++;
|
|
203
|
+
logger.warn('Analytics batch send failed', {
|
|
204
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
205
|
+
count: eventsToSend.length,
|
|
206
|
+
consecutiveFailures: this.consecutiveFailures,
|
|
207
|
+
});
|
|
208
|
+
// Open circuit if too many failures (3.7)
|
|
209
|
+
if (this.consecutiveFailures >= this.MAX_CONSECUTIVE_FAILURES) {
|
|
210
|
+
this.circuitOpen = true;
|
|
211
|
+
this.circuitOpenUntil = new Date(Date.now() + this.CIRCUIT_BREAKER_RESET_MS);
|
|
212
|
+
logger.error('Analytics circuit breaker opened', undefined, {
|
|
213
|
+
consecutiveFailures: this.consecutiveFailures,
|
|
214
|
+
resetAt: this.circuitOpenUntil.toISOString(),
|
|
215
|
+
securityEvent: true,
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
// Don't re-queue events to avoid memory buildup
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Start periodic flush timer
|
|
223
|
+
*/
|
|
224
|
+
startFlushTimer() {
|
|
225
|
+
this.flushTimer = setInterval(() => {
|
|
226
|
+
this.flush().catch((err) => {
|
|
227
|
+
logger.warn('Analytics flush timer error', {
|
|
228
|
+
error: err instanceof Error ? err.message : 'Unknown error',
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
}, this.FLUSH_INTERVAL_MS);
|
|
232
|
+
// Don't prevent process exit
|
|
233
|
+
this.flushTimer.unref();
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Stop flush timer
|
|
237
|
+
*/
|
|
238
|
+
stopFlushTimer() {
|
|
239
|
+
if (this.flushTimer) {
|
|
240
|
+
clearInterval(this.flushTimer);
|
|
241
|
+
this.flushTimer = null;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Generate unique session ID
|
|
246
|
+
* Used for tracking tool call sequences in detailed mode
|
|
247
|
+
*/
|
|
248
|
+
generateSessionId() {
|
|
249
|
+
return crypto.randomBytes(16).toString('hex');
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Public shutdown method called by main shutdown handler
|
|
253
|
+
* Ensures buffered events are sent before process exits
|
|
254
|
+
*/
|
|
255
|
+
async shutdown() {
|
|
256
|
+
if (this.isShuttingDown) {
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
this.isShuttingDown = true;
|
|
260
|
+
logger.debug('Analytics shutdown initiated', {
|
|
261
|
+
bufferSize: this.buffer.length,
|
|
262
|
+
});
|
|
263
|
+
this.stopFlushTimer();
|
|
264
|
+
// Flush remaining events
|
|
265
|
+
if (this.buffer.length > 0) {
|
|
266
|
+
await this.flush();
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Get current buffer size (for testing)
|
|
271
|
+
*/
|
|
272
|
+
getBufferSize() {
|
|
273
|
+
return this.buffer.length;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Get session ID (for testing)
|
|
277
|
+
*/
|
|
278
|
+
getSessionId() {
|
|
279
|
+
return this.sessionId;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
//# sourceMappingURL=collector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collector.js","sourceRoot":"","sources":["../../src/analytics/collector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analytics configuration and singleton collector instance
|
|
3
|
+
* Loads settings from environment variables with secure defaults
|
|
4
|
+
*/
|
|
5
|
+
import { AnalyticsCollector } from './collector.js';
|
|
6
|
+
/**
|
|
7
|
+
* Singleton analytics collector instance
|
|
8
|
+
* Exported for use throughout the application
|
|
9
|
+
*/
|
|
10
|
+
export declare const analytics: AnalyticsCollector;
|
|
11
|
+
/**
|
|
12
|
+
* Re-export types for convenience
|
|
13
|
+
*/
|
|
14
|
+
export type { AnalyticsLevel, ToolExecutionMetadata } from './types.js';
|
|
15
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/analytics/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAUH,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AA+KpD;;;GAGG;AACH,eAAO,MAAM,SAAS,oBAAgD,CAAC;AAEvE;;GAEG;AACH,YAAY,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC"}
|