v0.2.0Latest
Disk persistence, server-driven cache policy, and two new companion crates.
Added`Persister` trait with async `load` / `save`, and the `PersistSnapshot` / `PersistedEntry` / `PersistError` / `PERSIST_VERSION` types that adapters serialize to and from.
Added`QueryClient::persist_with(persister, opts, cx) -> PersistHandle`, a debounced driver that coalesces bursts of cache mutations into one snapshot per window (default 500 ms) and writes only entries younger than `max_age` (default 24 h).
Added`hydrate(client, persister, filter, max_age, cx)` to restore a cold-start cache from disk, re-checking the persist version before applying entries.
Added`PersistOptions` (`filter` / `max_age` / `debounce`) and `PersistFilter` (`Exact` / `Prefix` / `All`) to scope what gets persisted.
Added`SerializerRegistry` / `DeserializerRegistry` for round-tripping typed values through `serde_json::Value` without leaking concrete types into the core layer.
Added`NoopPersister` for tests and disabled-persistence modes.
Added`Fetched<T>` fetcher result wrapper in `core`: return `Result<Fetched<T>, E>` to let a fetcher attach a server-derived `CachePolicy` that overrides the caller's per-query policy on success.
Added`Fetched::new` (no override), `Fetched::with_policy` (override), and `Fetched::with_meta` (persist-gated opaque metadata, e.g. an HTTP `CacheMeta` for cheap `304` refetches after relaunch).
Added`use_query_with_policy` and `fetch_query_with_policy` hooks that accept `Fetched`-returning fetchers.
Added`cache_policy_from_headers(&HeaderMap)` turns `Cache-Control` into a `CachePolicy` per [RFC 9111]: `no-store` / `no-cache` → `NoCache`, `max-age` / `s-maxage` → `Ttl`, and `stale-while-revalidate` → `StaleWhileRevalidate`. Directive names are matched case-insensitively and values may be quoted.
Added`HttpCache<B>` in-memory cache layer, generic over an `HttpBackend` trait so any request library can plug in.
Added`BackendResponse`, `Conditionals` (ETag / `If-Modified-Since`), and a serializable `CacheMeta` for persistence round-trip.
AddedOptional `ReqwestBackend` behind the `reqwest` cargo feature; `reqwest` is never a hard dependency.
AddedDepends on `gpui-query` `core` only — no GPUI — keeping `http` / `bytes` / `reqwest` out of the core crate.
Added`FilePersister`, an atomic, durable `Persister`: each save writes to a sibling temp file, fsyncs it (issuing `F_FULLFSYNC` on macOS for true durability), renames it over the target, then fsyncs the parent directory on POSIX so a crash mid-write never corrupts the cache.
AddedTolerant load: missing file → empty snapshot; corrupt JSON/bincode → logged warning + empty snapshot (no panic); version mismatch → typed `PersistError::VersionMismatch`.
Added`PersistFormat::Json` (default, inspectable) and `PersistFormat::Bincode` (compact), plus `FilePersister::json` / `::bincode` / `::in_cache_dir` constructors.
Added`PersistError` surfaces retryable Windows `ERROR_ACCESS_DENIED` (antivirus / concurrent reader) as a distinct `Permission` variant so callers can back off, while preserving the original `io::Error` chain elsewhere.
ChangedNew `persist` cargo feature gates the persistence module (and the `serde_json` / `thiserror` deps); `core` and `client` stay free of it.
ChangedThe workspace gains two crates: `gpui-query-http` (core-only) and `gpui-query-persist` (pulls `persist` + `client` + `hook`).
ChangedError sanitization now strips connection strings, tokens, paths, emails, and hex keys from messages (documented in the main crate README).