Skip to content

Releases: respawn-app/FlowMVI

3.1.0-beta06

17 Dec 18:26
13ccefa
Compare
Choose a tag to compare

🐞 Bug Fixes

  • add missing overload of no-action store with scope
  • fix crash on android in time travel plugin

❔ Other

  • add separate plugin publishing workflow
  • set up IDE plugin verification on CI

📚 Docs

  • simplify and update readme
  • update issue templates
  • simplify quickstart

3.1.0-beta05

09 Dec 14:43
cde594a
Compare
Choose a tag to compare

IDE plugin update: https://plugins.jetbrains.com/plugin/25766-flowmvi

Huge performance improvements in this version! Benchmarks have been set up to compare & improve library performance. This round of improvements focuses on plugin CPU performance.

Runs were conducted on a Macbook Pro M1 machine where a store was created, then reduced 10 000 intents in various modes , then stopped:

  • Optimized FMVI configuration went from 2568 us -> 683 us / 10k intents = 376% improvement!
  • Atomic FMVI configuration where state transactions are serialized is always slower than the non-atomic one. It went from 16529 to just 1110 us / 10k intents at the cost of (optionally) sacrificing transaction re-entrancy, which was rarely used in real apps. That's a whopping 1490% improvement in performance!
  • A "traditional' MVI set-up without FMVI performs at 418.501 / 10k intents, which means the library overhead is just 40% of having another flow in your container. The entire library's overhead is now just 26.4 nanoseconds per intent reduced, similar to having a single lambda in your reducer code.
  • This release puts FlowMVI on par with the fastest MVI frameworks on the market which do not offer many of this library's features.

🧨 Api Changes

  • updateStateImmediate is now inline. This will require additional imports in your code.
  • the state property of the store is now an inline property. Additional imports will be needed in your code if you are using it.

🚀 New Features

  • Optimized recover machinery when exception handling is not defined
  • If intent handler is not defined, Store now skips the intent pipeline entirely. Attempts to send intents will throw.
  • New Property in the store configuration builder - StateStrategy. It allows to configure whether state transactions will be immediate (best performance), but not thread-safe, Atomic with no reentrancy (2x slower than the Immediate), or Atomic with reentrant locks (15x slower than Immediate). Most apps can migrate to the new approach and check if their stores throw RecursiveStateTransactionException on debug builds. It will help prevent issues, but will not be run on non-debuggable stores to prevent crashes in prod.
  • New property allowTransientSubscriptions that allows fine-grained control of whether subscribers can unsubscribe on their own. Previously stores relied on the debuggable prop which is not flexible enough.
  • New plugin resetStatePlugin which cleans the store's state each time it is stopped. Useful if you want to not preserve store's state when it is restarted, unlike the default behavior.
  • New Periodic SaveBehavior that allows you to save the store's state at given intervals.

Debugger / Plugin updates:

  • Updated live templates with a better generated setup. It now generates Store builder DSL for you. Use fmvid to generate a decorator.

📚 Docs

  • Document new prebuilt plugins
  • Document Decorators on the website
  • New Quickstart guide rewritten from scratch

3.1.0-beta04

28 Nov 14:34
ec94511
Compare
Choose a tag to compare

IDE plugin update: https://plugins.jetbrains.com/plugin/25766-flowmvi

Docs on the website are still upcoming, I didn't have time to write the articles yet due to the amount of new features. Docs will be updated in the next few days. The source code is however documented well enough.

🧨 Api Changes

  • reverse order for time travel installation for plugin test dsl. This can break some tests that were relying on the time travel having an old value of state / intents instead of new. This was a mistake in api design all along that is now fixed.
  • change behavior of store lifecycle functions to not wait for next store lifecycle event to close, instead skipping the operation
  • make various Unrecoverable exceptions separate subclasses, add StoreTimeoutException. This means a different exception will be thrown for different errors in the store. Still, do not try to catch it.

Debugger / Plugin updates:

  • added live templates for the plugin. Install the plugin and use combinations to create:
    • fmvic - anew container
    • fmvip - a new plugin
    • fmvilp - a new lazy plugin
    • fmvim - models (LCE state, intents and actions).
    • fmvis - new composable screen with FMVI.
      I encourage you to use this feature, as it eliminates all the remaining boilerplate associated with the library.
  • improve ui of the error reporting and theming of plugins
  • ui improvements for debug server (selection and buttons)
  • improve intent formatting on debugger
  • update plugin build properties, add description
  • update input field design + add validation error parsing
  • fix debugger state manipulation filling the queue resulting in an infinite loop
  • fix some issues with filter updates for debugger
  • fix stale filters used on timeline of the debugger
  • fix some deadlocks on connect screen of the debugger

