feat(app): offline-кэш GET-запросов на дашборде — фаза 5
CacheInterceptor кэширует каждый успешный GET по путь+параметры в drift (sqlite нативно, wasm+OPFS в браузере) и подменяет им сетевую ошибку; провайдер отдаёт Cached<T>, экран показывает баннер «данные на …». Контракт для остальных экранов — docs/ai/offline-cache.md. flake.nix: libsecret/pkg-config для линуксовой сборки, jq/curl для just app-web-assets (сборка sqlite3.wasm + drift_worker.js).
This commit is contained in:
Vendored
+31
@@ -0,0 +1,31 @@
|
||||
import 'package:dio/dio.dart';
|
||||
|
||||
/// A value from the API, or the last one [CacheInterceptor] had on file for the
|
||||
/// same endpoint+params when the live request failed. `fetchedAt` is null for
|
||||
/// a live answer — that is the one bit a screen needs to decide whether to
|
||||
/// show a `StaleBanner`. See `docs/ai/offline-cache.md`.
|
||||
class Cached<T> {
|
||||
const Cached(this.data, {this.fetchedAt});
|
||||
|
||||
final T data;
|
||||
final DateTime? fetchedAt;
|
||||
}
|
||||
|
||||
extension CachedResponseX<T> on Response<T> {
|
||||
/// Wraps this response's data with the staleness [CacheInterceptor] recorded
|
||||
/// in `extra['fetchedAt']`. A provider that wants offline support returns
|
||||
/// `r.cached` instead of `r.data!`.
|
||||
Cached<T> get cached => Cached(data as T, fetchedAt: extra['fetchedAt'] as DateTime?);
|
||||
}
|
||||
|
||||
/// The oldest of several fetch times, or null if none of them is stale.
|
||||
/// Screens with several cached providers show one banner for the lot rather
|
||||
/// than one per tile.
|
||||
DateTime? oldestFetch(Iterable<DateTime?> fetchedAt) {
|
||||
DateTime? oldest;
|
||||
for (final at in fetchedAt) {
|
||||
if (at == null) continue;
|
||||
if (oldest == null || at.isBefore(oldest)) oldest = at;
|
||||
}
|
||||
return oldest;
|
||||
}
|
||||
Reference in New Issue
Block a user