letsfg 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/README.md +121 -0
- package/dist/chunk-LKAF7U4R.mjs +460 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +708 -0
- package/dist/cli.mjs +339 -0
- package/dist/index.d.mts +278 -0
- package/dist/index.d.ts +278 -0
- package/dist/index.js +511 -0
- package/dist/index.mjs +36 -0
- package/package.json +50 -0
package/dist/cli.mjs
ADDED
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
LetsFG,
|
|
4
|
+
LetsFGError,
|
|
5
|
+
offerSummary
|
|
6
|
+
} from "./chunk-LKAF7U4R.mjs";
|
|
7
|
+
|
|
8
|
+
// src/cli.ts
|
|
9
|
+
function getFlag(args, flag, alias) {
|
|
10
|
+
for (let i = 0; i < args.length; i++) {
|
|
11
|
+
if (args[i] === flag || alias && args[i] === alias) {
|
|
12
|
+
const val = args[i + 1];
|
|
13
|
+
args.splice(i, 2);
|
|
14
|
+
return val;
|
|
15
|
+
}
|
|
16
|
+
if (args[i].startsWith(`${flag}=`)) {
|
|
17
|
+
const val = args[i].split("=").slice(1).join("=");
|
|
18
|
+
args.splice(i, 1);
|
|
19
|
+
return val;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return void 0;
|
|
23
|
+
}
|
|
24
|
+
function hasFlag(args, flag) {
|
|
25
|
+
const idx = args.indexOf(flag);
|
|
26
|
+
if (idx >= 0) {
|
|
27
|
+
args.splice(idx, 1);
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
function getAllFlags(args, flag, alias) {
|
|
33
|
+
const results = [];
|
|
34
|
+
let i = 0;
|
|
35
|
+
while (i < args.length) {
|
|
36
|
+
if (args[i] === flag || alias && args[i] === alias) {
|
|
37
|
+
results.push(args[i + 1]);
|
|
38
|
+
args.splice(i, 2);
|
|
39
|
+
} else {
|
|
40
|
+
i++;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return results;
|
|
44
|
+
}
|
|
45
|
+
async function cmdSearch(args) {
|
|
46
|
+
const jsonOut = hasFlag(args, "--json") || hasFlag(args, "-j");
|
|
47
|
+
const apiKey = getFlag(args, "--api-key", "-k");
|
|
48
|
+
const baseUrl = getFlag(args, "--base-url");
|
|
49
|
+
const returnDate = getFlag(args, "--return", "-r");
|
|
50
|
+
const adults = parseInt(getFlag(args, "--adults", "-a") || "1");
|
|
51
|
+
const cabin = getFlag(args, "--cabin", "-c");
|
|
52
|
+
const stops = parseInt(getFlag(args, "--max-stops", "-s") || "2");
|
|
53
|
+
const currency = getFlag(args, "--currency") || "EUR";
|
|
54
|
+
const limit = parseInt(getFlag(args, "--limit", "-l") || "20");
|
|
55
|
+
const sort = getFlag(args, "--sort") || "price";
|
|
56
|
+
const [origin, destination, date] = args;
|
|
57
|
+
if (!origin || !destination || !date) {
|
|
58
|
+
console.error("Usage: letsfg search <origin> <destination> <date> [options]");
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
const bt = new LetsFG({ apiKey, baseUrl });
|
|
62
|
+
const result = await bt.search(origin, destination, date, {
|
|
63
|
+
returnDate,
|
|
64
|
+
adults,
|
|
65
|
+
cabinClass: cabin,
|
|
66
|
+
maxStopovers: stops,
|
|
67
|
+
currency,
|
|
68
|
+
limit,
|
|
69
|
+
sort
|
|
70
|
+
});
|
|
71
|
+
if (jsonOut) {
|
|
72
|
+
console.log(JSON.stringify({
|
|
73
|
+
passenger_ids: result.passenger_ids,
|
|
74
|
+
total_results: result.total_results,
|
|
75
|
+
offers: result.offers.map((o) => ({
|
|
76
|
+
id: o.id,
|
|
77
|
+
price: o.price,
|
|
78
|
+
currency: o.currency,
|
|
79
|
+
airlines: o.airlines,
|
|
80
|
+
owner_airline: o.owner_airline,
|
|
81
|
+
route: [o.outbound.segments[0]?.origin, ...o.outbound.segments.map((s) => s.destination)].join(" \u2192 "),
|
|
82
|
+
duration_seconds: o.outbound.total_duration_seconds,
|
|
83
|
+
stopovers: o.outbound.stopovers,
|
|
84
|
+
conditions: o.conditions,
|
|
85
|
+
is_locked: o.is_locked
|
|
86
|
+
}))
|
|
87
|
+
}, null, 2));
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (!result.offers.length) {
|
|
91
|
+
console.log(`No flights found for ${origin} \u2192 ${destination} on ${date}`);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
console.log(`
|
|
95
|
+
${result.total_results} offers | ${origin} \u2192 ${destination} | ${date}`);
|
|
96
|
+
console.log(` Passenger IDs: ${JSON.stringify(result.passenger_ids)}
|
|
97
|
+
`);
|
|
98
|
+
result.offers.forEach((o, i) => {
|
|
99
|
+
console.log(` ${(i + 1).toString().padStart(3)}. ${offerSummary(o)}`);
|
|
100
|
+
console.log(` ID: ${o.id}`);
|
|
101
|
+
});
|
|
102
|
+
console.log(`
|
|
103
|
+
To unlock: letsfg unlock <offer_id>`);
|
|
104
|
+
console.log(` Passenger IDs needed for booking: ${JSON.stringify(result.passenger_ids)}
|
|
105
|
+
`);
|
|
106
|
+
}
|
|
107
|
+
async function cmdUnlock(args) {
|
|
108
|
+
const jsonOut = hasFlag(args, "--json") || hasFlag(args, "-j");
|
|
109
|
+
const apiKey = getFlag(args, "--api-key", "-k");
|
|
110
|
+
const baseUrl = getFlag(args, "--base-url");
|
|
111
|
+
const offerId = args[0];
|
|
112
|
+
if (!offerId) {
|
|
113
|
+
console.error("Usage: letsfg unlock <offer_id>");
|
|
114
|
+
process.exit(1);
|
|
115
|
+
}
|
|
116
|
+
const bt = new LetsFG({ apiKey, baseUrl });
|
|
117
|
+
const result = await bt.unlock(offerId);
|
|
118
|
+
if (jsonOut) {
|
|
119
|
+
console.log(JSON.stringify(result, null, 2));
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (result.unlock_status === "unlocked") {
|
|
123
|
+
console.log(`
|
|
124
|
+
\u2713 Offer unlocked!`);
|
|
125
|
+
console.log(` Confirmed price: ${result.confirmed_currency} ${result.confirmed_price?.toFixed(2)}`);
|
|
126
|
+
console.log(` Expires at: ${result.offer_expires_at}`);
|
|
127
|
+
console.log(` $1 unlock fee charged`);
|
|
128
|
+
console.log(`
|
|
129
|
+
Next: letsfg book ${offerId} --passenger '{...}' --email you@example.com
|
|
130
|
+
`);
|
|
131
|
+
} else {
|
|
132
|
+
console.error(` \u2717 Unlock failed: ${result.message}`);
|
|
133
|
+
process.exit(1);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
async function cmdBook(args) {
|
|
137
|
+
const jsonOut = hasFlag(args, "--json") || hasFlag(args, "-j");
|
|
138
|
+
const apiKey = getFlag(args, "--api-key", "-k");
|
|
139
|
+
const baseUrl = getFlag(args, "--base-url");
|
|
140
|
+
const email = getFlag(args, "--email", "-e") || "";
|
|
141
|
+
const phone = getFlag(args, "--phone") || "";
|
|
142
|
+
const passengerStrs = getAllFlags(args, "--passenger", "-p");
|
|
143
|
+
const offerId = args[0];
|
|
144
|
+
if (!offerId || !passengerStrs.length || !email) {
|
|
145
|
+
console.error(`Usage: letsfg book <offer_id> --passenger '{"id":"pas_xxx",...}' --email you@example.com`);
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
const passengers = passengerStrs.map((s) => JSON.parse(s));
|
|
149
|
+
const bt = new LetsFG({ apiKey, baseUrl });
|
|
150
|
+
const result = await bt.book(offerId, passengers, email, phone);
|
|
151
|
+
if (jsonOut) {
|
|
152
|
+
console.log(JSON.stringify(result, null, 2));
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
if (result.status === "confirmed") {
|
|
156
|
+
console.log(`
|
|
157
|
+
\u2713 Booking confirmed!`);
|
|
158
|
+
console.log(` PNR: ${result.booking_reference}`);
|
|
159
|
+
console.log(` Flight: ${result.currency} ${result.flight_price.toFixed(2)}`);
|
|
160
|
+
console.log(` Fee: ${result.currency} ${result.service_fee.toFixed(2)} (${result.service_fee_percentage}%)`);
|
|
161
|
+
console.log(` Total: ${result.currency} ${result.total_charged.toFixed(2)}`);
|
|
162
|
+
console.log(` Order: ${result.order_id}
|
|
163
|
+
`);
|
|
164
|
+
} else {
|
|
165
|
+
console.error(` \u2717 Booking failed`);
|
|
166
|
+
console.error(JSON.stringify(result.details, null, 2));
|
|
167
|
+
process.exit(1);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
async function cmdLocations(args) {
|
|
171
|
+
const jsonOut = hasFlag(args, "--json") || hasFlag(args, "-j");
|
|
172
|
+
const apiKey = getFlag(args, "--api-key", "-k");
|
|
173
|
+
const baseUrl = getFlag(args, "--base-url");
|
|
174
|
+
const query = args[0];
|
|
175
|
+
if (!query) {
|
|
176
|
+
console.error("Usage: letsfg locations <city-or-airport-name>");
|
|
177
|
+
process.exit(1);
|
|
178
|
+
}
|
|
179
|
+
const bt = new LetsFG({ apiKey, baseUrl });
|
|
180
|
+
const result = await bt.resolveLocation(query);
|
|
181
|
+
if (jsonOut) {
|
|
182
|
+
console.log(JSON.stringify(result, null, 2));
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
if (!result.length) {
|
|
186
|
+
console.log(`No locations found for '${query}'`);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
for (const loc of result) {
|
|
190
|
+
const iata = (loc.iata_code || "???").padEnd(5);
|
|
191
|
+
const name = loc.name || "";
|
|
192
|
+
const type = loc.type || "";
|
|
193
|
+
const city = loc.city_name || "";
|
|
194
|
+
const country = loc.country || "";
|
|
195
|
+
console.log(` ${iata} ${name} (${type}) \u2014 ${city}, ${country}`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
async function cmdRegister(args) {
|
|
199
|
+
const jsonOut = hasFlag(args, "--json") || hasFlag(args, "-j");
|
|
200
|
+
const baseUrl = getFlag(args, "--base-url");
|
|
201
|
+
const name = getFlag(args, "--name", "-n");
|
|
202
|
+
const email = getFlag(args, "--email", "-e");
|
|
203
|
+
const owner = getFlag(args, "--owner") || "";
|
|
204
|
+
const desc = getFlag(args, "--desc") || "";
|
|
205
|
+
if (!name || !email) {
|
|
206
|
+
console.error("Usage: letsfg register --name my-agent --email agent@example.com");
|
|
207
|
+
process.exit(1);
|
|
208
|
+
}
|
|
209
|
+
const result = await LetsFG.register(name, email, baseUrl, owner, desc);
|
|
210
|
+
if (jsonOut) {
|
|
211
|
+
console.log(JSON.stringify(result, null, 2));
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
console.log(`
|
|
215
|
+
\u2713 Agent registered!`);
|
|
216
|
+
console.log(` Agent ID: ${result.agent_id}`);
|
|
217
|
+
console.log(` API Key: ${result.api_key}`);
|
|
218
|
+
console.log(`
|
|
219
|
+
Save your API key:`);
|
|
220
|
+
console.log(` export LETSFG_API_KEY=${result.api_key}`);
|
|
221
|
+
console.log(`
|
|
222
|
+
Next: LetsFG setup-payment --token tok_visa
|
|
223
|
+
`);
|
|
224
|
+
}
|
|
225
|
+
async function cmdSetupPayment(args) {
|
|
226
|
+
const jsonOut = hasFlag(args, "--json") || hasFlag(args, "-j");
|
|
227
|
+
const apiKey = getFlag(args, "--api-key", "-k");
|
|
228
|
+
const baseUrl = getFlag(args, "--base-url");
|
|
229
|
+
const token = getFlag(args, "--token", "-t") || "tok_visa";
|
|
230
|
+
const bt = new LetsFG({ apiKey, baseUrl });
|
|
231
|
+
const result = await bt.setupPayment(token);
|
|
232
|
+
if (jsonOut) {
|
|
233
|
+
console.log(JSON.stringify(result, null, 2));
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
if (result.status === "ready") {
|
|
237
|
+
console.log(`
|
|
238
|
+
\u2713 Payment ready! You can now unlock offers and book flights.
|
|
239
|
+
`);
|
|
240
|
+
} else {
|
|
241
|
+
console.error(` \u2717 Payment setup failed: ${result.message || result.status}`);
|
|
242
|
+
process.exit(1);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
async function cmdMe(args) {
|
|
246
|
+
const jsonOut = hasFlag(args, "--json") || hasFlag(args, "-j");
|
|
247
|
+
const apiKey = getFlag(args, "--api-key", "-k");
|
|
248
|
+
const baseUrl = getFlag(args, "--base-url");
|
|
249
|
+
const bt = new LetsFG({ apiKey, baseUrl });
|
|
250
|
+
const profile = await bt.me();
|
|
251
|
+
if (jsonOut) {
|
|
252
|
+
console.log(JSON.stringify(profile, null, 2));
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
const p = profile;
|
|
256
|
+
const u = p.usage || {};
|
|
257
|
+
console.log(`
|
|
258
|
+
Agent: ${p.agent_name} (${p.agent_id})`);
|
|
259
|
+
console.log(` Email: ${p.email}`);
|
|
260
|
+
console.log(` Tier: ${p.tier}`);
|
|
261
|
+
console.log(` Payment: ${p.payment_ready ? "\u2713 Ready" : "\u2717 Not set up"}`);
|
|
262
|
+
console.log(` Searches: ${u.total_searches || 0}`);
|
|
263
|
+
console.log(` Unlocks: ${u.total_unlocks || 0}`);
|
|
264
|
+
console.log(` Bookings: ${u.total_bookings || 0}`);
|
|
265
|
+
console.log(` Total spent: $${((u.total_spent_cents || 0) / 100).toFixed(2)}
|
|
266
|
+
`);
|
|
267
|
+
}
|
|
268
|
+
var HELP = `
|
|
269
|
+
LetsFG \u2014 Agent-native flight search & booking.
|
|
270
|
+
|
|
271
|
+
Search 400+ airlines at raw airline prices \u2014 $20-50 cheaper than OTAs.
|
|
272
|
+
Search is FREE. Unlock: $1. Book: FREE after unlock.
|
|
273
|
+
|
|
274
|
+
Commands:
|
|
275
|
+
search <origin> <dest> <date> Search for flights (FREE)
|
|
276
|
+
locations <query> Resolve city name to IATA codes
|
|
277
|
+
unlock <offer_id> Unlock offer ($1)
|
|
278
|
+
book <offer_id> --passenger ... Book flight (FREE after unlock)
|
|
279
|
+
register --name ... --email ... Register new agent
|
|
280
|
+
setup-payment Set up payment card
|
|
281
|
+
me Show agent profile
|
|
282
|
+
|
|
283
|
+
Options:
|
|
284
|
+
--json, -j Output raw JSON
|
|
285
|
+
--api-key, -k API key (or set LETSFG_API_KEY)
|
|
286
|
+
--base-url API URL (default: https://api.letsfg.co)
|
|
287
|
+
|
|
288
|
+
Examples:
|
|
289
|
+
letsfg search GDN BER 2026-03-03 --sort price
|
|
290
|
+
letsfg search LON BCN 2026-04-01 --return 2026-04-08 --json
|
|
291
|
+
letsfg unlock off_xxx
|
|
292
|
+
letsfg book off_xxx -p '{"id":"pas_xxx","given_name":"John","family_name":"Doe","born_on":"1990-01-15"}' -e john@ex.com
|
|
293
|
+
`;
|
|
294
|
+
async function main() {
|
|
295
|
+
const args = process.argv.slice(2);
|
|
296
|
+
const command = args.shift();
|
|
297
|
+
try {
|
|
298
|
+
switch (command) {
|
|
299
|
+
case "search":
|
|
300
|
+
await cmdSearch(args);
|
|
301
|
+
break;
|
|
302
|
+
case "unlock":
|
|
303
|
+
await cmdUnlock(args);
|
|
304
|
+
break;
|
|
305
|
+
case "book":
|
|
306
|
+
await cmdBook(args);
|
|
307
|
+
break;
|
|
308
|
+
case "locations":
|
|
309
|
+
await cmdLocations(args);
|
|
310
|
+
break;
|
|
311
|
+
case "register":
|
|
312
|
+
await cmdRegister(args);
|
|
313
|
+
break;
|
|
314
|
+
case "setup-payment":
|
|
315
|
+
await cmdSetupPayment(args);
|
|
316
|
+
break;
|
|
317
|
+
case "me":
|
|
318
|
+
await cmdMe(args);
|
|
319
|
+
break;
|
|
320
|
+
case "--help":
|
|
321
|
+
case "-h":
|
|
322
|
+
case "help":
|
|
323
|
+
case void 0:
|
|
324
|
+
console.log(HELP);
|
|
325
|
+
break;
|
|
326
|
+
default:
|
|
327
|
+
console.error(`Unknown command: ${command}`);
|
|
328
|
+
console.log(HELP);
|
|
329
|
+
process.exit(1);
|
|
330
|
+
}
|
|
331
|
+
} catch (e) {
|
|
332
|
+
if (e instanceof LetsFGError) {
|
|
333
|
+
console.error(`Error: ${e.message}`);
|
|
334
|
+
process.exit(1);
|
|
335
|
+
}
|
|
336
|
+
throw e;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
main();
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LetsFG — Agent-native flight search & booking SDK for Node.js/TypeScript.
|
|
3
|
+
*
|
|
4
|
+
* 75 airline connectors run locally via Python + backend API for enterprise GDS/NDC sources.
|
|
5
|
+
* Zero external JS dependencies. Uses native fetch (Node 18+).
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { LetsFG, searchLocal } from 'letsfg';
|
|
10
|
+
*
|
|
11
|
+
* // Local search — FREE, no API key
|
|
12
|
+
* const local = await searchLocal('SHA', 'CTU', '2026-03-20');
|
|
13
|
+
*
|
|
14
|
+
* // Full API — search + unlock + book
|
|
15
|
+
* const bt = new LetsFG({ apiKey: 'trav_...' });
|
|
16
|
+
* const flights = await bt.search('GDN', 'BER', '2026-03-03');
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
interface FlightSegment {
|
|
20
|
+
airline: string;
|
|
21
|
+
airline_name: string;
|
|
22
|
+
flight_no: string;
|
|
23
|
+
origin: string;
|
|
24
|
+
destination: string;
|
|
25
|
+
origin_city: string;
|
|
26
|
+
destination_city: string;
|
|
27
|
+
departure: string;
|
|
28
|
+
arrival: string;
|
|
29
|
+
duration_seconds: number;
|
|
30
|
+
cabin_class: string;
|
|
31
|
+
aircraft: string;
|
|
32
|
+
}
|
|
33
|
+
interface FlightRoute {
|
|
34
|
+
segments: FlightSegment[];
|
|
35
|
+
total_duration_seconds: number;
|
|
36
|
+
stopovers: number;
|
|
37
|
+
}
|
|
38
|
+
interface FlightOffer {
|
|
39
|
+
id: string;
|
|
40
|
+
price: number;
|
|
41
|
+
currency: string;
|
|
42
|
+
price_formatted: string;
|
|
43
|
+
outbound: FlightRoute;
|
|
44
|
+
inbound: FlightRoute | null;
|
|
45
|
+
airlines: string[];
|
|
46
|
+
owner_airline: string;
|
|
47
|
+
bags_price: Record<string, number>;
|
|
48
|
+
availability_seats: number | null;
|
|
49
|
+
conditions: Record<string, string>;
|
|
50
|
+
is_locked: boolean;
|
|
51
|
+
fetched_at: string;
|
|
52
|
+
booking_url: string;
|
|
53
|
+
}
|
|
54
|
+
interface FlightSearchResult {
|
|
55
|
+
search_id: string;
|
|
56
|
+
offer_request_id: string;
|
|
57
|
+
passenger_ids: string[];
|
|
58
|
+
origin: string;
|
|
59
|
+
destination: string;
|
|
60
|
+
currency: string;
|
|
61
|
+
offers: FlightOffer[];
|
|
62
|
+
total_results: number;
|
|
63
|
+
search_params: Record<string, unknown>;
|
|
64
|
+
pricing_note: string;
|
|
65
|
+
}
|
|
66
|
+
interface UnlockResult {
|
|
67
|
+
offer_id: string;
|
|
68
|
+
unlock_status: string;
|
|
69
|
+
payment_charged: boolean;
|
|
70
|
+
payment_amount_cents: number;
|
|
71
|
+
payment_currency: string;
|
|
72
|
+
payment_intent_id: string;
|
|
73
|
+
confirmed_price: number | null;
|
|
74
|
+
confirmed_currency: string;
|
|
75
|
+
offer_expires_at: string;
|
|
76
|
+
message: string;
|
|
77
|
+
}
|
|
78
|
+
interface Passenger {
|
|
79
|
+
id: string;
|
|
80
|
+
given_name: string;
|
|
81
|
+
family_name: string;
|
|
82
|
+
born_on: string;
|
|
83
|
+
gender?: string;
|
|
84
|
+
title?: string;
|
|
85
|
+
email?: string;
|
|
86
|
+
phone_number?: string;
|
|
87
|
+
}
|
|
88
|
+
interface BookingResult {
|
|
89
|
+
booking_id: string;
|
|
90
|
+
status: string;
|
|
91
|
+
booking_type: string;
|
|
92
|
+
offer_id: string;
|
|
93
|
+
flight_price: number;
|
|
94
|
+
service_fee: number;
|
|
95
|
+
service_fee_percentage: number;
|
|
96
|
+
total_charged: number;
|
|
97
|
+
currency: string;
|
|
98
|
+
order_id: string;
|
|
99
|
+
booking_reference: string;
|
|
100
|
+
unlock_payment_id: string;
|
|
101
|
+
fee_payment_id: string;
|
|
102
|
+
created_at: string;
|
|
103
|
+
details: Record<string, unknown>;
|
|
104
|
+
}
|
|
105
|
+
interface SearchOptions {
|
|
106
|
+
returnDate?: string;
|
|
107
|
+
adults?: number;
|
|
108
|
+
children?: number;
|
|
109
|
+
infants?: number;
|
|
110
|
+
cabinClass?: 'M' | 'W' | 'C' | 'F';
|
|
111
|
+
maxStopovers?: number;
|
|
112
|
+
currency?: string;
|
|
113
|
+
limit?: number;
|
|
114
|
+
sort?: 'price' | 'duration';
|
|
115
|
+
/** Max concurrent browser instances (1-32). Omit for auto-detect based on system RAM. */
|
|
116
|
+
maxBrowsers?: number;
|
|
117
|
+
}
|
|
118
|
+
interface CheckoutProgress {
|
|
119
|
+
status: string;
|
|
120
|
+
step: string;
|
|
121
|
+
step_index: number;
|
|
122
|
+
airline: string;
|
|
123
|
+
source: string;
|
|
124
|
+
offer_id: string;
|
|
125
|
+
total_price: number;
|
|
126
|
+
currency: string;
|
|
127
|
+
booking_url: string;
|
|
128
|
+
screenshot_b64: string;
|
|
129
|
+
message: string;
|
|
130
|
+
can_complete_manually: boolean;
|
|
131
|
+
elapsed_seconds: number;
|
|
132
|
+
details: Record<string, unknown>;
|
|
133
|
+
}
|
|
134
|
+
interface LetsFGConfig {
|
|
135
|
+
apiKey?: string;
|
|
136
|
+
baseUrl?: string;
|
|
137
|
+
timeout?: number;
|
|
138
|
+
}
|
|
139
|
+
declare const ErrorCode: {
|
|
140
|
+
readonly SUPPLIER_TIMEOUT: "SUPPLIER_TIMEOUT";
|
|
141
|
+
readonly RATE_LIMITED: "RATE_LIMITED";
|
|
142
|
+
readonly SERVICE_UNAVAILABLE: "SERVICE_UNAVAILABLE";
|
|
143
|
+
readonly NETWORK_ERROR: "NETWORK_ERROR";
|
|
144
|
+
readonly INVALID_IATA: "INVALID_IATA";
|
|
145
|
+
readonly INVALID_DATE: "INVALID_DATE";
|
|
146
|
+
readonly INVALID_PASSENGERS: "INVALID_PASSENGERS";
|
|
147
|
+
readonly UNSUPPORTED_ROUTE: "UNSUPPORTED_ROUTE";
|
|
148
|
+
readonly MISSING_PARAMETER: "MISSING_PARAMETER";
|
|
149
|
+
readonly INVALID_PARAMETER: "INVALID_PARAMETER";
|
|
150
|
+
readonly AUTH_INVALID: "AUTH_INVALID";
|
|
151
|
+
readonly PAYMENT_REQUIRED: "PAYMENT_REQUIRED";
|
|
152
|
+
readonly PAYMENT_DECLINED: "PAYMENT_DECLINED";
|
|
153
|
+
readonly OFFER_EXPIRED: "OFFER_EXPIRED";
|
|
154
|
+
readonly OFFER_NOT_UNLOCKED: "OFFER_NOT_UNLOCKED";
|
|
155
|
+
readonly FARE_CHANGED: "FARE_CHANGED";
|
|
156
|
+
readonly ALREADY_BOOKED: "ALREADY_BOOKED";
|
|
157
|
+
readonly BOOKING_FAILED: "BOOKING_FAILED";
|
|
158
|
+
};
|
|
159
|
+
type ErrorCodeType = (typeof ErrorCode)[keyof typeof ErrorCode];
|
|
160
|
+
declare const ErrorCategory: {
|
|
161
|
+
readonly TRANSIENT: "transient";
|
|
162
|
+
readonly VALIDATION: "validation";
|
|
163
|
+
readonly BUSINESS: "business";
|
|
164
|
+
};
|
|
165
|
+
type ErrorCategoryType = (typeof ErrorCategory)[keyof typeof ErrorCategory];
|
|
166
|
+
declare class LetsFGError extends Error {
|
|
167
|
+
statusCode: number;
|
|
168
|
+
response: Record<string, unknown>;
|
|
169
|
+
errorCode: string;
|
|
170
|
+
errorCategory: ErrorCategoryType;
|
|
171
|
+
isRetryable: boolean;
|
|
172
|
+
constructor(message: string, statusCode?: number, response?: Record<string, unknown>, errorCode?: string);
|
|
173
|
+
}
|
|
174
|
+
declare class AuthenticationError extends LetsFGError {
|
|
175
|
+
constructor(message: string, response?: Record<string, unknown>);
|
|
176
|
+
}
|
|
177
|
+
declare class PaymentRequiredError extends LetsFGError {
|
|
178
|
+
constructor(message: string, response?: Record<string, unknown>);
|
|
179
|
+
}
|
|
180
|
+
declare class OfferExpiredError extends LetsFGError {
|
|
181
|
+
constructor(message: string, response?: Record<string, unknown>);
|
|
182
|
+
}
|
|
183
|
+
declare class ValidationError extends LetsFGError {
|
|
184
|
+
constructor(message: string, statusCode?: number, response?: Record<string, unknown>, errorCode?: string);
|
|
185
|
+
}
|
|
186
|
+
/** One-line offer summary */
|
|
187
|
+
declare function offerSummary(offer: FlightOffer): string;
|
|
188
|
+
/** Get cheapest offer from search results */
|
|
189
|
+
declare function cheapestOffer(result: FlightSearchResult): FlightOffer | null;
|
|
190
|
+
/**
|
|
191
|
+
* Search flights using 73 local airline connectors — FREE, no API key needed.
|
|
192
|
+
*
|
|
193
|
+
* Requires: pip install letsfg && playwright install chromium
|
|
194
|
+
*
|
|
195
|
+
* @param origin - IATA code (e.g., "SHA")
|
|
196
|
+
* @param destination - IATA code (e.g., "CTU")
|
|
197
|
+
* @param dateFrom - Departure date "YYYY-MM-DD"
|
|
198
|
+
* @param options - Optional: currency, adults, limit, etc.
|
|
199
|
+
*/
|
|
200
|
+
declare function searchLocal(origin: string, destination: string, dateFrom: string, options?: Partial<SearchOptions>): Promise<FlightSearchResult>;
|
|
201
|
+
declare class LetsFG {
|
|
202
|
+
private apiKey;
|
|
203
|
+
private baseUrl;
|
|
204
|
+
private timeout;
|
|
205
|
+
constructor(config?: LetsFGConfig);
|
|
206
|
+
private requireApiKey;
|
|
207
|
+
/**
|
|
208
|
+
* Search for flights — FREE, unlimited.
|
|
209
|
+
*
|
|
210
|
+
* @param origin - IATA code (e.g., "GDN", "LON")
|
|
211
|
+
* @param destination - IATA code (e.g., "BER", "BCN")
|
|
212
|
+
* @param dateFrom - Departure date "YYYY-MM-DD"
|
|
213
|
+
* @param options - Optional search parameters
|
|
214
|
+
*/
|
|
215
|
+
search(origin: string, destination: string, dateFrom: string, options?: SearchOptions): Promise<FlightSearchResult>;
|
|
216
|
+
/**
|
|
217
|
+
* Resolve a city/airport name to IATA codes.
|
|
218
|
+
*/
|
|
219
|
+
resolveLocation(query: string): Promise<Array<Record<string, unknown>>>;
|
|
220
|
+
/**
|
|
221
|
+
* Unlock a flight offer — $1 fee.
|
|
222
|
+
* Confirms price, reserves for 30 minutes.
|
|
223
|
+
*/
|
|
224
|
+
unlock(offerId: string): Promise<UnlockResult>;
|
|
225
|
+
/**
|
|
226
|
+
* Book a flight — FREE after unlock.
|
|
227
|
+
* Creates a real airline reservation with PNR.
|
|
228
|
+
*
|
|
229
|
+
* Always provide idempotencyKey to prevent double-bookings on retry.
|
|
230
|
+
*/
|
|
231
|
+
book(offerId: string, passengers: Passenger[], contactEmail: string, contactPhone?: string, idempotencyKey?: string): Promise<BookingResult>;
|
|
232
|
+
/**
|
|
233
|
+
* Set up payment method (payment token).
|
|
234
|
+
*/
|
|
235
|
+
setupPayment(token?: string): Promise<Record<string, unknown>>;
|
|
236
|
+
/**
|
|
237
|
+
* Start automated checkout — drives to payment page, NEVER submits payment.
|
|
238
|
+
*
|
|
239
|
+
* Requires unlock first ($1 fee). Returns progress with screenshot and
|
|
240
|
+
* booking URL for manual completion.
|
|
241
|
+
*
|
|
242
|
+
* @param offerId - Offer ID from search results
|
|
243
|
+
* @param passengers - Passenger details (use test data for safety)
|
|
244
|
+
* @param checkoutToken - Token from unlock() response
|
|
245
|
+
*/
|
|
246
|
+
startCheckout(offerId: string, passengers: Passenger[], checkoutToken: string): Promise<CheckoutProgress>;
|
|
247
|
+
/**
|
|
248
|
+
* Start checkout locally via Python (runs on your machine).
|
|
249
|
+
* Requires: pip install letsfg && playwright install chromium
|
|
250
|
+
*
|
|
251
|
+
* @param offer - Full FlightOffer object from search results
|
|
252
|
+
* @param passengers - Passenger details
|
|
253
|
+
* @param checkoutToken - Token from unlock()
|
|
254
|
+
*/
|
|
255
|
+
startCheckoutLocal(offer: FlightOffer, passengers: Passenger[], checkoutToken: string): Promise<CheckoutProgress>;
|
|
256
|
+
/**
|
|
257
|
+
* Get current agent profile and usage stats.
|
|
258
|
+
*/
|
|
259
|
+
me(): Promise<Record<string, unknown>>;
|
|
260
|
+
/**
|
|
261
|
+
* Register a new agent — no API key needed.
|
|
262
|
+
*/
|
|
263
|
+
static register(agentName: string, email: string, baseUrl?: string, ownerName?: string, description?: string): Promise<Record<string, unknown>>;
|
|
264
|
+
private post;
|
|
265
|
+
private get;
|
|
266
|
+
private request;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Get system resource profile and recommended concurrency settings.
|
|
270
|
+
* Calls the Python backend's system-info detection.
|
|
271
|
+
*/
|
|
272
|
+
declare function systemInfo(): Promise<Record<string, unknown>>;
|
|
273
|
+
|
|
274
|
+
declare const BoostedTravel: typeof LetsFG;
|
|
275
|
+
declare const BoostedTravelError: typeof LetsFGError;
|
|
276
|
+
type BoostedTravelConfig = LetsFGConfig;
|
|
277
|
+
|
|
278
|
+
export { AuthenticationError, type BookingResult, BoostedTravel, type BoostedTravelConfig, BoostedTravelError, type CheckoutProgress, ErrorCategory, type ErrorCategoryType, ErrorCode, type ErrorCodeType, type FlightOffer, type FlightRoute, type FlightSearchResult, type FlightSegment, LetsFG, type LetsFGConfig, LetsFGError, OfferExpiredError, type Passenger, PaymentRequiredError, type SearchOptions, type UnlockResult, ValidationError, cheapestOffer, LetsFG as default, systemInfo as getSystemInfo, searchLocal as localSearch, offerSummary, searchLocal, systemInfo };
|