🚀 New Features

  • Kotlin 2.1
  • add undelivered intent callback to plugin dsl #106
  • add undelivered action handler to the plugin API
  • add shutdown context with some store API to onStop callback
  • implement an optimized plugin structure with optional chain links to enhance performance
  • implement store decorators and relevant DSLs
  • implement dsl to install decorators in stores
  • implement tests illustrating relationship between decorators and stores
  • add IntentTimeout decorator
  • add ConflateDecorator for intents and actions
  • implement RetryDecorator
  • add undelivered intent / action logging to the loggingPlugin
  • improve performance by reducing context switching in the store #105

📚 Docs

  • document decorator code
  • update stale documentation
  • Document prebuilt decorators
  • add docs for store exceptions

3.1.0-beta02

06 Nov 13:52
5809cfa
Compare
Choose a tag to compare

🧨 Api Changes

  • Reversed the order of onStop invocations. The onStop callback in plugins is now invoked in the opposite order (bottom to top)! This change was made to support using and referencing plugins or values of a store (such as cache) in the onStop callback. Most users shouldn't be affected, but ideally you should check each place where onStop is used manually.
  • Changed the return type of Store.start to a new object - StoreLifecycle which can be used to wait for the store to start, stop, and shut it down. Unfortunately this is a source-incompatible change.

🚀 New Features

  • First release of the Debugger IDE plugin 💫!
  • Added AsyncCache plugin, Deinit plugin, and onStop() callback for stores. The documentation hasn't been added to the website for those yet.
  • enable wasmWasi target for :core module
  • implement new StoreLifecycle API that allows to wait while the store starts and stops
  • set up dynamic color scheme for ide plugin
  • update theme colors for sample app and debugger
  • make android module multiplatform (however much that makes sense). Since androidx ViewModel is KMP now, you can use the android module on more targets. While the module name does not make much sense, it will stay this way for now for compatibility.

🐞 Bug Fixes

  • fix debugger app cache folder name
  • don't start debugger server if it is already running, that can lead to crashes in the IDE plugin

❔ Other

  • update deps - Kotlin 2.0.21, Compose 1.7.
  • update changelog label parser
  • update app deps
  • update gradle and new gradle properties
  • bump target SDK to 35 on Android
  • #98 add link to report issues with debugger to GH

3.1.0-beta01

11 Sep 23:04
22f5766
Compare
Choose a tag to compare

🚀 New Features

  • lower log level of the debugger to Trace
  • print a warning and disable debugger if store is not debuggable
  • add handling of new events to control the store with the debugger
  • implement navigation for the debugger
  • add two pane support to debugger
  • add ability to send commands to the store from the debugger

🐞 Bug Fixes

  • reduce api surface for awaitSubscribersPlugin
  • migrate to produceState for subscribeDsl for better state handling

❔ Other

  • small renames
  • update ktor to rc

3.0.1-beta02

11 Sep 08:55
a55a540
Compare
Choose a tag to compare
3.0.1-beta02 Pre-release
Pre-release

❔ Other

This is a maintenance release for those using CMP 1.7-beta01, kotlin 2.0.20 and ktor 3.0 to support the binary compatibility.

Changes:

3.0.0 🚀

26 May 13:35
001a2a0
Compare
Choose a tag to compare

🧨 Breaking changes

🚨 Behavior change - the number of subscribers that onSubscribe receives has been changed from previous to current. I.e. onSubscribe will now get a number bigger by one. Please manually check each usage of onSubscribe in the project right after you update. 🚨

  • Compile-time error: JobManager is now a generic class, which means expression val jobs = manageJobs() requires a type argument now. To fix, simply provide the return type expicitly:
    val jobs: JobManager<Jobs> = manageJobs()
    
  • Removed deprecated android-compose artifact. You can now just use compose which is multiplatform.
  • Merged android-view and android artifacts - please remove android-view
  • Store will now check if it has been launched before it is subscribed to. This will result in an exception if not. Opt-out of this behavior using allowIdleSubscriptions = true. This check will not be run when debuggable = false
  • Verify each method of store plugin builder is only called once. The plugin builder will now throw if you attempt to invoke a given callback multiple times. For example, onStart { } ; onStart { } will now throw

