streambox_core 1.4.1 copy "streambox_core: ^1.4.1" to clipboard
streambox_core: ^1.4.1 copied to clipboard

Core for stream-based caching and data strategy architecture.

streambox logo

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.

Build Status pub package codecov style: very good analysis Verified Publisher


✨ 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: loading, success, error, initial
  • 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:

  • DataLoading β€” loading in progress
  • DataSuccess β€” data successfully loaded
  • DataError β€” an error occurred
  • DataInitial β€” The state that indicates a repository's data has been cleared (flushed)

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 parameters
  • fetchOnInit to trigger the first request on creation
  • replayLast to replay the last emitted state to new subscribers
  • fetchAwait to perform a fetch and await the first emitted state

πŸ—„οΈ 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
class ItemResponse {
  // fromJson...
  // toJson...
}

@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 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> {}

class FetchParams implements RequestParams {
  FetchParams({required this.page, required this.size});

  final int page;
  final int size;

  @override
  String get cacheKey => 'cacheKey: $page-$size';
}

// πŸ“‚ di module
final exampleRepo = ExampleRepoImpl(
  dataSource: ExampleDataSource(
    api: ExampleApiInterface(dio),
    cacheStrategy: CacheThenRefreshStrategy(
      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

πŸ›  Global Error Handling #

Provides a mechanism for global error observation and handling. You can register an StreamBoxErrorObserver to be notified of any errors that occur within your repositories. This is useful for centralized logging, analytics, or displaying toast notifications to the user without needing to handle errors in every single repository subscription.

The StreamBoxErrorObservers singleton manager allows you to easily register and unregister observers.

Example

This example shows how to create a custom error observer for logging errors.

final class AnalyticsErrorObserver implements StreamBoxErrorObserver {
  const AnalyticsErrorObserver();

  @override
  void onError(String repo, Object error, StackTrace? stackTrace) {
    // Log the error to your analytics service
    AnalyticsService.instance.logError(
      'Repo: $repo',
      error: error,
      stackTrace: stackTrace,
    );
  }
}

// Register the observer in your app's main function or DI module
void main() {
  StreamBoxErrorObservers.instance.register(const AnalyticsErrorObserver());
  // ... rest of your app setup
}

1
likes
160
points
194
downloads

Publisher

verified publisherkalaganov.dev

Weekly Downloads

Core for stream-based caching and data strategy architecture.

Repository (GitHub)
View/report issues

Topics

#repository #caching #reactive #strategy #core

Documentation

API reference

License

MIT (license)

Dependencies

meta

More

Packages that depend on streambox_core