smart_repository 0.2.0 copy "smart_repository: ^0.2.0" to clipboard
smart_repository: ^0.2.0 copied to clipboard

Policy-driven coordination for remote and local repository data.

smart_repository #

Policy-driven coordination for remote and local repository data. The package has no runtime dependencies and knows nothing about HTTP clients, databases, or state-management frameworks.

Quick start #

import 'package:smart_repository/smart_repository.dart';

final repository = SmartRepository<User>(
  remote: api.getUser,
  local: storage.getUser,
  saveLocal: storage.saveUser,
  deleteLocal: storage.deleteUser,
  localTimestamp: storage.getUserStoredAt,
  config: const SmartRepositoryConfig(
    defaultPolicy: RepositoryPolicy.networkFirst,
    maxAge: Duration(minutes: 15),
  ),
);

final result = await repository.get();
switch (result) {
  case RepositorySuccess(:final data, :final source, :final isStale):
    print('$data from $source (stale: $isStale)');
  case RepositoryFailure(:final error):
    print(error);
}

Callbacks are normalized internally. Larger projects may instead implement ReadDataSource<T>, WriteDataSource<T>, and DeleteDataSource and pass the corresponding *Source arguments.

Policies #

Policy Contract
networkOnly Read remote; optionally persist; fail on remote error.
cacheOnly Read local only; a miss returns RepositoryCacheMissException.
cacheFirst Return usable cache; stale/missing cache triggers remote; stale cache can be fallback.
networkFirst Read remote; allowed remote failures fall back to stale local data.
staleWhileRevalidate Return cache immediately; stale/unknown cache refreshes in background.
cacheAndNetwork Return any cache immediately and always refresh in background.

Unknown freshness is usable for cacheFirst, but refreshable for staleWhileRevalidate. Invalidation marks cached data stale.

Streams #

watch() replays current state to every new subscriber. It emits repository events only; it is not a state-management framework.

For stale-while-revalidate with stale cache, order is:

RepositoryLoading
RepositoryData(local)
RepositoryRefreshing(local)
RepositoryData(remote)

The operation result and stream state are separate models. To avoid a Dart name collision, one-shot errors use RepositoryFailure; stream errors use RepositoryFailureState.

Errors and fallback #

Errors remain generic. mapError can translate transport-specific exceptions, then fallbackWhen decides whether local fallback is safe. This prevents cases such as silently serving a cached user after an authorization failure.

final repository = SmartRepository<User>(
  remote: api.getUser,
  local: storage.getUser,
  mapError: (error, stackTrace) => parseApiError(error),
  fallbackWhen: (error) => error is OfflineFailure,
);

Concurrent remote reads are deduplicated by default. refresh(force: true) bypasses an in-flight request. Call dispose() when repository lifecycle ends.

Keyed repositories #

SmartRepositoryFamily<K, T> lazily owns one independent repository per key. Requests for the same key deduplicate; different keys run independently.

final users = SmartRepositoryFamily<int, User>(
  remote: (id) => api.getUser(id),
  local: (id) => storage.getUser(id),
  saveLocal: (id, user) => storage.saveUser(id, user),
  deleteLocal: storage.deleteUser,
);

final result = await users.get(42, policy: RepositoryPolicy.cacheFirst);
final states = users.watch(42);

await users.remove(42); // Dispose and forget only key 42.
await users.dispose();  // Dispose every active key.

Family retains created keys until remove(key) or dispose() is called. Persistent data is untouched by remove; use clear(key) to delete it.

Observability #

Extend RepositoryObserver<T> to connect logging, metrics, tracing, Sentry, or analytics without package dependencies. Hooks cover reads, local hits/misses, remote requests, fallback, persistence, invalidation, and clearing.

final repository = SmartRepository<User>(
  remote: api.getUser,
  observers: [RepositoryMetrics()],
);

Observers used by a family receive repositoryKey. Observer exceptions are isolated and never affect repository results.

Scope #

Version 0.2 focuses on single-value, basic-list, and keyed reads. Pagination, mutations, and cancellation remain future additions.

Flutter example #

Full cross-platform demo lives in example/. No backend needed:

cd example
flutter pub get
flutter run
0
likes
0
points
476
downloads

Publisher

verified publisherpinz.dev

Weekly Downloads

Policy-driven coordination for remote and local repository data.

Repository (GitHub)
View/report issues

License

unknown (license)

More

Packages that depend on smart_repository