🚀 New Features

  • Compose and lifecycle support is now multiplatform! With androidx.lifecycle being multiplatform, the library automatically uses system lifecycle to subscribe to the store.
    • However, if you are using a navigation library with a custom lifecycle support, such as Decompose, you can pass the lifecycle as a composition local (using the essenty integration) or manually as a function parameter.
  • Remote Debugging! A new module family debugger-* allows to debug your stores remotely, with a dedicated app provided for Linux, MacOS, Windows.
  • Essenty Integration! Two new modules: essenty and essenty-compose provide integration with Decompose and Essenty libraries, including lifecycle, retained instances and saved state. Essenty setup explained in docs
  • Wasm and JS support for all modules. saveStatePlugin will persist the state to local storage on browser targets by default
  • New flag atomicStateUpdates in store builders allows disabling serialization / atomicity of state transactions if that is not needed, improving performance. true by default
  • Stores now have StoreLogger parameter which
    • can be overridden and decorated
    • is available in the store's code and plugins
    • fully multiplatform and automatic
      You can set or remove the store logger using the configure block. If a value is not set, then if debuggable is true, a platform logger will be used, and if false, no-op logger will.
  • Added a new "queue" property for Undo/Redo to observe changes to the queue
  • Implemented a new multiplatform sample app for Wasm, Android, Desktop and iOS to showcase main features, integration with decompose, DI setup and lifecycle setup.
  • savedStatePlugin now provides logging information
  • serializeState plugin now has a default Json instance provided. Using it is recommended if your json instance is not lenient enough to ignore schema changes.
  • Library performance was optimized to reduce object allocation, lambda creation and function indirection. With k2, lambdas which are extensively used in the library should become more performant. Also optimizations were made to the subscription lifecycle handling to make it faster & more reliable.
  • Implemented a new Lazy Plugin DSL where plugin will now have access to the store configuration that installs it and that will be built at the store creation time, not at the property instantiation time.
    • This Lazy DSL replaces the old lazyPlugin function.
    • Convert an existing plugin into a lazy one to get access to the config by calling LazyPlugin { config -> }
    • Create a lazy plugin using lazyPlugin builder function and use the config property
    • StoreConfiguration is now also available from PipelineContext, so you can invoke logging calls and determine if the store is debuggable

🐞 Bug fixes

  • Fixed file name for serializeState function using store name instead of actual name
  • Fix Savers handling cancellation exceptions
  • Added a missing overload of Time Travel that would create and return the object for the user
  • Store will now not print logs when the state has not changed (stayed the same)
  • Fixed race with concurrent subscriptions to the store where job was relaunched too many times
  • Fixed store builder allowing to install 0 plugins
  • Synchronize disallowRestart plugin operations
  • Ensured subscription events are always sent and processed. This should fix rare bugs where the number of subscribers was quickly conflated to the same value sometimes.
  • Fixed issues where store configuration was accessible and changeable from plugins and from callbacks. This will now not compile instead of silently failing.
  • Disallowed nested plugin callback invocation e.g. onStart { onStart { } }

📚 Docs

  • Project Icon, banner, and star history
  • Documentation on prebuilt plugins
  • Docs on lazy plugins
  • Docs for store configuration parameters
  • Docs on remote debugger setup
  • Expanded FAQ
  • Docs for essenty integration

⭐️ Deprecations

  • Deprecated parentStorePlugin in favor of a simple store.collect suspending function. It's much more flexible and allows to merge the incoming state with other data sources
  • Deprecated platformLoggingPlugin, nativeLoggingPlugin, consoleLoggingPlugin, logcatLoggingPlugin as a default loggingPlugin now uses store logger by default
  • Deprecated parameters of savedStatePlugin which were accepting a file and a directory, because on wasm targets local storage is used. A new overload that takes a path is now used.
  • New configure { } block DSL replaced the old store configuration properties. You can no longer access store configuration in the store builder. This change was made to ensure users do not access store configuration before it's actually created, because while the store is being built, the configuration may change. This will also prevent users from changing the store configuration inside the plugins, which makes no sense as the configuration is not valid anymore.
  • Many default parameters were removed from multiple plugins because those parameters are now obtained from the Store configuration using Lazy Plugin DSL. This includes logger, debugger, save state and some other plugins. Only non-mandatory parameters were removed. You can safely remove them as well.

Changes since 2.5.0-alpha12

Features

  • un-deprecate overloads of subscribe where the lifecycle is not provided explicitly
  • deprecate useState and rename to updateStateImmediate with auto-replace
  • change the return value of onSubscribe to return the new subscriber count
  • Kotlin 2.0, compose 1.6.10
  • allow overriding name and logger for the logging plugin
  • update docs for v3.0

Bug fixes

  • Bring back stateProvider under a deprecation message to reduce migration complexity
  • Bring back removed logging plugin as it was removed too early
  • Bring back removed nameByType temporarily to reduce migration complexity

2.5.0-alpha12

01 May 17:59
ee5ecbe
Compare
Choose a tag to compare
2.5.0-alpha12 Pre-release
Pre-release

Breaking Changes

  • Verify each method of store plugin builder is only called once, reduce lambda allocations. The plugin builder will now throw if you attempt to invoke a given callback multiple times. For example, onStart { } ; onStart { }
  • Disallowed nested invocation of plugin builder callbacks. Previously it was possible to call onStart { onStart { } }. Now such usages will fail at compilation time because the second invocation will never be executed.

