boostedtravel 0.1.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/README.md +81 -0
- package/dist/chunk-GIJTJ3JU.mjs +199 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +520 -0
- package/dist/cli.mjs +339 -0
- package/dist/index.d.mts +177 -0
- package/dist/index.d.ts +177 -0
- package/dist/index.js +228 -0
- package/dist/index.mjs +18 -0
- package/package.json +50 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
AuthenticationError: () => AuthenticationError,
|
|
24
|
+
BoostedTravel: () => BoostedTravel,
|
|
25
|
+
BoostedTravelError: () => BoostedTravelError,
|
|
26
|
+
PaymentRequiredError: () => PaymentRequiredError,
|
|
27
|
+
cheapestOffer: () => cheapestOffer,
|
|
28
|
+
default: () => index_default,
|
|
29
|
+
offerSummary: () => offerSummary
|
|
30
|
+
});
|
|
31
|
+
module.exports = __toCommonJS(index_exports);
|
|
32
|
+
var BoostedTravelError = class extends Error {
|
|
33
|
+
statusCode;
|
|
34
|
+
response;
|
|
35
|
+
constructor(message, statusCode = 0, response = {}) {
|
|
36
|
+
super(message);
|
|
37
|
+
this.name = "BoostedTravelError";
|
|
38
|
+
this.statusCode = statusCode;
|
|
39
|
+
this.response = response;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
var AuthenticationError = class extends BoostedTravelError {
|
|
43
|
+
constructor(message, response = {}) {
|
|
44
|
+
super(message, 401, response);
|
|
45
|
+
this.name = "AuthenticationError";
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
var PaymentRequiredError = class extends BoostedTravelError {
|
|
49
|
+
constructor(message, response = {}) {
|
|
50
|
+
super(message, 402, response);
|
|
51
|
+
this.name = "PaymentRequiredError";
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
function routeStr(route) {
|
|
55
|
+
if (!route.segments.length) return "";
|
|
56
|
+
const codes = [route.segments[0].origin, ...route.segments.map((s) => s.destination)];
|
|
57
|
+
return codes.join(" \u2192 ");
|
|
58
|
+
}
|
|
59
|
+
function durationHuman(seconds) {
|
|
60
|
+
const h = Math.floor(seconds / 3600);
|
|
61
|
+
const m = Math.floor(seconds % 3600 / 60);
|
|
62
|
+
return `${h}h${m.toString().padStart(2, "0")}m`;
|
|
63
|
+
}
|
|
64
|
+
function offerSummary(offer) {
|
|
65
|
+
const route = routeStr(offer.outbound);
|
|
66
|
+
const dur = durationHuman(offer.outbound.total_duration_seconds);
|
|
67
|
+
const airline = offer.owner_airline || offer.airlines[0] || "?";
|
|
68
|
+
return `${offer.currency} ${offer.price.toFixed(2)} | ${airline} | ${route} | ${dur} | ${offer.outbound.stopovers} stop(s)`;
|
|
69
|
+
}
|
|
70
|
+
function cheapestOffer(result) {
|
|
71
|
+
if (!result.offers.length) return null;
|
|
72
|
+
return result.offers.reduce((min, o) => o.price < min.price ? o : min, result.offers[0]);
|
|
73
|
+
}
|
|
74
|
+
var DEFAULT_BASE_URL = "https://api.boostedchat.com";
|
|
75
|
+
var BoostedTravel = class {
|
|
76
|
+
apiKey;
|
|
77
|
+
baseUrl;
|
|
78
|
+
timeout;
|
|
79
|
+
constructor(config = {}) {
|
|
80
|
+
this.apiKey = config.apiKey || process.env.BOOSTEDTRAVEL_API_KEY || "";
|
|
81
|
+
this.baseUrl = (config.baseUrl || process.env.BOOSTEDTRAVEL_BASE_URL || DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
82
|
+
this.timeout = config.timeout || 3e4;
|
|
83
|
+
if (!this.apiKey) {
|
|
84
|
+
throw new AuthenticationError(
|
|
85
|
+
"API key required. Set apiKey in config or BOOSTEDTRAVEL_API_KEY env var. Get one: POST /api/v1/agents/register"
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// ── Core methods ─────────────────────────────────────────────────────
|
|
90
|
+
/**
|
|
91
|
+
* Search for flights — FREE, unlimited.
|
|
92
|
+
*
|
|
93
|
+
* @param origin - IATA code (e.g., "GDN", "LON")
|
|
94
|
+
* @param destination - IATA code (e.g., "BER", "BCN")
|
|
95
|
+
* @param dateFrom - Departure date "YYYY-MM-DD"
|
|
96
|
+
* @param options - Optional search parameters
|
|
97
|
+
*/
|
|
98
|
+
async search(origin, destination, dateFrom, options = {}) {
|
|
99
|
+
const body = {
|
|
100
|
+
origin: origin.toUpperCase(),
|
|
101
|
+
destination: destination.toUpperCase(),
|
|
102
|
+
date_from: dateFrom,
|
|
103
|
+
adults: options.adults ?? 1,
|
|
104
|
+
children: options.children ?? 0,
|
|
105
|
+
infants: options.infants ?? 0,
|
|
106
|
+
max_stopovers: options.maxStopovers ?? 2,
|
|
107
|
+
currency: options.currency ?? "EUR",
|
|
108
|
+
limit: options.limit ?? 20,
|
|
109
|
+
sort: options.sort ?? "price"
|
|
110
|
+
};
|
|
111
|
+
if (options.returnDate) body.return_from = options.returnDate;
|
|
112
|
+
if (options.cabinClass) body.cabin_class = options.cabinClass;
|
|
113
|
+
return this.post("/api/v1/flights/search", body);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Resolve a city/airport name to IATA codes.
|
|
117
|
+
*/
|
|
118
|
+
async resolveLocation(query) {
|
|
119
|
+
const data = await this.get(`/api/v1/flights/locations/${encodeURIComponent(query)}`);
|
|
120
|
+
if (Array.isArray(data)) return data;
|
|
121
|
+
if (data && Array.isArray(data.locations)) return data.locations;
|
|
122
|
+
return data ? [data] : [];
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Unlock a flight offer — $1 fee.
|
|
126
|
+
* Confirms price, reserves for 30 minutes.
|
|
127
|
+
*/
|
|
128
|
+
async unlock(offerId) {
|
|
129
|
+
return this.post("/api/v1/bookings/unlock", { offer_id: offerId });
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Book a flight — 2.5% service fee.
|
|
133
|
+
* Creates a real airline reservation with PNR.
|
|
134
|
+
*/
|
|
135
|
+
async book(offerId, passengers, contactEmail, contactPhone = "") {
|
|
136
|
+
return this.post("/api/v1/bookings/book", {
|
|
137
|
+
offer_id: offerId,
|
|
138
|
+
booking_type: "flight",
|
|
139
|
+
passengers,
|
|
140
|
+
contact_email: contactEmail,
|
|
141
|
+
contact_phone: contactPhone
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Set up payment method (payment token).
|
|
146
|
+
*/
|
|
147
|
+
async setupPayment(token = "tok_visa") {
|
|
148
|
+
return this.post("/api/v1/agents/setup-payment", { token });
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Get current agent profile and usage stats.
|
|
152
|
+
*/
|
|
153
|
+
async me() {
|
|
154
|
+
return this.get("/api/v1/agents/me");
|
|
155
|
+
}
|
|
156
|
+
// ── Static methods ───────────────────────────────────────────────────
|
|
157
|
+
/**
|
|
158
|
+
* Register a new agent — no API key needed.
|
|
159
|
+
*/
|
|
160
|
+
static async register(agentName, email, baseUrl, ownerName = "", description = "") {
|
|
161
|
+
const url = (baseUrl || DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
162
|
+
const resp = await fetch(`${url}/api/v1/agents/register`, {
|
|
163
|
+
method: "POST",
|
|
164
|
+
headers: { "Content-Type": "application/json" },
|
|
165
|
+
body: JSON.stringify({
|
|
166
|
+
agent_name: agentName,
|
|
167
|
+
email,
|
|
168
|
+
owner_name: ownerName,
|
|
169
|
+
description
|
|
170
|
+
})
|
|
171
|
+
});
|
|
172
|
+
const data = await resp.json();
|
|
173
|
+
if (!resp.ok) {
|
|
174
|
+
throw new BoostedTravelError(
|
|
175
|
+
data.detail || `Registration failed (${resp.status})`,
|
|
176
|
+
resp.status,
|
|
177
|
+
data
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
return data;
|
|
181
|
+
}
|
|
182
|
+
// ── Internal ────────────────────────────────────────────────────────
|
|
183
|
+
async post(path, body) {
|
|
184
|
+
return this.request(path, {
|
|
185
|
+
method: "POST",
|
|
186
|
+
body: JSON.stringify(body)
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
async get(path) {
|
|
190
|
+
return this.request(path, { method: "GET" });
|
|
191
|
+
}
|
|
192
|
+
async request(path, init) {
|
|
193
|
+
const controller = new AbortController();
|
|
194
|
+
const timer = setTimeout(() => controller.abort(), this.timeout);
|
|
195
|
+
try {
|
|
196
|
+
const resp = await fetch(`${this.baseUrl}${path}`, {
|
|
197
|
+
...init,
|
|
198
|
+
headers: {
|
|
199
|
+
"Content-Type": "application/json",
|
|
200
|
+
"X-API-Key": this.apiKey,
|
|
201
|
+
"User-Agent": "boostedtravel-js/0.1.0",
|
|
202
|
+
...init.headers || {}
|
|
203
|
+
},
|
|
204
|
+
signal: controller.signal
|
|
205
|
+
});
|
|
206
|
+
const data = await resp.json();
|
|
207
|
+
if (!resp.ok) {
|
|
208
|
+
const detail = data.detail || `API error (${resp.status})`;
|
|
209
|
+
if (resp.status === 401) throw new AuthenticationError(detail, data);
|
|
210
|
+
if (resp.status === 402) throw new PaymentRequiredError(detail, data);
|
|
211
|
+
throw new BoostedTravelError(detail, resp.status, data);
|
|
212
|
+
}
|
|
213
|
+
return data;
|
|
214
|
+
} finally {
|
|
215
|
+
clearTimeout(timer);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
var index_default = BoostedTravel;
|
|
220
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
221
|
+
0 && (module.exports = {
|
|
222
|
+
AuthenticationError,
|
|
223
|
+
BoostedTravel,
|
|
224
|
+
BoostedTravelError,
|
|
225
|
+
PaymentRequiredError,
|
|
226
|
+
cheapestOffer,
|
|
227
|
+
offerSummary
|
|
228
|
+
});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AuthenticationError,
|
|
3
|
+
BoostedTravel,
|
|
4
|
+
BoostedTravelError,
|
|
5
|
+
PaymentRequiredError,
|
|
6
|
+
cheapestOffer,
|
|
7
|
+
index_default,
|
|
8
|
+
offerSummary
|
|
9
|
+
} from "./chunk-GIJTJ3JU.mjs";
|
|
10
|
+
export {
|
|
11
|
+
AuthenticationError,
|
|
12
|
+
BoostedTravel,
|
|
13
|
+
BoostedTravelError,
|
|
14
|
+
PaymentRequiredError,
|
|
15
|
+
cheapestOffer,
|
|
16
|
+
index_default as default,
|
|
17
|
+
offerSummary
|
|
18
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "boostedtravel",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Agent-native flight search & booking. 300+ airlines, cheaper than OTAs. Built for autonomous AI agents.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"boostedtravel": "dist/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist/",
|
|
13
|
+
"README.md",
|
|
14
|
+
"LICENSE"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsup src/index.ts src/cli.ts --format cjs,esm --dts --clean",
|
|
18
|
+
"prepublishOnly": "npm run build"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"flights",
|
|
22
|
+
"travel",
|
|
23
|
+
"booking",
|
|
24
|
+
"agent",
|
|
25
|
+
"ai",
|
|
26
|
+
"cli",
|
|
27
|
+
"autonomous",
|
|
28
|
+
"mcp",
|
|
29
|
+
"openai",
|
|
30
|
+
"airline",
|
|
31
|
+
"ndc",
|
|
32
|
+
"search",
|
|
33
|
+
"ndc"
|
|
34
|
+
],
|
|
35
|
+
"author": "BoostedTravel",
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "https://github.com/boostedtravel/boostedtravel-js"
|
|
40
|
+
},
|
|
41
|
+
"homepage": "https://boostedchat.com",
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@types/node": "^25.3.3",
|
|
44
|
+
"tsup": "^8.0.0",
|
|
45
|
+
"typescript": "^5.3.0"
|
|
46
|
+
},
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=18.0.0"
|
|
49
|
+
}
|
|
50
|
+
}
|