mcp-travelcode 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.
Files changed (70) hide show
  1. package/README.md +133 -0
  2. package/build/auth/cli-auth.d.ts +16 -0
  3. package/build/auth/cli-auth.js +281 -0
  4. package/build/auth/token-store.d.ts +39 -0
  5. package/build/auth/token-store.js +113 -0
  6. package/build/client/api-client.d.ts +42 -0
  7. package/build/client/api-client.js +235 -0
  8. package/build/client/types.d.ts +420 -0
  9. package/build/client/types.js +3 -0
  10. package/build/config.d.ts +9 -0
  11. package/build/config.js +30 -0
  12. package/build/formatters/aerodatabox-formatter.d.ts +6 -0
  13. package/build/formatters/aerodatabox-formatter.js +246 -0
  14. package/build/formatters/airline-formatter.d.ts +3 -0
  15. package/build/formatters/airline-formatter.js +12 -0
  16. package/build/formatters/airport-formatter.d.ts +4 -0
  17. package/build/formatters/airport-formatter.js +28 -0
  18. package/build/formatters/flight-formatter.d.ts +13 -0
  19. package/build/formatters/flight-formatter.js +100 -0
  20. package/build/formatters/hotel-formatter.d.ts +4 -0
  21. package/build/formatters/hotel-formatter.js +55 -0
  22. package/build/formatters/order-formatter.d.ts +8 -0
  23. package/build/formatters/order-formatter.js +115 -0
  24. package/build/http-server.d.ts +16 -0
  25. package/build/http-server.js +164 -0
  26. package/build/index.d.ts +3 -0
  27. package/build/index.js +16 -0
  28. package/build/polling/flight-poller.d.ts +11 -0
  29. package/build/polling/flight-poller.js +60 -0
  30. package/build/server.d.ts +4 -0
  31. package/build/server.js +54 -0
  32. package/build/tools/cancel-order.d.ts +9 -0
  33. package/build/tools/cancel-order.js +24 -0
  34. package/build/tools/check-order-cancellation.d.ts +8 -0
  35. package/build/tools/check-order-cancellation.js +22 -0
  36. package/build/tools/check-order-modification.d.ts +8 -0
  37. package/build/tools/check-order-modification.js +22 -0
  38. package/build/tools/create-order.d.ts +75 -0
  39. package/build/tools/create-order.js +52 -0
  40. package/build/tools/get-airport-delay-stats.d.ts +9 -0
  41. package/build/tools/get-airport-delay-stats.js +31 -0
  42. package/build/tools/get-airport-flights.d.ts +13 -0
  43. package/build/tools/get-airport-flights.js +78 -0
  44. package/build/tools/get-airport.d.ts +8 -0
  45. package/build/tools/get-airport.js +25 -0
  46. package/build/tools/get-flight-delay-stats.d.ts +8 -0
  47. package/build/tools/get-flight-delay-stats.js +28 -0
  48. package/build/tools/get-flight-results.d.ts +16 -0
  49. package/build/tools/get-flight-results.js +68 -0
  50. package/build/tools/get-flight-status.d.ts +11 -0
  51. package/build/tools/get-flight-status.js +42 -0
  52. package/build/tools/get-hotel-location.d.ts +8 -0
  53. package/build/tools/get-hotel-location.js +27 -0
  54. package/build/tools/get-order.d.ts +8 -0
  55. package/build/tools/get-order.js +22 -0
  56. package/build/tools/list-orders.d.ts +16 -0
  57. package/build/tools/list-orders.js +46 -0
  58. package/build/tools/modify-order.d.ts +10 -0
  59. package/build/tools/modify-order.js +33 -0
  60. package/build/tools/search-airlines.d.ts +9 -0
  61. package/build/tools/search-airlines.js +29 -0
  62. package/build/tools/search-airports.d.ts +9 -0
  63. package/build/tools/search-airports.js +30 -0
  64. package/build/tools/search-flights.d.ts +17 -0
  65. package/build/tools/search-flights.js +82 -0
  66. package/build/tools/search-hotel-locations.d.ts +9 -0
  67. package/build/tools/search-hotel-locations.js +23 -0
  68. package/build/tools/search-hotels.d.ts +46 -0
  69. package/build/tools/search-hotels.js +106 -0
  70. package/package.json +60 -0
