@ibicash/geolayers-sdk 1.0.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/dist/index.js ADDED
@@ -0,0 +1,972 @@
1
+ // src/core/client.ts
2
+ import axios from "axios";
3
+
4
+ // src/types/api.ts
5
+ import { z } from "zod";
6
+ var LayerProvider = /* @__PURE__ */ ((LayerProvider2) => {
7
+ LayerProvider2["VOLCANOES"] = "volcanoes";
8
+ LayerProvider2["ACTIVE_VOLCANOES"] = "active-volcanoes";
9
+ LayerProvider2["WILDFIRES"] = "wildfires";
10
+ LayerProvider2["ACTIVE_STORMS"] = "active-storms";
11
+ LayerProvider2["RECENT_STORMS"] = "recent-storms";
12
+ LayerProvider2["EARTHQUAKES"] = "earthquakes";
13
+ LayerProvider2["BUOYS_RECENT"] = "buoys-recent";
14
+ LayerProvider2["BUOYS_LATEST"] = "buoys-latest";
15
+ LayerProvider2["NWS_STATIONS"] = "nws-weather-stations";
16
+ LayerProvider2["AZOS_NETWORK"] = "azos-weather-network";
17
+ LayerProvider2["WIS2_STATIONS"] = "wis2-stations";
18
+ LayerProvider2["GLOBAL_FLIGHTS"] = "global-flights";
19
+ LayerProvider2["LIVE_FLIGHTS"] = "live-flights";
20
+ LayerProvider2["FLIGHT_SCHEDULE"] = "flight-schedule";
21
+ return LayerProvider2;
22
+ })(LayerProvider || {});
23
+ var LayerMetadataSchema = z.object({
24
+ source: z.string(),
25
+ cacheTTL: z.number(),
26
+ cached: z.boolean(),
27
+ snapshotId: z.string().optional()
28
+ });
29
+ var createLayerResponseSchema = (dataSchema) => z.object({
30
+ provider: z.string(),
31
+ data: dataSchema,
32
+ timestamp: z.string(),
33
+ count: z.number().optional(),
34
+ metadata: LayerMetadataSchema.optional()
35
+ });
36
+
37
+ // src/types/geojson.ts
38
+ import { z as z2 } from "zod";
39
+ var PositionSchema = z2.tuple([z2.number(), z2.number()]).rest(z2.number());
40
+ var GeometrySchema = z2.discriminatedUnion("type", [
41
+ z2.object({ type: z2.literal("Point"), coordinates: PositionSchema }),
42
+ z2.object({ type: z2.literal("LineString"), coordinates: z2.array(PositionSchema) }),
43
+ z2.object({ type: z2.literal("Polygon"), coordinates: z2.array(z2.array(PositionSchema)) }),
44
+ z2.object({ type: z2.literal("MultiPoint"), coordinates: z2.array(PositionSchema) }),
45
+ z2.object({ type: z2.literal("MultiLineString"), coordinates: z2.array(z2.array(PositionSchema)) }),
46
+ z2.object({ type: z2.literal("MultiPolygon"), coordinates: z2.array(z2.array(z2.array(PositionSchema))) })
47
+ ]);
48
+ var createFeatureSchema = (propsSchema) => z2.object({
49
+ type: z2.literal("Feature"),
50
+ geometry: GeometrySchema,
51
+ properties: propsSchema,
52
+ id: z2.union([z2.string(), z2.number()]).optional()
53
+ });
54
+ var createFeatureCollectionSchema = (propsSchema) => z2.object({
55
+ type: z2.literal("FeatureCollection"),
56
+ features: z2.array(createFeatureSchema(propsSchema)),
57
+ bbox: z2.array(z2.number()).optional()
58
+ });
59
+ var EarthquakePropsSchema = z2.object({
60
+ mag: z2.number(),
61
+ place: z2.string(),
62
+ time: z2.number(),
63
+ updated: z2.number(),
64
+ tz: z2.number().nullable().optional(),
65
+ url: z2.string(),
66
+ detail: z2.string(),
67
+ felt: z2.number().nullable().optional(),
68
+ cdi: z2.number().nullable().optional(),
69
+ mmi: z2.number().nullable().optional(),
70
+ alert: z2.string().nullable().optional(),
71
+ status: z2.string(),
72
+ tsunami: z2.number(),
73
+ sig: z2.number(),
74
+ net: z2.string(),
75
+ code: z2.string(),
76
+ ids: z2.string(),
77
+ sources: z2.string(),
78
+ types: z2.string(),
79
+ nst: z2.number().nullable().optional(),
80
+ dmin: z2.number().nullable().optional(),
81
+ rms: z2.number().nullable().optional(),
82
+ gap: z2.number().nullable().optional(),
83
+ magType: z2.string(),
84
+ type: z2.string(),
85
+ title: z2.string()
86
+ });
87
+ var VolcanoPropsSchema = z2.object({
88
+ volcanoNumber: z2.number().nullable().optional(),
89
+ volcanoName: z2.string(),
90
+ volcanicLandform: z2.string().nullable().optional(),
91
+ primaryVolcanoType: z2.string().nullable().optional(),
92
+ lastEruptionYear: z2.union([z2.string(), z2.number()]).nullable().optional(),
93
+ country: z2.string(),
94
+ region: z2.string().nullable().optional(),
95
+ subregion: z2.string().nullable().optional(),
96
+ geologicalSummary: z2.string().nullable().optional(),
97
+ latitude: z2.number().nullable().optional(),
98
+ longitude: z2.number().nullable().optional(),
99
+ elevation: z2.number().nullable().optional(),
100
+ tectonicSetting: z2.string().nullable().optional(),
101
+ geologicEpoch: z2.string().nullable().optional(),
102
+ evidenceCategory: z2.string().nullable().optional(),
103
+ primaryPhotoLink: z2.string().nullable().optional(),
104
+ primaryPhotoCaption: z2.string().nullable().optional(),
105
+ primaryPhotoCredit: z2.string().nullable().optional(),
106
+ majorRockType: z2.string().nullable().optional()
107
+ });
108
+ var ActiveVolcanoPropsSchema = z2.object({
109
+ name: z2.string(),
110
+ eventtype: z2.string().optional(),
111
+ eventid: z2.number().optional(),
112
+ episodeid: z2.number().optional(),
113
+ eventname: z2.string().optional(),
114
+ glide: z2.string().optional(),
115
+ description: z2.string().optional(),
116
+ htmldescription: z2.string().optional(),
117
+ icon: z2.string().optional(),
118
+ iconoverall: z2.string().optional(),
119
+ url: z2.object({
120
+ geometry: z2.string().optional(),
121
+ report: z2.string().optional(),
122
+ details: z2.string().optional()
123
+ }).optional(),
124
+ alertlevel: z2.string().optional(),
125
+ alertscore: z2.number().optional(),
126
+ episodealertlevel: z2.string().optional(),
127
+ episodealertscore: z2.number().optional(),
128
+ istemporary: z2.string().optional(),
129
+ iscurrent: z2.string().optional(),
130
+ country: z2.string().optional(),
131
+ fromdate: z2.string().optional(),
132
+ todate: z2.string().optional(),
133
+ datemodified: z2.string().optional(),
134
+ iso3: z2.string().optional(),
135
+ source: z2.string().optional(),
136
+ sourceid: z2.string().optional(),
137
+ polygonlabel: z2.string().optional(),
138
+ class: z2.string().optional(),
139
+ affectedcountries: z2.array(z2.object({
140
+ iso2: z2.string().optional(),
141
+ iso3: z2.string().optional(),
142
+ countryname: z2.string().optional()
143
+ })).optional(),
144
+ severitydata: z2.object({
145
+ severity: z2.number().optional(),
146
+ severitytext: z2.string().optional(),
147
+ severityunit: z2.string().optional()
148
+ }).optional(),
149
+ marketType: z2.literal("volcano").optional(),
150
+ volcname: z2.string().optional()
151
+ });
152
+ var WeatherStationPropsSchema = z2.object({
153
+ id: z2.string().optional(),
154
+ wigos_station_identifier: z2.string().optional(),
155
+ station_identifier: z2.string().optional(),
156
+ // Fallback
157
+ name: z2.string().optional(),
158
+ station_name: z2.string().optional(),
159
+ // Fallback
160
+ provider: z2.string().optional(),
161
+ country: z2.string().optional(),
162
+ baseUrl: z2.string().optional(),
163
+ wis2CollectionId: z2.string().optional(),
164
+ marketType: z2.string().optional(),
165
+ metadata: z2.record(z2.string(), z2.unknown()).optional(),
166
+ measurements: z2.record(
167
+ z2.string(),
168
+ z2.object({
169
+ value: z2.union([z2.number(), z2.string()]),
170
+ unit: z2.string().optional()
171
+ })
172
+ ).optional()
173
+ });
174
+ var StormPropsSchema = z2.object({
175
+ objectid: z2.number().optional(),
176
+ stormname: z2.string().optional(),
177
+ stormid: z2.string().optional(),
178
+ stormnum: z2.number().optional(),
179
+ stormtype: z2.string().optional(),
180
+ dtg: z2.number().optional(),
181
+ year: z2.number().optional(),
182
+ month: z2.string().optional(),
183
+ day: z2.number().optional(),
184
+ hhmm: z2.string().optional(),
185
+ tau: z2.number().optional(),
186
+ mslp: z2.number().optional(),
187
+ basin: z2.string().optional(),
188
+ intensity: z2.number().optional(),
189
+ ss: z2.number().optional(),
190
+ lat: z2.number().optional(),
191
+ lon: z2.number().optional(),
192
+ // Alias/Common names used in clients/tests
193
+ category: z2.number().optional(),
194
+ windSpeed: z2.number().optional(),
195
+ pressure: z2.number().optional(),
196
+ status: z2.string().optional()
197
+ });
198
+ var WildfirePropsSchema = z2.object({
199
+ brightness: z2.number(),
200
+ bright_ti4: z2.number().optional(),
201
+ bright_ti5: z2.number().optional(),
202
+ scan: z2.number().optional(),
203
+ track: z2.number().optional(),
204
+ acq_date: z2.string(),
205
+ acq_time: z2.string(),
206
+ satellite: z2.string().optional(),
207
+ instrument: z2.string().optional(),
208
+ confidence: z2.union([z2.number(), z2.string()]).optional(),
209
+ version: z2.string().optional(),
210
+ frp: z2.number().optional(),
211
+ daynight: z2.string().optional()
212
+ });
213
+ var MeasurementValueSchema = z2.object({
214
+ value: z2.number(),
215
+ unit: z2.string(),
216
+ quality: z2.enum(["good", "suspect", "estimated", "missing"]).optional()
217
+ });
218
+ var StandardMeasurementsSchema = z2.record(z2.string(), MeasurementValueSchema);
219
+ var StandardObservationSchema = z2.object({
220
+ timestamp: z2.string().or(z2.date()),
221
+ stationId: z2.string(),
222
+ latitude: z2.number().optional(),
223
+ longitude: z2.number().optional(),
224
+ measurements: StandardMeasurementsSchema,
225
+ metadata: z2.record(z2.string(), z2.unknown()).optional(),
226
+ imageUrl: z2.string().optional()
227
+ });
228
+ var ObservationQueryResultSchema = z2.object({
229
+ stationId: z2.string(),
230
+ observations: z2.array(StandardObservationSchema),
231
+ count: z2.number(),
232
+ timeRange: z2.object({
233
+ start: z2.string().or(z2.date()),
234
+ end: z2.string().or(z2.date())
235
+ }),
236
+ provider: z2.string(),
237
+ cached: z2.boolean()
238
+ });
239
+ var FlightPropsSchema = z2.object({
240
+ // OpenSky Fields
241
+ icao24: z2.string().optional(),
242
+ callsign: z2.string().optional(),
243
+ originCountry: z2.string().optional(),
244
+ // Airplanes Live Fields
245
+ hex: z2.string().optional(),
246
+ flight: z2.string().optional(),
247
+ registration: z2.string().optional(),
248
+ type: z2.string().optional(),
249
+ // Common / Shared
250
+ velocity: z2.number().nullable().optional(),
251
+ geoAltitude: z2.number().nullable().optional(),
252
+ onGround: z2.boolean().nullable().optional(),
253
+ verticalRate: z2.number().nullable().optional(),
254
+ baroAltitude: z2.union([z2.number(), z2.string()]).nullable().optional(),
255
+ squawk: z2.string().nullable().optional(),
256
+ spi: z2.boolean().nullable().optional(),
257
+ positionSource: z2.number().nullable().optional(),
258
+ groundSpeed: z2.number().nullable().optional(),
259
+ track: z2.number().nullable().optional(),
260
+ // LiveFlights synonym
261
+ trueTrack: z2.number().nullable().optional(),
262
+ // GlobalFlights synonym
263
+ emergency: z2.string().nullable().optional(),
264
+ category: z2.string().nullable().optional(),
265
+ // Timestamps
266
+ timePosition: z2.number().nullable().optional(),
267
+ lastContact: z2.number().nullable().optional(),
268
+ // Sensors
269
+ sensors: z2.array(z2.number()).nullable().optional()
270
+ });
271
+ var EventPayloadSchema = z2.object({
272
+ provider: z2.string(),
273
+ type: z2.enum(["Feature", "FeatureCollection"]),
274
+ data: z2.unknown(),
275
+ // Pode ser qualquer um dos GeoJSONs acima
276
+ timestamp: z2.string(),
277
+ action: z2.enum(["created", "updated", "deleted"]).optional()
278
+ });
279
+ var FlightScheduleResponseSchema = z2.object({
280
+ provider: z2.string(),
281
+ data: z2.record(z2.string(), z2.unknown()),
282
+ // AeroDataBox returns varied structure
283
+ timestamp: z2.string(),
284
+ count: z2.number().optional(),
285
+ metadata: z2.object({
286
+ source: z2.string(),
287
+ cacheTTL: z2.number(),
288
+ cached: z2.boolean()
289
+ }).optional()
290
+ });
291
+ var ObservationProviderSchema = z2.enum(["wis2", "iem", "buoy", "openmeteo", "nws"]);
292
+ var StationObservationsResultSchema = z2.object({
293
+ stationId: z2.string(),
294
+ provider: ObservationProviderSchema,
295
+ observations: z2.array(StandardObservationSchema),
296
+ count: z2.number(),
297
+ timeRange: z2.object({
298
+ start: z2.string().or(z2.date()),
299
+ end: z2.string().or(z2.date())
300
+ }),
301
+ source: z2.literal("data-warehouse")
302
+ });
303
+ var LatestObservationResultSchema = z2.object({
304
+ stationId: z2.string(),
305
+ provider: ObservationProviderSchema,
306
+ observation: StandardObservationSchema.nullable(),
307
+ source: z2.literal("data-warehouse")
308
+ });
309
+ var BboxObservationsResultSchema = z2.object({
310
+ bbox: z2.tuple([z2.number(), z2.number(), z2.number(), z2.number()]),
311
+ provider: ObservationProviderSchema,
312
+ observations: z2.array(StandardObservationSchema),
313
+ count: z2.number(),
314
+ timeRange: z2.object({
315
+ start: z2.string().or(z2.date()),
316
+ end: z2.string().or(z2.date())
317
+ }),
318
+ source: z2.literal("data-warehouse")
319
+ });
320
+ var ObservationStatsResultSchema = z2.object({
321
+ provider: z2.string(),
322
+ totalObservations: z2.number(),
323
+ source: z2.literal("data-warehouse")
324
+ });
325
+
326
+ // src/core/config.ts
327
+ var DEFAULT_CONFIG = {
328
+ baseUrl: (typeof process !== "undefined" ? process.env.GEOLAYERS_BASE_URL : void 0) || "",
329
+ timeout: 3e4,
330
+ retries: 2
331
+ };
332
+
333
+ // src/core/errors.ts
334
+ var GeoLayersError = class extends Error {
335
+ constructor(message) {
336
+ super(message);
337
+ this.name = "GeoLayersError";
338
+ }
339
+ };
340
+ var GeoLayersApiError = class extends GeoLayersError {
341
+ constructor(message, statusCode, response) {
342
+ super(message);
343
+ this.statusCode = statusCode;
344
+ this.response = response;
345
+ this.name = "GeoLayersApiError";
346
+ }
347
+ };
348
+ var GeoLayersValidationError = class extends GeoLayersError {
349
+ constructor(message, errors) {
350
+ super(message);
351
+ this.errors = errors;
352
+ this.name = "GeoLayersValidationError";
353
+ }
354
+ };
355
+
356
+ // src/core/client.ts
357
+ var BaseClient = class {
358
+ http;
359
+ config;
360
+ constructor(config) {
361
+ this.config = { ...DEFAULT_CONFIG, ...config };
362
+ this.http = axios.create({
363
+ baseURL: this.config.baseUrl,
364
+ timeout: this.config.timeout
365
+ });
366
+ this.setupInterceptors();
367
+ }
368
+ setupInterceptors() {
369
+ this.http.interceptors.request.use((config) => {
370
+ config.headers["X-API-Key"] = this.config.apiKey;
371
+ return config;
372
+ });
373
+ }
374
+ isRetryableError(error) {
375
+ if (!error.response) return true;
376
+ const status = error.response.status;
377
+ return status >= 500 || status === 429;
378
+ }
379
+ async delay(ms) {
380
+ return new Promise((resolve) => setTimeout(resolve, ms));
381
+ }
382
+ async executeWithRetry(requestFn) {
383
+ const maxRetries = this.config.retries ?? 2;
384
+ let lastError = null;
385
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
386
+ try {
387
+ const response = await requestFn();
388
+ return response.data;
389
+ } catch (err) {
390
+ const error = err;
391
+ lastError = error;
392
+ const isLastAttempt = attempt === maxRetries;
393
+ if (isLastAttempt || !this.isRetryableError(error)) {
394
+ break;
395
+ }
396
+ const delayMs = Math.pow(2, attempt) * 1e3;
397
+ await this.delay(delayMs);
398
+ }
399
+ }
400
+ if (!lastError.response) {
401
+ throw new GeoLayersApiError(lastError.message, 0);
402
+ }
403
+ const { status, data } = lastError.response;
404
+ let message;
405
+ if (typeof data?.message === "string") {
406
+ message = data.message;
407
+ } else if (Array.isArray(data?.message)) {
408
+ message = data.message.join("; ");
409
+ } else if (typeof data?.error === "string") {
410
+ message = data.error;
411
+ } else if (data?.error?.message) {
412
+ message = data.error.message;
413
+ } else {
414
+ message = lastError.message ?? "Unknown error";
415
+ }
416
+ throw new GeoLayersApiError(message, status, data);
417
+ }
418
+ async get(url, params) {
419
+ return this.executeWithRetry(
420
+ () => this.http.get(url, { params })
421
+ );
422
+ }
423
+ async post(url, body) {
424
+ return this.executeWithRetry(
425
+ () => this.http.post(url, body)
426
+ );
427
+ }
428
+ /**
429
+ * Helper to parse GeoJSON responses with Zod validation.
430
+ * Eliminates repetitive schema creation across domains.
431
+ */
432
+ parseGeoJSON(data, propsSchema) {
433
+ const schema = createLayerResponseSchema(createFeatureCollectionSchema(propsSchema));
434
+ return schema.parse(data);
435
+ }
436
+ };
437
+
438
+ // src/domains/aviation.ts
439
+ var AviationDomain = class extends BaseClient {
440
+ /**
441
+ * Get all currently tracked flights globally (OpenSky).
442
+ * @param filters Optional bounding box filters. Defaults to whole world.
443
+ */
444
+ async getGlobalFlights(filters = {}) {
445
+ const params = {
446
+ lamin: filters.lamin ?? -90,
447
+ lomin: filters.lomin ?? -180,
448
+ lamax: filters.lamax ?? 90,
449
+ lomax: filters.lomax ?? 180
450
+ };
451
+ const data = await this.get("/geojson/flights/global", params);
452
+ return this.parseGeoJSON(data, FlightPropsSchema);
453
+ }
454
+ /**
455
+ * Get live flights (subset of global flights).
456
+ * @param filters Center point and radius filters. Defaults to New York if not provided.
457
+ */
458
+ async getLiveFlights(filters = { lat: 40.7128, lng: -74.006 }) {
459
+ const params = {
460
+ lat: filters.lat,
461
+ lng: filters.lng,
462
+ radius: filters.radius ?? 250
463
+ };
464
+ const data = await this.get("/geojson/flights/live", params);
465
+ return this.parseGeoJSON(data, FlightPropsSchema);
466
+ }
467
+ /**
468
+ * Get flight schedule/details by callsign from AeroDataBox.
469
+ * @param callsign Flight identifier (e.g., 'UAL1234', 'AA100')
470
+ * @returns Raw flight schedule data from AeroDataBox API.
471
+ *
472
+ * @example
473
+ * ```ts
474
+ * const schedule = await sdk.aviation.getFlightSchedule('UAL1234');
475
+ * console.log(schedule.data); // Flight details from AeroDataBox
476
+ * ```
477
+ */
478
+ async getFlightSchedule(callsign) {
479
+ const data = await this.get("/geojson/flights/schedule", { callsign });
480
+ return FlightScheduleResponseSchema.parse(data);
481
+ }
482
+ };
483
+
484
+ // src/domains/events.ts
485
+ import { z as z3 } from "zod";
486
+ var GeoLayersEventTypeSchema = z3.enum([
487
+ "earthquake.new",
488
+ "earthquake.updated",
489
+ "storm.new",
490
+ "storm.updated",
491
+ "wildfire.new",
492
+ "wildfire.updated",
493
+ "volcano.alert",
494
+ "snapshot.completed",
495
+ "snapshot.failed",
496
+ "observation.batch"
497
+ ]);
498
+ var EventTypesResponseSchema = z3.object({
499
+ types: z3.array(GeoLayersEventTypeSchema),
500
+ descriptions: z3.record(z3.string(), z3.string())
501
+ });
502
+ var EventsDomain = class extends BaseClient {
503
+ /**
504
+ * Get list of available event types for the event stream.
505
+ * @returns Object with event types array and their descriptions.
506
+ *
507
+ * @example
508
+ * ```ts
509
+ * const { types, descriptions } = await sdk.eventsMeta.getEventTypes();
510
+ * console.log(types); // ['earthquake.new', 'storm.new', ...]
511
+ * console.log(descriptions['earthquake.new']); // 'New earthquake detected'
512
+ * ```
513
+ */
514
+ async getEventTypes() {
515
+ const data = await this.get("/events/types");
516
+ return EventTypesResponseSchema.parse(data);
517
+ }
518
+ };
519
+
520
+ // src/domains/fire.ts
521
+ var FireDomain = class extends BaseClient {
522
+ /**
523
+ * Get list of active wildfires/heat anomalies.
524
+ * @param filters Optional filters. Default: last 1 day.
525
+ */
526
+ async getWildfires(filters = {}) {
527
+ const params = { days: filters.days ?? 1 };
528
+ const data = await this.get("/geojson/wildfires", params);
529
+ return this.parseGeoJSON(data, WildfirePropsSchema);
530
+ }
531
+ };
532
+
533
+ // src/domains/maritime.ts
534
+ var MaritimeDomain = class extends BaseClient {
535
+ /**
536
+ * Get NOAA buoy stations (locations).
537
+ */
538
+ async getBuoyStations() {
539
+ const data = await this.get("/geojson/buoys/stations");
540
+ return this.parseGeoJSON(data, WeatherStationPropsSchema);
541
+ }
542
+ /**
543
+ * Get latest buoy observations (real-time-ish).
544
+ */
545
+ async getLatestBuoyObservations() {
546
+ const data = await this.get("/geojson/buoys/observations");
547
+ return this.parseGeoJSON(data, WeatherStationPropsSchema);
548
+ }
549
+ /**
550
+ * Get historical observations for a specific buoy.
551
+ * @param buoyId The buoy identifier.
552
+ * @param filters Date range filters.
553
+ */
554
+ async getBuoyObservations(buoyId, filters) {
555
+ const data = await this.get(`/observations/buoy/${buoyId}`, filters);
556
+ return ObservationQueryResultSchema.parse(data);
557
+ }
558
+ };
559
+
560
+ // src/domains/observations.ts
561
+ var ObservationsDomain = class extends BaseClient {
562
+ /**
563
+ * Get active WIS2 stations that reported data in the last 24 hours.
564
+ */
565
+ async getActiveWis2Stations() {
566
+ const rawData = await this.get("/observations/wis2/stations/active");
567
+ return this.parseActiveStationsResponse(rawData, "wis2");
568
+ }
569
+ /**
570
+ * Get active IEM/AZOS stations that reported data in the last 24 hours.
571
+ */
572
+ async getActiveIemStations() {
573
+ const rawData = await this.get("/observations/iem/stations/active");
574
+ return this.parseActiveStationsResponse(rawData, "iem");
575
+ }
576
+ /**
577
+ * Get observations for a station from the data warehouse.
578
+ * @param stationId The station identifier.
579
+ * @param filters Query filters including provider and date range.
580
+ */
581
+ async getStationObservations(stationId, filters) {
582
+ const params = this.buildDateParams(filters);
583
+ const data = await this.get(`/observations/station/${stationId}`, params);
584
+ return StationObservationsResultSchema.parse(data);
585
+ }
586
+ /**
587
+ * Get the latest observation for a station from the data warehouse.
588
+ * @param stationId The station identifier.
589
+ * @param provider The observation provider.
590
+ */
591
+ async getLatestObservation(stationId, provider) {
592
+ const data = await this.get(`/observations/station/${stationId}/latest`, { provider });
593
+ return LatestObservationResultSchema.parse(data);
594
+ }
595
+ /**
596
+ * Get observations within a geographic bounding box.
597
+ * @param filters Bounding box coordinates and query filters.
598
+ */
599
+ async getObservationsByBbox(filters) {
600
+ const params = {
601
+ ...this.buildDateParams(filters),
602
+ minLon: filters.minLon,
603
+ minLat: filters.minLat,
604
+ maxLon: filters.maxLon,
605
+ maxLat: filters.maxLat
606
+ };
607
+ const data = await this.get("/observations/bbox", params);
608
+ return BboxObservationsResultSchema.parse(data);
609
+ }
610
+ /**
611
+ * Get data warehouse statistics.
612
+ * @param provider Optional provider filter. If not specified, returns stats for all providers.
613
+ */
614
+ async getStats(provider) {
615
+ const params = provider ? { provider } : {};
616
+ const data = await this.get("/observations/stats", params);
617
+ return ObservationStatsResultSchema.parse(data);
618
+ }
619
+ /**
620
+ * Convert time preset to absolute date range parameters.
621
+ */
622
+ buildDateParams(filters) {
623
+ const params = {
624
+ provider: filters.provider
625
+ };
626
+ if (filters.limit !== void 0) {
627
+ params.limit = filters.limit;
628
+ }
629
+ if (filters.start && filters.end) {
630
+ params.start = filters.start;
631
+ params.end = filters.end;
632
+ return params;
633
+ }
634
+ if (filters.timePreset) {
635
+ const now = /* @__PURE__ */ new Date();
636
+ const presetMs = {
637
+ "1h": 60 * 60 * 1e3,
638
+ "24h": 24 * 60 * 60 * 1e3,
639
+ "7d": 7 * 24 * 60 * 60 * 1e3,
640
+ "30d": 30 * 24 * 60 * 60 * 1e3
641
+ };
642
+ const ms = presetMs[filters.timePreset];
643
+ params.start = new Date(now.getTime() - ms).toISOString();
644
+ params.end = now.toISOString();
645
+ }
646
+ return params;
647
+ }
648
+ /**
649
+ * Parse active stations response.
650
+ * The endpoint may return either a FeatureCollection directly or wrapped in LayerResponse.
651
+ */
652
+ parseActiveStationsResponse(rawData, provider) {
653
+ const featureCollection = rawData;
654
+ if (featureCollection?.type === "FeatureCollection") {
655
+ const features = (featureCollection.features ?? []).map((f) => {
656
+ const feature = f;
657
+ return {
658
+ type: "Feature",
659
+ geometry: feature.geometry,
660
+ properties: WeatherStationPropsSchema.parse(feature.properties ?? {}),
661
+ id: feature.id
662
+ };
663
+ });
664
+ return {
665
+ provider: `active-stations-${provider}`,
666
+ data: {
667
+ type: "FeatureCollection",
668
+ features
669
+ },
670
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
671
+ count: features.length
672
+ };
673
+ }
674
+ return this.parseGeoJSON(rawData, WeatherStationPropsSchema);
675
+ }
676
+ };
677
+
678
+ // src/domains/seismic.ts
679
+ var PRESET_HOURS = {
680
+ "1h": 1,
681
+ "24h": 24,
682
+ "7d": 24 * 7,
683
+ "30d": 24 * 30
684
+ };
685
+ function getTimeRange(preset) {
686
+ const now = /* @__PURE__ */ new Date();
687
+ const hoursAgo = PRESET_HOURS[preset];
688
+ const start = new Date(now.getTime() - hoursAgo * 60 * 60 * 1e3);
689
+ return {
690
+ startTime: start.toISOString(),
691
+ endTime: now.toISOString()
692
+ };
693
+ }
694
+ var SeismicDomain = class extends BaseClient {
695
+ /**
696
+ * Get earthquakes from a specific time range and minimum magnitude.
697
+ *
698
+ * @param filters - Optional filters. Default: last 24 hours.
699
+ * @returns Promise with earthquake data as GeoJSON FeatureCollection.
700
+ *
701
+ * @example Using default (last 24 hours)
702
+ * ```ts
703
+ * const earthquakes = await sdk.seismic.getEarthquakes();
704
+ * ```
705
+ *
706
+ * @example Using a preset
707
+ * ```ts
708
+ * const earthquakes = await sdk.seismic.getEarthquakes({ timePreset: '7d', minMagnitude: 4.0 });
709
+ * ```
710
+ *
711
+ * @example Using custom date range
712
+ * ```ts
713
+ * const earthquakes = await sdk.seismic.getEarthquakes({
714
+ * startTime: '2024-01-01T00:00:00Z',
715
+ * endTime: '2024-01-31T23:59:59Z',
716
+ * minMagnitude: 5.0,
717
+ * });
718
+ * ```
719
+ */
720
+ async getEarthquakes(filters) {
721
+ const { timePreset = "24h", startTime, endTime, minMagnitude } = filters ?? {};
722
+ const timeRange = startTime && endTime ? { startTime, endTime } : getTimeRange(timePreset);
723
+ const params = {
724
+ ...timeRange,
725
+ ...minMagnitude !== void 0 && { minMagnitude }
726
+ };
727
+ const data = await this.get("/geojson/earthquakes", params);
728
+ return this.parseGeoJSON(data, EarthquakePropsSchema);
729
+ }
730
+ };
731
+
732
+ // src/domains/tropical.ts
733
+ var TropicalDomain = class extends BaseClient {
734
+ /**
735
+ * Get list of currently active tropical storms/hurricanes.
736
+ */
737
+ async getActiveStorms() {
738
+ const data = await this.get("/geojson/storms/active");
739
+ return this.parseGeoJSON(data, StormPropsSchema);
740
+ }
741
+ /**
742
+ * Get list of recent tropical storms/hurricanes.
743
+ */
744
+ async getRecentStorms() {
745
+ const data = await this.get("/geojson/storms/recent");
746
+ return this.parseGeoJSON(data, StormPropsSchema);
747
+ }
748
+ };
749
+
750
+ // src/domains/volcanic.ts
751
+ import { z as z4 } from "zod";
752
+ var VolcanoesResponseSchema = z4.object({
753
+ provider: z4.string(),
754
+ data: z4.array(createFeatureSchema(VolcanoPropsSchema)),
755
+ timestamp: z4.string(),
756
+ count: z4.number().optional(),
757
+ metadata: LayerMetadataSchema.optional()
758
+ });
759
+ var VolcanicDomain = class extends BaseClient {
760
+ /**
761
+ * Get list of Holocene volcanoes (Smithsonian Institution).
762
+ * Note: API returns array of Features, normalized to FeatureCollection here.
763
+ */
764
+ async getVolcanoes() {
765
+ const raw = await this.get("/geojson/volcanoes");
766
+ const parsed = VolcanoesResponseSchema.parse(raw);
767
+ return {
768
+ provider: parsed.provider,
769
+ data: {
770
+ type: "FeatureCollection",
771
+ features: parsed.data
772
+ },
773
+ timestamp: parsed.timestamp,
774
+ count: parsed.count,
775
+ metadata: parsed.metadata
776
+ };
777
+ }
778
+ /**
779
+ * Get list of currently active volcanoes (GDACS).
780
+ */
781
+ async getActiveVolcanoes() {
782
+ const data = await this.get("/geojson/volcanoes/active");
783
+ return this.parseGeoJSON(data, ActiveVolcanoPropsSchema);
784
+ }
785
+ };
786
+
787
+ // src/domains/weather.ts
788
+ var WeatherDomain = class extends BaseClient {
789
+ /**
790
+ * Get weather stations from WIS2 network.
791
+ * @param filters Optional pagination filters.
792
+ */
793
+ async getWis2Stations(filters = {}) {
794
+ const params = {
795
+ limit: filters.limit ?? 100,
796
+ offset: filters.offset ?? 0
797
+ };
798
+ const data = await this.get("/geojson/stations/wis2", params);
799
+ return this.parseGeoJSON(data, WeatherStationPropsSchema);
800
+ }
801
+ /**
802
+ * Get historical observations for a WIS2 station.
803
+ * @param stationId The station identifier.
804
+ * @param filters Date range and optional WIS2-specific filters.
805
+ */
806
+ async getWis2Observations(stationId, filters) {
807
+ const data = await this.get(`/observations/wis2/${stationId}`, filters);
808
+ return ObservationQueryResultSchema.parse(data);
809
+ }
810
+ /**
811
+ * Get weather stations from IEM/AZOS network.
812
+ */
813
+ async getIemStations() {
814
+ const data = await this.get("/geojson/stations/azos");
815
+ return this.parseGeoJSON(data, WeatherStationPropsSchema);
816
+ }
817
+ /**
818
+ * Get historical observations for an IEM station.
819
+ * @param stationId The station identifier.
820
+ * @param filters Date range filters.
821
+ */
822
+ async getIemObservations(stationId, filters) {
823
+ const data = await this.get(`/observations/iem/${stationId}`, filters);
824
+ return ObservationQueryResultSchema.parse(data);
825
+ }
826
+ /**
827
+ * Get weather stations from NWS (National Weather Service) network.
828
+ */
829
+ async getNWSWeatherStations() {
830
+ const data = await this.get("/geojson/stations/nws");
831
+ return this.parseGeoJSON(data, WeatherStationPropsSchema);
832
+ }
833
+ /**
834
+ * Get active stations that have reported data in the last 24 hours.
835
+ * @param type The station network type ('iem' or 'wis2').
836
+ *
837
+ * Note: This endpoint returns FeatureCollection directly (not LayerResponse envelope).
838
+ */
839
+ async getActiveStations(type) {
840
+ const rawData = await this.get("/stations/active", { type });
841
+ const featureCollection = rawData;
842
+ if (featureCollection?.type === "FeatureCollection") {
843
+ const features = (featureCollection.features ?? []).map((f) => {
844
+ const feature = f;
845
+ return {
846
+ type: "Feature",
847
+ geometry: feature.geometry,
848
+ properties: WeatherStationPropsSchema.parse(feature.properties ?? {}),
849
+ id: feature.id
850
+ };
851
+ });
852
+ return {
853
+ provider: `active-stations-${type}`,
854
+ data: {
855
+ type: "FeatureCollection",
856
+ features
857
+ },
858
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
859
+ count: features.length
860
+ };
861
+ }
862
+ return this.parseGeoJSON(rawData, WeatherStationPropsSchema);
863
+ }
864
+ };
865
+
866
+ // src/events/stream.ts
867
+ import { EventEmitter } from "events";
868
+ var EventStream = class extends EventEmitter {
869
+ eventSource = null;
870
+ url;
871
+ constructor(config) {
872
+ super();
873
+ this.url = `${config.baseUrl}/events/stream?apiKey=${config.apiKey}`;
874
+ }
875
+ /**
876
+ * Start listening to the event stream.
877
+ */
878
+ connect() {
879
+ if (this.eventSource) return;
880
+ this.eventSource = new EventSource(this.url);
881
+ this.eventSource.onmessage = (event) => {
882
+ try {
883
+ const rawData = JSON.parse(event.data);
884
+ const payload = EventPayloadSchema.parse(rawData);
885
+ this.emit("data", payload);
886
+ this.emit(payload.provider, payload);
887
+ } catch (err) {
888
+ this.emit("error", err);
889
+ }
890
+ };
891
+ this.eventSource.onerror = (err) => {
892
+ this.emit("error", err);
893
+ };
894
+ }
895
+ /**
896
+ * Stop listening to the event stream.
897
+ */
898
+ disconnect() {
899
+ if (this.eventSource) {
900
+ this.eventSource.close();
901
+ this.eventSource = null;
902
+ }
903
+ }
904
+ on(event, listener) {
905
+ return super.on(event, listener);
906
+ }
907
+ off(event, listener) {
908
+ return super.off(event, listener);
909
+ }
910
+ };
911
+
912
+ // src/index.ts
913
+ var GeoLayersSDK = class {
914
+ seismic;
915
+ volcanic;
916
+ tropical;
917
+ fire;
918
+ weather;
919
+ maritime;
920
+ aviation;
921
+ /** Observation data warehouse and active stations */
922
+ observations;
923
+ /** Real-time event stream (SSE) */
924
+ events;
925
+ /** Event metadata operations (REST) */
926
+ eventsMeta;
927
+ constructor(config) {
928
+ this.seismic = new SeismicDomain(config);
929
+ this.volcanic = new VolcanicDomain(config);
930
+ this.tropical = new TropicalDomain(config);
931
+ this.fire = new FireDomain(config);
932
+ this.weather = new WeatherDomain(config);
933
+ this.maritime = new MaritimeDomain(config);
934
+ this.aviation = new AviationDomain(config);
935
+ this.observations = new ObservationsDomain(config);
936
+ this.events = new EventStream(config);
937
+ this.eventsMeta = new EventsDomain(config);
938
+ }
939
+ };
940
+ var index_default = GeoLayersSDK;
941
+ export {
942
+ ActiveVolcanoPropsSchema,
943
+ BboxObservationsResultSchema,
944
+ DEFAULT_CONFIG,
945
+ EarthquakePropsSchema,
946
+ EventPayloadSchema,
947
+ FlightPropsSchema,
948
+ FlightScheduleResponseSchema,
949
+ GeoLayersApiError,
950
+ GeoLayersError,
951
+ GeoLayersSDK,
952
+ GeoLayersValidationError,
953
+ GeometrySchema,
954
+ LatestObservationResultSchema,
955
+ LayerMetadataSchema,
956
+ LayerProvider,
957
+ MeasurementValueSchema,
958
+ ObservationProviderSchema,
959
+ ObservationQueryResultSchema,
960
+ ObservationStatsResultSchema,
961
+ StandardMeasurementsSchema,
962
+ StandardObservationSchema,
963
+ StationObservationsResultSchema,
964
+ StormPropsSchema,
965
+ VolcanoPropsSchema,
966
+ WeatherStationPropsSchema,
967
+ WildfirePropsSchema,
968
+ createFeatureCollectionSchema,
969
+ createFeatureSchema,
970
+ createLayerResponseSchema,
971
+ index_default as default
972
+ };