Skip to content

Latest commit

 

History

History
246 lines (207 loc) · 13.9 KB

File metadata and controls

246 lines (207 loc) · 13.9 KB

Changelog

All notable changes to this project are documented here. The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

0.1.1 - 2026-08-21

No functional changes: the published files are identical to 0.1.0. This release exists to move publishing onto npm trusted publishing (OIDC).

Changed

  • Released through npm trusted publishing instead of a long-lived automation token. 0.1.0 was pushed from a personal account holding a granular token with write access to every package that account could reach; the release now authenticates per-run against SkyLink-API/SkyLink-API-TypeScript-SDK and no npm credential is stored in the repository at all.
  • The release job runs on Node 24 (npm 11.17). Node 22 bundles npm 10, which cannot request an OIDC token and silently falls back to token auth — a misconfigured release would have looked green while quietly skipping trusted publishing.

Note

  • Still published without a provenance attestation: npm cannot mint one while the source repository is private. Nothing needs to change here for it to appear — the workflow adds the flag on its own once the repository is public.

0.1.0 - 2026-08-17

First public release. Covers the SkyLink API v3.1 surface.

Fixed

Defects found and fixed during the pre-release audit, before anything shipped.

  • Aborting a request did not interrupt the retry backoff wait. RequestOptions.signal is documented to cancel the call immediately, and it did — except while the transport was sleeping between retries, where a bare setTimeout ignored the signal entirely. After a 503 with Retry-After: 60 a caller's controller.abort() would hang for up to a minute before the loop noticed. The backoff wait now uses the same abort-aware sleep as the polling helpers, so an abort rejects immediately with APIConnectionError; the sleep test seam gained an optional AbortSignal second parameter.

  • briefing.flight() and briefing.pdf() timed out on every call with the default client. A briefing is composed by a language model over both airports' weather and NOTAMs and takes far longer than the 30 000 ms DEFAULT_TIMEOUT_MS: measured live on 2026-08-15, format: "json" took 37–128 s, "markdown" 30–50 s, "plain_text" up to 85 s and the PDF ~52 s. Every one of those aborted, and because a timeout is retried the caller waited ~120 s to be told a healthy endpoint had failed. Both routes now carry the new BRIEFING_TIMEOUT_MS (180 000 ms) on the request spec itself.

    This is the first use of the new RequestSpec.timeout field, an endpoint-level default: a per-call { timeout } still wins, and every other endpoint keeps the client's timeout untouched. Retries are deliberately left on — a real 503 should still be retried — so cap both yourself where a slow page is worse than no briefing:

    await sky.briefing.flight(
      { origin: "KJFK", destination: "KLAX" },
      { timeout: 60_000, maxRetries: 0 },
    );

    Matches the same fix in the Python SDK.

  • batch.metars() and batch.tafs() accept parsed through the new BatchWeatherOptions, overloaded so { parsed: true } narrows the result to BatchResult<ParsedMetarResponse> / BatchResult<ParsedTafResponse>. Previously the calls hard-coded an empty params object (weather.metar(icao, {}, options)), so asking for the decoded block was impossible — and everything in skylink-api/weather (flightCategory, ceilingFt, the unit parsers) reads decoded fields and could only answer null on the result. Colouring a board of airports by flight category is the main reason to batch METARs, and it could not be done. Matches the same fix in the Python SDK.

Changed

  • ml.flightTime() takes { origin, destination }. It previously exposed the endpoint's own query keys { from, to }, which disagreed with the Python SDK (ml.flight_time(origin=, destination=), where the rename is deliberate and documented) and with this SDK's own compose.routeBrief(origin, destination) — which called flightTime({ from, to }) internally. Divergence between the two SDKs is a defect by contract, so the names are now the same on both sides.

