@happyvertical/weather 0.74.8

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/AGENT.md ADDED
@@ -0,0 +1,33 @@
1
+ # @happyvertical/weather
2
+
3
+ <!-- BEGIN AGENT:GENERATED -->
4
+ ## Purpose
5
+ Weather data provider abstraction for HAppyVertical SDK
6
+
7
+ ## Package Map
8
+ - Package: `@happyvertical/weather`
9
+ - Hierarchy path: `@happyvertical/sdk > packages > weather`
10
+ - Workspace position: `30 of 30` local packages
11
+ - Internal dependencies: `@happyvertical/utils`
12
+ - Internal dependents: none
13
+ - Knowledge graph files: `AGENT.md`, `metadata.json`, `ecosystem-manifest.json`
14
+
15
+ ## Build & Test
16
+ ```bash
17
+ pnpm --filter @happyvertical/weather build
18
+ pnpm --filter @happyvertical/weather test
19
+ pnpm --filter @happyvertical/weather clean
20
+ ```
21
+
22
+ ## Agent Correction Loops
23
+ - If module resolution or export errors mention a workspace dependency, build the dependency first (`pnpm --filter @happyvertical/utils build`) and then rerun `pnpm --filter @happyvertical/weather build`.
24
+ - If tests or exports fail after API, type, or bundle changes, run `pnpm --filter @happyvertical/weather clean` followed by `pnpm --filter @happyvertical/weather build` and `pnpm --filter @happyvertical/weather test`.
25
+ - If failures span multiple packages or Turborepo ordering looks wrong, run `pnpm build` and `pnpm typecheck` from the repo root before retrying package-scoped commands.
26
+
27
+ ## Ecosystem Relationships
28
+ - Provides: Weather data provider abstraction for HAppyVertical SDK
29
+ - Implements: none
30
+ - Requires: @happyvertical/utils
31
+ - Stability: stable (Primary package surface is described as implemented and production-oriented.)
32
+ <!-- END AGENT:GENERATED -->
33
+
package/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright <2025> <Happy Vertical Corporation>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,160 @@
1
+ # @happyvertical/weather
2
+
3
+ Weather data provider abstraction for the HAppyVertical SDK.
4
+
5
+ ## Overview
6
+
7
+ The `@happyvertical/weather` package provides a unified interface for fetching weather forecasts from multiple providers. It follows the same architectural pattern as `@happyvertical/ai`, `@happyvertical/files`, and `@happyvertical/sql`.
8
+
9
+ ## Supported Providers
10
+
11
+ - **Environment Canada** - Government weather service for Canadian locations (free)
12
+ - **OpenWeatherMap** - Global weather data with free and paid tiers
13
+ - Standard API: 5-day/3-hour forecasts (free tier)
14
+ - One Call API 3.0: 48hr hourly + 8-day daily forecasts (paid tier)
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ pnpm add @happyvertical/weather
20
+ ```
21
+
22
+ ## Claude Code Context
23
+
24
+ Install Claude Code context files for AI-assisted development:
25
+
26
+ ```bash
27
+ npx have-weather-context
28
+ ```
29
+
30
+ This copies the package's `AGENT.md` documentation and `metadata.json` metadata to your project's `.claude/` directory, enabling Claude to provide better assistance when working with this package.
31
+
32
+ ## Usage
33
+
34
+ ### Basic Example
35
+
36
+ ```typescript
37
+ import { getWeatherAdapter } from '@happyvertical/weather';
38
+
39
+ // Create adapter for Environment Canada
40
+ const weather = await getWeatherAdapter({
41
+ provider: 'environment-canada'
42
+ });
43
+
44
+ // Fetch forecast for a location (latitude, longitude)
45
+ const forecasts = await weather.fetchForLocation(51.0447, -114.0719);
46
+
47
+ forecasts.forEach(forecast => {
48
+ console.log(`${forecast.timestamp}: ${forecast.temperature}°C - ${forecast.conditions}`);
49
+ });
50
+ ```
51
+
52
+ ### OpenWeatherMap (Free Tier)
53
+
54
+ ```typescript
55
+ const weather = await getWeatherAdapter({
56
+ provider: 'openweathermap',
57
+ apiKey: process.env.OPENWEATHER_API_KEY
58
+ });
59
+
60
+ const forecasts = await weather.fetchForLocation(51.0447, -114.0719);
61
+ ```
62
+
63
+ ### OpenWeatherMap One Call (Paid Tier)
64
+
65
+ ```typescript
66
+ const weather = await getWeatherAdapter({
67
+ provider: 'openweathermap-onecall',
68
+ apiKey: process.env.OPENWEATHER_API_KEY
69
+ });
70
+
71
+ const forecasts = await weather.fetchForLocation(51.0447, -114.0719);
72
+ ```
73
+
74
+ ### Environment Variable Configuration
75
+
76
+ ```bash
77
+ # .env
78
+ HAVE_WEATHER_PROVIDER=openweathermap
79
+ OPENWEATHER_API_KEY=your-api-key-here
80
+ HAVE_WEATHER_TIMEOUT=15000
81
+ ```
82
+
83
+ ```typescript
84
+ // Automatically uses environment variables
85
+ const weather = await getWeatherAdapter();
86
+ const forecasts = await weather.fetchForLocation(51.0447, -114.0719);
87
+ ```
88
+
89
+ ## API Reference
90
+
91
+ ### `getWeatherAdapter(options?): Promise<IWeatherAdapter>`
92
+
93
+ Factory function for creating weather adapters.
94
+
95
+ **Options:**
96
+ - `provider`: `'environment-canada' | 'openweathermap' | 'openweathermap-onecall'`
97
+ - `apiKey`: API key (required for OpenWeatherMap providers)
98
+ - `timeout`: Request timeout in milliseconds (default: 10000)
99
+
100
+ ### `IWeatherAdapter`
101
+
102
+ ```typescript
103
+ interface IWeatherAdapter {
104
+ fetchForLocation(
105
+ latitude: number,
106
+ longitude: number,
107
+ options?: FetchOptions
108
+ ): Promise<WeatherForecast[]>
109
+
110
+ testConnection(): Promise<boolean>
111
+
112
+ supportsLocation(latitude: number, longitude: number): Promise<boolean>
113
+ }
114
+ ```
115
+
116
+ ### `WeatherForecast`
117
+
118
+ ```typescript
119
+ interface WeatherForecast {
120
+ timestamp: Date
121
+ temperature: number // °C
122
+ feelsLike?: number // °C
123
+ temperatureMin?: number // °C
124
+ temperatureMax?: number // °C
125
+ conditions: string // Human-readable description
126
+ humidity: number // Percentage 0-100
127
+ windSpeed: number // km/h
128
+ windDirection?: number // Degrees 0-360
129
+ windGust?: number // km/h
130
+ pressure?: number // hPa
131
+ cloudCover?: number // Percentage 0-100
132
+ visibility?: number // km
133
+ precipProbability?: number // Percentage 0-100
134
+ precipAmount?: number // mm
135
+ confidence?: number // Provider's confidence 0-100
136
+ raw: any // Provider-specific raw data
137
+ }
138
+ ```
139
+
140
+ ## Environment Variables
141
+
142
+ | Variable | Type | Description |
143
+ |----------|------|-------------|
144
+ | `HAVE_WEATHER_PROVIDER` | string | Provider name |
145
+ | `OPENWEATHER_API_KEY` | string | OpenWeatherMap API key |
146
+ | `HAVE_WEATHER_TIMEOUT` | number | Request timeout (ms) |
147
+
148
+ ## Provider Comparison
149
+
150
+ | Feature | Environment Canada | OpenWeatherMap | OWM One Call |
151
+ |---------|-------------------|----------------|--------------|
152
+ | **Cost** | Free | Free tier available | Paid |
153
+ | **Coverage** | Canada only | Global | Global |
154
+ | **Forecast** | Day/night | 3-hour for 5 days | Hourly + daily |
155
+ | **API Key** | Not required | Required | Required |
156
+ | **Update Frequency** | ~hourly | 3 hours | hourly |
157
+
158
+ ## License
159
+
160
+ MIT
@@ -0,0 +1 @@
1
+ export { }
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=claude-context.d.ts.map
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ import { existsSync as o, mkdirSync as i, copyFileSync as m } from "node:fs";
3
+ import { dirname as s, join as e } from "node:path";
4
+ import { fileURLToPath as d } from "node:url";
5
+ const l = s(d(import.meta.url)), t = e(l, "../.."), a = e(process.cwd(), ".claude");
6
+ o(a) || i(a, { recursive: !0 });
7
+ const n = "weather", r = o(e(t, "AGENT.md")) ? e(t, "AGENT.md") : e(t, "CLAUDE.md"), c = o(e(t, "metadata.json")) ? e(t, "metadata.json") : e(t, ".claude-meta.json");
8
+ o(r) && m(r, e(a, `have-${n}.md`));
9
+ o(c) && m(c, e(a, `have-${n}.meta.json`));
10
+ console.log(`✓ Installed @happyvertical/${n} context to .claude/`);
@@ -0,0 +1,369 @@
1
+ /**
2
+ * Authentication error - thrown when API key is invalid or missing
3
+ */
4
+ export declare class AuthenticationError extends WeatherError {
5
+ constructor(provider: string, message?: string);
6
+ }
7
+
8
+ /**
9
+ * Calculate distance between two coordinates using Haversine formula
10
+ *
11
+ * @param lat1 - First latitude
12
+ * @param lon1 - First longitude
13
+ * @param lat2 - Second latitude
14
+ * @param lon2 - Second longitude
15
+ * @returns Distance in kilometers
16
+ */
17
+ export declare function calculateDistance(lat1: number, lon1: number, lat2: number, lon2: number): number;
18
+
19
+ /**
20
+ * Ensure coordinates are valid, throw error if not
21
+ *
22
+ * @param provider - Provider name for error messages
23
+ * @param latitude - Latitude to validate
24
+ * @param longitude - Longitude to validate
25
+ * @throws InvalidLocationError if coordinates are invalid
26
+ */
27
+ export declare function ensureValidCoordinates(provider: string, latitude: number, longitude: number): void;
28
+
29
+ /**
30
+ * Environment Canada provider options
31
+ */
32
+ export declare interface EnvironmentCanadaOptions {
33
+ provider: 'environment-canada';
34
+ /** Request timeout in milliseconds (default: 10000) */
35
+ timeout?: number;
36
+ }
37
+
38
+ /**
39
+ * Convert temperature from Fahrenheit to Celsius
40
+ *
41
+ * @param fahrenheit - Temperature in Fahrenheit
42
+ * @returns Temperature in Celsius
43
+ */
44
+ export declare function fahrenheitToCelsius(fahrenheit: number): number;
45
+
46
+ /**
47
+ * Fetch options for weather data
48
+ */
49
+ export declare interface FetchOptions {
50
+ /** Request timeout in milliseconds */
51
+ timeout?: number;
52
+ /** Maximum number of forecast periods to return */
53
+ limit?: number;
54
+ /** Force refresh even if cached data exists */
55
+ forceRefresh?: boolean;
56
+ }
57
+
58
+ /**
59
+ * Create a weather adapter instance
60
+ *
61
+ * @param options - Weather adapter options or undefined to use environment variables
62
+ * @returns Weather adapter instance
63
+ *
64
+ * @example
65
+ * ```typescript
66
+ * // Use environment variables (HAVE_WEATHER_PROVIDER, OPENWEATHER_API_KEY)
67
+ * const weather = await getWeatherAdapter();
68
+ *
69
+ * // Explicit configuration
70
+ * const weather = await getWeatherAdapter({
71
+ * provider: 'openweathermap',
72
+ * apiKey: 'your-api-key'
73
+ * });
74
+ * ```
75
+ */
76
+ declare function getWeatherAdapter(options?: PartialWeatherAdapterOptions): Promise<IWeatherAdapter>;
77
+ export default getWeatherAdapter;
78
+ export { getWeatherAdapter }
79
+
80
+ /**
81
+ * Google Weather API provider options
82
+ */
83
+ export declare interface GoogleWeatherOptions {
84
+ provider: 'google-weather';
85
+ /** Google API key (required) */
86
+ apiKey: string;
87
+ /** Request timeout in milliseconds (default: 10000) */
88
+ timeout?: number;
89
+ }
90
+
91
+ /**
92
+ * Fetch options for historical weather data.
93
+ */
94
+ export declare interface HistoricalFetchOptions extends FetchOptions {
95
+ /** Start of the requested historical window */
96
+ start: Date | string;
97
+ /** End of the requested historical window. Defaults to start. */
98
+ end?: Date | string;
99
+ /** Requested granularity. Providers may support only hourly data. */
100
+ interval?: 'hourly';
101
+ }
102
+
103
+ /**
104
+ * Invalid location error - thrown when location is invalid or unsupported
105
+ */
106
+ export declare class InvalidLocationError extends WeatherError {
107
+ constructor(provider: string, latitude: number, longitude: number, message?: string);
108
+ }
109
+
110
+ /**
111
+ * Check if location is in Canada (very rough approximation)
112
+ * Based on latitude/longitude bounding box
113
+ *
114
+ * @param latitude - Location latitude
115
+ * @param longitude - Location longitude
116
+ * @returns true if location appears to be in Canada
117
+ */
118
+ export declare function isInCanada(latitude: number, longitude: number): boolean;
119
+
120
+ /**
121
+ * Public weather adapter interface (identical to IWeatherProvider)
122
+ * This is the interface returned by getWeatherAdapter()
123
+ */
124
+ export declare type IWeatherAdapter = IWeatherProvider;
125
+
126
+ /**
127
+ * Core weather provider interface
128
+ * All weather providers must implement this interface
129
+ */
130
+ export declare interface IWeatherProvider {
131
+ /** Provider name for logging and identification */
132
+ readonly name: string;
133
+ /** Provider type */
134
+ readonly providerType: 'government' | 'community' | 'commercial';
135
+ /**
136
+ * Fetch weather forecasts for a location
137
+ *
138
+ * @param latitude - Location latitude (-90 to 90)
139
+ * @param longitude - Location longitude (-180 to 180)
140
+ * @param options - Fetch options
141
+ * @returns Array of weather forecasts
142
+ */
143
+ fetchForLocation(latitude: number, longitude: number, options?: FetchOptions): Promise<WeatherForecast[]>;
144
+ /**
145
+ * Fetch historical weather observations for a location.
146
+ *
147
+ * Providers that cannot serve historical data must reject with
148
+ * UnsupportedWeatherCapabilityError instead of silently falling back.
149
+ *
150
+ * @param latitude - Location latitude (-90 to 90)
151
+ * @param longitude - Location longitude (-180 to 180)
152
+ * @param options - Historical fetch options
153
+ * @returns Array of historical weather observations
154
+ */
155
+ fetchHistoricalForLocation(latitude: number, longitude: number, options: HistoricalFetchOptions): Promise<WeatherForecast[]>;
156
+ /**
157
+ * Test connection to the weather API
158
+ *
159
+ * @returns true if connection successful, false otherwise
160
+ */
161
+ testConnection(): Promise<boolean>;
162
+ /**
163
+ * Check if provider supports a specific location
164
+ *
165
+ * @param latitude - Location latitude
166
+ * @param longitude - Location longitude
167
+ * @returns true if location is supported
168
+ */
169
+ supportsLocation(latitude: number, longitude: number): Promise<boolean>;
170
+ }
171
+
172
+ /**
173
+ * Convert temperature from Kelvin to Celsius
174
+ *
175
+ * @param kelvin - Temperature in Kelvin
176
+ * @returns Temperature in Celsius
177
+ */
178
+ export declare function kelvinToCelsius(kelvin: number): number;
179
+
180
+ /**
181
+ * Convert wind speed from m/s to km/h
182
+ *
183
+ * @param metersPerSecond - Wind speed in m/s
184
+ * @returns Wind speed in km/h
185
+ */
186
+ export declare function metersPerSecondToKmPerHour(metersPerSecond: number): number;
187
+
188
+ /**
189
+ * Convert visibility from meters to kilometers
190
+ *
191
+ * @param meters - Visibility in meters
192
+ * @returns Visibility in kilometers
193
+ */
194
+ export declare function metersToKilometers(meters: number): number;
195
+
196
+ /**
197
+ * Convert wind speed from mph to km/h
198
+ *
199
+ * @param milesPerHour - Wind speed in mph
200
+ * @returns Wind speed in km/h
201
+ */
202
+ export declare function milesPerHourToKmPerHour(milesPerHour: number): number;
203
+
204
+ /**
205
+ * Convert visibility from miles to kilometers
206
+ *
207
+ * @param miles - Visibility in miles
208
+ * @returns Visibility in kilometers
209
+ */
210
+ export declare function milesToKilometers(miles: number): number;
211
+
212
+ /**
213
+ * No results error - thrown when provider returns no forecast data
214
+ */
215
+ export declare class NoResultsError extends WeatherError {
216
+ constructor(provider: string, latitude: number, longitude: number);
217
+ }
218
+
219
+ /**
220
+ * Open-Meteo provider options
221
+ */
222
+ export declare interface OpenMeteoOptions {
223
+ provider: 'open-meteo';
224
+ /** Request timeout in milliseconds (default: 10000) */
225
+ timeout?: number;
226
+ }
227
+
228
+ /**
229
+ * OpenWeatherMap One Call API provider options (paid tier)
230
+ */
231
+ export declare interface OpenWeatherMapOneCallOptions {
232
+ provider: 'openweathermap-onecall';
233
+ /** OpenWeatherMap API key (required) */
234
+ apiKey: string;
235
+ /** Request timeout in milliseconds (default: 10000) */
236
+ timeout?: number;
237
+ }
238
+
239
+ /**
240
+ * OpenWeatherMap provider options (free tier)
241
+ */
242
+ export declare interface OpenWeatherMapOptions {
243
+ provider: 'openweathermap';
244
+ /** OpenWeatherMap API key (required) */
245
+ apiKey: string;
246
+ /** Request timeout in milliseconds (default: 10000) */
247
+ timeout?: number;
248
+ }
249
+
250
+ /* Excluded from this release type: PACKAGE_VERSION_INITIALIZED */
251
+
252
+ /**
253
+ * Partial provider options for environment variable configuration
254
+ */
255
+ export declare type PartialWeatherAdapterOptions = Partial<Omit<EnvironmentCanadaOptions, 'provider'>> & Partial<Omit<OpenWeatherMapOptions, 'provider'>> & Partial<Omit<OpenWeatherMapOneCallOptions, 'provider'>> & Partial<Omit<GoogleWeatherOptions, 'provider'>> & Partial<Omit<OpenMeteoOptions, 'provider'>> & {
256
+ provider?: 'environment-canada' | 'openweathermap' | 'openweathermap-onecall' | 'google-weather' | 'open-meteo';
257
+ };
258
+
259
+ /**
260
+ * Rate limit error - thrown when API rate limit is exceeded
261
+ */
262
+ export declare class RateLimitError extends WeatherError {
263
+ constructor(provider: string, retryAfter?: number);
264
+ }
265
+
266
+ /**
267
+ * Unsupported capability error - thrown when a provider cannot serve an optional capability.
268
+ */
269
+ export declare class UnsupportedWeatherCapabilityError extends WeatherError {
270
+ constructor(provider: string, capability: string, message?: string);
271
+ }
272
+
273
+ /**
274
+ * Shared utilities for weather providers
275
+ */
276
+ /**
277
+ * Validate coordinates
278
+ *
279
+ * @param latitude - Latitude to validate (-90 to 90)
280
+ * @param longitude - Longitude to validate (-180 to 180)
281
+ * @returns Validation result with optional error message
282
+ */
283
+ export declare function validateCoordinates(latitude: number, longitude: number): {
284
+ valid: boolean;
285
+ error?: string;
286
+ };
287
+
288
+ /**
289
+ * Discriminated union of all provider options
290
+ */
291
+ export declare type WeatherAdapterOptions = EnvironmentCanadaOptions | OpenWeatherMapOptions | OpenWeatherMapOneCallOptions | GoogleWeatherOptions | OpenMeteoOptions;
292
+
293
+ /**
294
+ * Weather alert from Google Weather API
295
+ */
296
+ export declare interface WeatherAlert {
297
+ /** Alert identifier */
298
+ id: string;
299
+ /** Alert headline */
300
+ headline: string;
301
+ /** Detailed description */
302
+ description: string;
303
+ /** Severity level */
304
+ severity: string;
305
+ /** Alert start time */
306
+ startTime: Date;
307
+ /** Alert end time */
308
+ endTime: Date;
309
+ /** Raw API response */
310
+ raw: any;
311
+ }
312
+
313
+ /**
314
+ * Weather error - base class for weather-related errors
315
+ */
316
+ export declare class WeatherError extends Error {
317
+ readonly provider: string;
318
+ readonly code?: string | undefined;
319
+ readonly details?: any | undefined;
320
+ constructor(message: string, provider: string, code?: string | undefined, details?: any | undefined);
321
+ }
322
+
323
+ /**
324
+ * Weather package type definitions
325
+ *
326
+ * Provides standardized interfaces for weather data providers
327
+ */
328
+ /**
329
+ * Standard weather forecast data structure
330
+ * All providers must return this format
331
+ */
332
+ export declare interface WeatherForecast {
333
+ /** Forecast timestamp */
334
+ timestamp: Date;
335
+ /** Temperature in Celsius */
336
+ temperature: number;
337
+ /** Feels-like temperature in Celsius (optional) */
338
+ feelsLike?: number;
339
+ /** Minimum temperature in Celsius (optional) */
340
+ temperatureMin?: number;
341
+ /** Maximum temperature in Celsius (optional) */
342
+ temperatureMax?: number;
343
+ /** Human-readable conditions description */
344
+ conditions: string;
345
+ /** Humidity percentage (0-100) */
346
+ humidity: number;
347
+ /** Wind speed in km/h */
348
+ windSpeed: number;
349
+ /** Wind direction in degrees (0-360, optional) */
350
+ windDirection?: number;
351
+ /** Wind gust speed in km/h (optional) */
352
+ windGust?: number;
353
+ /** Atmospheric pressure in hPa (optional) */
354
+ pressure?: number;
355
+ /** Cloud cover percentage (0-100, optional) */
356
+ cloudCover?: number;
357
+ /** Visibility in kilometers (optional) */
358
+ visibility?: number;
359
+ /** Precipitation probability percentage (0-100, optional) */
360
+ precipProbability?: number;
361
+ /** Precipitation amount in mm (optional) */
362
+ precipAmount?: number;
363
+ /** Provider's confidence in forecast (0-100, optional) */
364
+ confidence?: number;
365
+ /** Raw provider-specific data */
366
+ raw: any;
367
+ }
368
+
369
+ export { }