@mharj/openweathermap 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +7 -0
  2. package/dist/OpenWeatherV2.d.ts +108 -0
  3. package/dist/OpenWeatherV2.js +174 -0
  4. package/dist/OpenWeatherV2.js.map +1 -0
  5. package/dist/index.d.ts +4 -0
  6. package/dist/index.js +8 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/interfaces/IOpenWeatherV2.d.ts +7 -0
  9. package/dist/interfaces/IOpenWeatherV2.js +3 -0
  10. package/dist/interfaces/IOpenWeatherV2.js.map +1 -0
  11. package/dist/interfaces/index.d.ts +1 -0
  12. package/dist/interfaces/index.js +5 -0
  13. package/dist/interfaces/index.js.map +1 -0
  14. package/dist/lib/fetchUtils.d.ts +5 -0
  15. package/dist/lib/fetchUtils.js +17 -0
  16. package/dist/lib/fetchUtils.js.map +1 -0
  17. package/dist/lib/index.d.ts +1 -0
  18. package/dist/lib/index.js +5 -0
  19. package/dist/lib/index.js.map +1 -0
  20. package/dist/types/ISO3166-Countries.d.ts +7 -0
  21. package/dist/types/ISO3166-Countries.js +260 -0
  22. package/dist/types/ISO3166-Countries.js.map +1 -0
  23. package/dist/types/index.d.ts +11 -0
  24. package/dist/types/index.js +11 -0
  25. package/dist/types/index.js.map +1 -0
  26. package/dist/types/v2/Icon.d.ts +17 -0
  27. package/dist/types/v2/Icon.js +19 -0
  28. package/dist/types/v2/Icon.js.map +1 -0
  29. package/dist/types/v2/Language.d.ts +4 -0
  30. package/dist/types/v2/Language.js +53 -0
  31. package/dist/types/v2/Language.js.map +1 -0
  32. package/dist/types/v2/index.d.ts +229 -0
  33. package/dist/types/v2/index.js +80 -0
  34. package/dist/types/v2/index.js.map +1 -0
  35. package/dist/types/v2/weatherIdGroup.d.ts +262 -0
  36. package/dist/types/v2/weatherIdGroup.js +317 -0
  37. package/dist/types/v2/weatherIdGroup.js.map +1 -0
  38. package/package.json +89 -0