Documentation catching up with backend fixes shipped in the 2026-08 API release. No behaviour changes — every one of these endpoints already worked through the SDK once the server side was corrected; what was wrong was the SDK telling users they were broken.

  • CONTINENTS / geo.countries({ continent: "NA" }) no longer carry the "accepted and then matches nothing" warning. The backend used to read its reference CSV with pandas, which parses the literal NA as not-a-number, so North America was unqueryable. Verified live on 2026-08-15: 41 countries and 440 regions.
  • compose.northAmericaCountries() is documented as a convenience rather than a workaround, and its @todo (which also wrongly predicted the method would start returning nothing) is gone. The method is kept — it is public API, and its predicate still accepts the historical null/"" spellings alongside "NA". geo.countries({ continent: "NA" }) is now the cheaper route and is documented as such.
  • TicketOffer.original_price / .original_currency are no longer documented as absent. The ticket service emits them (JFK→LAX: price_usd: 168.52, original_price: 137, original_currency: "CHF"), which finally makes the price_usd-is-not-always-USD caveat actionable.
  • TicketSearchResponse.count now warns that the list is long rather than short: JFK→LAX returned 111 offers and LHR→JFK 120.

Deprecated

  • { from, to } on ml.flightTime(). Still accepted and still works — the parameters are a union of both spellings, origin/destination win when both are present — but the type is marked @deprecated. Existing code compiles unchanged.

Added

