# Tau Ceti

Type-safe travel tooling — route pathfinding, fare calculation, NDC shopping, GDS adapters, schedule data, and more. Built on Bun and Zod.

```
npm install tau-ceti
```

---

## Quick Start

```ts
import { TauCeti } from "tau-ceti";

const tc = new TauCeti();

// Each sub-module is lazy-loaded and accessible via a typed property
tc.iataTypes.AirportCodeSchema.parse("SYD"); // Zod schemas
tc.dates.utcNow();                            // DateTime utilities
```

---

## Examples

### Pathfinding — Multi-Segment Routes

Find the optimal multi-hop flight path between any two airports using NBA* (bi-directional A\*).

```ts
import { getRegionRoutes, PathfindingEngine } from "tau-ceti/routes";

// Load route data for a region (lazy, binary-encoded for speed)
const euRoutes = await getRegionRoutes("EU");

// Or load ALL regions — merges NA, EU, APAC, ME, LATAM, OTHER
const allRoutes = await getRegionRoutes("ALL");

// Construct the engine (reusable — build once, query many times)
const engine = new PathfindingEngine(allRoutes);

// Find the best path from Brisbane to Bangkok, max 3 stops
const itinerary = engine.findPath("BNE", "BKK", {
  maxStops: 3,
  weightBy: "km", // "km" or "min"
});

if (itinerary) {
  console.log(`Total: ${itinerary.totalDistanceKm} km, ${itinerary.totalDurationMin} min`);
  for (const leg of itinerary.legs) {
    console.log(`${leg.origin} → ${leg.destination} (${leg.carriers.join(", ")})`);
  }
}

// Filter by preferred carriers
const qantasOnly = engine.findPath("SYD", "LAX", {
  preferredCarriers: ["QF"],
});
```

Supports direct routes (O(1) lookup), multi-segment search, carrier filters, and configurable edge weights.

### Route Lookup — Query, Check, Stats

```ts
import { findRoutes, routeExists, getDestinations, getAirportRouteStats } from "tau-ceti/routes";

const routes = await getRegionRoutes("ALL");

// Find all routes from SYD to MEL
const results = findRoutes(routes, { origin: "SYD", destination: "MEL" });
// => [{ destination: "MEL", carriers: ["QF", "VA", "JQ"], distanceKm: 707, durationMin: 105 }]

// Check if a direct route exists
const exists = routeExists(routes, "LHR", "JFK"); // true

// List all destinations from an airport
const destinations = getDestinations(routes, "DUB");
// => ["LHR", "CDG", "AMS", "JFK", ...]

// Get route statistics for an airport
const stats = getAirportRouteStats(routes, "SYD");
// => { routeCount: 79, carrierCount: 45, totalDistanceKm: 523456 }
```

### RouteIndex — Spatial & Adjacency Indexing

```ts
import { RouteIndex } from "tau-ceti/routes";

const allRoutes = await getRegionRoutes("ALL");
const index = new RouteIndex(allRoutes, airportCoordMap); // optional coordinate map

// O(1) route lookup
const routes = index.findRoutes("LHR", "JFK");

// Nearby airport search (requires coordinates)
const nearby = index.findNearby(51.47, -0.4543, 100); // airports within 100km of LHR

// Airport stats from index
const stats = index.getAirportStats("AKL");
```

### Decode Binary Data Directly

```ts
import { decodeRegion } from "tau-ceti/routes";
const buffer = await fetch("https://example.com/eu.bin").then((r) => r.arrayBuffer());
const routes = await decodeRegion("EU", buffer);
```

### Fare Calculation — Taxes & Surcharges

Calculate fare quotes with per-jurisdiction tax profiles (AU, US, UK, IE, NZ) and ATPCO-style rules.