New Features

  • Add lazy thread-safety mode to lazy store builder functions
  • Make UnrecoverableException open
  • Warn about possible component context leak when using essenty DSL.
  • Implement StateKeeper integration for essenty. You can now invoke keepState or install(keepStatePlugin()) to persist the state using Essenty StateKeeper
  • Implement subscription DSL for components in the essenty integration. You can now subscribe in the components.
  • Add dsl to create retained stores using container factory

Docs:

  • Update decompose sample feature to follow the new essenty api

Bug Fixes

  • fix await subscribers condition for completing the wait period
  • fix storeBuilder vararg plugin installation order

Other

  • Change sample code theme to Atom One

2.5.0-alpha11

26 Apr 15:29
2.5.0-alpha11
f4843d4
Compare
Choose a tag to compare
2.5.0-alpha11 Pre-release
Pre-release

Breaking Changes

  • New configure { } block DSL replaced the old store configuration properties. You can no longer access store configuration in the store builder. This change was made to ensure users do not access store configuration before it's actually created, because while the store is being built, the configuration may change. Old properties were deprecated. This will also prevent users from changing the store configuration inside the plugins, which makes no sense as the configuration will not change at this point.
  • JobManager plugin will now accept generic parameters. Your code won't compile if you previously did not provide those. Please declare the type explicitly: val jobs: JobManager<String> = manageJobs()
  • #51: Store will now check if it has been launched before it is subscribed to. This will result in an exception if not. Opt-out of this behavior using allowIdleSubscriptions = true. This check will not be run when debuggable = false
  • Many default parameters were removed from multiple plugins because those parameters are now obtained from the Store configuration using Lazy Plugin DSL. This includes logger, debugger, save state and some other plugins. Only non-mandatory parameters were removed. You can safely remove them as well.
  • Removed deprecated: consoleLogging, parentStore, savedState, nativeLogging, androidLogging plugins

New Features

  • Implemented a new Lazy Plugin DSL where plugin will now have access to the store configuration that installs it and that will be built at the store creation time, not at the property instantiation time. This Lazy DSL replaces the old lazyPlugin function.
    • Convert an existing plugin into a lazy one to get access to the config by calling LazyPlugin { config -> }
    • Create a lazy plugin using lazyPlugin and use the config property
  • Ensured subscription events are always sent and processed. This should fix rare bugs where the number of subscribers was quickly conflated to the same value sometimes.
  • Added automatic logging to plugin test dsl
  • Added StoreConfiguration to pipeline context
  • Do not require name for the store in Essenty DSL
  • Added return value to AwaitSubscribers plugin - it will now return the SubscriberManager
  • Implemented two-pane layout for sample app
  • Sample app will now be uploaded for desktop with GH Actions

Bug Fixes

  • Store will now not print logs when the state has not changed (stayed the same)
  • Fixed race with concurrent subscriptions to the store where job was relaunched too many times
  • Fixed store builder allowing to install 0 plugins
  • Use generic iterable for composite plugin
  • Fixed bug report template layout
  • Fixed some outdated documentation
  • Use immediate dispatcher on native store
  • Store Builder plugins are now thread-safe when creating
  • Synchronize disallowRestart plugin operations
  • Add queue size parameter to time travel plugin

Docs

  • Updated docs for v3.0, adding lazy plugin and configure block sections
  • Split documentation into better sections with dedicated pages for android, compose
  • Added lazy plugin explanation to docs
  • Added documentation on prebuilt plugins, explaining how, when and for what to use them

Other

  • Inline reentrant lock calls
  • Add some more inlines to state update functions
  • Provide coroutine scope to plugin test dsl
  • Fixed flaky tests, add tests for while subscribed plugin
  • Internal cleanup of store code
  • Added toString to plugin test scope
  • Made store configuration a public class
  • Compose Multiplatform 1.6.10-beta02

2.5.0-alpha08

17 Apr 23:45
6978dbf
Compare
Choose a tag to compare
2.5.0-alpha08 Pre-release
Pre-release
  • Fixed saved state module for wasm and js targets not being able to persist the state. Browser targets do not support saving state to files, so the plugin will save the state to local storage instead.
  • Added LoggingSaver that logs save and restore operations to a StoreLogger
  • Added logging to default saved state plugin
  • Replaced old dsl for serializeState with one that takes a path directly to support non-file saving. Previous dsl is available on non-browser targets, but deprecated in favor of the simpler approach above
  • Added a default Json instance as an argument to the serializeState plugin so that clients can omit providing their own Json. The default instance is lenient to reduce number of failed restorations when the schema changes.
  • Cleanup of automatic naming logic for some plugins to avoid issues when code is obfuscated.
  • Default file name for state is now the serial name of the class being saved for serializeState
  • Added ability to select code in the sample app
  • Fixed sample app layout issues
  • Deployed wasm sample app to the website