@@ -0,0 +1,235 @@
1
+ import { getValidToken } from "../auth/token-store.js";
2
+ export class TravelCodeAuthError extends Error {
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = "TravelCodeAuthError";
6
+ }
7
+ }
8
+ export class TravelCodeNotFoundError extends Error {
9
+ constructor(message) {
10
+ super(message);
11
+ this.name = "TravelCodeNotFoundError";
12
+ }
13
+ }
14
+ export class TravelCodeValidationError extends Error {
15
+ constructor(message) {
16
+ super(message);
17
+ this.name = "TravelCodeValidationError";
18
+ }
19
+ }
20
+ export class TravelCodeServerError extends Error {
21
+ constructor(message) {
22
+ super(message);
23
+ this.name = "TravelCodeServerError";
24
+ }
25
+ }
26
+ export class TravelCodeApiClient {
27
+ baseUrl;
28
+ token;
29
+ issuer;
30
+ constructor(config) {
31
+ this.baseUrl = config.apiBaseUrl;
32
+ this.token = config.apiToken;
33
+ this.issuer = config.oauthIssuer ?? "";
34
+ }
35
+ /**
36
+ * Ensures the token is still valid, refreshing via OAuth if needed.
37
+ * Falls back to the current token if refresh is not available.
38
+ */
39
+ async ensureValidToken() {
40
+ if (!this.issuer)
41
+ return; // static token, no refresh
42
+ const freshToken = await getValidToken(this.issuer);
43
+ if (freshToken) {
44
+ this.token = freshToken;
45
+ }
46
+ }
47
+ async get(path, params) {
48
+ await this.ensureValidToken();
49
+ const url = new URL(`${this.baseUrl}${path}`);
50
+ if (params) {
51
+ for (const [key, value] of Object.entries(params)) {
52
+ if (value !== undefined) {
53
+ url.searchParams.set(key, String(value));
54
+ }
55
+ }
56
+ }
57
+ const response = await fetch(url.toString(), {
58
+ method: "GET",
59
+ headers: this.headers(),
60
+ });
61
+ return this.handleResponse(response);
62
+ }
63
+ async post(path, body, extraHeaders) {
64
+ await this.ensureValidToken();
65
+ const headers = {
66
+ ...this.headers(),
67
+ "Content-Type": "application/json",
68
+ ...extraHeaders,
69
+ };
70
+ const response = await fetch(`${this.baseUrl}${path}`, {
71
+ method: "POST",
72
+ headers,
73
+ body: body !== undefined ? JSON.stringify(body) : undefined,
74
+ });
75
+ return this.handleResponse(response);
76
+ }
77
+ async getAerodatabox(aerodataboxPath, params) {
78
+ await this.ensureValidToken();
79
+ // Build the AeroDataBox path with query params
80
+ const pathUrl = new URL(`https://placeholder${aerodataboxPath}`);
81
+ if (params) {
82
+ for (const [key, value] of Object.entries(params)) {
83
+ if (value !== undefined) {
84
+ pathUrl.searchParams.set(key, String(value));
85
+ }
86
+ }
87
+ }
88
+ const fullAeroPath = pathUrl.pathname + pathUrl.search;
89
+ // Proxy URL: strip /v1 from base URL, route through /flight/aerodatabox
90
+ const proxyBaseUrl = this.baseUrl.replace(/\/v1\/?$/, "");
91
+ const proxyUrl = new URL(`${proxyBaseUrl}/flight/aerodatabox`);
92
+ proxyUrl.searchParams.set("path", fullAeroPath);
93
+ const response = await fetch(proxyUrl.toString(), {
94
+ method: "GET",
95
+ headers: this.headers(),
96
+ });
97
+ return this.handleResponse(response);
98
+ }
99
+ /**
100
+ * POST request that returns an SSE stream.
101
+ * Collects events and returns them as an array of {event, data} objects.
102
+ */
103
+ async postSSE(path, body, timeoutMs = 130_000) {
104
+ await this.ensureValidToken();
105
+ // Hotels API uses accessToken in body, not Bearer header
106
+ const bodyWithToken = { ...body, accessToken: this.token };
107
+ const controller = new AbortController();
108
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
109
+ try {
110
+ const response = await fetch(`${this.baseUrl}${path}`, {
111
+ method: "POST",
112
+ headers: {
113
+ "Content-Type": "application/json",
114
+ "X-Source": "mcp-server",
115
+ Accept: "text/event-stream",
116
+ },
117
+ body: JSON.stringify(bodyWithToken),
118
+ signal: controller.signal,
119
+ });
120
+ if (!response.ok) {
121
+ let errorMessage;
122
+ try {
123
+ const errorBody = (await response.json());
124
+ errorMessage = errorBody.message || errorBody.text || `HTTP ${response.status}`;
125
+ }
126
+ catch {
127
+ errorMessage = `HTTP ${response.status}: ${response.statusText}`;
128
+ }
129
+ if (response.status === 401)
130
+ throw new TravelCodeAuthError(errorMessage);
131
+ if (response.status === 404)
132
+ throw new TravelCodeNotFoundError(errorMessage);
133
+ if (response.status >= 500)
134
+ throw new TravelCodeServerError(errorMessage);
135
+ throw new Error(`API error: ${errorMessage}`);
136
+ }
137
+ if (!response.body) {
138
+ throw new Error("No response body for SSE stream");
139
+ }
140
+ const events = [];
141
+ const reader = response.body.getReader();
142
+ const decoder = new TextDecoder();
143
+ let buffer = "";
144
+ let currentEvent = "";
145
+ while (true) {
146
+ const { done, value } = await reader.read();
147
+ if (done)
148
+ break;
149
+ buffer += decoder.decode(value, { stream: true });
150
+ const lines = buffer.split("\n");
151
+ buffer = lines.pop() ?? "";
152
+ for (const line of lines) {
153
+ if (line.startsWith("event: ")) {
154
+ currentEvent = line.slice(7).trim();
155
+ }
156
+ else if (line.startsWith("data: ")) {
157
+ const raw = line.slice(6);
158
+ try {
159
+ const data = JSON.parse(raw);
160
+ events.push({ event: currentEvent, data });
161
+ // Stop reading after terminal events
162
+ if (currentEvent === "completed" || currentEvent === "error" || currentEvent === "timeout") {
163
+ reader.cancel();
164
+ return events;
165
+ }
166
+ }
167
+ catch {
168
+ // skip malformed JSON lines
169
+ }
170
+ }
171
+ }
172
+ }
173
+ return events;
174
+ }
175
+ finally {
176
+ clearTimeout(timer);
177
+ }
178
+ }
179
+ /**
180
+ * GET with accessToken as query parameter (used by hotel location endpoints).
181
+ */
182
+ async getWithTokenParam(path, params) {
183
+ await this.ensureValidToken();
184
+ const allParams = { ...params, accessToken: this.token };
185
+ const url = new URL(`${this.baseUrl}${path}`);
186
+ for (const [key, value] of Object.entries(allParams)) {
187
+ if (value !== undefined) {
188
+ url.searchParams.set(key, String(value));
189
+ }
190
+ }
191
+ const response = await fetch(url.toString(), {
192
+ method: "GET",
193
+ headers: {
194
+ "X-Source": "mcp-server",
195
+ Accept: "application/json",
196
+ },
197
+ });
198
+ return this.handleResponse(response);
199
+ }
200
+ headers() {
201
+ return {
202
+ Authorization: `Bearer ${this.token}`,
203
+ "X-Source": "mcp-server",
204
+ Accept: "application/json",
205
+ };
206
+ }
207
+ async handleResponse(response) {
208
+ if (response.ok) {
209
+ return (await response.json());
210
+ }
211
+ let errorMessage;
212
+ try {
213
+ const errorBody = (await response.json());
214
+ errorMessage = errorBody.message || errorBody.text || `HTTP ${response.status}`;
215
+ }
216
+ catch {
217
+ errorMessage = `HTTP ${response.status}: ${response.statusText}`;
218
+ }
219
+ switch (response.status) {
220
+ case 400:
221
+ case 422:
222
+ throw new TravelCodeValidationError(errorMessage);
223
+ case 401:
224
+ throw new TravelCodeAuthError(errorMessage);
225
+ case 404:
226
+ throw new TravelCodeNotFoundError(errorMessage);
227
+ default:
228
+ if (response.status >= 500) {
229
+ throw new TravelCodeServerError(errorMessage);
230
+ }
231
+ throw new Error(`API error: ${errorMessage}`);
232
+ }
233
+ }
234
+ }
235
+ //# sourceMappingURL=api-client.js.map
@@ -0,0 +1,420 @@
1
+ export interface AirportCountry {
2
+ title: string;
3
+ titleEn: string;
4
+ code: string;
5
+ }
6
+ export interface AirportCity {
7
+ code: string;
8
+ title: string;
9
+ titleEn: string;
10
+ }
11
+ export interface Airport {
12
+ id: string | number;
13
+ code: string;
14
+ title: string;
15
+ titleEn: string;
16
+ country?: AirportCountry;
17
+ city?: AirportCity;
18
+ isAirport?: boolean;
19
+ sort?: number;
20
+ }
21
+ export interface Airline {
22
+ id: number;
23
+ code: string;
24
+ title: string;
25
+ }
26
+ export interface FlightSearchRequest {
27
+ locationFrom: string;
28
+ locationTo: string;
29
+ date: string;
30
+ dateEnd?: string;
31
+ cabinClass: string;
32
+ adults: number;
33
+ children: number;
34
+ infants: number;
35
+ airlines?: string[];
36
+ }
37
+ export interface FlightSearchCreateResponse {
38
+ status: string;
39
+ errors: string[];
40
+ warnings: string[];
41
+ cacheId: string;
42
+ countServices: number;
43
+ countFinishedServices: number;
44
+ countFailedServices: number;
45
+ count: number;
46
+ completed: boolean;
47
+ }
48
+ export interface FlightSegmentEndpoint {
49
+ iata_code: string;
50
+ at: string;
51
+ terminal: string;
52
+ airport: {
53
+ iata_code: string;
54
+ title: string;
55
+ };
56
+ }
57
+ export interface FlightSegment {
58
+ departure: FlightSegmentEndpoint;
59
+ arrival: FlightSegmentEndpoint;
60
+ carrier_code: string;
61
+ number: string;
62
+ duration: string;
63
+ cabin: string;
64
+ }
65
+ export interface FlightItinerary {
66
+ duration: string;
67
+ segments: FlightSegment[];
68
+ transfers: number;
69
+ }
70
+ export interface FlightPrice {
71
+ currency: string;
72
+ totalPrice: number;
73
+ inclusivePrice: number;
74
+ exclusivePrice: number;
75
+ }
76
+ export interface FlightOfferItem {
77
+ service: string;
78
+ type: string;
79
+ availableSeats: number;
80
+ cabinClass: string;
81
+ airline: string;
82
+ includeBaggage: boolean;
83
+ include_baggage?: {
84
+ count: number;
85
+ unit: string;
86
+ };
87
+ price: FlightPrice;
88
+ itineraries: FlightItinerary[];
89
+ id: number;
90
+ }
91
+ export interface FlightOffer {
92
+ totalPrice: number;
93
+ totalPriceNet: number;
94
+ durationTime: string;
95
+ items: FlightOfferItem[];
96
+ }
97
+ export interface DictionaryAirport {
98
+ title: string;
99
+ titleEn: string;
100
+ city?: {
101
+ code: string;
102
+ title: string;
103
+ titleEn: string;
104
+ };
105
+ country?: {
106
+ code: string;
107
+ title: string;
108
+ titleEn: string;
109
+ };
110
+ }
111
+ export interface FlightSearchResultsResponse {
112
+ status: string;
113
+ cacheId: string;
114
+ items: FlightOffer[];
115
+ total: number;
116
+ limit: number;
117
+ offset: number;
118
+ currency: string;
119
+ currencySign: string;
120
+ completed?: boolean;
121
+ countServices?: number;
122
+ countFinishedServices?: number;
123
+ countFailedServices?: number;
124
+ count?: number;
125
+ airlines?: Record<string, string>;
126
+ filters?: string[];
127
+ dictionaries?: {
128
+ airports?: Record<string, DictionaryAirport>;
129
+ };
130
+ }
131
+ export interface AeroFlightTime {
132
+ utc?: string;
133
+ local?: string;
134
+ }
135
+ export interface AeroFlightEndpoint {
136
+ airport?: {
137
+ icao?: string;
138
+ iata?: string;
139
+ name?: string;
140
+ shortName?: string;
141
+ municipalityName?: string;
142
+ location?: {
143
+ lat?: number;
144
+ lon?: number;
145
+ };
146
+ countryCode?: string;
147
+ };
148
+ scheduledTime?: AeroFlightTime;
149
+ revisedTime?: AeroFlightTime;
150
+ predictedTime?: AeroFlightTime;
151
+ actualTime?: AeroFlightTime;
152
+ terminal?: string;
153
+ gate?: string;
154
+ baggageBelt?: string;
155
+ checkInDesk?: string;
156
+ quality?: string[];
157
+ }
158
+ export interface AeroFlightAircraft {
159
+ reg?: string;
160
+ modeS?: string;
161
+ model?: string;
162
+ image?: {
163
+ url?: string;
164
+ webUrl?: string;
165
+ author?: string;
166
+ title?: string;
167
+ description?: string;
168
+ };
169
+ }
170
+ export interface AeroFlightStatus {
171
+ type?: string;
172
+ status?: string;
173
+ departure: AeroFlightEndpoint;
174
+ arrival: AeroFlightEndpoint;
175
+ number?: string;
176
+ callSign?: string;
177
+ airline?: {
178
+ name?: string;
179
+ iata?: string;
180
+ icao?: string;
181
+ };
182
+ aircraft?: AeroFlightAircraft;
183
+ location?: {
184
+ pressureAltFt?: number;
185
+ gsKt?: number;
186
+ lat?: number;
187
+ lon?: number;
188
+ };
189
+ codeshareStatus?: string;
190
+ isCargo?: boolean;
191
+ greatCircleDistance?: {
192
+ meter?: number;
193
+ km?: number;
194
+ mile?: number;
195
+ };
196
+ }
197
+ export type AeroFlightStatusResponse = AeroFlightStatus[];
198
+ export interface AeroBoardFlight {
199
+ departure: AeroFlightEndpoint;
200
+ arrival: AeroFlightEndpoint;
201
+ number?: string;
202
+ status?: string;
203
+ codeshareStatus?: string;
204
+ isCargo?: boolean;
205
+ airline?: {
206
+ name?: string;
207
+ iata?: string;
208
+ icao?: string;
209
+ };
210
+ aircraft?: {
211
+ model?: string;
212
+ reg?: string;
213
+ };
214
+ }
215
+ export interface AeroAirportBoardResponse {
216
+ departures?: AeroBoardFlight[];
217
+ arrivals?: AeroBoardFlight[];
218
+ }
219
+ export interface AeroFlightDelayStats {
220
+ route?: {
221
+ from?: string;
222
+ to?: string;
223
+ };
224
+ averageDelayMin?: number;
225
+ cancelledPercentage?: number;
226
+ delayDistribution?: Array<{
227
+ bucket?: string;
228
+ percentage?: number;
229
+ }>;
230
+ medianDelayMin?: number;
231
+ onTimePercentage?: number;
232
+ observations?: number;
233
+ }
234
+ export interface AeroAirportDelayInfo {
235
+ averageDelayMin?: number;
236
+ delayIndex?: number;
237
+ medianDelayMin?: number;
238
+ cancellations?: number;
239
+ totalFlights?: number;
240
+ }
241
+ export interface AeroAirportDelayStats {
242
+ airport?: {
243
+ iata?: string;
244
+ name?: string;
245
+ };
246
+ date?: string;
247
+ departures?: AeroAirportDelayInfo;
248
+ arrivals?: AeroAirportDelayInfo;
249
+ }
250
+ export interface OrderShort {
251
+ orderId: number;
252
+ code: string;
253
+ status: string;
254
+ totalPrice: number;
255
+ currency: string;
256
+ paymentStatus: string;
257
+ createdAt: string | null;
258
+ }
259
+ export interface OrderList {
260
+ items: OrderShort[];
261
+ total: number;
262
+ offset: number;
263
+ limit: number;
264
+ }
265
+ export interface OrderPassenger {
266
+ id: number;
267
+ firstName: string;
268
+ lastName: string;
269
+ type: string;
270
+ }
271
+ export interface OrderService {
272
+ id: number;
273
+ type: string;
274
+ title: string;
275
+ status: string;
276
+ date: string;
277
+ priceGross: number;
278
+ priceNet: number;
279
+ ticketNumber?: string;
280
+ pnr?: string;
281
+ }
282
+ export interface OrderTicket {
283
+ ticketNumber: string;
284
+ serviceId: number;
285
+ type: string;
286
+ status: string;
287
+ }
288
+ export interface OrderFull {
289
+ orderId: number;
290
+ code: string;
291
+ status: string;
292
+ totalPrice: number;
293
+ currency: string;
294
+ passengers: OrderPassenger[];
295
+ services: OrderService[];
296
+ tickets?: OrderTicket[];
297
+ paymentStatus: string;
298
+ ticketingDeadline: string | null;
299
+ createdAt: string | null;
300
+ updatedAt: string | null;
301
+ }
302
+ export interface CancelCheckRefund {
303
+ estimatedAmount: number;
304
+ penalty: number;
305
+ currency: string;
306
+ type: string;
307
+ }
308
+ export interface CancelCheckResponse {
309
+ cancellable: boolean;
310
+ refund?: CancelCheckRefund | null;
311
+ deadline?: string | null;
312
+ rules?: string | null;
313
+ }
314
+ export interface CancelResultRefund {
315
+ amount: number;
316
+ currency: string;
317
+ type: string;
318
+ penalty: number;
319
+ }
320
+ export interface CancelResult {
321
+ orderId: number;
322
+ status: string;
323
+ cancelledAt: string | null;
324
+ refund?: CancelResultRefund | null;
325
+ }
326
+ export interface ModifyCheckService {
327
+ serviceId: number;
328
+ title: string;
329
+ allowedChanges: string[];
330
+ }
331
+ export interface ModifyCheckResponse {
332
+ modifiable: boolean;
333
+ services?: ModifyCheckService[];
334
+ }
335
+ export interface ModifyResult {
336
+ orderId: number;
337
+ status: string;
338
+ }
339
+ export interface HotelLocationChild {
340
+ id: string | number;
341
+ partner: string;
342
+ name: string;
343
+ address: string;
344
+ countryCode: string;
345
+ }
346
+ export interface HotelLocationGroup {
347
+ type: string;
348
+ text: string;
349
+ children: HotelLocationChild[];
350
+ }
351
+ export interface HotelLocationSearchResponse {
352
+ items: HotelLocationGroup[];
353
+ time: number;
354
+ }
355
+ export interface HotelLocationDetail {
356
+ id: number;
357
+ nameRu: string;
358
+ nameEn: string;
359
+ entityType: string;
360
+ }
361
+ export interface HotelLocationDetailResponse {
362
+ result: HotelLocationDetail;
363
+ }
364
+ export interface HotelRoomGuests {
365
+ adults: number;
366
+ children?: number;
367
+ childrenAges?: number[];
368
+ }
369
+ export interface HotelSearchFilter {
370
+ minPrice?: number;
371
+ maxPrice?: number;
372
+ starRating?: number[];
373
+ boards?: string[];
374
+ payments?: string[];
375
+ }
376
+ export interface HotelOffer {
377
+ id?: number;
378
+ name?: string;
379
+ stars?: number;
380
+ address?: string;
381
+ image?: string;
382
+ price?: number;
383
+ currency?: string;
384
+ board?: string;
385
+ boardName?: string;
386
+ rooms?: number;
387
+ cancellation?: string;
388
+ [key: string]: unknown;
389
+ }
390
+ export interface HotelSSEConnected {
391
+ status: string;
392
+ cached?: boolean;
393
+ }
394
+ export interface HotelSSEHotelsBatch {
395
+ batch: number;
396
+ count: number;
397
+ hotels: HotelOffer[];
398
+ }
399
+ export interface HotelSSESortedBatch {
400
+ count: number;
401
+ total: number;
402
+ chunk: number;
403
+ hotels: HotelOffer[];
404
+ }
405
+ export interface HotelSSECount {
406
+ batch: number;
407
+ count: number;
408
+ total: number;
409
+ }
410
+ export interface HotelSSECompleted {
411
+ count: number;
412
+ hotels: HotelOffer[];
413
+ cacheKey: string;
414
+ }
415
+ export interface ApiErrorResponse {
416
+ code: number;
417
+ message?: string;
418
+ text?: string;
419
+ }
420
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,3 @@
1
+ // --- Airports ---
2
+ export {};
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,9 @@
1
+ export interface TravelCodeConfig {
2
+ apiBaseUrl: string;
3
+ apiToken: string;
4
+ oauthIssuer?: string;
5
+ pollIntervalMs: number;
6
+ pollTimeoutMs: number;
7
+ }
8
+ export declare function loadConfig(): Promise<TravelCodeConfig>;
9
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1,30 @@
1
+ import { getValidToken } from "./auth/token-store.js";
2
+ const DEFAULT_ISSUER = "https://travel-code.com";
3
+ export async function loadConfig() {
4
+ const apiBaseUrl = process.env.TRAVELCODE_API_BASE_URL || "https://api.travel-code.com/v1";
5
+ const issuer = process.env.OAUTH_ISSUER || DEFAULT_ISSUER;
6
+ // 1. Try env variable first (backward compat)
7
+ let apiToken = process.env.TRAVELCODE_API_TOKEN;
8
+ let oauthIssuer;
9
+ // 2. Try saved OAuth tokens
10
+ if (!apiToken) {
11
+ const savedToken = await getValidToken(issuer);
12
+ if (savedToken) {
13
+ apiToken = savedToken;
14
+ oauthIssuer = issuer; // enable auto-refresh in ApiClient
15
+ }
16
+ }
17
+ if (!apiToken) {
18
+ throw new Error("No API token available.\n" +
19
+ " Option 1: Run 'npx mcp-travelcode auth' to authenticate via OAuth\n" +
20
+ " Option 2: Set TRAVELCODE_API_TOKEN environment variable");
21
+ }
22
+ return {
23
+ apiBaseUrl: apiBaseUrl.replace(/\/+$/, ""),
24
+ apiToken,
25
+ oauthIssuer,
26
+ pollIntervalMs: parseInt(process.env.TRAVELCODE_POLL_INTERVAL_MS || "2000", 10),
27
+ pollTimeoutMs: parseInt(process.env.TRAVELCODE_POLL_TIMEOUT_MS || "90000", 10),
28
+ };
29
+ }
30
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1,6 @@
1
+ import { AeroFlightStatus, AeroBoardFlight, AeroFlightDelayStats, AeroAirportDelayStats } from "../client/types.js";
2
+ export declare function formatFlightStatus(flights: AeroFlightStatus[], flightNumber: string, date: string): string;
3
+ export declare function formatAirportBoard(flights: AeroBoardFlight[], airportCode: string, direction: string, fromTime: string, toTime: string): string;
4
+ export declare function formatFlightDelayStats(stats: AeroFlightDelayStats, flightNumber: string): string;
5
+ export declare function formatAirportDelayStats(stats: AeroAirportDelayStats, airportCode: string, date: string): string;
6
+ //# sourceMappingURL=aerodatabox-formatter.d.ts.map