```ts
import { calculateFare, TaxCalculator } from "tau-ceti/fare";

// Single-leg fare quote
const quote = calculateFare({
  components: [
    {
      origin: "DUB",
      destination: "LHR",
      baseAmount: 120,
      currency: "EUR",
      fareClass: "Y",
      fareType: "published",
    },
  ],
  cabinClass: "economy",
  fareType: "published",
  taxRegion: "IE",
  isDomestic: false,
});

console.log(quote.totalAmount); // base + taxes + surcharges
console.log(quote.taxes);       // tax breakdown (ATT, etc.)

// TaxCalculator for custom queries
const calc = new TaxCalculator();

// IE domestic: 23% VAT + ATT (€0 suspended)
calc.calculateTax("IE", 200, true, "EUR");

// NZ domestic: 15% GST, ETS NZ$5, PSC NZ$35, ASL NZ$3.50, BCL NZ$18
calc.calculateTax("NZ", 300, true, "NZD");

// Register a custom tax profile
calc.registerProfile({
  region: "JP",
  calculateTax(baseFare, isDomestic, currency) {
    return [{
      code: "JP",
      name: "Japan Departure Tax",
      amount: 1000,
      currency,
      jurisdiction: "JP",
    }];
  },
});
```

### Fare Rule Parsing

```ts
import { FareRuleParser, FareRuleValidator } from "tau-ceti/fare";

const parser = new FareRuleParser();
const rules = parser.parse(`
  CATEGORY 15 - SALE RESTRICTIONS
  FARE BASIS: Y26AON
  TRAVEL PERIOD: 01JAN26-30JUN26
  ADVANCE RESERVATION: 14 DAYS
  MINIMUM STAY: 3 DAYS
  MAXIMUM STAY: 30 DAYS
`);

const validator = new FareRuleValidator();
const valid = validator.validate(fareQuote, rules);
```

### Baggage Fee Calculator

```ts
import { calculateBaggage, registerBaggageFeeProfile, DEFAULT_FEE_PROFILE } from "tau-ceti/fare";

const result = calculateBaggage({
  items: [
    { type: "checked", weightKg: 23, count: 1 },
    { type: "carry-on", weightKg: 7, count: 1 },
  ],
  cabinClass: "economy",
  origin: "SYD",
  destination: "LAX",
});

console.log(result.totalFee); // baggage fee total
console.log(result.appliedProfile); // which profile was matched

// Register a custom baggage fee profile
registerBaggageFeeProfile({
  region: "NZ",
  name: "NZ Domestic",
  checked: { firstBag: 0, secondBag: 35, maxWeightKg: 23, pieces: true },
  carryOn: { included: true, maxWeightKg: 7, maxPieces: 1 },
  excessRatePerKg: 15,
  currency: "NZD",
});
```

### Holiday Surcharges

```ts
import {
  registerHolidaySurchargeProfile,
  resolveHolidaySurcharges,
  AU_HOLIDAY_SURCHARGE,
} from "tau-ceti/fare";

const surcharges = resolveHolidaySurcharges("2026-12-25", "AU", "AUD");
console.log(surcharges); // [{ code: "PKH", name: "AU Peak Holiday Surcharge", amount: 25, currency: "AUD" }]

// Register a custom holiday surcharge profile
registerHolidaySurchargeProfile({
  region: "JP",
  holidaySurcharges: [
    { code: "GWK", name: "Golden Week Peak", amount: 50, currency: "JPY" },
  ],
  preHolidaySurcharges: [],
  postHolidaySurcharges: [],
});
```

### Currency Lookup

```ts
import { currencyForCountry } from "tau-ceti/fare";

const aud = currencyForCountry("AU"); // "AUD"
const usd = currencyForCountry("US"); // "USD"
const eur = currencyForCountry("IE"); // "EUR"
```

### Sales Tax Lookup (Offline VAT/GST)

Powered by the `sales-tax` package — zero network calls, covers 50+ countries.

```ts
import {
  getSalesTaxForCountry,
  getAmountWithSalesTax,
  hasSalesTax,
  formatTaxRate,
} from "tau-ceti/fare";

// Get NZ GST rate (15%)
const nzTax = await getSalesTaxForCountry("NZ");
// => { type: "gst", rate: 0.15, currency: "NZD", ... }

// Get IE VAT rate (23%)
const ieTax = await getSalesTaxForCountry("IE");
// => { type: "vat", rate: 0.23, currency: "EUR", ... }

// Calculate total with tax
const result = await getAmountWithSalesTax("NZ", 100);
// => { price: 100, total: 115, rate: 0.15, type: "gst", currency: "NZD" }

// Utility checks
hasSalesTax("AU"); // true
formatTaxRate(0.15); // "15%"
```