Client

  • SkyLink client with eager readonly namespaces, resolved configuration on client.config and client.baseUrl.
  • Two distribution channels via provider: "rapidapi"the default — (https://skylink-api.p.rapidapi.com, X-RapidAPI-Key + X-RapidAPI-Host, RAPIDAPI_KEY falling back to SKYLINK_API_KEY) and "direct" (https://data.skylinkapi.com/v3.1, x-api-key, SKYLINK_API_KEY only). Both expose an identical method surface.
  • baseUrl override for staging and local backends; supplying it makes the API key optional, so keyless DISABLE_AUTH deployments work.
  • Options: apiKey, provider ("rapidapi"), baseUrl, timeout (30 000 ms), maxRetries (3), historyPlan ("ultra"), defaultHeaders, fetch.
  • Per-request RequestOptions: timeout, maxRetries, headers, signal.
  • client.lastRateLimit from the quota headers of every response, error responses included — X-RateLimit-Requests-{Limit,Remaining,Reset} on RapidAPI and X-RateLimit-{Limit,Remaining,Reset} on the direct channel, the former taking precedence. RapidAPI's X-RateLimit-rapid-free-plans-hard-limit-* headers are ignored: they report the marketplace's free-tier ceiling, not the plan's quota.
  • client.request() / client.requestWithResponse() as escape hatches for untyped endpoints.

Namespaces (21) — weather, airports, airlines, navaids, geo, adsb, aircraft, charts, delays, notams, schedules, ml, carbon, briefing, routes, tickets, webhooks, history, plus the three client-side ones (batch, poll, compose) — and the client-level shortcuts flightStatus() and distance().

  • weathermetar, taf (both overloaded on parsed), windsAloft, pireps, airsigmet.
  • airportssearch, nearby, byIp, searchText.
  • airlinessearch. navaidslist (client-side "at least one filter" check).
  • geocountries, country, regions, region.
  • adsbaircraft (the one paginated endpoint), statistics, health.
  • aircraftbyRegistration, byIcao24 (discriminated union on found), performance, databaseStats.
  • chartsbyAirport, byCategory, sources; charts typed as Partial<Record<ChartCategory, Chart[]>>.
  • delaysfaa (nationwide and per airport). notamsbyAirport.
  • schedulesdepartures, arrivals; flight rows keep their PascalCase wire keys.
  • mlflightTime with the wire parameter names from / to.
  • carbonestimate. ticketssearch.
  • briefingflight overloaded on format ("json" → object, text formats → string) and pdfUint8Array.
  • routesbyCallsign (union on source), byAirport, pairs.
  • webhookscreate (201), list, update, delete (204 → void), eventTypes; envelopes unwrapped to arrays.
  • historyflights, flight, track, positions (dispatches ICAO24 vs registration by shape), positionsByIcao24, positionsByRegistration, airportTraffic, all parameterized by the ultra / mega plan prefix.

Developer experience

  • sky.batchmetars, tafs, notams, airports (IATA/ICAO classified per code), flightStatuses: one entry per input identifier holding the response or its SkyLinkError, five requests in flight by default, duplicates collapsed. Helpers successes, failures, isBatchError, throwForErrors, mapConcurrent.
  • sky.composeairportBrief, flightBrief, routeBrief, enrichAdsb, schedulesWithStatus, northAmericaCountries. Parts are fetched in parallel and a failed part is collected into brief.errors under its own name instead of throwing; only the primary call (airport lookup, flight status, schedule board) propagates. include/exclude decide what is requested, so a deselected part costs no quota. Briefs fetch weather with parsed: true; flightBrief prices CO₂ from the route's ICAO pair and falls back to the callsign; schedulesWithStatus accepts IATA or ICAO and requests each distinct flight number once.
  • sky.pollflightStatus (changes only, stops on a terminal status) and adsb (appeared/updated/disappeared diffs plus the full snapshot) as async generators; 429 and 5xx are waited out, interval/maxIterations/AbortSignal end the loop.
  • Async iterators over the two paginated shapes: adsb.iterAircraft() (limit/offset, with a repeated-page guard) and history.iterFlights() (time windows clamped to the plan's retention).
  • Zero-dependency helper modules, also published as subpath entry points (skylink-api/units, /spatial, /idents, /weather, /geojson, /sentinels, /batch, /cache, /csv): unit conversions and the prose/P6SM parsers, great-circle and bounding-box maths, track statistics and RDP simplification, flight-category/ceiling/wind components, identifier classification, sentinel narrowing, RFC 7946 GeoJSON exporters and RFC 4180 toCsv().
  • Opt-in response cache (MemoryCache, CacheProtocol, resolveTtl, CACHE_HIT_HEADER): off unless configured, per-operation TTLs in milliseconds, successful GETs only, LRU eviction on a monotonic clock.
  • Quota observers client.onRateLimit() (every response that carried the headers) and client.onQuotaLow() (once per crossing, re-armed on reset), plus SkyLink.fromEnv() and client.withOptions() for clones that share the connection pool but not state.
  • webhooks.ensure() for idempotent subscription setup.

Transport

  • Zero runtime dependencies: native fetch, AbortController, URLSearchParams.
  • Retry policy: 429/500/502/503/504 and transport failures, full-jitter exponential backoff (random() * min(8 s, 500 ms * 2^attempt)), Retry-After honoured in both the seconds and HTTP-date forms (capped at 60 s). POST retried only on 429.
  • Overall per-attempt deadline enforced with AbortController; external AbortSignal cancels immediately without retrying.
  • Query serialization that drops nullish values, lower-cases booleans, comma-joins bounding boxes and CSV filters, and formats dates per endpoint (DD-MM-YYYY for schedules, YYYY-MM-DD for tickets, ISO 8601 for history).
  • Response decoding for JSON, text, binary (Uint8Array) and empty (204) bodies.

Errors

  • SkyLinkErrorAPIConnectionError / APITimeoutError and APIStatusError (status, statusCode, headers, body, code) → BadRequestError, AuthenticationError, PermissionDeniedError, NotFoundError, UnprocessableEntityError (errors[]), RateLimitError (rateLimit, retryAfter), InternalServerError, ServiceUnavailableError.
  • One parser for the three error-body shapes the API emits: gateway { error, message, code }, HTTPException { detail } and validation { detail: [{ loc, msg, type }] }.
  • HTTP 200 "not found" sentinels are modelled as types, not exceptions: the found: true | false union on aircraft lookup, error on IP airport search and note on history search.

Types

  • Compile-time-only interfaces mirroring the wire exactly — snake_case fields, PascalCase schedules rows, usageType on navaids — with no index signatures and no runtime validation. ISO 8601 values are typed string; scraped/opaque times (flight status, NOTAM validity, delay durations) are left unparsed.

Packaging

  • Dual ESM + CJS build with declaration files for both, exports map, sideEffects: false, Node >= 20.
  • CI on Node 20/22/24 (Biome, tsc --noEmit, build, vitest) and tag-triggered publishing with npm provenance.
  • Ten runnable examples in examples/ — weather, ADS-B, briefings, history, webhooks, batch, compose, polling, helper exports, cache and quota — and an env-gated integration suite.