{"id":50666666,"url":"https://github.com/decocms/fast-flights-ts","last_synced_at":"2026-06-08T07:03:52.924Z","repository":{"id":350964087,"uuid":"1208905865","full_name":"decocms/fast-flights-ts","owner":"decocms","description":"Port of fast_flights to TypeScript focused on performance and low dep count.","archived":false,"fork":false,"pushed_at":"2026-04-13T01:41:05.000Z","size":967,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-13T02:25:06.299Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/decocms.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-12T22:28:09.000Z","updated_at":"2026-04-13T01:41:12.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/decocms/fast-flights-ts","commit_stats":null,"previous_names":["decocms/fast-flights-ts"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/decocms/fast-flights-ts","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/decocms%2Ffast-flights-ts","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/decocms%2Ffast-flights-ts/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/decocms%2Ffast-flights-ts/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/decocms%2Ffast-flights-ts/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/decocms","download_url":"https://codeload.github.com/decocms/fast-flights-ts/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/decocms%2Ffast-flights-ts/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34051772,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-08T02:00:07.615Z","response_time":111,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-08T07:03:28.021Z","updated_at":"2026-06-08T07:03:52.916Z","avatar_url":"https://github.com/decocms.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n# fast-flights-ts\n\nFast, strongly-typed Google Flights scraper for Node.js.\nCalls Google's internal RPC endpoint directly -- no HTML scraping, no browser required.\n\n```bash\nnpm install fast-flights-ts\n```\n\n\u003c/div\u003e\n\n\u003e Forked from [AWeirdDev/flights](https://github.com/AWeirdDev/flights) (Python).\n\u003e Ported to TypeScript by [Claude Opus 4.6](https://claude.ai).\n\n## Quick start\n\n```typescript\nimport { createQuery, Passengers, getFlights } from \"fast-flights-ts\";\n\nconst query = createQuery({\n  flights: [\n    { date: \"2026-05-25\", from_airport: \"GIG\", to_airport: \"SFO\" },\n  ],\n  seat: \"economy\",\n  trip: \"one-way\",\n  passengers: new Passengers({ adults: 1 }),\n  currency: \"USD\",\n});\n\nconst results = await getFlights(query);\n\nfor (const flight of results) {\n  console.log(\n    flight.airlines.join(\", \"),\n    `$${flight.price}`,\n    flight.flights.map((f) =\u003e `${f.from_airport.code}-\u003e${f.to_airport.code}`).join(\" \"),\n  );\n}\n```\n\n## Multi-city\n\nMulti-city and open-jaw queries work out of the box:\n\n```typescript\nconst query = createQuery({\n  flights: [\n    { date: \"2026-05-21\", from_airport: \"GIG\", to_airport: \"LAX\" },\n    { date: \"2026-05-28\", from_airport: \"SFO\", to_airport: \"GIG\" },\n  ],\n  seat: \"business\",\n  trip: \"multi-city\",\n  passengers: new Passengers({ adults: 1 }),\n});\n\nconst results = await getFlights(query);\n```\n\n## Options\n\n`getFlights` and `fetchFlightsHtml` accept a second argument:\n\n```typescript\nconst results = await getFlights(query, {\n  timeout: 15_000,       // ms, default 30s\n  maxRetries: 3,         // retry on 429/503/timeout, default 0\n  retryDelay: 2_000,     // base delay with exponential backoff + jitter\n  signal: controller.signal, // external AbortSignal\n  debug: true,           // log to console\n});\n```\n\n## Integrations\n\n### Bright Data\n\nWhen using an integration, the library falls back to HTML scraping:\n\n```typescript\nimport { getFlights, BrightData } from \"fast-flights-ts\";\n\nconst results = await getFlights(query, {\n  integration: new BrightData({ api_key: \"your-key\" }),\n});\n```\n\nEnv vars: `BRIGHT_DATA_API_KEY`, `BRIGHT_DATA_API_URL`, `BRIGHT_DATA_SERP_ZONE`.\n\n## API\n\n### `createQuery(options)`\n\n| Option | Type | Default |\n|--------|------|---------|\n| `flights` | `FlightQueryInput[]` | required |\n| `seat` | `\"economy\" \\| \"premium-economy\" \\| \"business\" \\| \"first\"` | `\"economy\"` |\n| `trip` | `\"round-trip\" \\| \"one-way\" \\| \"multi-city\"` | `\"one-way\"` |\n| `passengers` | `Passengers` | 1 adult |\n| `language` | `Language \\| \"\"` | `\"\"` |\n| `currency` | `Currency \\| \"\"` | `\"\"` |\n| `max_stops` | `number \\| null` | `null` |\n\n### `getFlights(query, options?)`\n\nReturns `Promise\u003cFlightResults\u003e` -- an array of `Flights` with attached `metadata`.\n\n### `Passengers`\n\n```typescript\nnew Passengers({ adults: 2, children: 1, infants_in_seat: 0, infants_on_lap: 0 })\n```\n\nMax 9 total. Infants on lap cannot exceed adult count.\n\n## Error handling\n\nAll errors extend `FlightError`:\n\n```typescript\nimport { FlightError, HttpError, CaptchaError, TimeoutError, ParseError } from \"fast-flights-ts\";\n\ntry {\n  await getFlights(query);\n} catch (e) {\n  if (e instanceof TimeoutError) { /* request timed out */ }\n  if (e instanceof HttpError) { /* e.status, e.responseLength */ }\n  if (e instanceof CaptchaError) { /* Google wants a CAPTCHA */ }\n  if (e instanceof ParseError) { /* unexpected response format */ }\n}\n```\n\nRetry is automatic for 429, 502, 503, 504, and timeouts when `maxRetries \u003e 0`.\n\n## Response types\n\n```typescript\ninterface Flights {\n  type: string;\n  price: number;\n  airlines: string[];\n  flights: SingleFlight[];\n  carbon: CarbonEmission;\n}\n\ninterface SingleFlight {\n  from_airport: Airport; // { code, name }\n  to_airport: Airport;\n  departure: SimpleDatetime;\n  arrival: SimpleDatetime;\n  duration: number; // minutes\n  plane_type: string;\n}\n\ninterface FlightResults extends Array\u003cFlights\u003e {\n  metadata: JsMetadata; // { airlines, alliances }\n}\n```\n\n## Benchmarks\n\nCompared against the original [Python implementation](https://github.com/AWeirdDev/flights) v3 (10,000 iterations, `bash bench/cross-lang.sh`).\n\n### Encoding (query + protobuf + base64)\n\n| | ops/sec | latency |\n|-|---------|---------|\n| Python v3 | 214,626 | 4.7 us |\n| **TypeScript** | **462,181** | **2.2 us** |\n\n**2.2x faster.**\n\n### Parsing (20-flight payload, JSON extract + mapping)\n\n| | ops/sec | latency |\n|-|---------|---------|\n| Python v3 | 17,711 | 56.5 us |\n| **TypeScript** | **53,911** | **18.5 us** |\n\n**3.0x faster.**\n\n### Detailed breakdown (`npm run bench`)\n\n| Operation | ops/sec | mean |\n|-----------|---------|------|\n| `encodeInfo` (simple) | 833,718 | 1.2 us |\n| `encodeInfo` (complex) | 341,613 | 2.9 us |\n| `encodeInfoToBase64` | 768,435 | 1.3 us |\n| `createQuery` | 16,330,189 | 0.06 us |\n| `createQuery` + `toStr()` | 728,724 | 1.4 us |\n| `parseRpcResponse` (5 flights) | 151,354 | 6.6 us |\n| `parseRpcResponse` (50 flights) | 17,604 | 56.8 us |\n| `parseRpcResponse` (200 flights) | 4,368 | 229 us |\n\n## How it works\n\n1. **Query** -- builds flight parameters (dates, airports, seat, passengers)\n2. **RPC** -- POSTs directly to Google's `GetShoppingResults` endpoint\n3. **Parse** -- strips `)]}'` prefix, extracts nested JSON with flight data\n4. **Fallback** -- HTML scraping via `node-libcurl` or `fetch` when using integrations\n\nThe RPC approach is used by default for structured queries. It works for all trip types (one-way, round-trip, multi-city) and returns more results than HTML scraping (best + other flights).\n\n### Why it's fast\n\n- **Direct RPC** -- no HTML to download or parse, ~35KB response vs ~2MB HTML\n- **Manual protobuf encoder** (~80 lines, no protobufjs)\n- **Zero runtime dependencies** -- `node-libcurl` is optional\n- **20 KB** bundled (ESM + CJS dual output)\n\n## Development\n\n```bash\nnpm install\nnpm run typecheck\nnpm test            # 21 tests\nnpm run bench\nnpm run build\n```\n\n## License\n\nMIT -- see [LICENSE](LICENSE).\n\nOriginal Python library by [AWeirdDev](https://github.com/AWeirdDev).\nRPC approach inspired by [swoop](https://github.com/saraswatayu/swoop).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdecocms%2Ffast-flights-ts","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdecocms%2Ffast-flights-ts","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdecocms%2Ffast-flights-ts/lists"}