### NDC Shopping — Single & Multi-Segment

Search flight offers via IATA NDC. Supports single origin-destination and multi-segment (connecting) itineraries.

```ts
import { searchOffers } from "tau-ceti/ndc";

// Single O&D — SYD → LAX (sync builder, returns AirShoppingRq)
const request = searchOffers({
  origin: "SYD",
  destination: "LAX",
  departureDate: "2026-07-15",
  passengers: [{ paxId: "ADULT_1", ptc: "ADT" }],
});
// The request object is sent via httpRequest or your HTTP layer

// Multi-segment — DUB → LHR → AKL → ZQN
const multiRequest = searchOffers({
  segments: [
    { origin: "DUB", destination: "LHR", departureDate: "2026-07-15" },
    { origin: "LHR", destination: "AKL", departureDate: "2026-07-15" },
    { origin: "AKL", destination: "ZQN", departureDate: "2026-07-16" },
  ],
  passengers: [{ paxId: "ADULT_1", ptc: "ADT" }],
  cabinCode: "economy",
});

// Parse a raw AirShoppingRS into normalized offers
import { parseOfferResponse } from "tau-ceti/ndc";
const normalized = parseOfferResponse(rawResponse);
console.log(normalized); // NormalizedOffer[]
```

### NDC Order, Ancillary & Mock Server

```ts
import { orderCreate, ancillaryBasket, serviceList, MockNdcServer } from "tau-ceti/ndc";

// Create an order from a selected offer (sync builder)
const order = orderCreate({
  offerId: "OFFER-123",
  offerItemId: "ITEM_001",
  passengers: [
    { paxId: "PAX_1", firstName: "Jane", lastName: "Doe", ptc: "ADT" },
  ],
});
// Returns OrderCreateRq — send via httpRequest, then parse response:
import { parseOrderView } from "tau-ceti/ndc";
const normalized = parseOrderView(rawResponse);
console.log(normalized.orderId); // "ORDER-ABC123"

// Ancillary basket — build from ServiceListRS items + selected IDs
const basket = ancillaryBasket(items, ["SRV_BAG_1", "SRV_SEAT_12A"]);

// Service list — query available ancillaries (sync builder)
const services = serviceList({ offerId: "OFFER-123", offerItemId: "ITEM_001" });
console.log(services.items); // available ancillaries

// Mock NDC server for testing
const mockServer = new MockNdcServer({ port: 3090 });
await mockServer.start();
// Serves fake NDC responses on localhost:3090
// mockServer.stop() when done
```

### Airline & Aircraft Lookup

Query the OpenFlights airline database (14,000+ airlines) and 45 commercial aircraft types.

```ts
import {
  findAirlineByIata,
  findAirlineByIcao,
  searchAirlines,
  resolveAirlineName,
  getAirlinesByCountry,
  isActiveAirline,
  findAircraftByIata,
  findAircraftByIcao,
  searchAircraft,
  estimateFlightTime,
  estimateFuelConsumption,
  getAircraftByCategory,
  getAircraftByMinRange,
} from "tau-ceti/iata-types";

// Airline lookups
const airline = findAirlineByIata("BA");
// => { iata: "BA", icao: "BAW", name: "British Airways", country: "United Kingdom", active: true }

const icao = findAirlineByIcao("BAW");
const airlinesInNZ = getAirlinesByCountry("New Zealand");
const name = resolveAirlineName("BA"); // "British Airways"
const active = isActiveAirline("BA");  // true

// Aircraft lookups
const plane = findAircraftByIata("738");
// => { iata: "738", icao: "B738", name: "Boeing 737-800", category: "narrowbody", rangeKm: 5436, cruiseSpeedKmph: 839 }

const flightTime = estimateFlightTime("738", 1200); // minutes at cruise
const fuel = estimateFuelConsumption("738", 1200);  // kg
const longHaul = getAircraftByMinRange(10000);       // aircraft capable of 10,000+ km
const narrowbodies = getAircraftByCategory("narrowbody");
```

