Skip to content

About

A Blazor State management library by TimeWarp.

Topics

Resources

Stars

611 stars

Watchers

14 watching

Forks

Latest commit

 

History

4,307 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Stars workflow Forks License Issues Open OpenSSF Scorecard

nuget nuget

Twitter Dotnet

Discord Twitter Twitter

logo

TimeWarp.State

TimeWarp.State (previously known as Blazor-State) is a fully asynchronous state management library. The core package has no Blazor dependency, so console and other non-UI hosts can dispatch actions through the same store. Blazor components, JavaScript interop, and render subscriptions are in TimeWarp.State.Blazor. It handles both Reducers and Effects consistently using async Handlers.

By utilizing the TimeWarp.Mediator pipeline, TimeWarp.State enables a flexible, middleware-driven architecture for managing state, similar to the request-processing pipeline in ASP.NET. This approach allows developers to inject custom behaviors, such as logging, validation, and caching, directly into the state management flow.

Hosts consume TimeWarp.Mediator 15.0.0-beta.5 (TimeWarp.Mediator and, on the host, TimeWarp.Mediator.Generators) via generated AddGeneratedMediator<ClientPipeline>() / named pipelines — not MediatR and not reflection AddMediator(). Import TimeWarp.Mediator.Generated (or TimeWarpMediatorNamespace); the extension is internal there, and implicit usings do not include it.

In addition to the core library, we offer TimeWarp.State.Blazor (components, JavaScript interop, render subscriptions), TimeWarp.State.Plus (routing, persistence, action tracking; depends on TimeWarp.State.Blazor; package id unchanged), and TimeWarp.State.Telemetry (OpenTelemetry action spans for the Aspire dashboard or any OTel backend). TimeWarp DevTools is a dev-only Blazor inspector (AddTimeWarpStateDevTools()) on top of those spans. It is the action log, state tree, and diff. It is not a production dependency. The console sample dispatches an action without Blazor. The persistence sample shows session storage and local storage with [PersistentState]. The render control sample shows ShouldRender, parameter checks, and RegisterRenderTrigger. The telemetry sample wires the DevTools app into Aspire, including the WebAssembly counter.

Give a Star! ⭐

If you find this project useful, please give it a star. Thanks!

Getting Started

I recommend the state and action handler sample for a step-by-step guide to building a Blazor app with TimeWarp.State. The published docs are at timewarpengineering.github.io/timewarp-state.

See full documentation.

logo

Installation

Requirements: consuming projects target net11.0 and build with a .NET 11 SDK. The analyzers and source generators in the package compile against Roslyn 5.9 (Microsoft.CodeAnalysis.CSharp 5.9.0), so the compiler must be Roslyn 5.9 or later: .NET 11 SDK preview.6 or later (every RC qualifies). On the .NET 10 line that is SDK 10.0.400 or later. See 12.0.0-beta.18.

dotnet add package TimeWarp.State
dotnet add package TimeWarp.State.Blazor
dotnet add package TimeWarp.State.Plus
dotnet add package TimeWarp.State.Telemetry

Blazor hosts call AddTimeWarpState and AddTimeWarpStateBlazor. Console hosts call AddTimeWarpState only. See Migrate to 12.0.0-beta.10.

Check out the latest NuGet packages on the TimeWarp Enterprises NuGet page.

Writing an action

An action lives in a nested *ActionSet inside the state it changes. The recommended shape marks the Action with [Reducer] and declares one static Reduce method. The source generator writes the handler:

public sealed partial class CounterState : State<CounterState>
{
  public int Count { get; private set; }

  public override void Initialize() => Count = 0;

  public static partial class IncrementCountActionSet
  {
    [Reducer]
    public sealed class Action(int amount) : IAction
    {
      public int Amount { get; } = amount;
    }

    private static void Reduce(CounterState state, Action action) => state.Count += action.Amount;
  }
}

await CounterState.IncrementCount(amount: 5); // generated dispatch method

Write the Handler : StateActionHandler<Action> yourself instead when the action does async work, needs injected services, or does more than change the state synchronously. That long shape keeps working, and one state can mix both. See Actions.

JavaScript dispatch

JavaScript can dispatch actions with timeWarpState.DispatchRequest(name, request). It is opt-in: allow each action explicitly, everything else is rejected.

builder.Services.AddJavaScriptDispatch(b => b.Allow<CounterState.IncrementCountActionSet.Action>());

See Enable JavaScript interop.

Action catalog

Mark user-facing actions with [CatalogAction] to enumerate and execute them at runtime, for example from a Ctrl-K command palette or as agent tools:

public static class AddPasskeyActionSet
{
  [CatalogAction(Description = "Add a passkey to the signed-in account.", Permissions = ["credentials.write"])]
  public sealed class Action : IAction
  {
    public Action(string label) { Label = label; }
    public string Label { get; }
  }
}
builder.Services.AddActionCatalog(typeof(AssemblyMarker).Assembly);

ActionCatalogEntry entry = actionCatalog.Find("Credentials.AddPasskey")!;
await entry.Execute(store, ["Laptop"]);

The source generator emits a per-assembly registry with name, description, permissions, visibility, parameters and input schema, plus a reflection-free Execute. It is opt-in: unmarked actions are never cataloged. Permissions are opaque ids that the consumer enforces; [TrackAction] (busy indicator) is unrelated. See Action catalog.

Releases

View the Release Notes for detailed information on each release.

Unlicense

License
This project is licensed under the Unlicense.

Contributing

Your contributions are welcome! Before starting any work, please open a discussion.

Help with the documentation is also greatly appreciated.

Contact

If you have an issue and don't receive a timely response, feel free to reach out on our Discord server.

Discord

About

A Blazor State management library by TimeWarp.

Topics

Resources

Stars

611 stars

Watchers

14 watching

Forks

Releases

Packages

Used by

Contributors

Languages