bloc_signals_hydrate 0.9.0 copy "bloc_signals_hydrate: ^0.9.0" to clipboard
bloc_signals_hydrate: ^0.9.0 copied to clipboard

State persistence and hydration adapters for BlocSignal state containers.

bloc_signals_hydrate

⚡ bloc_signals_hydrate

"With the rigor of BLoC and the flex and speed of Signals"

State persistence and hydration adapters for BlocSignal state containers.

HydratedCubitSignal and HydratedBlocSignal automatically persist state changes to storage and restore state synchronously during container instantiation across app restarts.


🌐 Ecosystem Packages #

The BlocSignal monorepo consists of 10 modular packages:

Package Version Description
bloc_signals pub Core pure Dart reactive state primitives bridging BLoC & Signals
bloc_signals_flutter pub Flutter UI bindings, providers, builders, listeners & selectors
bloc_signals_jaspr pub Jaspr web component integration and state binding for BlocSignal
bloc_signals_riverpod pub Bidirectional Riverpod 2/3 interop adapters & provider extensions
bloc_signals_hydrate pub Automated synchronous local state persistence & hydration
bloc_signals_replay pub Undo & redo state history tracking for CubitSignal and BlocSignal
bloc_signals_otel pub OpenTelemetry tracing and span generation for state transitions
bloc_signals_devtools pub Universal DevTools telemetry observer using dart:developer
bloc_signals_test pub Declarative unit testing utilities (blocSignalTest)
bloc_signals_lint pub Custom analyzer lint rules & automated IDE quick-fixes

⚡ Key Features #

  • 📦 dynamic / Object? JSON Support: fromJson(dynamic json) and toJson(StateType state) accept primitives (num, String, bool, List, Map). Primitive states do not require map wrappers like {"value": 42}!
  • Synchronous Initial Hydration: State is restored synchronously during constructor execution—meaning initial widget builds render hydrated data immediately with zero frame flicker.
  • 🛠️ Zero-Dependency Default: Ships with MemoryHydratedStorage for fast in-memory unit testing out-of-the-box.

🚀 Getting Started #

Add bloc_signals_hydrate to your pubspec.yaml:

dependencies:
  bloc_signals: ^0.2.5
  bloc_signals_hydrate: ^0.1.1

💡 Quick Examples #

1. Primitive State Hydration (HydratedCubitSignal) #

import 'package:bloc_signals_hydrate/bloc_signals_hydrate.dart';

class CounterCubit extends HydratedCubitSignal<int> {
  CounterCubit() : super(initialState: 0);

  void increment() => emit(stateValue + 1);

  @override
  int? fromJson(dynamic json) => json as int?;

  @override
  dynamic toJson(int state) => state; // Return primitive directly!
}

2. Complex Object Hydration (HydratedBlocSignal) #

import 'package:bloc_signals_hydrate/bloc_signals_hydrate.dart';

class UserCubit extends HydratedCubitSignal<UserModel> {
  UserCubit() : super(initialState: UserModel.anonymous);

  @override
  UserModel? fromJson(dynamic json) {
    if (json is Map<String, dynamic>) {
      return UserModel.fromJson(json);
    }
    return null;
  }

  @override
  dynamic toJson(UserModel state) => state.toJson();
}

3. Storage Keys & Instance Scoping #

Storage keys are derived via the storageToken getter ('$storagePrefix${id != null ? '_$id' : ''}').

  • Singletons: Omit id (defaults to null). Storage key automatically uses the class name (e.g. 'CounterCubit').
  • Multi-Instance: Pass id via constructor to scope storage per user/session (CounterCubit(id: 'user_123') -> key 'CounterCubit_user_123').
  • Custom Keys: Override storageToken or storagePrefix directly for custom key formats:
class CounterCubit extends HydratedCubitSignal<int> {
  CounterCubit() : super(initialState: 0);

  // 100% custom storage key stored in SharedPreferences
  @override
  String get storageToken => 'app_v2_counter_key';
}

4. Built-in Storage Adapters (SharedPreferences & FlutterSecureStorage) #

package:bloc_signals_hydrate provides pre-built, tree-shakable adapters for SharedPreferences and FlutterSecureStorage via sub-library entrypoints:

SharedPreferences

import 'package:bloc_signals_hydrate/bloc_signals_hydrate.dart';
import 'package:bloc_signals_hydrate/shared_preferences.dart';
import 'package:shared_preferences/shared_preferences.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  final prefs = await SharedPreferences.getInstance();
  HydratedStorage.storage = SharedPreferencesHydratedStorage(prefs);

  runApp(const MyApp());
}

FlutterSecureStorage (Keychain / KeyStore / Web Crypto)

import 'package:bloc_signals_hydrate/bloc_signals_hydrate.dart';
import 'package:bloc_signals_hydrate/secure_storage.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  // Pre-load secure storage map for synchronous frame 1 hydration
  final secureStorage = const FlutterSecureStorage();
  HydratedStorage.storage = await SecureHydratedStorage.build(secureStorage);

  runApp(const MyApp());
}

⚖️ HydratedCubitSignal vs PersistentSignal (signals.dart) #

If you are evaluating state persistence approaches, both bloc_signals_hydrate and signals.dart's native PersistentSignal provide state persistence, but cater to different architectural patterns:

Feature HydratedCubitSignal / HydratedBlocSignal PersistentSignal (signals.dart)
Architecture Pattern BLoC container pattern (fromJson / toJson) Raw key-value signal primitive
Hydration Timing Synchronous during constructor execution (zero frame flicker) Asynchronous or synchronous depending on adapter
Observer Telemetry Integrated into BLoC onError / onChange observer pipeline Handled per-signal or via storage callbacks
Primitive Support Direct primitive return (toJson(int state) => state) Value adapter layers

Interoperability: Bridging PersistentSignal into BlocSignal #

If you already use PersistentSignal from package:signals, you can easily bridge it into a CubitSignal using an effect():

class CounterCubit extends CubitSignal<int> {
  CounterCubit(this.persistent) : super(initialState: persistent.value) {
    // Sync updates from PersistentSignal into Cubit state
    effect(() => emit(persistent.value));
  }

  final PersistentSignal<int> persistent;

  void increment() => persistent.value++;
}

🤖 AI Coding Assistant Skill #

This package is supported by an official pre-packaged AI Coding Skill representing state persistence guidelines, synchronous initial hydration semantics, and storage adapter rules for BlocSignal.

If you develop with AI coding assistants (such as Claude Code, Antigravity, Gemini, Cursor, or Codex), you can load the bloc-signals skill bundle to guide your assistant's code generation and analysis.


📜 License #

MIT License. See LICENSE for details.

0
likes
160
points
485
downloads

Documentation

API reference

Publisher

verified publisherstonehenge.com

Weekly Downloads

State persistence and hydration adapters for BlocSignal state containers.

Repository (GitHub)
View/report issues

Topics

#bloc #signals #hydrated #persistence

License

MIT (license)

Dependencies

bloc_signals, meta, signals_core

More

Packages that depend on bloc_signals_hydrate