### Airport Geo Utilities

```ts
import {
  airportDistance,
  airportDistanceDetailed,
  airportBearing,
  airportMidpoint,
  airportArcPoints,
  isDomesticRoute,
  findNearbyAirports,
  getAirportInfo,
  getAirportsByCountry,
} from "tau-ceti/iata-types";

// Distance between two airports (Haversine, km)
const dist = await airportDistance("SYD", "LAX"); // ~12070 km (null if not found)

// Detailed distance, bearing, flight time
const details = await airportDistanceDetailed("LHR", "JFK");
// => { distanceKm: 5540, distanceMiles: 3442, bearingDegrees: 292.5, compassDirection: "WNW", flightTimeMinutes: 396 }

// Initial bearing from origin to destination
const bearing = await airportBearing("SYD", "LAX"); // ~62.3 degrees (null if not found)

// Geographic midpoint between two airports
const mid = await airportMidpoint("DUB", "JFK");
// => { latitude: 53.2, longitude: -30.5 }  (null if not found)

// Generate arc points for a great-circle path
const arcPoints = await airportArcPoints("LHR", "DXB", 10); // 10 intermediate points

// Check if route is domestic
const domestic = await isDomesticRoute("SYD", "MEL"); // true (both in AU)

// Find nearby airports (requires airport-data-js)
const nearby = await findNearbyAirports("LHR", 500); // airports within 500km

// Airport info lookup
const info = await getAirportInfo("SYD");
// => { iata: "SYD", name: "Sydney Kingsford Smith Airport", city: "Sydney", country: "AU", lat: -33.94, lon: 151.17, tz: "Australia/Sydney" }

// Airports by country
const nzAirports = await getAirportsByCountry("NZ");
```

### ICAO / IATA Code Conversion

```ts
import { iataToIcao, icaoToIata } from "tau-ceti/iata-types";

const icao = iataToIcao("BA");       // "BAW"
const iata = icaoToIata("BAW");      // "BA"
const icaoAsync = await iataToIcaoAsync("QF"); // "QFA"
const iataAsync = await icaoToIataAsync("QFA"); // "QF"
```

### GDS Adapter Router

Connect to real GDS providers (Amadeus, Sabre, Navitaire, Travelport) with credential-gated routing. Works as stubs when no credentials are provided.

```ts
import { TauCeti } from "tau-ceti";

// Zero-config — all adapters return realistic stub data
const tc = new TauCeti();
const response = await tc.router.route({
  operation: "search",
  carrier: "BA",
  body: { origin: "LHR", destination: "JFK", date: "2026-07-15" },
});
console.log(response.data.offers); // 3 sample offers

// With credentials — real HTTP calls
const live = new TauCeti({
  providers: {
    amadeus: { clientId: process.env.AMADEUS_KEY, clientSecret: process.env.AMADEUS_SECRET },
    sabre: { clientId: process.env.SABRE_KEY, clientSecret: process.env.SABRE_SECRET },
  },
});

const liveResponse = await live.router.route({
  operation: "search",
  carrier: "BA",
  body: { origin: "LHR", destination: "JFK", date: "2026-07-15" },
});
```

The router auto-discovers which adapters have credentials and which fall back to stubs.

### Circuit Breaker & Rate Limiter

```ts
import { CircuitBreaker, RateLimiter } from "tau-ceti/air-connector";

const breaker = new CircuitBreaker({
  failureThreshold: 5,
  cooldownMs: 30000,
  successThreshold: 2,
});

// Before each request, check if allowed
if (!breaker.isAllowed()) {
  throw new Error("Circuit open — request blocked");
}
try {
  const result = await someGdsRequest();
  breaker.recordSuccess(); // Closed → Closed, or HalfOpen → Closed after threshold
} catch (err) {
  breaker.recordFailure(); // Track failure count, opens circuit at threshold
}

const limiter = new RateLimiter({
  requestsPerSecond: 10,
  burstSize: 20,
});

// Before each request
if (limiter.tryAcquire()) {
  // send request
} else {
  await limiter.acquire(); // wait for next token
}
```

