bmlt-query-client 1.0.1 → 1.0.2

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 BMLT Community
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/app.d.ts ADDED
@@ -0,0 +1,977 @@
1
+ export declare interface BaseSearchParams {
2
+ /** Data format for response */
3
+ format?: BmltDataFormat;
4
+ /** Language code for format names */
5
+ lang_enum?: Language;
6
+ /** JSONP callback function name */
7
+ callback?: string;
8
+ }
9
+
10
+ export declare class BmltClient {
11
+ private timeout;
12
+ private userAgent;
13
+ private geocodingService?;
14
+ private rootServerURL;
15
+ private defaultFormat;
16
+ constructor(options: BmltClientOptions);
17
+ /**
18
+ * Make a request to the BMLT API
19
+ */
20
+ private makeRequest;
21
+ /**
22
+ * Search for meetings
23
+ */
24
+ searchMeetings(params?: SearchResultsParams): Promise<Meeting[]>;
25
+ /**
26
+ * Search for meetings by geographic location using geocoding
27
+ */
28
+ searchMeetingsByAddress(params: GeographicSearchParams): Promise<Meeting[]>;
29
+ /**
30
+ * Search for meetings by coordinates
31
+ */
32
+ searchMeetingsByCoordinates(coordinates: Coordinates, radiusMiles?: number, radiusKm?: number, searchParams?: Omit<SearchResultsParams, 'lat_val' | 'long_val' | 'geo_width' | 'geo_width_km'>): Promise<Meeting[]>;
33
+ /**
34
+ * Get available meeting formats
35
+ */
36
+ getFormats(params?: FormatsParams): Promise<Format[]>;
37
+ /**
38
+ * Get service bodies
39
+ */
40
+ getServiceBodies(params?: ServiceBodiesParams): Promise<ServiceBody[]>;
41
+ /**
42
+ * Get meeting changes within a date range
43
+ */
44
+ getChanges(params?: ChangesParams): Promise<Change[]>;
45
+ /**
46
+ * Get available field keys
47
+ */
48
+ getFieldKeys(): Promise<FieldKey[]>;
49
+ /**
50
+ * Get field values for a specific field key
51
+ */
52
+ getFieldValues(params: FieldValuesParams): Promise<FieldValue[]>;
53
+ /**
54
+ * Get NAWS dump for a service body (CSV format only)
55
+ */
56
+ getNAWSDump(params: NAWSDumpParams): Promise<string>;
57
+ /**
58
+ * Get server information
59
+ */
60
+ getServerInfo(): Promise<ServerInfo>;
61
+ /**
62
+ * Get server coverage area
63
+ */
64
+ getCoverageArea(): Promise<CoverageArea>;
65
+ /**
66
+ * Geocode an address using the built-in geocoding service
67
+ */
68
+ geocodeAddress(address: string, options?: Partial<GeocodeOptions>): Promise<GeocodeResult>;
69
+ /**
70
+ * Reverse geocode coordinates to an address
71
+ */
72
+ reverseGeocode(coordinates: Coordinates, options?: Partial<GeocodeOptions>): Promise<GeocodeResult>;
73
+ /**
74
+ * Get the root server URL
75
+ */
76
+ getRootServerURL(): string;
77
+ /**
78
+ * Update the root server URL
79
+ */
80
+ setRootServerURL(url: string): void;
81
+ /**
82
+ * Get the default data format
83
+ */
84
+ getDefaultFormat(): BmltDataFormat;
85
+ /**
86
+ * Set the default data format
87
+ */
88
+ setDefaultFormat(format: BmltDataFormat): void;
89
+ /**
90
+ * Get geocoding service statistics
91
+ */
92
+ getGeocodingStats(): {
93
+ queueSize: number;
94
+ pendingCount: number;
95
+ } | null;
96
+ /**
97
+ * Clear the geocoding queue
98
+ */
99
+ clearGeocodingQueue(): void;
100
+ }
101
+
102
+ export declare interface BmltClientOptions {
103
+ /** Root server URL */
104
+ rootServerURL: string;
105
+ /** Default data format */
106
+ defaultFormat?: BmltDataFormat;
107
+ /** HTTP request timeout in milliseconds */
108
+ timeout?: number;
109
+ /** User agent string */
110
+ userAgent?: string;
111
+ /** Geocoding options */
112
+ geocodingOptions?: GeocodeOptions & RateLimitOptions;
113
+ /** Enable automatic geocoding for address searches */
114
+ enableGeocoding?: boolean;
115
+ }
116
+
117
+ /**
118
+ * Base types and enums for BMLT API
119
+ */
120
+ export declare enum BmltDataFormat {
121
+ JSON = "json",
122
+ JSONP = "jsonp",
123
+ TSML = "tsml",
124
+ CSV = "csv"
125
+ }
126
+
127
+ export declare enum BmltEndpoint {
128
+ GET_SEARCH_RESULTS = "GetSearchResults",
129
+ GET_FORMATS = "GetFormats",
130
+ GET_SERVICE_BODIES = "GetServiceBodies",
131
+ GET_CHANGES = "GetChanges",
132
+ GET_FIELD_KEYS = "GetFieldKeys",
133
+ GET_FIELD_VALUES = "GetFieldValues",
134
+ GET_NAWS_DUMP = "GetNAWSDump",
135
+ GET_SERVER_INFO = "GetServerInfo",
136
+ GET_COVERAGE_AREA = "GetCoverageArea"
137
+ }
138
+
139
+ export declare interface BmltError extends Error {
140
+ statusCode?: number;
141
+ response?: unknown;
142
+ }
143
+
144
+ /**
145
+ * Comprehensive error handling for BMLT Query Client
146
+ */
147
+ export declare enum BmltErrorType {
148
+ API_ERROR = "ApiError",
149
+ NETWORK_ERROR = "NetworkError",
150
+ VALIDATION_ERROR = "ValidationError",
151
+ GEOCODING_ERROR = "GeocodingError",
152
+ RATE_LIMIT_ERROR = "RateLimitError",
153
+ TIMEOUT_ERROR = "TimeoutError",
154
+ AUTHENTICATION_ERROR = "AuthenticationError",
155
+ SERVER_ERROR = "ServerError",
156
+ CLIENT_ERROR = "ClientError",
157
+ CONFIGURATION_ERROR = "ConfigurationError"
158
+ }
159
+
160
+ export declare class BmltQueryError extends Error {
161
+ readonly type: BmltErrorType;
162
+ readonly statusCode?: number;
163
+ readonly response?: unknown;
164
+ readonly originalError?: Error;
165
+ readonly context?: Record<string, unknown>;
166
+ constructor(type: BmltErrorType, message: string, options?: {
167
+ statusCode?: number;
168
+ response?: unknown;
169
+ originalError?: Error;
170
+ context?: Record<string, unknown>;
171
+ });
172
+ /**
173
+ * Check if error is of a specific type
174
+ */
175
+ isType(type: BmltErrorType): boolean;
176
+ /**
177
+ * Check if error is retryable
178
+ */
179
+ isRetryable(): boolean;
180
+ /**
181
+ * Check if error is a client-side error (4xx)
182
+ */
183
+ isClientError(): boolean;
184
+ /**
185
+ * Check if error is a server-side error (5xx)
186
+ */
187
+ isServerError(): boolean;
188
+ /**
189
+ * Get a user-friendly error message
190
+ */
191
+ getUserMessage(): string;
192
+ /**
193
+ * Convert error to JSON for logging
194
+ */
195
+ toJSON(): {
196
+ name: string;
197
+ type: BmltErrorType;
198
+ message: string;
199
+ statusCode: number | undefined;
200
+ response: unknown;
201
+ context: Record<string, unknown> | undefined;
202
+ stack: string | undefined;
203
+ originalError: {
204
+ name: string;
205
+ message: string;
206
+ stack: string | undefined;
207
+ } | undefined;
208
+ };
209
+ }
210
+
211
+ /**
212
+ * Build a BMLT API URL with parameters
213
+ */
214
+ export declare function buildBmltURL(options: URLBuilderOptions): string;
215
+
216
+ export declare interface Change {
217
+ /** Change ID */
218
+ change_id: string;
219
+ /** Meeting ID affected by change */
220
+ meeting_id: string;
221
+ /** Service body ID */
222
+ service_body_id: string;
223
+ /** User ID who made change */
224
+ user_id: string;
225
+ /** User name who made change */
226
+ user_name: string;
227
+ /** Change date (YYYY-MM-DD) */
228
+ change_date: string;
229
+ /** Change time (HH:MM:SS) */
230
+ change_time: string;
231
+ /** Change type */
232
+ change_type: string;
233
+ /** Change description */
234
+ change_description: string;
235
+ /** Meeting name before change */
236
+ original_meeting_name?: string;
237
+ /** Meeting name after change */
238
+ changed_meeting_name?: string;
239
+ /** JSON object with detailed changes */
240
+ json_data?: unknown;
241
+ /** Root server URI (for aggregator mode) */
242
+ root_server_uri?: string;
243
+ }
244
+
245
+ export declare interface ChangesParams extends BaseSearchParams {
246
+ /** Start date in YYYY-MM-DD format */
247
+ start_date?: string;
248
+ /** End date in YYYY-MM-DD format */
249
+ end_date?: string;
250
+ /** Specific meeting ID */
251
+ meeting_id?: number;
252
+ /** Service body ID */
253
+ service_body_id?: number;
254
+ }
255
+
256
+ export declare interface Coordinates {
257
+ latitude: number;
258
+ longitude: number;
259
+ }
260
+
261
+ export declare interface CoverageArea {
262
+ /** North boundary */
263
+ north_latitude: number;
264
+ /** South boundary */
265
+ south_latitude: number;
266
+ /** East boundary */
267
+ east_longitude: number;
268
+ /** West boundary */
269
+ west_longitude: number;
270
+ }
271
+
272
+ /**
273
+ * Factory class for creating specific error types
274
+ */
275
+ export declare class ErrorFactory {
276
+ static createApiError(message: string, statusCode?: number, response?: unknown, originalError?: Error): BmltQueryError;
277
+ static createNetworkError(message: string, originalError?: Error): BmltQueryError;
278
+ static createTimeoutError(message: string, originalError?: Error): BmltQueryError;
279
+ static createValidationError(message: string, context?: Record<string, unknown>): BmltQueryError;
280
+ static createGeocodingError(message: string, originalError?: Error, context?: Record<string, unknown>): BmltQueryError;
281
+ static createRateLimitError(message: string, statusCode?: number, response?: unknown): BmltQueryError;
282
+ static createConfigurationError(message: string, context?: Record<string, unknown>): BmltQueryError;
283
+ }
284
+
285
+ /**
286
+ * Error handler utility class
287
+ */
288
+ export declare class ErrorHandler {
289
+ /**
290
+ * Handle and transform fetch errors
291
+ */
292
+ static handleFetchError(error: unknown, response?: Response): BmltQueryError;
293
+ /**
294
+ * @deprecated Use handleFetchError instead
295
+ */
296
+ static handleAxiosError(error: any): BmltQueryError;
297
+ /**
298
+ * Handle validation errors with detailed context
299
+ */
300
+ static handleValidationError(field: string, value: unknown, expectedType: string, constraints?: string[]): BmltQueryError;
301
+ /**
302
+ * Handle endpoint validation errors
303
+ */
304
+ static handleEndpointError(endpoint: string, format: string): BmltQueryError;
305
+ /**
306
+ * Handle URL validation errors
307
+ */
308
+ static handleUrlError(url: string, reason: string): BmltQueryError;
309
+ /**
310
+ * Handle coordinate validation errors
311
+ */
312
+ static handleCoordinateError(latitude?: number, longitude?: number, reason?: string): BmltQueryError;
313
+ /**
314
+ * Wrap and enhance existing errors
315
+ */
316
+ static wrapError(originalError: Error, context: string, additionalContext?: Record<string, unknown>): BmltQueryError;
317
+ }
318
+
319
+ /**
320
+ * Extract numeric IDs from various parameter formats
321
+ */
322
+ export declare function extractIds(value: unknown): number[];
323
+
324
+ export declare interface FieldKey {
325
+ /** Field key */
326
+ key: string;
327
+ /** Field description */
328
+ description: string;
329
+ }
330
+
331
+ export declare interface FieldValue {
332
+ /** Field key */
333
+ key: string;
334
+ /** Field value */
335
+ value: string;
336
+ /** Meeting ID */
337
+ meeting_id: string;
338
+ }
339
+
340
+ export declare interface FieldValuesParams extends BaseSearchParams {
341
+ /** The field key to get values for (required) */
342
+ meeting_key: string;
343
+ /** Comma-separated list of format IDs to limit field values to */
344
+ specific_formats?: string;
345
+ /** Include all formats */
346
+ all_formats?: boolean;
347
+ }
348
+
349
+ export declare interface Format {
350
+ /** Format ID */
351
+ shared_id_bigint: string;
352
+ /** Format key string */
353
+ key_string: string;
354
+ /** Format name */
355
+ name_string: string;
356
+ /** Format description */
357
+ description_string: string;
358
+ /** Language */
359
+ lang: string;
360
+ /** Root server URI (for aggregator mode) */
361
+ root_server_uri?: string;
362
+ }
363
+
364
+ export declare interface FormatsParams extends BaseSearchParams {
365
+ /** Show all formats */
366
+ show_all?: boolean;
367
+ /** Array of format IDs to include/exclude */
368
+ format_ids?: number[];
369
+ /** Array of format key strings to filter by */
370
+ key_strings?: string[];
371
+ }
372
+
373
+ /**
374
+ * Format time values for BMLT API
375
+ */
376
+ export declare function formatTimeValue(hours?: number, minutes?: number): {
377
+ hours?: number;
378
+ minutes?: number;
379
+ };
380
+
381
+ export declare interface GeocodeOptions {
382
+ retryCount?: number;
383
+ timeout?: number;
384
+ userAgent?: string;
385
+ /** Country code for region bias (e.g., 'us', 'ca', 'gb') */
386
+ countryCode?: string;
387
+ /** Viewbox for region bias [minLon, minLat, maxLon, maxLat] */
388
+ viewbox?: [number, number, number, number];
389
+ /** Bounded search - restrict results to viewbox */
390
+ bounded?: boolean;
391
+ }
392
+
393
+ export declare interface GeocodeResult {
394
+ /** Geocoded coordinates */
395
+ coordinates: Coordinates;
396
+ /** Display name of the geocoded address */
397
+ display_name: string;
398
+ /** Geocoding confidence (0-1) */
399
+ confidence?: number;
400
+ /** Address components */
401
+ address?: {
402
+ house_number?: string;
403
+ road?: string;
404
+ neighbourhood?: string;
405
+ suburb?: string;
406
+ city?: string;
407
+ county?: string;
408
+ state?: string;
409
+ postcode?: string;
410
+ country?: string;
411
+ };
412
+ }
413
+
414
+ export declare class GeocodingService {
415
+ private baseURL;
416
+ private queue;
417
+ private readonly defaultOptions;
418
+ constructor(options?: GeocodeOptions & RateLimitOptions);
419
+ /**
420
+ * Make a fetch request with timeout and error handling
421
+ */
422
+ private fetchWithTimeout;
423
+ /**
424
+ * Geocode an address using Nominatim
425
+ */
426
+ geocode(address: string, options?: Partial<GeocodeOptions>): Promise<GeocodeResult>;
427
+ /**
428
+ * Batch geocode multiple addresses
429
+ */
430
+ batchGeocode(addresses: string[], options?: Partial<GeocodeOptions>): Promise<GeocodeResult[]>;
431
+ /**
432
+ * Reverse geocode coordinates to an address
433
+ */
434
+ reverseGeocode(coordinates: Coordinates, options?: Partial<GeocodeOptions>): Promise<GeocodeResult>;
435
+ /**
436
+ * Get the current queue size
437
+ */
438
+ getQueueSize(): number;
439
+ /**
440
+ * Get the number of pending operations
441
+ */
442
+ getPendingCount(): number;
443
+ /**
444
+ * Clear the queue
445
+ */
446
+ clearQueue(): void;
447
+ /**
448
+ * Set concurrency limit
449
+ */
450
+ setConcurrency(concurrency: number): void;
451
+ }
452
+
453
+ export declare interface GeographicSearchParams {
454
+ /** Address to geocode and search around */
455
+ address: string;
456
+ /** Search radius in miles */
457
+ radiusMiles?: number;
458
+ /** Search radius in kilometers */
459
+ radiusKm?: number;
460
+ /** Sort results by distance */
461
+ sortByDistance?: boolean;
462
+ /** Other search parameters */
463
+ searchParams?: Omit<SearchResultsParams, 'lat_val' | 'long_val' | 'geo_width' | 'geo_width_km' | 'sort_results_by_distance'>;
464
+ }
465
+
466
+ /**
467
+ * Convert kilometers to miles
468
+ */
469
+ export declare function kilometersToMiles(km: number): number;
470
+
471
+ export declare enum Language {
472
+ ENGLISH = "en",
473
+ GERMAN = "de",
474
+ DANISH = "dk",
475
+ SPANISH = "es",
476
+ PERSIAN = "fa",
477
+ FRENCH = "fr",
478
+ ITALIAN = "it",
479
+ POLISH = "pl",
480
+ PORTUGUESE = "pt",
481
+ SWEDISH = "sv"
482
+ }
483
+
484
+ export declare interface Meeting {
485
+ /** Meeting ID */
486
+ id_bigint: string;
487
+ /** Weekday (1-7) */
488
+ weekday_tinyint: number;
489
+ /** Venue type (1=In-person, 2=Virtual, 3=Hybrid) */
490
+ venue_type: number;
491
+ /** Start time (24-hour format HH:MM:SS) */
492
+ start_time: string;
493
+ /** Duration time (HH:MM:SS) */
494
+ duration_time: string;
495
+ /** Time zone */
496
+ time_zone?: string;
497
+ /** Meeting name */
498
+ meeting_name: string;
499
+ /** Location text */
500
+ location_text: string;
501
+ /** Location info */
502
+ location_info?: string;
503
+ /** Location street address */
504
+ location_street?: string;
505
+ /** Location neighborhood */
506
+ location_neighborhood?: string;
507
+ /** Location borough */
508
+ location_municipality?: string;
509
+ /** Location city/town */
510
+ location_city_subsection?: string;
511
+ /** Location postal code */
512
+ location_postal_code_1?: string;
513
+ /** Location province/state */
514
+ location_province?: string;
515
+ /** Location nation */
516
+ location_nation?: string;
517
+ /** Latitude */
518
+ latitude: number;
519
+ /** Longitude */
520
+ longitude: number;
521
+ /** Published status (0=unpublished, 1=published) */
522
+ published: number;
523
+ /** Email contact */
524
+ email_contact?: string;
525
+ /** World Committee Code */
526
+ worldid_mixed?: string;
527
+ /** Shared group ID */
528
+ shared_group_id_bigint?: string;
529
+ /** Service body ID */
530
+ service_body_bigint: string;
531
+ /** Meeting formats (comma-separated format IDs) */
532
+ format_shared_id_list?: string;
533
+ /** Meeting comments */
534
+ comments?: string;
535
+ /** Virtual meeting URL */
536
+ virtual_meeting_link?: string;
537
+ /** Virtual meeting additional info */
538
+ virtual_meeting_additional_info?: string;
539
+ /** Root server URI (for aggregator mode) */
540
+ root_server_uri?: string;
541
+ /** Distance from search point (when using geographic search) */
542
+ distance_in_km?: number;
543
+ /** Distance in miles from search point */
544
+ distance_in_miles?: number;
545
+ }
546
+
547
+ export declare class MeetingQueryBuilder {
548
+ private params;
549
+ private client;
550
+ constructor(client: BmltClient);
551
+ /**
552
+ * Include or exclude specific meeting IDs
553
+ */
554
+ meetingIds(ids: number | number[], exclude?: boolean): this;
555
+ /**
556
+ * Include meetings on specific weekdays
557
+ */
558
+ onWeekdays(...days: Weekday[]): this;
559
+ /**
560
+ * Exclude meetings on specific weekdays
561
+ */
562
+ notOnWeekdays(...days: Weekday[]): this;
563
+ /**
564
+ * Filter by venue types
565
+ */
566
+ venueTypes(...types: VenueType[]): this;
567
+ /**
568
+ * Include only in-person meetings
569
+ */
570
+ inPersonOnly(): this;
571
+ /**
572
+ * Include only virtual meetings
573
+ */
574
+ virtualOnly(): this;
575
+ /**
576
+ * Include only hybrid meetings
577
+ */
578
+ hybridOnly(): this;
579
+ /**
580
+ * Include virtual and hybrid meetings
581
+ */
582
+ virtualOrHybrid(): this;
583
+ /**
584
+ * Filter by meeting formats
585
+ */
586
+ formats(formatIds: number | number[], exclude?: boolean): this;
587
+ /**
588
+ * Use OR logic for format matching instead of AND
589
+ */
590
+ anyFormat(): this;
591
+ /**
592
+ * Filter by service bodies
593
+ */
594
+ serviceBodies(serviceBodyIds: number | number[], exclude?: boolean): this;
595
+ /**
596
+ * Include child service bodies
597
+ */
598
+ includeChildServiceBodies(): this;
599
+ /**
600
+ * Search for specific text
601
+ */
602
+ searchText(text: string): this;
603
+ /**
604
+ * Meetings starting after specific time
605
+ */
606
+ startingAfter(hours: number, minutes?: number): this;
607
+ /**
608
+ * Meetings starting before specific time
609
+ */
610
+ startingBefore(hours: number, minutes?: number): this;
611
+ /**
612
+ * Meetings ending before specific time
613
+ */
614
+ endingBefore(hours: number, minutes?: number): this;
615
+ /**
616
+ * Minimum meeting duration
617
+ */
618
+ minimumDuration(hours?: number, minutes?: number): this;
619
+ /**
620
+ * Maximum meeting duration
621
+ */
622
+ maximumDuration(hours?: number, minutes?: number): this;
623
+ /**
624
+ * Search within geographic area by coordinates
625
+ */
626
+ nearCoordinates(coordinates: Coordinates, radiusMiles?: number, radiusKm?: number): this;
627
+ /**
628
+ * Search for specific field value
629
+ */
630
+ fieldValue(fieldKey: string, value: string): this;
631
+ /**
632
+ * Return only specific fields
633
+ */
634
+ selectFields(...fields: string[]): this;
635
+ /**
636
+ * Sort results by specific fields
637
+ */
638
+ sortBy(...fields: string[]): this;
639
+ /**
640
+ * Sort by predefined aliases
641
+ */
642
+ sortByAlias(alias: SortKey): this;
643
+ /**
644
+ * Sort by distance (requires geographic search)
645
+ */
646
+ sortByDistance(): this;
647
+ /**
648
+ * Set pagination
649
+ */
650
+ paginate(pageSize: number, pageNumber?: number): this;
651
+ /**
652
+ * Include unpublished meetings
653
+ */
654
+ includeUnpublished(): this;
655
+ /**
656
+ * Include only unpublished meetings
657
+ */
658
+ unpublishedOnly(): this;
659
+ /**
660
+ * Set language for format names
661
+ */
662
+ language(lang: Language): this;
663
+ /**
664
+ * Set response format
665
+ */
666
+ format(format: BmltDataFormat): this;
667
+ /**
668
+ * Include formats used in search results
669
+ */
670
+ includeFormats(): this;
671
+ /**
672
+ * Return only formats (requires includeFormats)
673
+ */
674
+ formatsOnly(): this;
675
+ /**
676
+ * Filter by root server IDs (aggregator mode)
677
+ */
678
+ rootServerIds(serverIds: number | number[], exclude?: boolean): this;
679
+ /**
680
+ * Get the current query parameters
681
+ */
682
+ getParams(): SearchResultsParams;
683
+ /**
684
+ * Reset the query builder
685
+ */
686
+ reset(): this;
687
+ /**
688
+ * Clone the current query builder
689
+ */
690
+ clone(): MeetingQueryBuilder;
691
+ /**
692
+ * Execute the search and return results
693
+ */
694
+ execute(): Promise<Meeting[]>;
695
+ /**
696
+ * Execute the search by geocoding an address first
697
+ */
698
+ executeNearAddress(address: string, radiusMiles?: number, radiusKm?: number, sortByDistance?: boolean): Promise<Meeting[]>;
699
+ }
700
+
701
+ /**
702
+ * Convert miles to kilometers
703
+ */
704
+ export declare function milesToKilometers(miles: number): number;
705
+
706
+ export declare interface NAWSDumpParams extends Record<string, unknown> {
707
+ /** Service body ID (required) */
708
+ sb_id: number;
709
+ }
710
+
711
+ export declare interface NominatimResponse {
712
+ place_id: number;
713
+ licence: string;
714
+ osm_type: string;
715
+ osm_id: number;
716
+ lat: string;
717
+ lon: string;
718
+ display_name: string;
719
+ address?: {
720
+ house_number?: string;
721
+ road?: string;
722
+ neighbourhood?: string;
723
+ suburb?: string;
724
+ city?: string;
725
+ town?: string;
726
+ village?: string;
727
+ county?: string;
728
+ state?: string;
729
+ postcode?: string;
730
+ country?: string;
731
+ country_code?: string;
732
+ };
733
+ importance?: number;
734
+ boundingbox: string[];
735
+ }
736
+
737
+ /**
738
+ * Normalize parameter values for BMLT API
739
+ */
740
+ export declare function normalizeParameters(params: Record<string, unknown>): Record<string, unknown>;
741
+
742
+ /**
743
+ * Convenience methods for common search patterns
744
+ */
745
+ export declare class QuickSearch {
746
+ private client;
747
+ constructor(client: BmltClient);
748
+ /**
749
+ * Search for today's meetings
750
+ */
751
+ today(): MeetingQueryBuilder;
752
+ /**
753
+ * Search for weekend meetings
754
+ */
755
+ weekend(): MeetingQueryBuilder;
756
+ /**
757
+ * Search for weekday meetings
758
+ */
759
+ weekdays(): MeetingQueryBuilder;
760
+ /**
761
+ * Search for evening meetings (after 5 PM)
762
+ */
763
+ evening(): MeetingQueryBuilder;
764
+ /**
765
+ * Search for morning meetings (before 12 PM)
766
+ */
767
+ morning(): MeetingQueryBuilder;
768
+ /**
769
+ * Search for virtual meetings only
770
+ */
771
+ virtual(): MeetingQueryBuilder;
772
+ /**
773
+ * Search for in-person meetings only
774
+ */
775
+ inPerson(): MeetingQueryBuilder;
776
+ /**
777
+ * Search by meeting name or location
778
+ */
779
+ byText(searchText: string): MeetingQueryBuilder;
780
+ }
781
+
782
+ export declare interface RateLimitOptions {
783
+ intervalCap?: number;
784
+ interval?: number;
785
+ carryoverConcurrencyCount?: boolean;
786
+ concurrency?: number;
787
+ }
788
+
789
+ export declare class RetryHandler {
790
+ static withRetry<T>(operation: () => Promise<T>, options: RetryOptions): Promise<T>;
791
+ }
792
+
793
+ /**
794
+ * Retry utility for handling retryable errors
795
+ */
796
+ export declare interface RetryOptions {
797
+ maxRetries: number;
798
+ baseDelay: number;
799
+ maxDelay: number;
800
+ factor: number;
801
+ onRetry?: (error: BmltQueryError, attempt: number) => void;
802
+ }
803
+
804
+ export declare interface SearchResultsParams extends BaseSearchParams {
805
+ /** Include specific meeting IDs (positive) or exclude (negative) */
806
+ meeting_ids?: number | number[];
807
+ /** Include formats used in search results */
808
+ get_used_formats?: boolean;
809
+ /** Return only formats (requires get_used_formats=true) */
810
+ get_formats_only?: boolean;
811
+ /** Include meetings on specific days */
812
+ weekdays?: Weekday | Weekday[];
813
+ /** Include meetings with specific venue types */
814
+ venue_types?: VenueType | VenueType[];
815
+ /** Include meetings with specific formats */
816
+ formats?: number | number[];
817
+ /** Use OR logic for format matching (default is AND) */
818
+ formats_comparison_operator?: 'OR';
819
+ /** Include meetings from specific service bodies */
820
+ services?: number | number[];
821
+ /** Include child service bodies when filtering by services */
822
+ recursive?: boolean;
823
+ /** Search for specific text */
824
+ SearchString?: string;
825
+ /** Search radius for geographic searches */
826
+ SearchStringRadius?: number;
827
+ /** Meetings starting after hour (0-23) */
828
+ StartsAfterH?: number;
829
+ /** Meetings starting after minute (0-59) */
830
+ StartsAfterM?: number;
831
+ /** Meetings starting before hour (0-23) */
832
+ StartsBeforeH?: number;
833
+ /** Meetings starting before minute (0-59) */
834
+ StartsBeforeM?: number;
835
+ /** Meetings ending before hour (0-23) */
836
+ EndsBeforeH?: number;
837
+ /** Meetings ending before minute (0-59) */
838
+ EndsBeforeM?: number;
839
+ /** Minimum duration in hours */
840
+ MinDurationH?: number;
841
+ /** Minimum duration in minutes */
842
+ MinDurationM?: number;
843
+ /** Maximum duration in hours */
844
+ MaxDurationH?: number;
845
+ /** Maximum duration in minutes */
846
+ MaxDurationM?: number;
847
+ /** Latitude for geographic search */
848
+ lat_val?: number;
849
+ /** Longitude for geographic search */
850
+ long_val?: number;
851
+ /** Search radius in miles */
852
+ geo_width?: number;
853
+ /** Search radius in kilometers */
854
+ geo_width_km?: number;
855
+ /** Sort results by distance when using geographic search */
856
+ sort_results_by_distance?: boolean;
857
+ /** Search for specific field value */
858
+ meeting_key?: string;
859
+ /** The value to search for */
860
+ meeting_key_value?: string;
861
+ /** Return only specific fields (comma-separated) */
862
+ data_field_key?: string;
863
+ /** Sort results by specific fields (comma-separated) */
864
+ sort_keys?: string;
865
+ /** Use predefined sort aliases */
866
+ sort_key?: SortKey;
867
+ /** Number of results per page */
868
+ page_size?: number;
869
+ /** Page number (defaults to 1) */
870
+ page_num?: number;
871
+ /** Published status: undefined=published only, 0=all, -1=unpublished only */
872
+ advanced_published?: 0 | -1;
873
+ /** Include specific root server IDs (for aggregator mode) */
874
+ root_server_ids?: number | number[];
875
+ }
876
+
877
+ export declare interface ServerInfo {
878
+ /** Server version */
879
+ version: string;
880
+ /** Available endpoints */
881
+ availableEndpoints: string[];
882
+ /** Supported formats */
883
+ supportedFormats: string[];
884
+ /** Supported languages */
885
+ langs: string[];
886
+ /** Native language */
887
+ nativeLang: string;
888
+ /** Server name */
889
+ name?: string;
890
+ /** Server description */
891
+ description?: string;
892
+ /** Coverage area information */
893
+ coverageArea?: CoverageArea;
894
+ }
895
+
896
+ export declare interface ServiceBodiesParams extends BaseSearchParams {
897
+ /** Array of service body IDs to include/exclude */
898
+ services?: number[];
899
+ /** Include child service bodies */
900
+ recursive?: boolean;
901
+ /** Include parent service bodies */
902
+ parents?: boolean;
903
+ }
904
+
905
+ export declare interface ServiceBody {
906
+ /** Service body ID */
907
+ id: string;
908
+ /** Service body name */
909
+ name: string;
910
+ /** Service body description */
911
+ description?: string;
912
+ /** Service body type */
913
+ type: string;
914
+ /** Service body URL */
915
+ url?: string;
916
+ /** Help line */
917
+ helpline?: string;
918
+ /** World service committee code */
919
+ world_id?: string;
920
+ /** Parent service body ID */
921
+ parent_id?: string;
922
+ /** Root server URI (for aggregator mode) */
923
+ root_server_uri?: string;
924
+ }
925
+
926
+ export declare enum SortKey {
927
+ WEEKDAY = "weekday",
928
+ TIME = "time",
929
+ TOWN = "town",
930
+ STATE = "state",
931
+ WEEKDAY_STATE = "weekday_state"
932
+ }
933
+
934
+ export declare interface URLBuilderOptions {
935
+ rootServerURL: string;
936
+ format: BmltDataFormat;
937
+ endpoint: BmltEndpoint;
938
+ parameters?: Record<string, unknown>;
939
+ }
940
+
941
+ /**
942
+ * Validate coordinate values
943
+ */
944
+ export declare function validateCoordinates(latitude: number, longitude: number): void;
945
+
946
+ /**
947
+ * Validate endpoint/format combinations
948
+ */
949
+ export declare function validateEndpointFormat(endpoint: BmltEndpoint, format: BmltDataFormat): void;
950
+
951
+ /**
952
+ * Validate radius values
953
+ */
954
+ export declare function validateRadius(radius: number): void;
955
+
956
+ /**
957
+ * Clean and validate a root server URL
958
+ */
959
+ export declare function validateRootServerURL(url: string): string;
960
+
961
+ export declare enum VenueType {
962
+ IN_PERSON = 1,
963
+ VIRTUAL = 2,
964
+ HYBRID = 3
965
+ }
966
+
967
+ export declare enum Weekday {
968
+ SUNDAY = 1,
969
+ MONDAY = 2,
970
+ TUESDAY = 3,
971
+ WEDNESDAY = 4,
972
+ THURSDAY = 5,
973
+ FRIDAY = 6,
974
+ SATURDAY = 7
975
+ }
976
+
977
+ export { }
package/package.json CHANGED
@@ -1,60 +1,58 @@
1
1
  {
2
2
  "name": "bmlt-query-client",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "A TypeScript client for querying BMLT (Basic Meeting List Tool) servers with built-in geocoding support",
5
5
  "type": "module",
6
- "main": "dist/index.cjs.js",
7
- "module": "dist/index.es.js",
8
- "types": "dist/index.d.ts",
6
+ "main": "dist/app.js",
7
+ "module": "dist/app.js",
8
+ "types": "dist/app.d.ts",
9
+ "browser": "dist/app.js",
9
10
  "exports": {
10
11
  ".": {
11
- "types": "./dist/index.d.ts",
12
- "import": "./dist/index.es.js",
13
- "require": "./dist/index.cjs.js"
12
+ "types": "./dist/app.d.ts",
13
+ "import": "./dist/app.js",
14
+ "browser": "./dist/app.js",
15
+ "default": "./dist/app.js"
14
16
  }
15
17
  },
16
18
  "scripts": {
17
19
  "build": "vite build",
18
- "build:esm": "vite build --config vite.esm.config.ts",
19
- "build:all": "npm run build && npm run build:esm",
20
- "dev": "vite build --watch",
20
+ "clean": "rimraf dist",
21
21
  "test": "vitest",
22
- "test:ui": "vitest --ui",
23
- "lint": "eslint src --ext .ts",
24
- "prepublishOnly": "npm run build:all",
25
- "clean": "rimraf dist"
22
+ "test:ci": "vitest run",
23
+ "lint": "eslint src --ext ts",
24
+ "type-check": "tsc --noEmit"
26
25
  },
27
26
  "keywords": [
28
27
  "bmlt",
29
28
  "meetings",
30
29
  "recovery",
31
30
  "na",
32
- "aa",
33
31
  "typescript",
34
32
  "geocoding",
35
33
  "api-client"
36
34
  ],
37
- "author": "Your Name",
35
+ "author": "Patrick Joyce",
38
36
  "license": "MIT",
39
37
  "repository": {
40
38
  "type": "git",
41
- "url": "https://github.com/your-username/bmlt-query-client.git"
39
+ "url": "https://github.com/bmlt-enabled/bmlt-query-client.git"
42
40
  },
43
41
  "dependencies": {
44
- "p-retry": "^6.2.0",
45
- "p-queue": "^8.0.1"
42
+ "p-queue": "^8.0.1",
43
+ "p-retry": "^6.2.0"
46
44
  },
47
45
  "devDependencies": {
48
46
  "@types/node": "^20.0.0",
49
47
  "@typescript-eslint/eslint-plugin": "^6.0.0",
50
48
  "@typescript-eslint/parser": "^6.0.0",
49
+ "@vitest/ui": "^3.2.4",
51
50
  "eslint": "^8.0.0",
52
51
  "rimraf": "^5.0.0",
53
52
  "typescript": "^5.0.0",
54
53
  "vite": "^7.0.0",
55
- "vitest": "^3.0.0",
56
- "@vitest/ui": "^3.2.4",
57
- "vite-plugin-dts": "^4.5.4"
54
+ "vite-plugin-dts": "^4.5.4",
55
+ "vitest": "^3.0.0"
58
56
  },
59
57
  "engines": {
60
58
  "node": ">=16"
package/vite.config.ts CHANGED
@@ -1,35 +1,28 @@
1
- /// <reference types="vitest/config" />
2
-
3
1
  import { defineConfig } from 'vite';
4
2
  import { resolve } from 'path';
5
3
  import dts from 'vite-plugin-dts';
6
4
 
5
+ // ES Module build for direct browser import via <script type="module">
7
6
  export default defineConfig({
8
- plugins: [dts()],
7
+ plugins: [
8
+ dts({
9
+ outDir: 'dist',
10
+ insertTypesEntry: true,
11
+ rollupTypes: true
12
+ })
13
+ ],
9
14
  build: {
10
15
  lib: {
11
16
  entry: resolve(__dirname, 'src/index.ts'),
12
- name: 'BmltQueryClient',
13
- fileName: (format) => `index.${format}.js`,
14
- formats: ['es', 'cjs']
15
- },
16
- rollupOptions: {
17
- external: ['axios', 'p-retry', 'p-queue'],
18
- output: {
19
- globals: {
20
- axios: 'axios',
21
- 'p-retry': 'pRetry',
22
- 'p-queue': 'PQueue'
23
- }
24
- }
17
+ fileName: () => 'app.js',
18
+ formats: ['es']
25
19
  },
20
+ outDir: 'dist',
26
21
  sourcemap: true,
27
- target: 'es2020'
28
- },
29
- test: {
30
- environment: 'node',
31
- globals: true,
32
- timeout: 30000,
33
- setupFiles: ['./test/setup.ts']
22
+ target: 'es2020',
23
+ rollupOptions: {
24
+ // Don't externalize any dependencies - bundle everything for browser use
25
+ external: []
26
+ }
34
27
  }
35
28
  });
@@ -1,20 +0,0 @@
1
- import { defineConfig } from 'vite';
2
- import { resolve } from 'path';
3
-
4
- // ES Module build for direct browser import via <script type="module">
5
- export default defineConfig({
6
- build: {
7
- lib: {
8
- entry: resolve(__dirname, 'src/index.ts'),
9
- fileName: () => 'app.js',
10
- formats: ['es']
11
- },
12
- outDir: 'dist',
13
- sourcemap: true,
14
- target: 'es2020',
15
- rollupOptions: {
16
- // Don't externalize any dependencies - bundle everything for browser use
17
- external: []
18
- }
19
- }
20
- });