Enterprise State Inspector
Enterprise-grade runtime insight for your Flutter state management layers. This package captures Riverpod and Bloc state transitions, stores them in an inspectable timeline, and ships with a Material overlay so teams can debug complex flows without leaving the app.
Quick start
-
Install & wire observers
final inspector = StateInspectorController.instance; Bloc.observer = StateInspectorBlocObserver(controller: inspector); runApp( ProviderScope( observers: [StateInspectorRiverpodObserver(controller: inspector)], child: MyBootstrap(inspector: inspector), ), ); -
Wrap your
MaterialApp/GetMaterialApp– use thebuilderparameter so the overlay inherits your app’sNavigator,Overlay, andDirectionality:class MyBootstrap extends StatelessWidget { const MyBootstrap({super.key, required this.inspector}); final StateInspectorController inspector; @override Widget build(BuildContext context) { return MaterialApp( builder: (context, child) => StateInspectorOverlay( controller: inspector, child: child ?? const SizedBox.shrink(), ), home: const HomePage(), ); } } -
Toggle the floating action button to reveal the timeline; search, pin, pause, or export events directly from the overlay.
Features
- First-class observers for Riverpod, Bloc/Cubit, and GetX so popular state managers stream straight into the timeline with diffs, metadata, and error capture.
- Unified adapter primitives (
StateInspectorAdapters) forValueListenable,Listenable, and stream-driven architectures—plug in MobX, Redux, ChangeNotifier, or your homegrown layer without new package dependencies. - A draggable overlay with pause/resume, pinning, diff visualisation, and rich search controls (regex, case-sensitive, multi-tag, severity, and time-range filters).
- Built-in analytics that surface top talkative origins, longest gaps between events, and per-kind counts so large timelines stay actionable.
- Inline annotation composer to tag, prioritise, and comment on events; attach screenshots/logs, merge metrics, and keep everything alongside the captured state.
- Multiple export formats: JSON (raw/session), Markdown summaries, and CLI-friendly tables ready to paste into tickets or chat threads.
- Live streaming hooks (
StateInspectorSyncDelegate/StreamSyncDelegate) for mirroring timelines to desktop/web companions over WebSocket or HTTP bridges. - Adapter registry + helpers (
observeStream,observeNotifier) so third-party state managers can auto-register adapters without core changes. - Analytics stream (
controller.analyticsStream) and broadcast event bus for powering custom dashboards or multi-client companions. - Comes with a fully wired example demo plus production-ready overlay theming that respects your app’s navigator, overlay, and directionality.
Screenshots & demo
Floating inspector pinned to the right, streaming Riverpod & Bloc updates while the app stays interactive.
Detail panel highlighting structured diffs, previous/current JSON snapshots, and metadata for a selected event.
Timeline search, event-kind filters, and a GetX counter emitting into the same session.
Animated tour showing pausing capture, pinning events, exporting sessions, and navigating diffs.
Detail panel showing how attachments appear alongside a captured event, including description and capture timestamp.
Pinned event carrying two related screenshots so investigators can jump straight to the visual evidence.
Demo controls that add placeholder screenshots during a session, illustrating how to bind your own capture workflow.
Example highlights
- Riverpod, Bloc, and GetX counters emit rich diffs and metadata into the same timeline.
- ValueListenable + ChangeNotifier adapters capture a slider, form field, and checkout cart without bespoke observers.
- Buttons in the demo add annotations, merge synthetic metrics, attach placeholder screenshots, and stream events to a console sink via
StreamSyncDelegate.
CLI companion
- Start the companion listener(重要:若只執行
dart run tool/timeline_companion.dart會僅綁定在 127.0.0.1,實體裝置或同區網的機器將無法連線):# 只給本機端 dart run tool/timeline_companion.dart 8787 # 或綁定所有介面,讓同區網裝置可連線 dart run tool/timeline_companion.dart 8787 0.0.0.0 - Run the example app, scroll to Inspector extras, adjust the WebSocket URL if needed (for emulators use your host IP), and tap Connect companion.
- 伴侶會列出本機 loopback 以及偵測到的區網 IPv4;若使用實體裝置,改用該 IPv4 即可連線。
- Timeline 事件與統計會即時輸出在終端,方便驗證遠端 DevTools 是否正常接收。
Getting started
-
Install the package
dependencies: enterprise_state_inspector: ^0.1.3 -
Wire the observers into your application bootstrap:
final inspector = StateInspectorController.instance; Bloc.observer = StateInspectorBlocObserver(controller: inspector); runApp( ProviderScope( observers: [StateInspectorRiverpodObserver(controller: inspector)], child: StateInspectorOverlay( controller: inspector, child: MyApp(), ), ), ); -
Embed the overlay via your app’s builder so the inspector sits alongside your existing
Navigator/Overlaystack.
Usage
- Riverpod integration: add
StateInspectorRiverpodObserverto theProviderScope.observerslist. Each provider emit/refresh shows up in the timeline with previous and next values. - Bloc integration: assign
Bloc.observerto an instance ofStateInspectorBlocObserver. CubitonChangeand BloconTransitioncallbacks automatically forward events to the inspector. - GetX integration: call
StateInspectorGetAdapter.observeRx(or the list/ map helpers) on theRxvalues you care about—dispose the returnedWorkerinonClose. Initial values and subsequent updates land in the same timeline with diffs. - Adapters for other managers: use
StateInspectorAdapters.observeValueListenableforValueNotifier/TextEditingController,observeListenableforChangeNotifier/MobX stores, or wrap Redux stores by piping their change stream intocontroller.capture. - Adapter registry: 呼叫
StateInspectorAdapterRegistry.register/install讓第三方 state manager 的 adapter 可以動態掛載;同時提供observeStream、observeNotifier等 helper 簡化實作。 - Overlay controls: tap the floating analytics FAB (or call
inspector.togglePanel()) to open/close the panel. Drive filters with event-kind chips, regex/case-sensitive search, tag selections, severity toggles, and time-range presets. Pause/resume capture, pin key events, and reset quickly. - Annotations & attachments: add inline notes with severity/tags, attach
screenshots or log files, and delete them once resolved. Tags automatically
feed the global filter sidebar. Screenshot attachments (
Add placeholder screenshotaction in the example) show up with descriptions and timestamps so the team knows exactly which visual evidence belongs to each state change. - Diff viewer: structured states (maps, lists, JSON-like objects) are normalised and diffed automatically. Inspect path-by-path changes in the detail panel without leaving the running app.
- Export & automation: generate JSON, Markdown summaries, or CLI tables with
exportAsJson,exportAsMarkdown, orexportAsCliTable. UseexportSessionJson()/importSessionJson()for full history restores. - Live sync: register a
StateInspectorSyncDelegate(例如StreamSyncDelegate或新的WebSocketSyncDelegate) 將事件推送到桌面/瀏覽器工具;StateTimelineEventBus可作為統一的事件匯流排,廣播給多個 listener 或自訂儀表板。
Minimal Riverpod + Bloc sample (see /example for the full demo):
final counterProvider =
StateNotifierProvider<CounterNotifier, int>((ref) => CounterNotifier());
class CounterNotifier extends StateNotifier<int> {
CounterNotifier() : super(0);
void increment() => state++;
}
class CounterBloc extends Bloc<CounterEvent, int> {
CounterBloc() : super(0) {
on<CounterEvent>((event, emit) => emit(state + 1));
}
}
class AppBootstrap extends StatelessWidget {
AppBootstrap({super.key}) : controller = StateInspectorController.instance;
final StateInspectorController controller;
@override
Widget build(BuildContext context) {
Bloc.observer = StateInspectorBlocObserver(controller: controller);
return ProviderScope(
observers: [StateInspectorRiverpodObserver(controller: controller)],
child: StateInspectorOverlay(
controller: controller,
child: const MyApp(),
),
);
}
}
Advanced APIs
- Access individual timeline entries (
StateChangeRecord) viacontroller.recordsto build custom tooling. Records now carry tags, metrics, annotations, attachments, and structured diffs for richer analytics. - Query aggregate insights through
controller.analytics(StateTimelineAnalytics) to surface hot origins, average/longest gaps, and per-kind counts. - Subscribe to
controller.analyticsStream或使用StateTimelineEventBus取得即時事件 與統計,方便串接自訂 DevTools/儀表板。 - Manage metadata at runtime with
addAnnotation,removeAnnotation,addTags,mergeMetrics,addAttachment, andremoveAttachmentto keep the timeline curated. - Subscribe to the live
controller.recordStreamor register aStateInspectorSyncDelegateto mirror events to remote tooling. - Export and rehydrate sessions with
exportSessionJson/importSessionJson, or generate Markdown/CLI reports withexportAsMarkdownandexportAsCliTablefor status updates. - Author your own adapters—either with
StateInspectorAdaptershelpers or by normalising state and callingcontroller.capture(...)directly when you need custom diff strategies.
class MyGetxController extends GetxController {
final RxInt count = 0.obs;
late final Worker _countWorker;
@override
void onInit() {
super.onInit();
_countWorker = StateInspectorGetAdapter.observeRx<int>(
count,
origin: 'myController.count',
);
}
@override
void onClose() {
_countWorker.dispose();
super.onClose();
}
}
// ValueListenable / ChangeNotifier / MobX style
final textController = TextEditingController();
final disposer = StateInspectorAdapters.observeValueListenable(
textController,
origin: 'loginForm.email',
);
// Later, dispose the observer (e.g. in State.dispose)
disposer.dispose();
// ChangeNotifier / MobX / Redux stores
final handle = StateInspectorAdapters.observeListenable(
store,
origin: 'cartStore',
stateResolver: () => store.snapshot(),
);
Example demo
Floating inspector pinned to the right, streaming Riverpod & Bloc updates while the app stays interactive.
Detail panel highlighting structured diffs, previous/current JSON snapshots, and metadata for a selected event.
Timeline search, event-kind filters, and a GetX counter emitting into the same session.
Animation: opening the overlay, pausing capture, pinning events, exporting sessions, and navigating diffs.
Support & feedback
Issues and feature requests are welcome on the GitHub tracker. Pull requests for additional adapters (e.g. MobX, GetX) are encouraged.