package/README.md ADDED
@@ -0,0 +1,7 @@
1
+ # Open Weather Map API
2
+
3
+ Open Weather Map API client for TypeScript.
4
+
5
+ Currently supports v2 API only (/data/2.5/weather)
6
+
7
+ ## [Documentation](https://mharj.github.io/ts-openweathermap/)
@@ -0,0 +1,108 @@
1
+ import { CountryCode, LangCode, Loadable, WeatherDataV2 } from './types';
2
+ import { Result } from 'mharj-result';
3
+ import type { ICacheOrAsync } from '@avanio/expire-cache';
4
+ import type { IOpenWeatherV2 } from './interfaces/IOpenWeatherV2';
5
+ /**
6
+ * Open Weather V2 API Common Options
7
+ * @default {lang: 'en', units: 'standard'} in API
8
+ * @example
9
+ * {lang: 'fi', units: 'metric'}
10
+ */
11
+ export type OpenWeatherV2CommonOptions = {
12
+ /**
13
+ * Language code
14
+ */
15
+ lang?: LangCode;
16
+ /**
17
+ * Weather units
18
+ */
19
+ units?: 'standard' | 'metric' | 'imperial';
20
+ };
21
+ /**
22
+ * Open Weather V2 API
23
+ * @example
24
+ * const weather = new OpenWeatherV2('your-api-key');
25
+ *
26
+ * const cache = new ExpireCache<WeatherDataV2>(undefined, undefined, 900000); // data 15 minutes in cache
27
+ * const weather = new OpenWeatherV2(() => Promise.resolve('your-api-key'), cache);
28
+ *
29
+ * const data: WeatherDataV2 = (await weather.getWeatherById(2643743)).unwrap(); // throws if error
30
+ * const data: WeatherDataV2 | undefined = (await weather.getWeatherByCity('Helsinki', 'fi')).ok();
31
+ *
32
+ * const result: Result<WeatherDataV2> = await weather.getWeatherByLatLon(60.1699, 24.9384);
33
+ * result.match({
34
+ * Ok: (data: WeatherDataV2) => console.log(data),
35
+ * Err: (err: DOMException | TypeError) => console.error(err),
36
+ * });
37
+ *
38
+ * if(result.isOk) {
39
+ * const data: WeatherDataV2 = data.ok();
40
+ * } else {
41
+ * const err: DOMException | TypeError = data.err();
42
+ * }
43
+ */
44
+ export declare class OpenWeatherV2 {
45
+ private cache;
46
+ private loadableApiKey;
47
+ private apiHandler;
48
+ /**
49
+ * OpenWeatherV2 constructor
50
+ * @param {Loadable<string>} loadableApiKey - Loadable API key
51
+ * @param {ICacheOrAsync<WeatherDataV2>=} cache - optional async cache implementation
52
+ * @param {IOpenWeatherV2=} apiHandler - optional API handler implementation for mocking
53
+ */
54
+ constructor(loadableApiKey: Loadable<string>, cache?: ICacheOrAsync<WeatherDataV2>, apiHandler?: IOpenWeatherV2);
55
+ /**
56
+ * get weather by Id
57
+ * @param {number} id - Weather station ID
58
+ * @param {OpenWeatherV2CommonOptions=} opts - Common options, example ```{lang: 'fi', units: 'metric'}```, defaults ```{lang: 'en', units: 'standard'}```
59
+ * @return {Promise<Result<WeatherDataV2, DOMException | TypeError>>} Weather data Result Promise
60
+ * @example
61
+ * const result: Result<WeatherDataV2, DOMException | TypeError> = await weather.getWeatherResultById(id: 564, {lang: 'fi'});
62
+ * if (result.isOk) {
63
+ * const weatherData: WeatherDataV2 = result.ok();
64
+ * } else {
65
+ * const error: DOMException | TypeError = result.err();
66
+ * }
67
+ */
68
+ getWeatherById(id: number, opts?: OpenWeatherV2CommonOptions): Promise<Result<WeatherDataV2, DOMException | TypeError>>;
69
+ /**
70
+ * get weather with city name and optional country code
71
+ * @param {string} city - City name
72
+ * @param {countryCode=} countryCode - Optional Country code
73
+ * @param {OpenWeatherV2CommonOptions=} opts - Common options, example ```{lang: 'fi', units: 'metric'}```, defaults ```{lang: 'en', units: 'standard'}```
74
+ * @return {Promise<Result<WeatherDataV2, DOMException | TypeError>>} Weather data Result Promise
75
+ * @example
76
+ * const result: Result<WeatherDataV2, DOMException | TypeError> = await weather.getWeatherByCity('Helsinki', 'fi', {lang: 'fi'});
77
+ * if (result.isOk) {
78
+ * const weatherData: WeatherDataV2 = result.ok();
79
+ * } else {
80
+ * const error: DOMException | TypeError = result.err();
81
+ * }
82
+ */
83
+ getWeatherByCity(city: string, countryCode?: CountryCode, opts?: OpenWeatherV2CommonOptions): Promise<Result<WeatherDataV2, DOMException | TypeError>>;
84
+ /**
85
+ * get weather with latitude and longitude with Result
86
+ * @param {number} lat - Latitude
87
+ * @param {number} lon - Longitude
88
+ * @param {OpenWeatherV2CommonOptions=} opts - Common options, example ```{lang: 'fi', units: 'metric'}```, defaults ```{lang: 'en', units: 'standard'}```
89
+ * @return {Promise<Result<WeatherDataV2, DOMException | TypeError>>} Weather data Result Promise
90
+ * @example
91
+ * const result: Result<WeatherDataV2, DOMException | TypeError> = await weather.getWeatherByLatLon(60.1699, 24.9384, {lang: 'fi'});
92
+ * if (result.isOk) {
93
+ * const weatherData: WeatherDataV2 = result.ok();
94
+ * } else {
95
+ * const error: DOMException | TypeError = result.err();
96
+ * }
97
+ */
98
+ getWeatherByLatLon(lat: number, lon: number, opts?: OpenWeatherV2CommonOptions): Promise<Result<WeatherDataV2, DOMException | TypeError>>;
99
+ private buildBaseParams;
100
+ /**
101
+ * build base cache key
102
+ * @param main - main cache key prefix
103
+ * @param opts - OpenWeatherV2CommonOptions
104
+ * @returns {CacheKey}
105
+ */
106
+ private buildBaseCacheKey;
107
+ private handleFetch;
108
+ }
@@ -0,0 +1,174 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OpenWeatherV2 = void 0;
4
+ const types_1 = require("./types");
5
+ const mharj_result_1 = require("mharj-result");
6
+ const fetchUtils_1 = require("./lib/fetchUtils");
7
+ const defaultImplementation = {
8
+ dataWeatherApi: async (params) => {
9
+ const resp = await fetch(`https://api.openweathermap.org/data/2.5/weather?${params.toString()}`);
10
+ if (!resp.ok) {
11
+ throw new Error(resp.statusText);
12
+ }
13
+ const data = (await resp.json());
14
+ (0, types_1.assertWeatherDataV2)(data);
15
+ return data;
16
+ },
17
+ };
18
+ /**
19
+ * Open Weather V2 API
20
+ * @example
21
+ * const weather = new OpenWeatherV2('your-api-key');
22
+ *
23
+ * const cache = new ExpireCache<WeatherDataV2>(undefined, undefined, 900000); // data 15 minutes in cache
24
+ * const weather = new OpenWeatherV2(() => Promise.resolve('your-api-key'), cache);
25
+ *
26
+ * const data: WeatherDataV2 = (await weather.getWeatherById(2643743)).unwrap(); // throws if error
27
+ * const data: WeatherDataV2 | undefined = (await weather.getWeatherByCity('Helsinki', 'fi')).ok();
28
+ *
29
+ * const result: Result<WeatherDataV2> = await weather.getWeatherByLatLon(60.1699, 24.9384);
30
+ * result.match({
31
+ * Ok: (data: WeatherDataV2) => console.log(data),
32
+ * Err: (err: DOMException | TypeError) => console.error(err),
33
+ * });
34
+ *
35
+ * if(result.isOk) {
36
+ * const data: WeatherDataV2 = data.ok();
37
+ * } else {
38
+ * const err: DOMException | TypeError = data.err();
39
+ * }
40
+ */
41
+ class OpenWeatherV2 {
42
+ cache;
43
+ loadableApiKey;
44
+ apiHandler;
45
+ /**
46
+ * OpenWeatherV2 constructor
47
+ * @param {Loadable<string>} loadableApiKey - Loadable API key
48
+ * @param {ICacheOrAsync<WeatherDataV2>=} cache - optional async cache implementation
49
+ * @param {IOpenWeatherV2=} apiHandler - optional API handler implementation for mocking
50
+ */
51
+ constructor(loadableApiKey, cache, apiHandler = defaultImplementation) {
52
+ this.loadableApiKey = loadableApiKey;
53
+ this.cache = cache;
54
+ this.apiHandler = apiHandler;
55
+ }
56
+ /**
57
+ * get weather by Id
58
+ * @param {number} id - Weather station ID
59
+ * @param {OpenWeatherV2CommonOptions=} opts - Common options, example ```{lang: 'fi', units: 'metric'}```, defaults ```{lang: 'en', units: 'standard'}```
60
+ * @return {Promise<Result<WeatherDataV2, DOMException | TypeError>>} Weather data Result Promise
61
+ * @example
62
+ * const result: Result<WeatherDataV2, DOMException | TypeError> = await weather.getWeatherResultById(id: 564, {lang: 'fi'});
63
+ * if (result.isOk) {
64
+ * const weatherData: WeatherDataV2 = result.ok();
65
+ * } else {
66
+ * const error: DOMException | TypeError = result.err();
67
+ * }
68
+ */
69
+ async getWeatherById(id, opts = {}) {
70
+ try {
71
+ const cacheKey = this.buildBaseCacheKey(`id:${id}`, opts);
72
+ let cacheEntry = this.cache && (await this.cache.get(cacheKey));
73
+ if (!cacheEntry) {
74
+ const params = await this.buildBaseParams(opts);
75
+ params.append('id', String(id));
76
+ cacheEntry = await this.handleFetch(cacheKey, params, opts);
77
+ }
78
+ return (0, mharj_result_1.Ok)(cacheEntry);
79
+ }
80
+ catch (err) {
81
+ return (0, mharj_result_1.Err)((0, fetchUtils_1.fetchErrorWrapper)(err));
82
+ }
83
+ }
84
+ /**
85
+ * get weather with city name and optional country code
86
+ * @param {string} city - City name
87
+ * @param {countryCode=} countryCode - Optional Country code
88
+ * @param {OpenWeatherV2CommonOptions=} opts - Common options, example ```{lang: 'fi', units: 'metric'}```, defaults ```{lang: 'en', units: 'standard'}```
89
+ * @return {Promise<Result<WeatherDataV2, DOMException | TypeError>>} Weather data Result Promise
90
+ * @example
91
+ * const result: Result<WeatherDataV2, DOMException | TypeError> = await weather.getWeatherByCity('Helsinki', 'fi', {lang: 'fi'});
92
+ * if (result.isOk) {
93
+ * const weatherData: WeatherDataV2 = result.ok();
94
+ * } else {
95
+ * const error: DOMException | TypeError = result.err();
96
+ * }
97
+ */
98
+ async getWeatherByCity(city, countryCode, opts = {}) {
99
+ try {
100
+ const cacheKey = this.buildBaseCacheKey(`q:${city}:${countryCode}`, opts);
101
+ let cacheEntry = this.cache && (await this.cache.get(cacheKey));
102
+ if (!cacheEntry) {
103
+ const params = await this.buildBaseParams(opts);
104
+ params.append('q', countryCode ? `${city},${countryCode}` : city);
105
+ cacheEntry = await this.handleFetch(cacheKey, params, opts);
106
+ }
107
+ return (0, mharj_result_1.Ok)(cacheEntry);
108
+ }
109
+ catch (err) {
110
+ return (0, mharj_result_1.Err)((0, fetchUtils_1.fetchErrorWrapper)(err));
111
+ }
112
+ }
113
+ /**
114
+ * get weather with latitude and longitude with Result
115
+ * @param {number} lat - Latitude
116
+ * @param {number} lon - Longitude
117
+ * @param {OpenWeatherV2CommonOptions=} opts - Common options, example ```{lang: 'fi', units: 'metric'}```, defaults ```{lang: 'en', units: 'standard'}```
118
+ * @return {Promise<Result<WeatherDataV2, DOMException | TypeError>>} Weather data Result Promise
119
+ * @example
120
+ * const result: Result<WeatherDataV2, DOMException | TypeError> = await weather.getWeatherByLatLon(60.1699, 24.9384, {lang: 'fi'});
121
+ * if (result.isOk) {
122
+ * const weatherData: WeatherDataV2 = result.ok();
123
+ * } else {
124
+ * const error: DOMException | TypeError = result.err();
125
+ * }
126
+ */
127
+ async getWeatherByLatLon(lat, lon, opts = {}) {
128
+ try {
129
+ const cacheKey = this.buildBaseCacheKey(`latlon:${lat}:${lon}`, opts);
130
+ let cacheEntry = this.cache && (await this.cache.get(cacheKey));
131
+ if (!cacheEntry) {
132
+ const params = await this.buildBaseParams(opts);
133
+ params.append('lat', String(lat));
134
+ params.append('lon', String(lon));
135
+ cacheEntry = await this.handleFetch(cacheKey, params, opts);
136
+ }
137
+ return (0, mharj_result_1.Ok)(cacheEntry);
138
+ }
139
+ catch (err) {
140
+ return (0, mharj_result_1.Err)((0, fetchUtils_1.fetchErrorWrapper)(err));
141
+ }
142
+ }
143
+ async buildBaseParams({ lang, units }) {
144
+ const apiKey = await (typeof this.loadableApiKey === 'function' ? this.loadableApiKey() : this.loadableApiKey);
145
+ const params = new URLSearchParams();
146
+ lang && params.append('lang', lang);
147
+ units && params.append('units', units);
148
+ params.append('appid', apiKey);
149
+ return params;
150
+ }
151
+ /**
152
+ * build base cache key
153
+ * @param main - main cache key prefix
154
+ * @param opts - OpenWeatherV2CommonOptions
155
+ * @returns {CacheKey}
156
+ */
157
+ buildBaseCacheKey(main, { lang, units }) {
158
+ return `${main}:${lang}:${units}`;
159
+ }
160
+ async handleFetch(cacheKey, params, opts) {
161
+ const data = await this.apiHandler.dataWeatherApi(params);
162
+ (0, types_1.assertWeatherDataV2)(data);
163
+ if (this.cache) {
164
+ await this.cache.set(cacheKey, data);
165
+ if (!cacheKey.startsWith('id:')) {
166
+ // update id cache too
167
+ await this.cache.set(this.buildBaseCacheKey(`id:${data.id}`, opts), data);
168
+ }
169
+ }
170
+ return data;
171
+ }
172
+ }
173
+ exports.OpenWeatherV2 = OpenWeatherV2;
174
+ //# sourceMappingURL=OpenWeatherV2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OpenWeatherV2.js","sourceRoot":"./src/","sources":["OpenWeatherV2.ts"],"names":[],"mappings":"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","sourcesContent":["import {assertWeatherDataV2, CountryCode, LangCode, Loadable, WeatherDataV2} from './types';\nimport {Err, Ok, Result} from 'mharj-result';\nimport {fetchErrorWrapper} from './lib/fetchUtils';\nimport type {ICacheOrAsync} from '@avanio/expire-cache';\nimport type {IOpenWeatherV2} from './interfaces/IOpenWeatherV2';\n\n/**\n * Open Weather V2 API Common Options\n * @default {lang: 'en', units: 'standard'} in API\n * @example\n * {lang: 'fi', units: 'metric'}\n */\nexport type OpenWeatherV2CommonOptions = {\n\t/**\n\t * Language code\n\t */\n\tlang?: LangCode;\n\t/**\n\t * Weather units\n\t */\n\tunits?: 'standard' | 'metric' | 'imperial';\n};\n\nconst defaultImplementation: IOpenWeatherV2 = {\n\tdataWeatherApi: async (params: URLSearchParams): Promise<WeatherDataV2> => {\n\t\tconst resp = await fetch(`https://api.openweathermap.org/data/2.5/weather?${params.toString()}`);\n\t\tif (!resp.ok) {\n\t\t\tthrow new Error(resp.statusText);\n\t\t}\n\t\tconst data = (await resp.json()) as unknown;\n\t\tassertWeatherDataV2(data);\n\t\treturn data;\n\t},\n};\n\n/**\n * Open Weather V2 API\n * @example\n * const weather = new OpenWeatherV2('your-api-key');\n *\n * const cache = new ExpireCache<WeatherDataV2>(undefined, undefined, 900000); // data 15 minutes in cache\n * const weather = new OpenWeatherV2(() => Promise.resolve('your-api-key'), cache);\n *\n * const data: WeatherDataV2 = (await weather.getWeatherById(2643743)).unwrap(); // throws if error\n * const data: WeatherDataV2 | undefined = (await weather.getWeatherByCity('Helsinki', 'fi')).ok();\n *\n * const result: Result<WeatherDataV2> = await weather.getWeatherByLatLon(60.1699, 24.9384);\n * result.match({\n * Ok: (data: WeatherDataV2) => console.log(data),\n * Err: (err: DOMException | TypeError) => console.error(err),\n * });\n *\n * if(result.isOk) {\n * const data: WeatherDataV2 = data.ok();\n * } else {\n * const err: DOMException | TypeError = data.err();\n * }\n */\nexport class OpenWeatherV2 {\n\tprivate cache: ICacheOrAsync<WeatherDataV2> | undefined;\n\tprivate loadableApiKey: Loadable<string>;\n\tprivate apiHandler: IOpenWeatherV2;\n\t/**\n\t * OpenWeatherV2 constructor\n\t * @param {Loadable<string>} loadableApiKey - Loadable API key\n\t * @param {ICacheOrAsync<WeatherDataV2>=} cache - optional async cache implementation\n\t * @param {IOpenWeatherV2=} apiHandler - optional API handler implementation for mocking\n\t */\n\tconstructor(loadableApiKey: Loadable<string>, cache?: ICacheOrAsync<WeatherDataV2>, apiHandler: IOpenWeatherV2 = defaultImplementation) {\n\t\tthis.loadableApiKey = loadableApiKey;\n\t\tthis.cache = cache;\n\t\tthis.apiHandler = apiHandler;\n\t}\n\n\t/**\n\t * get weather by Id\n\t * @param {number} id - Weather station ID\n\t * @param {OpenWeatherV2CommonOptions=} opts - Common options, example ```{lang: 'fi', units: 'metric'}```, defaults ```{lang: 'en', units: 'standard'}```\n\t * @return {Promise<Result<WeatherDataV2, DOMException | TypeError>>} Weather data Result Promise\n\t * @example\n\t * const result: Result<WeatherDataV2, DOMException | TypeError> = await weather.getWeatherResultById(id: 564, {lang: 'fi'});\n\t * if (result.isOk) {\n\t * const weatherData: WeatherDataV2 = result.ok();\n\t * } else {\n\t * const error: DOMException | TypeError = result.err();\n\t * }\n\t */\n\tpublic async getWeatherById(id: number, opts: OpenWeatherV2CommonOptions = {}): Promise<Result<WeatherDataV2, DOMException | TypeError>> {\n\t\ttry {\n\t\t\tconst cacheKey = this.buildBaseCacheKey(`id:${id}`, opts);\n\t\t\tlet cacheEntry = this.cache && (await this.cache.get(cacheKey));\n\t\t\tif (!cacheEntry) {\n\t\t\t\tconst params = await this.buildBaseParams(opts);\n\t\t\t\tparams.append('id', String(id));\n\t\t\t\tcacheEntry = await this.handleFetch(cacheKey, params, opts);\n\t\t\t}\n\t\t\treturn Ok(cacheEntry);\n\t\t} catch (err) {\n\t\t\treturn Err(fetchErrorWrapper(err));\n\t\t}\n\t}\n\n\t/**\n\t * get weather with city name and optional country code\n\t * @param {string} city - City name\n\t * @param {countryCode=} countryCode - Optional Country code\n\t * @param {OpenWeatherV2CommonOptions=} opts - Common options, example ```{lang: 'fi', units: 'metric'}```, defaults ```{lang: 'en', units: 'standard'}```\n\t * @return {Promise<Result<WeatherDataV2, DOMException | TypeError>>} Weather data Result Promise\n\t * @example\n\t * const result: Result<WeatherDataV2, DOMException | TypeError> = await weather.getWeatherByCity('Helsinki', 'fi', {lang: 'fi'});\n\t * if (result.isOk) {\n\t * const weatherData: WeatherDataV2 = result.ok();\n\t * } else {\n\t * const error: DOMException | TypeError = result.err();\n\t * }\n\t */\n\tpublic async getWeatherByCity(\n\t\tcity: string,\n\t\tcountryCode?: CountryCode,\n\t\topts: OpenWeatherV2CommonOptions = {},\n\t): Promise<Result<WeatherDataV2, DOMException | TypeError>> {\n\t\ttry {\n\t\t\tconst cacheKey = this.buildBaseCacheKey(`q:${city}:${countryCode}`, opts);\n\t\t\tlet cacheEntry = this.cache && (await this.cache.get(cacheKey));\n\t\t\tif (!cacheEntry) {\n\t\t\t\tconst params = await this.buildBaseParams(opts);\n\t\t\t\tparams.append('q', countryCode ? `${city},${countryCode}` : city);\n\t\t\t\tcacheEntry = await this.handleFetch(cacheKey, params, opts);\n\t\t\t}\n\t\t\treturn Ok(cacheEntry);\n\t\t} catch (err) {\n\t\t\treturn Err(fetchErrorWrapper(err));\n\t\t}\n\t}\n\n\t/**\n\t * get weather with latitude and longitude with Result\n\t * @param {number} lat - Latitude\n\t * @param {number} lon - Longitude\n\t * @param {OpenWeatherV2CommonOptions=} opts - Common options, example ```{lang: 'fi', units: 'metric'}```, defaults ```{lang: 'en', units: 'standard'}```\n\t * @return {Promise<Result<WeatherDataV2, DOMException | TypeError>>} Weather data Result Promise\n\t * @example\n\t * const result: Result<WeatherDataV2, DOMException | TypeError> = await weather.getWeatherByLatLon(60.1699, 24.9384, {lang: 'fi'});\n\t * if (result.isOk) {\n\t * const weatherData: WeatherDataV2 = result.ok();\n\t * } else {\n\t * const error: DOMException | TypeError = result.err();\n\t * }\n\t */\n\tpublic async getWeatherByLatLon(lat: number, lon: number, opts: OpenWeatherV2CommonOptions = {}): Promise<Result<WeatherDataV2, DOMException | TypeError>> {\n\t\ttry {\n\t\t\tconst cacheKey = this.buildBaseCacheKey(`latlon:${lat}:${lon}`, opts);\n\t\t\tlet cacheEntry = this.cache && (await this.cache.get(cacheKey));\n\t\t\tif (!cacheEntry) {\n\t\t\t\tconst params = await this.buildBaseParams(opts);\n\t\t\t\tparams.append('lat', String(lat));\n\t\t\t\tparams.append('lon', String(lon));\n\t\t\t\tcacheEntry = await this.handleFetch(cacheKey, params, opts);\n\t\t\t}\n\t\t\treturn Ok(cacheEntry);\n\t\t} catch (err) {\n\t\t\treturn Err(fetchErrorWrapper(err));\n\t\t}\n\t}\n\n\tprivate async buildBaseParams({lang, units}: OpenWeatherV2CommonOptions): Promise<URLSearchParams> {\n\t\tconst apiKey = await (typeof this.loadableApiKey === 'function' ? this.loadableApiKey() : this.loadableApiKey);\n\t\tconst params = new URLSearchParams();\n\t\tlang && params.append('lang', lang);\n\t\tunits && params.append('units', units);\n\t\tparams.append('appid', apiKey);\n\t\treturn params;\n\t}\n\n\t/**\n\t * build base cache key\n\t * @param main - main cache key prefix\n\t * @param opts - OpenWeatherV2CommonOptions\n\t * @returns {CacheKey}\n\t */\n\tprivate buildBaseCacheKey(main: string, {lang, units}: OpenWeatherV2CommonOptions): string {\n\t\treturn `${main}:${lang}:${units}`;\n\t}\n\n\tprivate async handleFetch(cacheKey: string, params: URLSearchParams, opts: OpenWeatherV2CommonOptions): Promise<WeatherDataV2> {\n\t\tconst data = await this.apiHandler.dataWeatherApi(params);\n\t\tassertWeatherDataV2(data);\n\t\tif (this.cache) {\n\t\t\tawait this.cache.set(cacheKey, data);\n\t\t\tif (!cacheKey.startsWith('id:')) {\n\t\t\t\t// update id cache too\n\t\t\t\tawait this.cache.set(this.buildBaseCacheKey(`id:${data.id}`, opts), data);\n\t\t\t}\n\t\t}\n\t\treturn data;\n\t}\n}\n"]}
@@ -0,0 +1,4 @@
1
+ export * from './OpenWeatherV2';
2
+ export * from './types';
3
+ export * from './lib';
4
+ export * from './interfaces';
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ tslib_1.__exportStar(require("./OpenWeatherV2"), exports);
5
+ tslib_1.__exportStar(require("./types"), exports);
6
+ tslib_1.__exportStar(require("./lib"), exports);
7
+ tslib_1.__exportStar(require("./interfaces"), exports);
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"./src/","sources":["index.ts"],"names":[],"mappings":";;;AAAA,0DAAgC;AAChC,kDAAwB;AACxB,gDAAsB;AACtB,uDAA6B","sourcesContent":["export * from './OpenWeatherV2';\nexport * from './types';\nexport * from './lib';\nexport * from './interfaces';\n"]}
@@ -0,0 +1,7 @@
1
+ import { WeatherDataV2 } from '../types/v2';
2
+ /**
3
+ * Interface for OpenWeatherMap API v2 implementation.
4
+ */
5
+ export interface IOpenWeatherV2 {
6
+ dataWeatherApi: (params: URLSearchParams) => Promise<WeatherDataV2>;
7
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=IOpenWeatherV2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IOpenWeatherV2.js","sourceRoot":"./src/","sources":["interfaces/IOpenWeatherV2.ts"],"names":[],"mappings":"","sourcesContent":["import {WeatherDataV2} from '../types/v2';\n\n/**\n * Interface for OpenWeatherMap API v2 implementation.\n */\nexport interface IOpenWeatherV2 {\n\tdataWeatherApi: (params: URLSearchParams) => Promise<WeatherDataV2>;\n}\n"]}
@@ -0,0 +1 @@
1
+ export * from './IOpenWeatherV2';
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ tslib_1.__exportStar(require("./IOpenWeatherV2"), exports);
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"./src/","sources":["interfaces/index.ts"],"names":[],"mappings":";;;AAAA,2DAAiC","sourcesContent":["export * from './IOpenWeatherV2';\n"]}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Ensures that the error is a DOMException or TypeError.
3
+ * @internal
4
+ */
5
+ export declare function fetchErrorWrapper(err: unknown): DOMException | TypeError;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fetchErrorWrapper = void 0;
4
+ /**
5
+ * Ensures that the error is a DOMException or TypeError.
6
+ * @internal
7
+ */
8
+ function fetchErrorWrapper(err) {
9
+ if (err instanceof DOMException || err instanceof TypeError) {
10
+ return err;
11
+ }
12
+ else {
13
+ return new TypeError(`Unknown error: ${String(err)}`);
14
+ }
15
+ }
16
+ exports.fetchErrorWrapper = fetchErrorWrapper;
17
+ //# sourceMappingURL=fetchUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetchUtils.js","sourceRoot":"./src/","sources":["lib/fetchUtils.ts"],"names":[],"mappings":";;;AAAA;;;GAGG;AACH,SAAgB,iBAAiB,CAAC,GAAY;IAC7C,IAAI,GAAG,YAAY,YAAY,IAAI,GAAG,YAAY,SAAS,EAAE;QAC5D,OAAO,GAAG,CAAC;KACX;SAAM;QACN,OAAO,IAAI,SAAS,CAAC,kBAAkB,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;KACtD;AACF,CAAC;AAND,8CAMC","sourcesContent":["/**\n * Ensures that the error is a DOMException or TypeError.\n * @internal\n */\nexport function fetchErrorWrapper(err: unknown): DOMException | TypeError {\n\tif (err instanceof DOMException || err instanceof TypeError) {\n\t\treturn err;\n\t} else {\n\t\treturn new TypeError(`Unknown error: ${String(err)}`);\n\t}\n}\n"]}
@@ -0,0 +1 @@
1
+ export * from './fetchUtils';
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ tslib_1.__exportStar(require("./fetchUtils"), exports);
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"./src/","sources":["lib/index.ts"],"names":[],"mappings":";;;AAAA,uDAA6B","sourcesContent":["export * from './fetchUtils';\n"]}
@@ -0,0 +1,7 @@
1
+ import { z } from 'zod';
2
+ export declare const CountryCodeList: readonly ["af", "ax", "al", "dz", "as", "ad", "ao", "ai", "aq", "ag", "ar", "am", "aw", "au", "at", "az", "bs", "bh", "bd", "bb", "by", "be", "bz", "bj", "bm", "bt", "bo", "bq", "ba", "bw", "bv", "br", "io", "bn", "bg", "bf", "bi", "kh", "cm", "ca", "cv", "ky", "cf", "td", "cl", "cn", "cx", "cc", "co", "km", "cg", "cd", "ck", "cr", "ci", "hr", "cu", "cw", "cy", "cz", "dk", "dj", "dm", "do", "ec", "eg", "sv", "gq", "er", "ee", "et", "fk", "fo", "fj", "fi", "fr", "gf", "pf", "tf", "ga", "gm", "ge", "de", "gh", "gi", "gr", "gl", "gd", "gp", "gu", "gt", "gg", "gn", "gw", "gy", "ht", "hm", "va", "hn", "hk", "hu", "is", "in", "id", "ir", "iq", "ie", "im", "il", "it", "jm", "jp", "je", "jo", "kz", "ke", "ki", "kp", "kr", "kw", "kg", "la", "lv", "lb", "ls", "lr", "ly", "li", "lt", "lu", "mo", "mk", "mg", "mw", "my", "mv", "ml", "mt", "mh", "mq", "mr", "mu", "yt", "mx", "fm", "md", "mc", "mn", "me", "ms", "ma", "mz", "mm", "na", "nr", "np", "nl", "nc", "nz", "ni", "ne", "ng", "nu", "nf", "mp", "no", "om", "pk", "pw", "ps", "pa", "pg", "py", "pe", "ph", "pn", "pl", "pt", "pr", "qa", "re", "ro", "ru", "rw", "bl", "sh", "kn", "lc", "mf", "pm", "vc", "ws", "sm", "st", "sa", "sn", "rs", "sc", "sl", "sg", "sx", "sk", "si", "sb", "so", "za", "gs", "ss", "es", "lk", "sd", "sr", "sj", "sz", "se", "ch", "sy", "tw", "tj", "tz", "th", "tl", "tg", "tk", "to", "tt", "tn", "tr", "tm", "tc", "tv", "ug", "ua", "ae", "gb", "us", "um", "uy", "uz", "vu", "ve", "vn", "vg", "vi", "wf", "eh", "ye", "zm", "zw"];
3
+ /**
4
+ * @internal
5
+ */
6
+ export declare const CountryCodeSchema: z.ZodEnum<["af", "ax", "al", "dz", "as", "ad", "ao", "ai", "aq", "ag", "ar", "am", "aw", "au", "at", "az", "bs", "bh", "bd", "bb", "by", "be", "bz", "bj", "bm", "bt", "bo", "bq", "ba", "bw", "bv", "br", "io", "bn", "bg", "bf", "bi", "kh", "cm", "ca", "cv", "ky", "cf", "td", "cl", "cn", "cx", "cc", "co", "km", "cg", "cd", "ck", "cr", "ci", "hr", "cu", "cw", "cy", "cz", "dk", "dj", "dm", "do", "ec", "eg", "sv", "gq", "er", "ee", "et", "fk", "fo", "fj", "fi", "fr", "gf", "pf", "tf", "ga", "gm", "ge", "de", "gh", "gi", "gr", "gl", "gd", "gp", "gu", "gt", "gg", "gn", "gw", "gy", "ht", "hm", "va", "hn", "hk", "hu", "is", "in", "id", "ir", "iq", "ie", "im", "il", "it", "jm", "jp", "je", "jo", "kz", "ke", "ki", "kp", "kr", "kw", "kg", "la", "lv", "lb", "ls", "lr", "ly", "li", "lt", "lu", "mo", "mk", "mg", "mw", "my", "mv", "ml", "mt", "mh", "mq", "mr", "mu", "yt", "mx", "fm", "md", "mc", "mn", "me", "ms", "ma", "mz", "mm", "na", "nr", "np", "nl", "nc", "nz", "ni", "ne", "ng", "nu", "nf", "mp", "no", "om", "pk", "pw", "ps", "pa", "pg", "py", "pe", "ph", "pn", "pl", "pt", "pr", "qa", "re", "ro", "ru", "rw", "bl", "sh", "kn", "lc", "mf", "pm", "vc", "ws", "sm", "st", "sa", "sn", "rs", "sc", "sl", "sg", "sx", "sk", "si", "sb", "so", "za", "gs", "ss", "es", "lk", "sd", "sr", "sj", "sz", "se", "ch", "sy", "tw", "tj", "tz", "th", "tl", "tg", "tk", "to", "tt", "tn", "tr", "tm", "tc", "tv", "ug", "ua", "ae", "gb", "us", "um", "uy", "uz", "vu", "ve", "vn", "vg", "vi", "wf", "eh", "ye", "zm", "zw"]>;
7
+ export type CountryCode = z.infer<typeof CountryCodeSchema>;