### Outage Simulator (Chaos Testing)

```ts
import { OutageSimulator, AmadeusAdapter } from "tau-ceti/air-connector";

// OutageSimulator wraps any GdsAdapter to inject failures (decorator pattern)
const adapter = new AmadeusAdapter(/* credentials */);
const chaos = new OutageSimulator(adapter, {
  failureRate: 0.3,       // 30% of calls fail
  failureTypes: ["timeout", "service-unavailable", "rate-limit"],
  latencyJitterMs: 2000,  // up to 2s simulated latency
  durationMs: 60000,      // chaos lasts 60s (0 = indefinite)
});

await chaos.send(request); // transparent — passes through or fails

chaos.isChaosActive();   // true
chaos.getFailureCount(); // count of injected failures
chaos.setChaosConfig({ failureRate: 0.5 }); // dial up mid-test
```

### HTTP Client

```ts
import { httpRequest, getOAuth2Token } from "tau-ceti/air-connector";

const response = await httpRequest(
  { baseUrl: "https://api.example.com", timeoutMs: 10000 },
  "/v1/search",
  "POST",
  { origin: "SYD", destination: "LAX" },
);

const token = await getOAuth2Token(
  {
    method: "oauth2",
    tokenUrl: "https://api.example.com/auth/token",
    clientId: "your-client-id",
    clientSecret: "your-client-secret",
  },
  optionalLogger,
);
```

### Schedule & Availability

```ts
import { checkAvailability, checkAvailabilityRange, InMemoryScheduleStore, ScheduleLookup } from "tau-ceti/schedule";

const store = new InMemoryScheduleStore();
store.addEntries([
  {
    airline: "NZ",
    flightNumber: "NZ123",
    origin: "AKL",
    destination: "ZQN",
    departureTimeUtc: "2026-07-15T07:00:00Z",
    arrivalTimeUtc: "2026-07-15T08:50:00Z",
    doop: "1234567",                        // 7-char DOOP pattern (1=Mon, 7=Sun)
    serviceType: "J",                        // J = scheduled passenger
    periodStart: "2026-01-01",
    periodEnd: "2026-12-31",
    aircraftType: "320",
    bookingClasses: ["Y", "J"],
  },
]);

const lookup = new ScheduleLookup(store);
const flights = lookup.lookupSchedule("AKL", "ZQN", "2026-07-15");

// Check availability for a specific entry on a given date
const scheduleEntry = flights[0];
if (scheduleEntry) {
  const available = checkAvailability(scheduleEntry, "2026-07-15");

  // Check availability over a date range
  const range = checkAvailabilityRange(scheduleEntry, "2026-07-01", "2026-07-31");
}
```

### Holiday-Aware Calendars

```ts
import {
  isPublicHoliday,
  iataSeasonDates,
  dstTransitionsForYear,
  registerHolidayProvider,
  DateHolidaysProvider,
  publicHolidays,
} from "tau-ceti/schedule";

// Check if a date is a public holiday
const holiday = isPublicHoliday("2026-12-25", "NZ"); // true

// List public holidays for a country and year
const holidays = publicHolidays("AU", 2026);

// IATA season dates (summer/winter)
const season = iataSeasonDates("2026"); // summer: Mar 28 - Oct 24

// DST transitions
const transitions = dstTransitionsForYear("Europe/London", 2026);

// Register a custom holiday provider
registerHolidayProvider({
  region: "NZ",
  holidays(year: number) {
    return [{ date: "2026-02-06", name: "Waitangi Day" }];
  },
});
```

### DOOP Patterns & Operating Days

```ts
import { dayOfWeekPattern, operatesOnDay, operatingDays } from "tau-ceti/schedule";

// Create a DOOP pattern: Mon/Wed/Fri
const pattern = dayOfWeekPattern([1, 3, 5]); // "1030500"

// Check if a DOOP pattern operates on a specific day (1=Mon, 7=Sun)
const operates = operatesOnDay(pattern, 1); // true (Monday)

// List operating day indices from a DOOP pattern
const days = operatingDays(pattern);
// => [1, 3, 5]
```

