google-fli 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/LICENSE +21 -0
- package/README.md +158 -0
- package/dist/core/airports.d.ts +31 -0
- package/dist/core/airports.d.ts.map +1 -0
- package/dist/core/airports.js +168 -0
- package/dist/core/airports.js.map +1 -0
- package/dist/core/builders.d.ts +30 -0
- package/dist/core/builders.d.ts.map +1 -0
- package/dist/core/builders.js +113 -0
- package/dist/core/builders.js.map +1 -0
- package/dist/core/currency.d.ts +21 -0
- package/dist/core/currency.d.ts.map +1 -0
- package/dist/core/currency.js +172 -0
- package/dist/core/currency.js.map +1 -0
- package/dist/core/dates.d.ts +22 -0
- package/dist/core/dates.d.ts.map +1 -0
- package/dist/core/dates.js +41 -0
- package/dist/core/dates.js.map +1 -0
- package/dist/core/index.d.ts +7 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +7 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/links.d.ts +39 -0
- package/dist/core/links.d.ts.map +1 -0
- package/dist/core/links.js +53 -0
- package/dist/core/links.js.map +1 -0
- package/dist/core/parsers.d.ts +34 -0
- package/dist/core/parsers.d.ts.map +1 -0
- package/dist/core/parsers.js +161 -0
- package/dist/core/parsers.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/models/airline.d.ts +1120 -0
- package/dist/models/airline.d.ts.map +1 -0
- package/dist/models/airline.js +2224 -0
- package/dist/models/airline.js.map +1 -0
- package/dist/models/airport.d.ts +7899 -0
- package/dist/models/airport.d.ts.map +1 -0
- package/dist/models/airport.js +15782 -0
- package/dist/models/airport.js.map +1 -0
- package/dist/models/google-flights/base.d.ts +232 -0
- package/dist/models/google-flights/base.d.ts.map +1 -0
- package/dist/models/google-flights/base.js +188 -0
- package/dist/models/google-flights/base.js.map +1 -0
- package/dist/models/google-flights/dates.d.ts +51 -0
- package/dist/models/google-flights/dates.d.ts.map +1 -0
- package/dist/models/google-flights/dates.js +222 -0
- package/dist/models/google-flights/dates.js.map +1 -0
- package/dist/models/google-flights/flights.d.ts +57 -0
- package/dist/models/google-flights/flights.d.ts.map +1 -0
- package/dist/models/google-flights/flights.js +224 -0
- package/dist/models/google-flights/flights.js.map +1 -0
- package/dist/models/google-flights/index.d.ts +4 -0
- package/dist/models/google-flights/index.d.ts.map +1 -0
- package/dist/models/google-flights/index.js +4 -0
- package/dist/models/google-flights/index.js.map +1 -0
- package/dist/models/index.d.ts +4 -0
- package/dist/models/index.d.ts.map +1 -0
- package/dist/models/index.js +4 -0
- package/dist/models/index.js.map +1 -0
- package/dist/search/client.d.ts +66 -0
- package/dist/search/client.d.ts.map +1 -0
- package/dist/search/client.js +205 -0
- package/dist/search/client.js.map +1 -0
- package/dist/search/concurrency.d.ts +45 -0
- package/dist/search/concurrency.d.ts.map +1 -0
- package/dist/search/concurrency.js +148 -0
- package/dist/search/concurrency.js.map +1 -0
- package/dist/search/dates.d.ts +33 -0
- package/dist/search/dates.d.ts.map +1 -0
- package/dist/search/dates.js +159 -0
- package/dist/search/dates.js.map +1 -0
- package/dist/search/decoders.d.ts +22 -0
- package/dist/search/decoders.d.ts.map +1 -0
- package/dist/search/decoders.js +333 -0
- package/dist/search/decoders.js.map +1 -0
- package/dist/search/exceptions.d.ts +21 -0
- package/dist/search/exceptions.d.ts.map +1 -0
- package/dist/search/exceptions.js +37 -0
- package/dist/search/exceptions.js.map +1 -0
- package/dist/search/flights.d.ts +57 -0
- package/dist/search/flights.d.ts.map +1 -0
- package/dist/search/flights.js +298 -0
- package/dist/search/flights.js.map +1 -0
- package/dist/search/helpers.d.ts +10 -0
- package/dist/search/helpers.d.ts.map +1 -0
- package/dist/search/helpers.js +30 -0
- package/dist/search/helpers.js.map +1 -0
- package/dist/search/index.d.ts +10 -0
- package/dist/search/index.d.ts.map +1 -0
- package/dist/search/index.js +10 -0
- package/dist/search/index.js.map +1 -0
- package/dist/search/proto.d.ts +69 -0
- package/dist/search/proto.d.ts.map +1 -0
- package/dist/search/proto.js +355 -0
- package/dist/search/proto.js.map +1 -0
- package/dist/search/urls.d.ts +9 -0
- package/dist/search/urls.d.ts.map +1 -0
- package/dist/search/urls.js +9 -0
- package/dist/search/urls.js.map +1 -0
- package/dist/search/wire.d.ts +14 -0
- package/dist/search/wire.d.ts.map +1 -0
- package/dist/search/wire.js +120 -0
- package/dist/search/wire.js.map +1 -0
- package/package.json +91 -0
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Flight search orchestrator — `GetShoppingResults` + `GetBookingResults`.
|
|
3
|
+
*
|
|
4
|
+
* 1:1 port of fli/search/flights.py.
|
|
5
|
+
*/
|
|
6
|
+
import { TripType } from "../models/google-flights/base.js";
|
|
7
|
+
import { FlightSearchFilters } from "../models/google-flights/flights.js";
|
|
8
|
+
import { getClient } from "./client.js";
|
|
9
|
+
import { parallelMap } from "./concurrency.js";
|
|
10
|
+
import { parseBookingChunk, parseFlightRow } from "./decoders.js";
|
|
11
|
+
import { SearchParseError } from "./exceptions.js";
|
|
12
|
+
import { buildBookingToken, buildTfsToken } from "./proto.js";
|
|
13
|
+
import { withLocaleParams } from "./urls.js";
|
|
14
|
+
import { iterWrbChunks, parseFirstWrbPayload } from "./wire.js";
|
|
15
|
+
export class SearchFlights {
|
|
16
|
+
static BASE_URL = "https://www.google.com/_/FlightsFrontendUi/data/travel.frontend.flights.FlightsFrontendService/GetShoppingResults";
|
|
17
|
+
static BOOKING_URL = "https://www.google.com/_/FlightsFrontendUi/data/travel.frontend.flights.FlightsFrontendService/GetBookingResults";
|
|
18
|
+
client;
|
|
19
|
+
_lastSessionId = null;
|
|
20
|
+
constructor(client) {
|
|
21
|
+
this.client = client ?? getClient();
|
|
22
|
+
}
|
|
23
|
+
/** Search for flights using the given filters. */
|
|
24
|
+
async search(filters, options = {}) {
|
|
25
|
+
const topN = options.topN ?? 5;
|
|
26
|
+
const flights = await this._fetchFlights(filters, {
|
|
27
|
+
currency: options.currency ?? null,
|
|
28
|
+
language: options.language ?? null,
|
|
29
|
+
country: options.country ?? null,
|
|
30
|
+
captureSession: true,
|
|
31
|
+
});
|
|
32
|
+
if (flights == null)
|
|
33
|
+
return null;
|
|
34
|
+
if (filters.trip_type === TripType.ONE_WAY)
|
|
35
|
+
return flights;
|
|
36
|
+
return this._expandMultiLeg(flights, filters, {
|
|
37
|
+
topN,
|
|
38
|
+
currency: options.currency ?? null,
|
|
39
|
+
language: options.language ?? null,
|
|
40
|
+
country: options.country ?? null,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
async _fetchFlights(filters, opts) {
|
|
44
|
+
const encoded = filters.encode();
|
|
45
|
+
const url = withLocaleParams(SearchFlights.BASE_URL, opts.currency, opts.language, opts.country);
|
|
46
|
+
const response = await this.client.post(url, { body: `f.req=${encoded}` });
|
|
47
|
+
const inner = parseFirstWrbPayload(response.text);
|
|
48
|
+
if (inner == null)
|
|
49
|
+
return null;
|
|
50
|
+
if (opts.captureSession)
|
|
51
|
+
this._captureSessionId(inner);
|
|
52
|
+
if (!Array.isArray(inner)) {
|
|
53
|
+
throw new SearchParseError("Shopping response shape changed — top-level is not an array");
|
|
54
|
+
}
|
|
55
|
+
const flightsRaw = [];
|
|
56
|
+
for (const i of [2, 3]) {
|
|
57
|
+
const block = inner[i];
|
|
58
|
+
if (Array.isArray(block) && Array.isArray(block[0])) {
|
|
59
|
+
for (const item of block[0])
|
|
60
|
+
flightsRaw.push(item);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const flights = [];
|
|
64
|
+
const failureSamples = [];
|
|
65
|
+
let anyFailure = false;
|
|
66
|
+
for (const row of flightsRaw) {
|
|
67
|
+
if (!Array.isArray(row))
|
|
68
|
+
continue;
|
|
69
|
+
try {
|
|
70
|
+
flights.push(parseFlightRow(row));
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
anyFailure = true;
|
|
74
|
+
const reason = `${err instanceof Error ? err.name : "Error"}: ${err instanceof Error ? err.message : String(err)}`;
|
|
75
|
+
if (!failureSamples.includes(reason) && failureSamples.length < 3) {
|
|
76
|
+
failureSamples.push(reason);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (flightsRaw.length > 0 && anyFailure && flights.length === 0) {
|
|
81
|
+
const sample = failureSamples.join("; ");
|
|
82
|
+
throw new SearchParseError(`Parsed 0/${flightsRaw.length} flight rows — Google response shape may have changed (sample reasons: ${sample})`);
|
|
83
|
+
}
|
|
84
|
+
return flights.length > 0 ? flights : null;
|
|
85
|
+
}
|
|
86
|
+
/** Fetch bookable fare options for a selected itinerary. */
|
|
87
|
+
async getBookingOptions(flight, filters, options = {}) {
|
|
88
|
+
const results = Array.isArray(flight) ? flight : [flight];
|
|
89
|
+
if (results.length === 0) {
|
|
90
|
+
throw new Error("flight argument must be a FlightResult or non-empty array of them");
|
|
91
|
+
}
|
|
92
|
+
const effectiveSession = options.sessionId ?? this._lastSessionId ?? null;
|
|
93
|
+
let token = options.bookingToken ?? null;
|
|
94
|
+
if (token == null &&
|
|
95
|
+
effectiveSession &&
|
|
96
|
+
results[results.length - 1].price != null) {
|
|
97
|
+
const last = results[results.length - 1];
|
|
98
|
+
const lastLeg = last.legs[last.legs.length - 1];
|
|
99
|
+
if (lastLeg) {
|
|
100
|
+
const airlineCode = lastLeg.airline.replace(/^_/, "");
|
|
101
|
+
token = buildBookingToken({
|
|
102
|
+
sessionId: effectiveSession,
|
|
103
|
+
airlineCode,
|
|
104
|
+
flightNumber: lastLeg.flight_number,
|
|
105
|
+
legIndex: 1,
|
|
106
|
+
priceCents: Math.round((last.price ?? 0) * 100),
|
|
107
|
+
currency: last.currency ?? options.currency ?? "USD",
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (token == null) {
|
|
112
|
+
token =
|
|
113
|
+
results[results.length - 1].booking_token ??
|
|
114
|
+
results[0].booking_token ??
|
|
115
|
+
null;
|
|
116
|
+
}
|
|
117
|
+
if (!token) {
|
|
118
|
+
throw new Error("Missing booking token. Call SearchFlights.search(...) before getBookingOptions(...) so the client can cache the session id, or pass `sessionId` / `bookingToken` explicitly.");
|
|
119
|
+
}
|
|
120
|
+
// Apply the selected_flight on a CLONE of the filters so we don't mutate the caller's input.
|
|
121
|
+
const prepared = cloneFilters(filters);
|
|
122
|
+
const segments = prepared.flight_segments;
|
|
123
|
+
if (results.length > segments.length) {
|
|
124
|
+
throw new Error(`flight has ${results.length} segments but filters has ${segments.length}`);
|
|
125
|
+
}
|
|
126
|
+
for (let i = 0; i < results.length; i++) {
|
|
127
|
+
const seg = segments[i];
|
|
128
|
+
const res = results[i];
|
|
129
|
+
if (seg && res)
|
|
130
|
+
seg.selected_flight = res;
|
|
131
|
+
}
|
|
132
|
+
const encoded = SearchFlights._encodeBookingPayload(token, prepared);
|
|
133
|
+
const url = withLocaleParams(SearchFlights.BOOKING_URL, options.currency ?? null, options.language ?? null, options.country ?? null);
|
|
134
|
+
const response = await this.client.post(url, { body: `f.req=${encoded}` });
|
|
135
|
+
const chunks = [...iterWrbChunks(response.text)];
|
|
136
|
+
if (chunks.length === 0)
|
|
137
|
+
return [];
|
|
138
|
+
const parsed = await parallelMap((chunk) => Promise.resolve(parseBookingChunk(chunk)), chunks);
|
|
139
|
+
const out = [];
|
|
140
|
+
for (const chunkOptions of parsed)
|
|
141
|
+
out.push(...chunkOptions);
|
|
142
|
+
return out;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Build a Google Flights deep-link URL for a specific itinerary.
|
|
146
|
+
*
|
|
147
|
+
* Constructs `https://www.google.com/travel/flights/booking?tfs=…` that opens
|
|
148
|
+
* the booking page pre-loaded with the given itinerary — the airline/OTA fare
|
|
149
|
+
* options and the "Continue" booking CTA included.
|
|
150
|
+
*
|
|
151
|
+
* The `tfs` itinerary token is fully deterministic (built from the flight's
|
|
152
|
+
* airports, dates and flight numbers); no session id or network round-trip is
|
|
153
|
+
* required, so the same itinerary always yields the same URL. This method
|
|
154
|
+
* never throws — on malformed input it falls back to the generic Google
|
|
155
|
+
* Flights URL.
|
|
156
|
+
*
|
|
157
|
+
* @param flight A single `FlightResult` (one-way / single segment) or an
|
|
158
|
+
* array of them (round-trip / multi-city, one element per travel direction).
|
|
159
|
+
*/
|
|
160
|
+
buildFlightBookingUrl(flight, options = {}) {
|
|
161
|
+
const results = Array.isArray(flight) ? flight : [flight];
|
|
162
|
+
// Round-trip is exactly 2 segments; one-way and multi-city (3+) both use
|
|
163
|
+
// isOneWay=true (f19=2). Only round-trip sets f19=1.
|
|
164
|
+
const isOneWay = results.length !== 2;
|
|
165
|
+
const iata = (x) => String(x).replace(/^_/, "");
|
|
166
|
+
// Match the decoder, which stores datetimes with local components
|
|
167
|
+
// (new Date(y, m-1, d, h, min)); read them back the same way.
|
|
168
|
+
const depDate = (d) => {
|
|
169
|
+
const y = d.getFullYear();
|
|
170
|
+
const m = String(d.getMonth() + 1).padStart(2, "0");
|
|
171
|
+
const day = String(d.getDate()).padStart(2, "0");
|
|
172
|
+
return `${y}-${m}-${day}`;
|
|
173
|
+
};
|
|
174
|
+
let url;
|
|
175
|
+
try {
|
|
176
|
+
const segments = results.map((result) => result.legs.map((leg) => ({
|
|
177
|
+
origin: iata(leg.departure_airport),
|
|
178
|
+
depDate: depDate(leg.departure_datetime),
|
|
179
|
+
dest: iata(leg.arrival_airport),
|
|
180
|
+
airline: iata(leg.airline),
|
|
181
|
+
flightNumber: leg.flight_number,
|
|
182
|
+
})));
|
|
183
|
+
const tfs = buildTfsToken(segments, { isOneWay });
|
|
184
|
+
url = `https://www.google.com/travel/flights/booking?tfs=${tfs}`;
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
url = "https://www.google.com/travel/flights";
|
|
188
|
+
}
|
|
189
|
+
return withLocaleParams(url, options.currency ?? null, options.language ?? null, options.country ?? null);
|
|
190
|
+
}
|
|
191
|
+
_captureSessionId(inner) {
|
|
192
|
+
if (!Array.isArray(inner))
|
|
193
|
+
return;
|
|
194
|
+
const first = inner[0];
|
|
195
|
+
if (!Array.isArray(first))
|
|
196
|
+
return;
|
|
197
|
+
const session = first[4];
|
|
198
|
+
if (typeof session === "string" && session.length > 0) {
|
|
199
|
+
this._lastSessionId = session;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
// ------------------------------------------------------------------
|
|
203
|
+
// Round-trip / multi-city expansion
|
|
204
|
+
// ------------------------------------------------------------------
|
|
205
|
+
async _expandMultiLeg(flights, filters, opts) {
|
|
206
|
+
const numSegments = filters.flight_segments.length;
|
|
207
|
+
const selectedCount = filters.flight_segments.filter((s) => s.selected_flight != null).length;
|
|
208
|
+
if (selectedCount >= numSegments - 1) {
|
|
209
|
+
return flights.map((f) => [f]);
|
|
210
|
+
}
|
|
211
|
+
const candidates = flights.slice(0, opts.topN);
|
|
212
|
+
const expand = async (outbound) => {
|
|
213
|
+
const nextFilters = cloneFilters(filters);
|
|
214
|
+
const seg = nextFilters.flight_segments[selectedCount];
|
|
215
|
+
if (seg)
|
|
216
|
+
seg.selected_flight = outbound;
|
|
217
|
+
const subFlights = await this._fetchFlights(nextFilters, {
|
|
218
|
+
currency: opts.currency,
|
|
219
|
+
language: opts.language,
|
|
220
|
+
country: opts.country,
|
|
221
|
+
captureSession: false,
|
|
222
|
+
});
|
|
223
|
+
if (subFlights == null)
|
|
224
|
+
return [outbound, null];
|
|
225
|
+
if (selectedCount + 1 < numSegments - 1) {
|
|
226
|
+
const expanded = await this._expandMultiLeg(subFlights, nextFilters, opts);
|
|
227
|
+
return [outbound, expanded];
|
|
228
|
+
}
|
|
229
|
+
return [outbound, subFlights];
|
|
230
|
+
};
|
|
231
|
+
const expansions = await parallelMap(expand, candidates);
|
|
232
|
+
const combos = [];
|
|
233
|
+
for (const [outbound, nextResults] of expansions) {
|
|
234
|
+
if (nextResults == null)
|
|
235
|
+
continue;
|
|
236
|
+
for (const nxt of nextResults) {
|
|
237
|
+
if (Array.isArray(nxt)) {
|
|
238
|
+
combos.push([outbound, ...nxt]);
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
combos.push([outbound, nxt]);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return combos;
|
|
246
|
+
}
|
|
247
|
+
// ------------------------------------------------------------------
|
|
248
|
+
// Booking payload construction
|
|
249
|
+
// ------------------------------------------------------------------
|
|
250
|
+
static _encodeBookingPayload(token, filters) {
|
|
251
|
+
const formatted = filters.format();
|
|
252
|
+
if (formatted.length < 2 || !Array.isArray(formatted[1])) {
|
|
253
|
+
throw new Error("filters.format() did not return a main struct at index 1; cannot construct a booking payload.");
|
|
254
|
+
}
|
|
255
|
+
let main = formatted[1];
|
|
256
|
+
if (main.length > 18)
|
|
257
|
+
main = main.slice(0, 18);
|
|
258
|
+
const payload = [[null, token], main, null, 0];
|
|
259
|
+
const wrapped = [null, JSON.stringify(payload)];
|
|
260
|
+
return encodeURIComponent(JSON.stringify(wrapped));
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
function cloneFilters(filters) {
|
|
264
|
+
// The constructor's date validator would re-reject past travel dates if
|
|
265
|
+
// we ran it on a clone — bypass by writing fields directly.
|
|
266
|
+
const out = Object.create(FlightSearchFilters.prototype);
|
|
267
|
+
Object.assign(out, {
|
|
268
|
+
trip_type: filters.trip_type,
|
|
269
|
+
passenger_info: { ...filters.passenger_info },
|
|
270
|
+
flight_segments: filters.flight_segments.map((s) => {
|
|
271
|
+
const clone = Object.create(Object.getPrototypeOf(s));
|
|
272
|
+
Object.assign(clone, {
|
|
273
|
+
departure_airport: s.departure_airport,
|
|
274
|
+
arrival_airport: s.arrival_airport,
|
|
275
|
+
travel_date: s.travel_date,
|
|
276
|
+
time_restrictions: s.time_restrictions,
|
|
277
|
+
selected_flight: s.selected_flight,
|
|
278
|
+
});
|
|
279
|
+
return clone;
|
|
280
|
+
}),
|
|
281
|
+
stops: filters.stops,
|
|
282
|
+
seat_type: filters.seat_type,
|
|
283
|
+
price_limit: filters.price_limit ? { ...filters.price_limit } : null,
|
|
284
|
+
airlines: filters.airlines ? [...filters.airlines] : null,
|
|
285
|
+
airlines_exclude: filters.airlines_exclude ? [...filters.airlines_exclude] : null,
|
|
286
|
+
alliances: filters.alliances ? [...filters.alliances] : null,
|
|
287
|
+
alliances_exclude: filters.alliances_exclude ? [...filters.alliances_exclude] : null,
|
|
288
|
+
max_duration: filters.max_duration,
|
|
289
|
+
layover_restrictions: filters.layover_restrictions ? { ...filters.layover_restrictions } : null,
|
|
290
|
+
sort_by: filters.sort_by,
|
|
291
|
+
exclude_basic_economy: filters.exclude_basic_economy,
|
|
292
|
+
emissions: filters.emissions,
|
|
293
|
+
bags: filters.bags ? { ...filters.bags } : null,
|
|
294
|
+
show_all_results: filters.show_all_results,
|
|
295
|
+
});
|
|
296
|
+
return out;
|
|
297
|
+
}
|
|
298
|
+
//# sourceMappingURL=flights.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flights.js","sourceRoot":"","sources":["../../src/search/flights.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Defensive accessors for the nested-list response payloads. Mirrors
|
|
3
|
+
* fli/search/_helpers.py.
|
|
4
|
+
*/
|
|
5
|
+
export declare function safeGet(seq: unknown, idx: number): unknown;
|
|
6
|
+
export declare function asBool(v: unknown): boolean | null;
|
|
7
|
+
export declare function asStr(v: unknown): string | null;
|
|
8
|
+
export declare function asInt(v: unknown): number | null;
|
|
9
|
+
export declare function asNonNegativeInt(v: unknown): number | null;
|
|
10
|
+
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/search/helpers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,wBAAgB,OAAO,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAK1D;AAED,wBAAgB,MAAM,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,IAAI,CAEjD;AAED,wBAAgB,KAAK,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAE/C;AAED,wBAAgB,KAAK,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAK/C;AAED,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAG1D"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Defensive accessors for the nested-list response payloads. Mirrors
|
|
3
|
+
* fli/search/_helpers.py.
|
|
4
|
+
*/
|
|
5
|
+
export function safeGet(seq, idx) {
|
|
6
|
+
if (Array.isArray(seq) && idx >= 0 && idx < seq.length) {
|
|
7
|
+
return seq[idx];
|
|
8
|
+
}
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
export function asBool(v) {
|
|
12
|
+
return typeof v === "boolean" ? v : null;
|
|
13
|
+
}
|
|
14
|
+
export function asStr(v) {
|
|
15
|
+
return typeof v === "string" && v.length > 0 ? v : null;
|
|
16
|
+
}
|
|
17
|
+
export function asInt(v) {
|
|
18
|
+
if (typeof v === "boolean")
|
|
19
|
+
return null;
|
|
20
|
+
if (typeof v !== "number")
|
|
21
|
+
return null;
|
|
22
|
+
if (!Number.isInteger(v))
|
|
23
|
+
return null;
|
|
24
|
+
return v;
|
|
25
|
+
}
|
|
26
|
+
export function asNonNegativeInt(v) {
|
|
27
|
+
const n = asInt(v);
|
|
28
|
+
return n != null && n >= 0 ? n : null;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/search/helpers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,UAAU,OAAO,CAAC,GAAY,EAAE,GAAW;IAC/C,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC;QACvD,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,CAAU;IAC/B,OAAO,OAAO,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,CAAU;IAC9B,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,CAAU;IAC9B,IAAI,OAAO,CAAC,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACxC,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACvC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACtC,OAAO,CAAC,CAAC;AACX,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,CAAU;IACzC,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACnB,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACxC,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { Client, type ClientOptions, type ClientResponse, getClient } from "./client.ts";
|
|
2
|
+
export { configureConcurrency, getDefaultMaxWorkers, parallelMap, TokenBucketRateLimiter, } from "./concurrency.ts";
|
|
3
|
+
export { type DatePrice, type DateSearchOptions, SearchDates } from "./dates.ts";
|
|
4
|
+
export { parseBookingChunk, parseFlightRow, } from "./decoders.ts";
|
|
5
|
+
export { SearchClientError, SearchConnectionError, SearchHTTPError, SearchParseError, SearchTimeoutError, } from "./exceptions.ts";
|
|
6
|
+
export { type BookingOptions, type BookingUrlOptions, SearchFlights, type SearchOptions, } from "./flights.ts";
|
|
7
|
+
export { type BuildTfsTokenOptions, buildBookingToken, buildTfsToken, decodeBookingToken, extractBookingTokenFromTfu, extractSessionIdFromTfu, type LegSpec, } from "./proto.ts";
|
|
8
|
+
export { withLocaleParams } from "./urls.ts";
|
|
9
|
+
export { iterWrbChunks, parseFirstWrbPayload } from "./wire.ts";
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/search/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,aAAa,EAAE,KAAK,cAAc,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACzF,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,WAAW,EACX,sBAAsB,GACvB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,iBAAiB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACjF,OAAO,EACL,iBAAiB,EACjB,cAAc,GACf,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,eAAe,EACf,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,aAAa,EACb,KAAK,aAAa,GACnB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,KAAK,oBAAoB,EACzB,iBAAiB,EACjB,aAAa,EACb,kBAAkB,EAClB,0BAA0B,EAC1B,uBAAuB,EACvB,KAAK,OAAO,GACb,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { Client, getClient } from "./client.js";
|
|
2
|
+
export { configureConcurrency, getDefaultMaxWorkers, parallelMap, TokenBucketRateLimiter, } from "./concurrency.js";
|
|
3
|
+
export { SearchDates } from "./dates.js";
|
|
4
|
+
export { parseBookingChunk, parseFlightRow, } from "./decoders.js";
|
|
5
|
+
export { SearchClientError, SearchConnectionError, SearchHTTPError, SearchParseError, SearchTimeoutError, } from "./exceptions.js";
|
|
6
|
+
export { SearchFlights, } from "./flights.js";
|
|
7
|
+
export { buildBookingToken, buildTfsToken, decodeBookingToken, extractBookingTokenFromTfu, extractSessionIdFromTfu, } from "./proto.js";
|
|
8
|
+
export { withLocaleParams } from "./urls.js";
|
|
9
|
+
export { iterWrbChunks, parseFirstWrbPayload } from "./wire.js";
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/search/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAA2C,SAAS,EAAE,MAAM,aAAa,CAAC;AACzF,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,WAAW,EACX,sBAAsB,GACvB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAA0C,WAAW,EAAE,MAAM,YAAY,CAAC;AACjF,OAAO,EACL,iBAAiB,EACjB,cAAc,GACf,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,eAAe,EACf,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAGL,aAAa,GAEd,MAAM,cAAc,CAAC;AACtB,OAAO,EAEL,iBAAiB,EACjB,aAAa,EACb,kBAAkB,EAClB,0BAA0B,EAC1B,uBAAuB,GAExB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal protobuf encoder for the GetBookingResults token.
|
|
3
|
+
*
|
|
4
|
+
* 1:1 port of fli/search/_proto.py — preserves the byte-perfect
|
|
5
|
+
* reproduction of a captured live booking token.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Construct the GetBookingResults outer[0][1] token.
|
|
9
|
+
*
|
|
10
|
+
* @returns base64-encoded protobuf token.
|
|
11
|
+
* @throws Error when any string argument is empty or price_cents is negative.
|
|
12
|
+
*/
|
|
13
|
+
export declare function buildBookingToken(args: {
|
|
14
|
+
sessionId: string;
|
|
15
|
+
airlineCode: string;
|
|
16
|
+
flightNumber: string;
|
|
17
|
+
legIndex: number;
|
|
18
|
+
priceCents: number;
|
|
19
|
+
currency?: string;
|
|
20
|
+
}): string;
|
|
21
|
+
/** Varint reader; returns `[value, newOffset]`.
|
|
22
|
+
*
|
|
23
|
+
* Uses `+= chunk * 2**shift` instead of `|= chunk << shift` because
|
|
24
|
+
* JavaScript's bitwise operators coerce to signed 32-bit integers, so
|
|
25
|
+
* `<<` past bit 30 corrupts the result. Numbers stay accurate up to
|
|
26
|
+
* `Number.MAX_SAFE_INTEGER` (2^53 − 1), which is plenty for prices and
|
|
27
|
+
* field tags but stops short of the full protobuf 64-bit varint range.
|
|
28
|
+
*/
|
|
29
|
+
export declare function _readVarint(buf: Uint8Array, off: number): [number, number];
|
|
30
|
+
type DecodedNested = Record<string, string | number>;
|
|
31
|
+
type DecodedToken = Record<string, string | number | DecodedNested>;
|
|
32
|
+
/** Decode a booking token (round-trip helper used by tests). */
|
|
33
|
+
export declare function decodeBookingToken(token: string): DecodedToken;
|
|
34
|
+
/** Extract the booking token from a `tfu` URL parameter (or full URL). */
|
|
35
|
+
export declare function extractBookingTokenFromTfu(tfu: string): string;
|
|
36
|
+
/** Extract the booking session id from a `tfu` parameter. */
|
|
37
|
+
export declare function extractSessionIdFromTfu(tfu: string): string;
|
|
38
|
+
/** One physical leg within a booking-URL segment. */
|
|
39
|
+
export interface LegSpec {
|
|
40
|
+
/** IATA code of the departure airport (e.g. `"SFO"`). */
|
|
41
|
+
origin: string;
|
|
42
|
+
/** Departure date in `YYYY-MM-DD` format. */
|
|
43
|
+
depDate: string;
|
|
44
|
+
/** IATA code of the arrival airport (e.g. `"PHX"`). */
|
|
45
|
+
dest: string;
|
|
46
|
+
/** Airline IATA code (e.g. `"AA"`). */
|
|
47
|
+
airline: string;
|
|
48
|
+
/** Flight number string (e.g. `"2413"`). */
|
|
49
|
+
flightNumber: string;
|
|
50
|
+
}
|
|
51
|
+
export interface BuildTfsTokenOptions {
|
|
52
|
+
/** `true` for one-way (incl. multi-city); `false` for round-trip. */
|
|
53
|
+
isOneWay?: boolean;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Build the `tfs` query parameter for a Google Flights deep-link URL.
|
|
57
|
+
*
|
|
58
|
+
* The `tfs` token encodes the complete itinerary — one segment per travel
|
|
59
|
+
* direction, each segment containing one leg per physical flight. It is
|
|
60
|
+
* deterministic (no session id required) and can be constructed purely from
|
|
61
|
+
* search-result data.
|
|
62
|
+
*
|
|
63
|
+
* 1:1 port of fli/search/_proto.py::build_tfs_token.
|
|
64
|
+
*
|
|
65
|
+
* @throws Error when `segments` is empty or any segment has no legs.
|
|
66
|
+
*/
|
|
67
|
+
export declare function buildTfsToken(segments: LegSpec[][], options?: BuildTfsTokenOptions): string;
|
|
68
|
+
export {};
|
|
69
|
+
//# sourceMappingURL=proto.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proto.d.ts","sourceRoot":"","sources":["../../src/search/proto.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAsEH;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,MAAM,CAyBT;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAkB1E;AAED,KAAK,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;AACrD,KAAK,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,aAAa,CAAC,CAAC;AAEpE,gEAAgE;AAChE,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,CAyE9D;AAED,0EAA0E;AAC1E,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAuD9D;AAED,6DAA6D;AAC7D,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAQ3D;AA2CD,qDAAqD;AACrD,MAAM,WAAW,OAAO;IACtB,yDAAyD;IACzD,MAAM,EAAE,MAAM,CAAC;IACf,6CAA6C;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC;IACb,uCAAuC;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,4CAA4C;IAC5C,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,qEAAqE;IACrE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,GAAE,oBAAyB,GAAG,MAAM,CA+C/F"}
|