streambox_core 1.3.0
streambox_core: ^1.3.0 copied to clipboard
Core for stream-based caching and data strategy architecture.

streambox_core #
A lightweight and extensible caching and repository framework for Dart & Flutter.
streambox_core helps you manage data fetching, caching, and reactive streams
with clean abstractions and powerful strategies.
✨ Features #
- Repository Pattern out of the box
- Built-in cache strategies:
- Cache First
- Cache Then Refresh
- No-Op (no caching)
- Composable data sources:
- Single source
- Chained sources
- Periodic fetch
- External stream integration
- Reactive state management via
Stream<DataState<T>> - Strongly typed request payloads: initial, loading, success, error
- Behavior & Broadcast stream adapters
- Easy to extend and integrate with your networking or persistence layer
📦 Installation #
Add to your pubspec.yaml:
dependencies:
streambox_core: ^latest_version
streambox_adapters: ^latest_version
🧩 Core Concepts #
DataState #
Represents the state of data flow:
DataInitial— no data yet or after a flush/resetDataLoading— loading in progressDataSuccess— data successfully loadedDataError— an error occurred
Cache Strategies #
- CacheFirstStrategy — returns cached data if available; fetches otherwise.
- CacheThenRefreshStrategy — returns cached data immediately and refreshes with a new fetch.
- NoOpCacheStrategy — always fetches fresh data without caching.
Repositories #
- SingleSourceRepo — wraps a single data source
- ChainedSourcesRepo — combines two dependent data sources
- PeriodicRepo — refetches data at a given interval
- BaseRepo — provides loading/error/flush helpers
Repositories optionally support:
initialFetchParamsto perform an immediate request with parametersfetchOnInitto trigger the first request on creationreplayLastto replay the last emitted state to new subscribers
🗄️ Storage Adapters #
Starting from version 1.2.0, storage adapters were moved into a separate
package streambox_adapters.
This keeps streambox_core lightweight and lets adapters evolve independently.
Available adapters in streambox_adapters #
- MemoryStoreAdapter — in-memory only, ideal for tests and prototyping
- AsyncSharedPrefsStorageAdapter — backed by SharedPreferencesAsync
- CachedSharedPrefsStorageAdapter — SharedPreferences with in-memory caching
- FlutterSecureStorageAdapter — secure encrypted storage
📘 Example Setup #
Below is an abstract example showing how to wire together a data source, a cache strategy, and a repository. Each component belongs to a specific application layer.
// 📂 data layer
@RestApi()
abstract interface class ExampleApiInterface {
factory ExampleApiInterface(Dio dio) = _ExampleApiInterface;
@GET('items')
Future<ItemResponse> fetchItems({
@Query('page') required int page,
@Query('size') required int size,
});
}
final class ExampleDataSource
extends BaseDataSource<FetchParams, ItemResponse> {
ExampleDataSource({
required ExampleApiInterface api,
required super.cacheStrategy,
}) : _api = api;
final ExampleApiInterface _api;
@override
Future<ItemResponse> request(FetchParams? params) {
assert(params != null);
return _api.fetchItems(page: params!.page, size: params.size);
}
}
final class ExampleCacheStrategy
extends CacheThenRefreshStrategy<FetchParams, ItemResponse> {
ExampleCacheStrategy({required super.cache});
@override
String resolveKey(FetchParams? params) => '${params?.page}-${params?.size}';
}
final class ExampleCache extends BaseKeyValueCache<ItemResponse> {
const ExampleCache({required super.store});
@override
String get keyPrefix => 'items';
@override
ItemResponse deserialize(String source) =>
ItemResponse.fromJson(decodeAsMap(source));
@override
String serialize(ItemResponse value) => encode(value.toJson());
}
final class ExampleRepoImpl
extends SingleSourceRepo<FetchParams, ItemResponse, ExampleEntity>
implements ExampleRepo {
ExampleRepoImpl({required super.dataSource});
@override
ExampleEntity map(FetchParams? params, ItemResponse value) =>
ExampleMapper(value).toEntity();
}
// 📂 domain layer
abstract interface class ExampleRepo
implements Repo<FetchParams, ExampleEntity> {}
// 📂 di module
final exampleRepo = ExampleRepoImpl(
dataSource: ExampleDataSource(
api: ExampleApiInterface(dio),
cacheStrategy: ExampleCacheStrategy(
cache: ExampleCache(store: MemoryStoreAdapter()),
),
),
);
If you don't need caching, simply replace the cache strategy with:
cacheStrategy: NoOpCacheStrategy(),
🛠 Extensibility #
You can implement:
- Custom
Cachebackends - Your own
CacheStrategy - Specialized
DataSourceintegrations - Custom storage adapters