### Mock Data Generators

Deterministic mock data for testing — schedules, fares, routes, and passenger manifests.

```ts
import {
  generateSchedule,
  generateFareSnapshot,
  generateRoutes,
  generatePassengerManifest,
  generateFlightLeg,
  generateFareQuotes,
  findRoute,
  populateScheduleStore,
  populateScheduleAndFares,
  SeededRng,
} from "tau-ceti/mock";

// First, find or generate routes
const route = findRoute("SYD", "MEL")!;          // look up a known mock route
const routes = generateRoutes({ market: "AU" }); // or generate a set

// Generate data from a MockRoute
const schedule = generateSchedule(route, "2026-07-15", { numFlights: 5 });
const fares = generateFareSnapshot(route, "economy");
const manifest = generatePassengerManifest(route, "QF401", "2026-07-15", { numPassengers: 50 });
const leg = generateFlightLeg(route, "2026-07-15T07:00");
const quotes = generateFareQuotes(routes, "2026-07-15", { numQuotes: 3 });

// Populate a schedule store with mock data
const { store, entries } = populateScheduleStore(routes, "2026-07-15", { days: 30 });

// Populate both schedule and fares at once
const { store: schedStore, entries: schedEntries, quotes: fareQuotes } =
  populateScheduleAndFares(routes, "2026-07-15", { days: 30, numQuotes: 3 });

// Find a specific mock route
const route = findRoute("SYD", "MEL");

// Seeded RNG for deterministic tests
const rng = new SeededRng(42);
console.log(rng.next()); // deterministic pseudo-random number
console.log(rng.pick(["QF", "VA", "JQ"])); // deterministic pick
```

### Ops — Real-Time Operations Toolkit

```ts
import { DelayPropagator, DisruptionHandler, FlightStatusWatcher, CrewTracker } from "tau-ceti/ops";

const propagator = new DelayPropagator();
propagator.propagateDelay("BA178", "JFK"); // inbound flight + outbound origin

const handler = new DisruptionHandler();
const options = handler.findRebookingOptions({ origin: "LHR", destination: "JFK", date: "2026-07-15" });

const watcher = new FlightStatusWatcher({ intervalMs: 30000 });
watcher.subscribe("BA178", (event) => console.log(event));

// Crew tracking
const tracker = new CrewTracker();
tracker.register({ name: "John Smith", base: "LHR", role: "captain", qualifications: ["B747"] });
const member = tracker.get("CREW_001");

// Rebooking providers
import { ScheduleFareRebookingProvider, OpsRebookingClient } from "tau-ceti/ops";

const rebooker = new ScheduleFareRebookingProvider(scheduleLookup, { taxRegion: "UK", isDomestic: false });
const rebookOptions = rebooker.findOptions({ origin: "LHR", destination: "JFK", date: "2026-07-15" });
```

### Mock Ops Server

```ts
import { MockOpsServer } from "tau-ceti/ops";

const mockServer = new MockOpsServer({ port: 3091 });
await mockServer.start();
// Serves mock flight events on localhost:3091
// GET /events, GET /events/latest, POST /events/generate
// mockServer.stop() when done
```

### Logger Integration

Optional logger wiring for fare calculation and schedule availability.

```ts
import { createStructuredLogger } from "tau-ceti/core";
import { checkAvailability, calculateFare } from "tau-ceti";

const logger = createStructuredLogger("info", { name: "my-app" });

// Pass logger to fare calculator for breakdown logging
const quote = calculateFare({
  components: [{ origin: "DUB", destination: "LHR", baseAmount: 120, currency: "EUR", fareClass: "Y", fareType: "published" }],
  cabinClass: "economy",
  fareType: "published",
  taxRegion: "IE",
  isDomestic: false,
  logger, // logs fare breakdown at info, warns on zero/negative amounts
});

// Pass logger to schedule availability (requires a ScheduleEntry)
const entry = scheduleLookup.lookupSchedule("AKL", "ZQN", "2026-07-15");
if (entry) {
  const available = checkAvailability(entry, "2026-07-15", undefined, undefined, logger);
}
```

