Skip to main content

CHANGELOG.md

# Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog and this project follows Semantic Versioning.

## [0.2.0] - 11.06.2026

### Added

- `:timeout` option for `Kagi.summarize/1..3`, the total request timeout in
  milliseconds. Precedence: per-call `:timeout`, then the client's
  `req_options[:receive_timeout]`, then the summarizer default of 60 seconds.
- `req` 0.6 support: the requirement is now `~> 0.5 or ~> 0.6`, and
  `cloaked_req` 0.4.2 carries the matching adapter support.
- `:invalid_session_token` error reason: tokens with characters that cannot
  appear in a cookie value (a pasted `Cookie` header, for example) are rejected
  before any request instead of being sent raw.

### Fixed

- `inspect(%Kagi.Client{})` no longer prints the session token; the field is
  redacted from the derived `Inspect` implementation.
- Search results keep Kagi's ranking: grouped and standard rows are parsed in
  one document-order pass, so `:limit` no longer drops grouped results that
  Kagi ranks near the top.
- Search queries that are not strings or lists of strings (charlists, keyword
  lists) return `:invalid_option` instead of being mangled or raising.
- `CloakedReq` adapter options (`:impersonate`, `:cookie_jar`, ...) passed via
  `:req_options` no longer raise `ArgumentError`; the adapter is attached
  before the configured options are merged.
- Maps results with drifting scalar types (numeric `price`, string `rating`,
  ...) normalize to `nil` instead of crashing `sort: :price` with a
  `FunctionClauseError`; integer ratings and distances convert to floats.
- Maps `:limit` is validated before the HTTP request, matching search, so an
  invalid value no longer burns an authenticated request.
- A `pois` value that is not an array of objects returns a descriptive
  `:parse_error` instead of raising.
- Maps and search parse errors no longer embed whole response payloads in the
  error message; inspected values are bounded.
- Maps queries that are not strings or lists of strings (charlists, keyword
  lists) return `:invalid_option` instead of being mangled or raising.

### Changed

- Challenge detection runs only when a page has no recognizable results and no
  longer downcases the whole HTML body on the happy path.
- Requests no longer follow redirects, so the session cookie cannot travel to
  another host. Re-enable with `redirect: true` in `:req_options`. The
  endpoint URL and method are pinned after configuration merging, so
  `:req_options` can never point a request at another host.
- Requests no longer retry transient HTTP errors behind the caller's back; a
  429 returns `:rate_limited` after a single attempt. Re-enable with
  `retry: :safe_transient` in `:req_options`.
- Transport failures now include the adapter's failure reason (timeout, DNS,
  TLS, ...) in the `:request_failed` error message.
- Summarizer requests default to a 60-second timeout instead of inheriting the
  adapter's 15-second total request timeout, which failed long summaries.
- Summarizer-reported failures (`"state": "error"` payloads and empty
  summaries) return the new `:summarizer_error` reason instead of
  `:parse_error`, so callers can tell an unfetchable URL from a client parsing
  bug. Code matching on `:parse_error` for these cases must be updated.

## [0.1.1] - 23.05.2026

### Changed

- Update `cloaked_req` to `~> 0.4.0`, which runs native HTTP requests on the shared Tokio runtime, aborts in-flight requests when the caller exits, and honours Req `connect_options` for proxy configuration.

## [0.1.0] - 17.05.2026

### Added

- Typed `Kagi.search/2`, `Kagi.search/3`, `Kagi.summarize/2`, and `Kagi.summarize/3` APIs.
- Typed `Kagi.maps/2` and `Kagi.maps/3` API with `%Kagi.Maps{}`, `%Kagi.MapsResult{}`, and `%Kagi.MapsResult.Coordinates{}` structs.
- Client-side maps sorting by `:relevance`, `:rating`, `:distance`, or `:price` with sensible default orders.
- Reusable `%Kagi.Client{}` with configurable session token resolution.
- `Req` transport by default and explicit `CloakedReq` transport support.
- Search, summarizer, and maps parsers ported from the Rust `kagi` CLI.
- Release, CI, and package documentation matching the companion Elixir libraries.