letsfg 2026.5.54 → 2026.5.55
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 +9 -98
- package/dist/chunk-7C3EKQ37.mjs +1768 -0
- package/dist/cli.js +267 -279
- package/dist/cli.mjs +10 -65
- package/dist/index.d.mts +300 -84
- package/dist/index.d.ts +300 -84
- package/dist/index.js +1525 -248
- package/dist/index.mjs +21 -7
- package/package.json +4 -2
- package/dist/chunk-LBHJ4GE4.mjs +0 -487
package/dist/index.d.ts
CHANGED
|
@@ -1,19 +1,286 @@
|
|
|
1
|
+
type TripPurpose = 'honeymoon' | 'special_occasion' | 'business' | 'ski' | 'beach' | 'city_break' | 'family_holiday' | 'graduation' | 'concert_festival' | 'sports_event' | 'spring_break';
|
|
2
|
+
declare const TRIP_PURPOSES: readonly TripPurpose[];
|
|
3
|
+
interface TripPurposeOptions {
|
|
4
|
+
tripPurpose?: TripPurpose | null;
|
|
5
|
+
tripPurposes?: ReadonlyArray<TripPurpose | null | undefined> | null;
|
|
6
|
+
}
|
|
7
|
+
declare function normalizeTripPurposes({ tripPurpose, tripPurposes }: TripPurposeOptions): TripPurpose[];
|
|
8
|
+
declare function getPrimaryTripPurpose(options: TripPurposeOptions): TripPurpose | undefined;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* LetsFG Personalized Flight Ranking Engine
|
|
12
|
+
*
|
|
13
|
+
* Open-source implementation of the scoring algorithm that powers letsfg.co.
|
|
14
|
+
* Scores each offer across 9 dimensions with personalization weights that shift
|
|
15
|
+
* based on trip context and purpose. Pure TypeScript — no external dependencies,
|
|
16
|
+
* safe to run in both Node and browser.
|
|
17
|
+
*
|
|
18
|
+
* Usage:
|
|
19
|
+
* import { rankOffers, type RankingContext } from 'letsfg/ranking'
|
|
20
|
+
* const ranked = rankOffers(offers, { tripContext: 'family', requireBag: true })
|
|
21
|
+
* // ranked[0].offer is the best pick, ranked[0].heroFacts explains why
|
|
22
|
+
*
|
|
23
|
+
* Companion modules in the same package:
|
|
24
|
+
* - trip-purpose.ts — TripPurpose type + normalization helpers
|
|
25
|
+
* - offer-details.ts — extractOfferDetailSignals, getOfferDetailBadges, etc.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
interface RankOfferSegment {
|
|
29
|
+
layover_minutes?: number;
|
|
30
|
+
airline?: string;
|
|
31
|
+
flight_number?: string;
|
|
32
|
+
aircraft?: string;
|
|
33
|
+
origin?: string;
|
|
34
|
+
destination?: string;
|
|
35
|
+
}
|
|
36
|
+
interface RankOffer {
|
|
37
|
+
id: string;
|
|
38
|
+
price: number;
|
|
39
|
+
/** Display total in the user's chosen currency (ticket + fee + ancillaries).
|
|
40
|
+
* When provided, this is used for all price scoring and penalty calculations
|
|
41
|
+
* instead of `price`. Callers should populate this so the ranking reflects
|
|
42
|
+
* exactly what the user will pay. */
|
|
43
|
+
displayPrice?: number;
|
|
44
|
+
google_flights_price?: number;
|
|
45
|
+
currency: string;
|
|
46
|
+
airline: string;
|
|
47
|
+
origin?: string;
|
|
48
|
+
destination?: string;
|
|
49
|
+
departure_time: string;
|
|
50
|
+
arrival_time: string;
|
|
51
|
+
duration_minutes: number;
|
|
52
|
+
stops: number;
|
|
53
|
+
segments?: RankOfferSegment[];
|
|
54
|
+
inbound?: {
|
|
55
|
+
departure_time?: string;
|
|
56
|
+
arrival_time?: string;
|
|
57
|
+
origin?: string;
|
|
58
|
+
destination?: string;
|
|
59
|
+
stops?: number;
|
|
60
|
+
/** Inbound-leg duration in minutes. Required for round-trip scoring to
|
|
61
|
+
* see the return leg in `scoreDuration`. When absent the inbound is
|
|
62
|
+
* treated as zero-duration (best case for the offer). */
|
|
63
|
+
duration_minutes?: number;
|
|
64
|
+
segments?: RankOfferSegment[];
|
|
65
|
+
};
|
|
66
|
+
ancillaries?: {
|
|
67
|
+
cabin_bag?: {
|
|
68
|
+
included?: boolean;
|
|
69
|
+
price?: number;
|
|
70
|
+
currency?: string;
|
|
71
|
+
description?: string;
|
|
72
|
+
};
|
|
73
|
+
checked_bag?: {
|
|
74
|
+
included?: boolean;
|
|
75
|
+
price?: number;
|
|
76
|
+
currency?: string;
|
|
77
|
+
description?: string;
|
|
78
|
+
};
|
|
79
|
+
seat_selection?: {
|
|
80
|
+
included?: boolean;
|
|
81
|
+
price?: number;
|
|
82
|
+
currency?: string;
|
|
83
|
+
description?: string;
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
conditions?: {
|
|
87
|
+
refund_before_departure?: 'allowed' | 'not_allowed' | 'allowed_with_fee' | 'unknown';
|
|
88
|
+
change_before_departure?: 'allowed' | 'not_allowed' | 'allowed_with_fee' | 'unknown';
|
|
89
|
+
[key: string]: string | undefined;
|
|
90
|
+
};
|
|
91
|
+
/** Quality tag set by upstream validateOfferBatch when the offer's intrinsic
|
|
92
|
+
* data is untrustworthy (date drift from search criteria, asymmetric leg
|
|
93
|
+
* durations, etc.). The ranker uses this as the highest-priority hero gate:
|
|
94
|
+
* a suspect offer can never be hero unless every offer in the pool is suspect.
|
|
95
|
+
* Rank-not-filter — suspect offers still appear as runner-ups. */
|
|
96
|
+
quality?: 'suspect' | string;
|
|
97
|
+
}
|
|
98
|
+
interface RankingContext {
|
|
99
|
+
tripContext?: 'solo' | 'couple' | 'family' | 'group' | 'business_traveler';
|
|
100
|
+
tripPurpose?: TripPurpose;
|
|
101
|
+
tripPurposes?: ReadonlyArray<TripPurpose>;
|
|
102
|
+
travelerCount?: number;
|
|
103
|
+
depTimePref?: 'early_morning' | 'morning' | 'afternoon' | 'evening' | 'night' | 'red_eye';
|
|
104
|
+
retTimePref?: 'early_morning' | 'morning' | 'afternoon' | 'evening' | 'night' | 'red_eye';
|
|
105
|
+
arrivalTimePref?: 'morning' | 'afternoon' | 'evening';
|
|
106
|
+
requireBag?: boolean;
|
|
107
|
+
requireSeat?: boolean;
|
|
108
|
+
requireMeals?: boolean;
|
|
109
|
+
requireCancellation?: boolean;
|
|
110
|
+
preferredAirline?: string;
|
|
111
|
+
preferQuickFlight?: boolean;
|
|
112
|
+
/** User said "direct" or "nonstop" — strongly boost stops weight but don't filter.
|
|
113
|
+
* If no directs exist, 1-stop will naturally float to the top over 3-stop. */
|
|
114
|
+
preferDirect?: boolean;
|
|
115
|
+
/** User explicitly asked for cheapest / lowest price — price dominates all other factors. */
|
|
116
|
+
preferCheapest?: boolean;
|
|
117
|
+
/** User asked for "1 stop" / "max 2 stops" / "at most 1 connection" — a soft cap
|
|
118
|
+
* on the number of stops. Offers exceeding the cap are gated out of the HERO slot
|
|
119
|
+
* (rank-not-filter: they still appear as runner-ups, just below within-cap offers).
|
|
120
|
+
* When no offer satisfies the cap it is relaxed like the other gates. preferDirect
|
|
121
|
+
* (an implicit cap of 0) is handled by the dedicated 'direct' path; this covers
|
|
122
|
+
* explicit caps >= 1, where the user tolerates a connection but not a 3-leg odyssey. */
|
|
123
|
+
maxStops?: number;
|
|
124
|
+
/** User explicitly wants — or is happy with — a LONG layover (a stopover to break
|
|
125
|
+
* the journey or see a city). Inverts the default short-layover preference in
|
|
126
|
+
* scoreLayover so longer connections score higher, and boosts the layover weight.
|
|
127
|
+
* Default (undefined/false) leaves the normal short-layover scoring intact. */
|
|
128
|
+
preferLongLayover?: boolean;
|
|
129
|
+
/** Hard lower bound on departure time, in minutes from midnight.
|
|
130
|
+
* Flights departing before this time receive a heavy score penalty (effectively filtered out). */
|
|
131
|
+
departAfterMins?: number;
|
|
132
|
+
/** Hard upper bound on departure time, in minutes from midnight. */
|
|
133
|
+
departBeforeMins?: number;
|
|
134
|
+
}
|
|
135
|
+
interface ScoreBreakdown {
|
|
136
|
+
price: number;
|
|
137
|
+
stops: number;
|
|
138
|
+
duration: number;
|
|
139
|
+
depTime: number;
|
|
140
|
+
arrivalTime: number;
|
|
141
|
+
baggage: number;
|
|
142
|
+
savings: number;
|
|
143
|
+
comfortHours: number;
|
|
144
|
+
layover: number;
|
|
145
|
+
}
|
|
146
|
+
interface RankedOffer<T extends RankOffer = RankOffer> {
|
|
147
|
+
offer: T;
|
|
148
|
+
score: number;
|
|
149
|
+
rank: number;
|
|
150
|
+
breakdown: ScoreBreakdown;
|
|
151
|
+
heroFacts: string[];
|
|
152
|
+
tradeoffs: string[];
|
|
153
|
+
/** Hero only: names of user-stated criteria gates that had to be relaxed to
|
|
154
|
+
* find a hero (no offer satisfied them all). Surfaced so the UI can banner
|
|
155
|
+
* the mismatch — e.g. "No direct flights on this route" or "No refundable
|
|
156
|
+
* fare available". Empty/undefined means the hero satisfied every stated
|
|
157
|
+
* criterion. Relax order: refund -> bag -> time -> direct. */
|
|
158
|
+
relaxedGates?: string[];
|
|
159
|
+
}
|
|
160
|
+
/** Remove near-duplicate offers: when multiple connectors return the same physical
|
|
161
|
+
* flight (e.g. Ryanair FR1234 from both the direct connector and Kiwi/Skyscanner),
|
|
162
|
+
* keep only the cheapest. Two offers are considered identical only when they share
|
|
163
|
+
* the same calendar date, route, airline, outbound timing buckets, inbound timing
|
|
164
|
+
* buckets (for round-trips), stop counts, and core fare conditions. Including the
|
|
165
|
+
* inbound leg prevents collapsing distinct return options for the same outbound. */
|
|
166
|
+
declare function deduplicateOffers<T extends RankOffer>(offers: T[]): T[];
|
|
167
|
+
/**
|
|
168
|
+
* Rank an array of flight offers by personalized score.
|
|
169
|
+
* Returns a new array sorted best-first. The original array is not mutated.
|
|
170
|
+
*
|
|
171
|
+
* @param offers Array of flight offers (any type extending RankOffer)
|
|
172
|
+
* @param ctx User intent context from the NL query parser
|
|
173
|
+
*/
|
|
174
|
+
declare function rankOffers<T extends RankOffer>(offers: T[], ctx: RankingContext, options?: {
|
|
175
|
+
skipDedup?: boolean;
|
|
176
|
+
}): RankedOffer<T>[];
|
|
177
|
+
/**
|
|
178
|
+
* From an already-ranked list, picks the top N offers that are genuinely
|
|
179
|
+
* different from each other — so runner-ups are real propositions, not just
|
|
180
|
+
* the same flight at +$3 from a different booking source.
|
|
181
|
+
*
|
|
182
|
+
* Two offers are considered "the same" for this purpose if both their
|
|
183
|
+
* departure time slot (3-hour window) AND their stop count are identical.
|
|
184
|
+
* Diversity requires differing in at least one of those dimensions.
|
|
185
|
+
*
|
|
186
|
+
* Falls back to next-best-ranked when the pool lacks enough diverse options.
|
|
187
|
+
*/
|
|
188
|
+
declare function selectDiverseTop<T extends RankOffer>(ranked: RankedOffer<T>[], n: number): RankedOffer<T>[];
|
|
189
|
+
/**
|
|
190
|
+
* Returns a short human-readable label describing the ranking profile
|
|
191
|
+
* that was applied (e.g. "City break", "Family holiday"). Returns null
|
|
192
|
+
* if the default generic profile is used.
|
|
193
|
+
*/
|
|
194
|
+
declare function getProfileLabel(ctx: RankingContext): string | null;
|
|
195
|
+
|
|
196
|
+
type OfferConditionState = 'allowed' | 'not_allowed' | 'allowed_with_fee' | 'unknown';
|
|
197
|
+
type OfferAmenityState = 'included' | 'available' | 'unavailable' | 'unknown';
|
|
198
|
+
type OfferAmenityConfidence = 'verified' | 'inferred' | 'unknown';
|
|
199
|
+
type OfferAmenitySource = 'ancillary' | 'condition' | 'unknown';
|
|
200
|
+
interface OfferDetailAncillary {
|
|
201
|
+
included?: boolean;
|
|
202
|
+
price?: number;
|
|
203
|
+
currency?: string;
|
|
204
|
+
description?: string;
|
|
205
|
+
}
|
|
206
|
+
interface OfferDetailConditions {
|
|
207
|
+
refund_before_departure?: OfferConditionState;
|
|
208
|
+
change_before_departure?: OfferConditionState;
|
|
209
|
+
[key: string]: string | undefined;
|
|
210
|
+
}
|
|
211
|
+
interface OfferDetailSegmentLike {
|
|
212
|
+
airline?: string;
|
|
213
|
+
flight_number?: string;
|
|
214
|
+
aircraft?: string;
|
|
215
|
+
}
|
|
216
|
+
interface OfferDetailLegLike {
|
|
217
|
+
segments?: OfferDetailSegmentLike[];
|
|
218
|
+
}
|
|
219
|
+
interface OfferDetailLike {
|
|
220
|
+
airline?: string;
|
|
221
|
+
flight_number?: string;
|
|
222
|
+
segments?: OfferDetailSegmentLike[];
|
|
223
|
+
inbound?: OfferDetailLegLike;
|
|
224
|
+
ancillaries?: {
|
|
225
|
+
cabin_bag?: OfferDetailAncillary;
|
|
226
|
+
checked_bag?: OfferDetailAncillary;
|
|
227
|
+
seat_selection?: OfferDetailAncillary;
|
|
228
|
+
};
|
|
229
|
+
conditions?: OfferDetailConditions;
|
|
230
|
+
}
|
|
231
|
+
type OfferServiceSignal = 'included' | 'available' | null;
|
|
232
|
+
interface OfferAmenityAssessment {
|
|
233
|
+
state: OfferAmenityState;
|
|
234
|
+
confidence: OfferAmenityConfidence;
|
|
235
|
+
source: OfferAmenitySource;
|
|
236
|
+
evidence?: string;
|
|
237
|
+
}
|
|
238
|
+
interface OfferDetailSignals {
|
|
239
|
+
refundability: OfferConditionState | null;
|
|
240
|
+
changeability: OfferConditionState | null;
|
|
241
|
+
meals: OfferServiceSignal;
|
|
242
|
+
refreshments: OfferServiceSignal;
|
|
243
|
+
insurance: OfferServiceSignal;
|
|
244
|
+
lounge: OfferServiceSignal;
|
|
245
|
+
wifi: OfferServiceSignal;
|
|
246
|
+
power: OfferServiceSignal;
|
|
247
|
+
entertainment: OfferServiceSignal;
|
|
248
|
+
amenities: {
|
|
249
|
+
meals: OfferAmenityAssessment;
|
|
250
|
+
refreshments: OfferAmenityAssessment;
|
|
251
|
+
insurance: OfferAmenityAssessment;
|
|
252
|
+
lounge: OfferAmenityAssessment;
|
|
253
|
+
wifi: OfferAmenityAssessment;
|
|
254
|
+
power: OfferAmenityAssessment;
|
|
255
|
+
entertainment: OfferAmenityAssessment;
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
interface OfferDetailBadge {
|
|
259
|
+
key: string;
|
|
260
|
+
label: string;
|
|
261
|
+
tone: 'positive' | 'neutral' | 'negative';
|
|
262
|
+
}
|
|
263
|
+
declare function extractOfferDetailSignals(offer: OfferDetailLike): OfferDetailSignals;
|
|
264
|
+
declare function getOfferDetailBadges(offer: OfferDetailLike): OfferDetailBadge[];
|
|
265
|
+
declare function getOfferDetailPromptNotes(offer: OfferDetailLike): string[];
|
|
266
|
+
|
|
1
267
|
/**
|
|
2
268
|
* LetsFG — Agent-native flight search & booking SDK for Node.js/TypeScript.
|
|
3
269
|
*
|
|
4
|
-
*
|
|
5
|
-
* Zero external JS dependencies. Uses native fetch (Node 18+).
|
|
270
|
+
* Server-side engine covers hundreds of airlines. Free search via PFS Bearer token
|
|
271
|
+
* or prepaid Developer API. Zero external JS dependencies. Uses native fetch (Node 18+).
|
|
6
272
|
*
|
|
7
273
|
* @example
|
|
8
274
|
* ```ts
|
|
9
|
-
* import { LetsFG
|
|
10
|
-
*
|
|
11
|
-
* // Local search — FREE, no API key
|
|
12
|
-
* const local = await searchLocal('SHA', 'CTU', '2026-03-20');
|
|
275
|
+
* import { LetsFG } from 'letsfg';
|
|
13
276
|
*
|
|
14
|
-
* //
|
|
15
|
-
* const bt = new LetsFG({
|
|
277
|
+
* // PFS (free, Bearer token from `letsfg auth`)
|
|
278
|
+
* const bt = new LetsFG({ bearerToken: process.env.LETSFG_BEARER_TOKEN });
|
|
16
279
|
* const flights = await bt.search('GDN', 'BER', '2026-03-03');
|
|
280
|
+
*
|
|
281
|
+
* // Developer API (prepaid credits)
|
|
282
|
+
* const bt2 = new LetsFG({ apiKey: 'trav_...' });
|
|
283
|
+
* const flights2 = await bt2.search('LHR', 'JFK', '2026-04-15');
|
|
17
284
|
* ```
|
|
18
285
|
*/
|
|
19
286
|
interface FlightSegment {
|
|
@@ -112,28 +379,11 @@ interface SearchOptions {
|
|
|
112
379
|
currency?: string;
|
|
113
380
|
limit?: number;
|
|
114
381
|
sort?: 'price' | 'duration';
|
|
115
|
-
/** Max concurrent browser instances (1-32). Omit for auto-detect based on system RAM. */
|
|
116
|
-
maxBrowsers?: number;
|
|
117
|
-
/** Search mode. Omit for full search (all 200+ connectors). 'fast' = OTAs + key direct airlines (~25 connectors, 20-40s). */
|
|
118
|
-
mode?: 'fast';
|
|
119
|
-
}
|
|
120
|
-
interface CheckoutProgress {
|
|
121
|
-
status: string;
|
|
122
|
-
step: string;
|
|
123
|
-
step_index: number;
|
|
124
|
-
airline: string;
|
|
125
|
-
source: string;
|
|
126
|
-
offer_id: string;
|
|
127
|
-
total_price: number;
|
|
128
|
-
currency: string;
|
|
129
|
-
booking_url: string;
|
|
130
|
-
screenshot_b64: string;
|
|
131
|
-
message: string;
|
|
132
|
-
can_complete_manually: boolean;
|
|
133
|
-
elapsed_seconds: number;
|
|
134
|
-
details: Record<string, unknown>;
|
|
135
382
|
}
|
|
136
383
|
interface LetsFGConfig {
|
|
384
|
+
/** PFS Bearer token from `letsfg auth`. Enables free search via POST /api/search polling. */
|
|
385
|
+
bearerToken?: string;
|
|
386
|
+
/** Developer API key (prepaid credits, no per-booking fee). */
|
|
137
387
|
apiKey?: string;
|
|
138
388
|
baseUrl?: string;
|
|
139
389
|
timeout?: number;
|
|
@@ -189,28 +439,22 @@ declare class ValidationError extends LetsFGError {
|
|
|
189
439
|
declare function offerSummary(offer: FlightOffer): string;
|
|
190
440
|
/** Get cheapest offer from search results */
|
|
191
441
|
declare function cheapestOffer(result: FlightSearchResult): FlightOffer | null;
|
|
192
|
-
/**
|
|
193
|
-
* Search flights using 73 local airline connectors — FREE, no API key needed.
|
|
194
|
-
*
|
|
195
|
-
* Requires: pip install letsfg && playwright install chromium
|
|
196
|
-
*
|
|
197
|
-
* @param origin - IATA code (e.g., "SHA")
|
|
198
|
-
* @param destination - IATA code (e.g., "CTU")
|
|
199
|
-
* @param dateFrom - Departure date "YYYY-MM-DD"
|
|
200
|
-
* @param options - Optional: currency, adults, limit, etc.
|
|
201
|
-
*/
|
|
202
|
-
declare function searchLocal(origin: string, destination: string, dateFrom: string, options?: Partial<SearchOptions>): Promise<FlightSearchResult>;
|
|
203
442
|
declare class LetsFG {
|
|
443
|
+
private bearerToken;
|
|
204
444
|
private apiKey;
|
|
205
445
|
private baseUrl;
|
|
206
446
|
private timeout;
|
|
207
447
|
constructor(config?: LetsFGConfig);
|
|
448
|
+
private requireAuth;
|
|
208
449
|
private requireApiKey;
|
|
450
|
+
/** True when using PFS Bearer token (free search path) */
|
|
451
|
+
private get usingPFS();
|
|
209
452
|
/**
|
|
210
|
-
* Search for flights — FREE
|
|
453
|
+
* Search for flights — FREE.
|
|
211
454
|
*
|
|
212
|
-
* Uses
|
|
213
|
-
*
|
|
455
|
+
* Uses PFS (Bearer token) or Developer API (X-API-Key) depending on config.
|
|
456
|
+
* PFS: async polling (POST /api/search -> poll /api/results/<id> every 10s).
|
|
457
|
+
* Developer API: synchronous 60-90s call.
|
|
214
458
|
*
|
|
215
459
|
* @param origin - IATA code (e.g., "GDN", "LON")
|
|
216
460
|
* @param destination - IATA code (e.g., "BER", "BCN")
|
|
@@ -218,73 +462,45 @@ declare class LetsFG {
|
|
|
218
462
|
* @param options - Optional search parameters
|
|
219
463
|
*/
|
|
220
464
|
search(origin: string, destination: string, dateFrom: string, options?: SearchOptions): Promise<FlightSearchResult>;
|
|
465
|
+
/** PFS path: POST /api/search -> poll /api/results/<id> */
|
|
466
|
+
private searchPFS;
|
|
221
467
|
/**
|
|
222
|
-
* Resolve a city/airport name to IATA codes
|
|
468
|
+
* Resolve a city/airport name to IATA codes.
|
|
223
469
|
*/
|
|
224
470
|
resolveLocation(query: string): Promise<Array<Record<string, unknown>>>;
|
|
225
471
|
/**
|
|
226
|
-
* Unlock a flight offer —
|
|
227
|
-
*
|
|
472
|
+
* Unlock a flight offer — confirms live price, reveals direct airline booking URL.
|
|
473
|
+
* Cost: 1% of ticket price, min $3. Free with Developer API.
|
|
228
474
|
*/
|
|
229
475
|
unlock(offerId: string): Promise<UnlockResult>;
|
|
230
476
|
/**
|
|
231
|
-
* Book a flight — charges ticket price via Stripe.
|
|
232
|
-
* Creates a real airline reservation with PNR.
|
|
233
|
-
*
|
|
477
|
+
* Book a flight via Developer API — charges ticket price via Stripe, creates real PNR.
|
|
234
478
|
* Always provide idempotencyKey to prevent double-bookings on retry.
|
|
235
479
|
*/
|
|
236
480
|
book(offerId: string, passengers: Passenger[], contactEmail: string, contactPhone?: string, idempotencyKey?: string): Promise<BookingResult>;
|
|
237
481
|
/**
|
|
238
|
-
* Set up payment method (required before booking).
|
|
482
|
+
* Set up payment method (required before unlock/booking).
|
|
239
483
|
*/
|
|
240
484
|
setupPayment(token?: string): Promise<Record<string, unknown>>;
|
|
241
|
-
/**
|
|
242
|
-
* Start automated checkout — drives to payment page, NEVER submits payment.
|
|
243
|
-
*
|
|
244
|
-
* Requires unlock first. Returns progress with screenshot and
|
|
245
|
-
* booking URL for manual completion.
|
|
246
|
-
*
|
|
247
|
-
* @param offerId - Offer ID from search results
|
|
248
|
-
* @param passengers - Passenger details (use test data for safety)
|
|
249
|
-
* @param checkoutToken - Token from unlock() response
|
|
250
|
-
*/
|
|
251
|
-
startCheckout(offerId: string, passengers: Passenger[], checkoutToken: string): Promise<CheckoutProgress>;
|
|
252
|
-
/**
|
|
253
|
-
* Start checkout locally via Python (runs on your machine).
|
|
254
|
-
* Requires: pip install letsfg && playwright install chromium
|
|
255
|
-
*
|
|
256
|
-
* @param offer - Full FlightOffer object from search results
|
|
257
|
-
* @param passengers - Passenger details
|
|
258
|
-
* @param checkoutToken - Token from unlock()
|
|
259
|
-
*/
|
|
260
|
-
startCheckoutLocal(offer: FlightOffer, passengers: Passenger[], checkoutToken: string): Promise<CheckoutProgress>;
|
|
261
|
-
/**
|
|
262
|
-
* Link GitHub account for FREE unlimited access.
|
|
263
|
-
*
|
|
264
|
-
* Star https://github.com/LetsFG/LetsFG, then call this with your username.
|
|
265
|
-
* Once verified, access is permanent.
|
|
266
|
-
*/
|
|
267
|
-
linkGithub(githubUsername: string): Promise<Record<string, unknown>>;
|
|
268
485
|
/**
|
|
269
486
|
* Get current agent profile and usage stats.
|
|
270
487
|
*/
|
|
271
488
|
me(): Promise<Record<string, unknown>>;
|
|
272
489
|
/**
|
|
273
|
-
* Register a new agent — no
|
|
490
|
+
* Register a new Developer API agent — no auth needed.
|
|
274
491
|
*/
|
|
275
492
|
static register(agentName: string, email: string, baseUrl?: string, ownerName?: string, description?: string): Promise<Record<string, unknown>>;
|
|
493
|
+
private postWithBearer;
|
|
494
|
+
private getNoAuth;
|
|
495
|
+
private getWithAuth;
|
|
496
|
+
private postWithAuth;
|
|
276
497
|
private post;
|
|
277
498
|
private get;
|
|
278
|
-
private
|
|
499
|
+
private requestWithHeaders;
|
|
279
500
|
}
|
|
280
|
-
/**
|
|
281
|
-
* Get system resource profile and recommended concurrency settings.
|
|
282
|
-
* Calls the Python backend's system-info detection.
|
|
283
|
-
*/
|
|
284
|
-
declare function systemInfo(): Promise<Record<string, unknown>>;
|
|
285
501
|
|
|
286
502
|
declare const BoostedTravel: typeof LetsFG;
|
|
287
503
|
declare const BoostedTravelError: typeof LetsFGError;
|
|
288
504
|
type BoostedTravelConfig = LetsFGConfig;
|
|
289
505
|
|
|
290
|
-
export { AuthenticationError, type BookingResult, BoostedTravel, type BoostedTravelConfig, BoostedTravelError,
|
|
506
|
+
export { AuthenticationError, type BookingResult, BoostedTravel, type BoostedTravelConfig, BoostedTravelError, ErrorCategory, type ErrorCategoryType, ErrorCode, type ErrorCodeType, type FlightOffer, type FlightRoute, type FlightSearchResult, type FlightSegment, LetsFG, type LetsFGConfig, LetsFGError, type OfferDetailSignals, OfferExpiredError, type Passenger, PaymentRequiredError, type RankOffer, type RankedOffer, type RankingContext, type ScoreBreakdown, type SearchOptions, TRIP_PURPOSES, type TripPurpose, type TripPurposeOptions, type UnlockResult, ValidationError, cheapestOffer, deduplicateOffers, LetsFG as default, extractOfferDetailSignals, getOfferDetailBadges, getOfferDetailPromptNotes, getPrimaryTripPurpose, getProfileLabel, normalizeTripPurposes, offerSummary, rankOffers, selectDiverseTop };
|