### Config & Stability System

```ts
import { parseConfig, TauCetiConfigSchema, checkStability, setStabilityLevel, getStabilityLevel } from "tau-ceti/core";

// Parse and validate config with Zod
const config = parseConfig({
  providers: { amadeus: { clientId: "xxx", clientSecret: "yyy" } },
  logLevel: "info",
});

// Module stability system — gate experimental features
const level = checkStability("stable", "ndc", "alpha"); // throws if configured level < required level
setStabilityLevel("alpha");                              // allow alpha modules
getStabilityLevel();                                     // "stable" | "beta" | "alpha"
```

### Date & Time Utilities

```ts
import { DateTime, Duration, utcNow, parseDateTime, formatIso8601, elapsedMinutes } from "tau-ceti/dates";
import { airportTimezone, isAustralianZone, zonedDateTime, isDstTransition, validateConnectionTime } from "tau-ceti/dates";

// Current UTC time
const now = utcNow();                          // DateTime object
const iso = formatIso8601(now);                // "2026-06-07T12:00:00.000Z"
const parsed = parseDateTime("2026-07-15");    // DateTime

// Duration between two dates
const dur = elapsedMinutes(utcNow(), someFutureDate); // number of minutes

// Airport timezone lookup
const tz = airportTimezone("SYD");                      // "Australia/Sydney"
const zdt = zonedDateTime("SYD", "2026-07-15T07:00");   // zoned DateTime

// DST transition check
const transition = isDstTransition("Europe/London", new Date("2026-03-29"));

// Connection time validation
const valid = validateConnectionTime("SYD", "MEL", 45); // true if 45min >= minimum connect time
```

### Subpath Imports

```ts
import { PathfindingEngine } from "tau-ceti/routes";
import { calculateFare, IE_TAX_PROFILE, NZ_TAX_PROFILE } from "tau-ceti/fare";
import { searchOffers } from "tau-ceti/ndc";
import { checkAvailability } from "tau-ceti/schedule";
import { createStructuredLogger, TauCeti } from "tau-ceti/core";
import { findAirlineByIata } from "tau-ceti/iata-types";
import { DateTime } from "tau-ceti/dates";
import { OutageSimulator } from "tau-ceti/air-connector";
import { DelayPropagator } from "tau-ceti/ops";
import { generateSchedule } from "tau-ceti/mock";
```

---

## Modules

| Import Path | Description |
|---|---|
| `tau-ceti` / `tau-ceti/core` | Umbrella SDK client (`TauCeti`), config, logger, stability |
| `tau-ceti/iata-types` | Zod schemas, airport/airline/aircraft DBs, geo utilities, ICAO/IATA codes, PNR types, flight schemas |
| `tau-ceti/dates` | Luxon wrappers, timezone maps, `DateTime` parsing, DST, connection time validation |
| `tau-ceti/ndc` | NDC offer/order shopping, multi-segment, ancillary baskets, mock server |
| `tau-ceti/schedule` | Flight schedule storage, availability lookups, holiday-aware calendars, DOOP patterns |
| `tau-ceti/fare` | Fare calculator, tax profiles (AU/US/UK/IE/NZ), ATPCO rules, baggage fees, sales-tax wrapper, holiday surcharges, currency lookup |
| `tau-ceti/air-connector` | GDS adapter layer — Amadeus, Sabre, Navitaire, Travelport, NDC, circuit breaker, rate limiter, outage simulator, HTTP client |
| `tau-ceti/ops` | Real-time ops — delay propagation, disruption handling, flight status, crew tracking, rebooking, mock ops server |
| `tau-ceti/mock` | Deterministic mock data generators — schedules, fares, routes, manifests, seeded RNG |
| `tau-ceti/routes` | Route data (lazy-loaded binary), multi-segment pathfinding engine, spatial indexing |

---

## Requirements

- **Bun** (runtime) — `bun` for development, `tsup` for npm distribution
- **TypeScript** 5.x (peer dependency)
- **Node 20+** (for npm consumption)