blackbox 0.7.1
blackbox: ^0.7.1 copied to clipboard
Deterministic reactive computation core with explicit dependency graphs, boxes, and flows. Designed for testable business logic and state pipelines.
0.7.1 #
- Added:
DependencyResolver.whenReadyOrNull<T>(source)— returns the source value when ready, ornullotherwise, without skipping the pump cycle. Use when a dependent box accepts an optional input and should compute regardless of whether the upstream has produced data yet. ComplementswhenReady<T>.
0.7.0 #
- Breaking:
- Renamed the async cache mixin
ManagedCache→AsyncManagedCache. Updatewith AsyncPersisted<...>, ManagedCache<...>towith AsyncPersisted<...>, AsyncManagedCache<...>. AsyncManagedCacheis now relaxed toon _AsyncBoxBaseand works standalone (in-memory TTL) withoutAsyncPersisted.
- Renamed the async cache mixin
- Added:
- New sync
ManagedCache<I, O>mixin onBox<I, O>— sync always-available value backed by an asyncfetch(input). Provides TTL, background refresh on access,refresh(),invalidateCache(), fail-open error handling, and automatic re-fetch on input change. Compose withPersistedto persist the cached value. - Sync
ManagedCachecomposed withPersistedprefers the disk-cached value overinitialValueon boot —initialValuebecomes the empty- disk fallback rather than a default that overwrites cached state.
- New sync
0.6.0 #
- Breaking:
- Removed
listenSync()andlistenAsync()— uselisten()instead. - Renamed
SyncOutput→SyncData. - Renamed
prepare()→onFirstCompute(). - Renamed
shouldEmitLoadingBeforeCompute()→shouldEmitLoading(). - Removed
Runtimeclasses — state management inlined into box base classes. - Sync
action()now returnsvoidinstead ofFuture<void>. AsyncBox.lateinit()replaced byLateAsyncBoxclass.
- Removed
- Added:
listen()accepts{bool skipFirst}to skip the immediate callback with current state.beforeCompute()hook on sync boxes (symmetric with async).Persistedmixin now supports dynamic rekey when input changes (symmetric withAsyncPersisted).
- Changed:
LateAsyncBoxextracted into its own file.- Async box base simplified: removed
_initialized,_pendingListeners,_requireInput.
0.5.1 #
- Fixed:
ManagedCacheno longer starts duplicate stale-cache refreshes while the first refresh is still in flight.refresh()now completes after the underlying async recompute finishes, not just after it is scheduled.
0.5.0 #
- Breaking:
- Removed
persistKeyparameter from all box constructors (Box,NoInputBox,AsyncBox,NoInputAsyncBox). - Removed
CachedAsyncSupportmixin — replaced byManagedCache. - Removed
persistenceKey,persistedAt, andclearPersistedValue()from_AsyncBoxBase— use mixin members instead.
- Removed
- Added:
Persisted<I, O>mixin for sync boxes — addwith Persisted<I, O>and implementpersistKeyFor(I input).AsyncPersisted<I, O>mixin for async boxes — save/restore only.ManagedCache<I, O>mixin (onAsyncPersisted) — TTL, stale-while-refresh,refresh(),invalidateCache().- Lifecycle hooks on box base classes:
resolveInitialValue(),onInitialized(),beforeCompute().
- Changed:
- Persistence is fully extracted from box base classes into opt-in mixins.
- Cache management is a separate layer:
AsyncPersistedfor save/restore, addManagedCachefor TTL and refresh controls. - Persist key is resolved once at init and never changes — to switch keys, destroy the box and create a new one.
0.4.4 #
- Add
CachedAsyncSupportfor persisted async cache with TTL-based lazy refresh. - Let async boxes control loading emission via
shouldEmitLoadingBeforeCompute(...). - Persist timestamps alongside cached values while keeping legacy raw cache reads compatible.
0.4.3 #
- Add
OutputSource.valueOrNullandOutputSource.requireValuefor ergonomic ready-value access. - Improve not-ready
StateErrormessages to include the current output state.
0.4.2 #
- Add
GraphBuilder.addEffect(...)for explicit fire-and-forget graph effects withcurrentandpreviousinputs.
0.4.1 #
- Add
awaitNextValueAfterAction(...)as a@visibleForTestinghelper for box and graph assertions. - Refresh persistence and setup documentation across the package README.
0.4.0 #
- Breaking:
- Removed
Box.lateinit()constructor — sync boxes always require input at construction. UseAsyncBox.lateinit()for deferred initialization. _SyncBoxBase._runtimeis nowlate final(non-nullable)
- Removed
0.3.2 #
- Fixed:
AsyncBox.lateinit()now returnsAsyncLoadingfromoutputandlistenbefore initialization (instead of throwingStateError)- Pending listeners are automatically flushed to the runtime when the box receives its first input
0.3.1 #
- Fixed:
Graph.start()no longer crashes onlateinitboxes — defers subscription until runtime is created by first pump cycle
0.3.0 #
- Breaking:
when()loading callback signature:() → R→(T? previousData) → Rwhen()error callback signature:(Object, StackTrace?) → R→(Object, StackTrace?, T? previousData) → R
- Added:
AsyncLoading.previousData— carries last known value during refreshAsyncError.previousData— carries last known value on error after refresh
0.2.0 #
- Breaking:
- Removed
LazyBox— usepersistKeyparameter on Box/AsyncBox constructors - Removed
computeValue()—NoInputBoxandNoInputAsyncBoxnow usecompute()directly - Renamed
dependencies:parameter toinput:in Graph.add() - Renamed
d.ready()tod.whenReady()in DependencyResolver - Removed
d.output()from DependencyResolver (usebox.outputdirectly) - Removed public
inputgetter from Box/AsyncBox
- Removed
- Added:
prepare(I input, O? previous)lifecycle hook — called once before first computedispose()lifecycle hook — called by Graph.dispose() for resource cleanuppersistKeyparameter on Box/AsyncBox constructors for built-in persistenceBlackboxPersistence.registerCodec<T>()for global codec registry- Graph signal tracing:
build(trace: true)for console output,onTrace:for custom handler PumpTrace/BoxTracedata classes for programmatic trace access
- Changed:
- Box hierarchy refactored: shared
_SyncBoxBase/_AsyncBoxBaseinternal base classes NoInputBox<O>andNoInputAsyncBox<O>are now independent fromBox<I,O>/AsyncBox<I,O>(both extend shared base)- All box types use
compute()as the override method name
- Box hierarchy refactored: shared
0.1.0 #
- Breaking:
Connector->GraphConnectorBuilder->GraphBuilderconnect(...)->add(...)connectWith(...)->addWith(...)PipelineBuilder.addWithDependencies(...)->addWith(...)FlowBoxBuilder()is now created viaFlowBox.builder()
- Changed:
- Updated docs, tests, and examples to the new graph/flow builder API
0.0.7 #
- Renamed:
- StateObserver -> FlowBox
- Breaking:
FlowBox<S>now requiresS extends FlowState
- Added:
FlowBoxBuilder.onLoading(...)andonError(...)for reacting toAsyncLoadingandAsyncError
- Changed:
- FlowBox is now a sync box without input (
Box<O>) onLoading(...)andonError(...)are compile-time restricted to async sources only
- FlowBox is now a sync box without input (
0.0.4 #
- Renamed:
- Graph -> Connector
- Flow -> StateObserver
0.0.3 #
- Added GraphBuilder
- Added Pipeline of Boxes
0.0.2 #
- Updated docs
0.0.1 #
- Initial release