// Lightweight client that talks to your PHP proxy via fetch. // Returns Airport/Flight objects with helpful methods. export class Airport { constructor(dto) { Object.assign(this, dto); } get display() { const code = this.iata || this.icao || ''; return `${code} – ${this.name}${this.city ? ' (' + this.city + ')' : ''}`; } } export class Flight { constructor(dto) { Object.assign(this, dto); } summary() { const s = []; if (this.departureAirport?.iata) s.push(this.departureAirport.iata); if (this.arrivalAirport?.iata) s.push(this.arrivalAirport.iata); const route = s.length ? s.join(' → ') : 'Flight'; const co2 = this.emissions?.co2_total ?? this.co2 ?? null; return co2 != null ? `${route}: ${co2} kg CO₂e` : route; } } export class Calco2latoClient { /** * @param {string} proxyUrl e.g. "/api-proxy.php" * @param {object} [options] * @param {number} [options.timeoutMs=10000] */ constructor(proxyUrl, { timeoutMs = 10000 } = {}) { this.proxyUrl = proxyUrl; this.timeoutMs = timeoutMs; } async _fetchJSON(payloadOrQuery) { const { method = 'GET', query = null, body = null } = payloadOrQuery; const url = new URL(this.proxyUrl, window.location.origin); if (query) { for (const [k, v] of Object.entries(query)) { if (v !== undefined && v !== null) url.searchParams.set(k, String(v)); } } const ctrl = new AbortController(); const t = setTimeout(() => ctrl.abort(), this.timeoutMs); try { const res = await fetch(url.toString(), { method, headers: body ? { 'Content-Type': 'application/json' } : undefined, body: body ? JSON.stringify(body) : undefined, credentials: 'include', signal: ctrl.signal, }); const data = await res.json().catch(() => ({})); if (!res.ok) { throw new Error(data?.error || `HTTP ${res.status}`); } return data; } finally { clearTimeout(t); } } // ---------- Airports ---------- /** * @param {string} q * @param {number} [limit=20] * @param {number} [offset=1] * @returns {Promise} */ async searchAirports(q, limit = 20, offset = 1) { const data = await this._fetchJSON({ method: 'GET', query: { endpoint: 'airports.search', iata: q, per_page: limit, page: offset } }); const items = Array.isArray(data?.results) ? data.results : (Array.isArray(data) ? data : []); return items.map(a => new Airport(a)); } // ---------- Flights ---------- /** * @param {object} params e.g. { origin: "FRA", destination: "LHR", date: "2025-09-20", pax: 1, cabin: "economy" } * @returns {Promise} */ async estimateFlight(params) { const data = await this._fetchJSON({ method: 'POST', body: { endpoint: 'flights.estimate', params } }); return new Flight(data.flights[0]); } }