streambox_core 1.2.0
streambox_core: ^1.2.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:
initialFetchParams
to perform an immediate request with parametersfetchOnInit
to trigger the first request on creationreplayLast
to 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
Cache
backends - Your own
CacheStrategy
- Specialized
DataSource
integrations - Custom storage adapters