├── .aiderignore ├── kanban ├── backlog │ ├── _._ │ └── scratch │ │ ├── overview.md │ │ ├── rejected.md │ │ ├── todo.md │ │ └── done.md ├── done │ └── _._ └── to-do │ └── -.- ├── .github ├── pull_request_template.md └── dependabot.yml ├── documentation ├── contributing │ └── overview.md ├── index.md ├── dev-ops │ └── toc.yml ├── features │ ├── toc.yml │ └── features.md ├── topics │ ├── routing.md │ ├── toc.yml │ └── enable-javascript-interop.md ├── model │ └── main.png ├── images │ ├── redux-dev-tools.png │ └── redux-route-state.png ├── .gitignore ├── tutorial │ └── default-template-screen-shot.png ├── partials │ ├── give-a-star.md │ ├── releases.md │ ├── license.md │ ├── contact.md │ ├── contributing.md │ ├── getting-started.md │ ├── acknowledgements.md │ └── installation.md ├── toc.yml ├── migrations │ ├── migration6-7.md │ ├── migration7-8.md │ ├── migration8-9.md │ ├── migration9-10.md │ ├── migration4-5.md │ ├── toc.yml │ └── migration1-2.md ├── release-notes │ ├── release7.0.0.md │ ├── release10.0.0.md │ ├── toc.yml │ ├── release3.0.0.md │ ├── release9.0.0.md │ ├── release1.0.0.md │ ├── release2.0.0.md │ └── release6.0.0.md └── blips │ ├── 2024-02-time-warp-state-11-release.md │ ├── 2024-02-routing-sample.md │ ├── 2024-02-action-tracking-sample.md │ ├── 2024-02-redux-dev-tools-sample.md │ └── 2024-02-state-action-handler-sample.md ├── source ├── timewarp-state │ ├── wwwroot │ │ ├── types │ │ │ ├── redux-dev-tools-types.d.ts │ │ │ ├── constants.d.ts │ │ │ ├── timewarp-state.d.ts │ │ │ ├── logger.d.ts │ │ │ ├── timewarp.state.lib.module.d.ts │ │ │ └── redux-dev-tools.d.ts │ │ ├── js │ │ │ ├── redux-dev-tools-types.js │ │ │ ├── redux-dev-tools-types.js.map │ │ │ ├── constants.js.map │ │ │ ├── constants.js │ │ │ ├── timewarp-state.js.map │ │ │ ├── logger.js.map │ │ │ ├── timewarp-state.js │ │ │ └── logger.js │ │ └── typescript │ │ │ ├── dot-net-reference.d.ts │ │ │ └── constants.ts │ ├── base │ │ ├── action.cs │ │ └── action-handler.cs │ ├── features │ │ ├── persistence │ │ │ ├── persistent-state-method.cs │ │ │ ├── abstractions │ │ │ │ └── i-persistence-service.cs │ │ │ └── attributes │ │ │ │ └── persistent-state-attribute.cs │ │ ├── redux-dev-tools │ │ │ ├── requests │ │ │ │ ├── i-redux-request.cs │ │ │ │ ├── start │ │ │ │ │ ├── start-request.cs │ │ │ │ │ └── start-handler.cs │ │ │ │ └── commit │ │ │ │ │ └── commit-request.cs │ │ │ ├── redux-action.cs │ │ │ └── dispatch-request.cs │ │ ├── render-subscriptions │ │ │ ├── non-nested-class-exception.cs │ │ │ └── render-subscription-context.md │ │ ├── pipeline │ │ │ ├── invalid-clone-exception.cs │ │ │ └── exception-notification.cs │ │ └── components │ │ │ ├── ReduxDevTools.razor │ │ │ └── components │ │ │ └── TimeWarpJavaScriptInterop.razor │ ├── store │ │ ├── state-initialized-notification.cs │ │ └── i-store.cs │ ├── global-suppressions.cs │ ├── assembly-marker.cs │ ├── components │ │ └── timewarp-state-component.render-reasons.cs │ ├── extensions │ │ ├── method-info-extensions.cs │ │ └── type-extensions.cs │ └── state │ │ └── i-state.cs ├── timewarp-state-plus │ ├── _imports.razor │ ├── features │ │ ├── timers │ │ │ ├── timer-config.cs │ │ │ ├── multi-timer-options.cs │ │ │ ├── timer-elapsed-notification.cs │ │ │ ├── multi-timer-post-processor.cs │ │ │ └── timer-state │ │ │ │ └── timer-state.reset-timers-on-activity.cs │ │ ├── action-tracking │ │ │ ├── pipeline │ │ │ │ └── track-action-attribute.cs │ │ │ └── action-tracking-state │ │ │ │ ├── action-tracking-state.debug.cs │ │ │ │ └── action-tracking-state.start-processing.cs │ │ ├── feature-flags │ │ │ └── feature-flag-state │ │ │ │ └── feature-flag-state.cs │ │ └── theme │ │ │ └── theme-state │ │ │ ├── theme-state.cs │ │ │ └── theme-state.update.cs │ ├── state │ │ └── i-timewarp-cacheable-state.cs │ ├── assembly-marker.cs │ └── global-usings.cs ├── timewarp-state-analyzer │ ├── AnalyzerReleases.Shipped.md │ ├── global-usings.cs │ ├── timewarp-state-analyzer.csproj │ └── AnalyzerReleases.Unshipped.md ├── timewarp-state-source-generator │ ├── global-usings.cs │ └── timewarp-state-source-generator.csproj └── timewarp-state-policies │ ├── global-usings.cs │ ├── have-json-constructor.cs │ ├── have-injectable-constructor.cs │ └── be-nested-in-state-custom-rule.cs ├── tests ├── test-app │ ├── test-app-server │ │ ├── global-usings.cs │ │ ├── wwwroot │ │ │ └── favicon.png │ │ ├── appsettings.Development.json │ │ ├── appsettings.json │ │ ├── components │ │ │ ├── Routes.razor │ │ │ ├── App.razor │ │ │ ├── layout │ │ │ │ └── MainLayout.razor │ │ │ └── _imports.razor │ │ ├── test-app-server.csproj │ │ └── Properties │ │ │ └── launchSettings.json │ ├── test-app-contracts │ │ ├── global-usings.cs │ │ ├── features │ │ │ ├── exception-handling │ │ │ │ └── throw-server-side-exception │ │ │ │ │ ├── throw-server-side-exception-response.cs │ │ │ │ │ └── throw-server-side-exception-request.cs │ │ │ └── weather-forecast │ │ │ │ └── queries │ │ │ │ └── get-weather-forecasts.cs │ │ └── test-app-contracts.csproj │ └── test-app-client │ │ ├── features │ │ ├── color │ │ │ ├── actions │ │ │ │ └── color-state.update.cs │ │ │ ├── color-state.cs │ │ │ └── color-state.debug.cs │ │ ├── event-stream │ │ │ ├── event-stream-state.debug.cs │ │ │ ├── event-stream-state.cs │ │ │ ├── components │ │ │ │ └── EventStream.razor │ │ │ └── actions │ │ │ │ └── add-event │ │ │ │ └── event-stream-state.add-event-action.cs │ │ ├── counter │ │ │ ├── components │ │ │ │ ├── counter.razor.cs │ │ │ │ └── Counter.razor │ │ │ ├── actions │ │ │ │ ├── non-nested-action │ │ │ │ │ ├── non-nested-action.cs │ │ │ │ │ └── non-nested-handler.cs │ │ │ │ ├── improper-nested-action │ │ │ │ │ ├── improper-nested-action.cs │ │ │ │ │ └── improper-nested-handler.cs │ │ │ │ ├── counter-state.increment-counter.cs │ │ │ │ └── counter-state.throw-exception.cs │ │ │ ├── counter-state.cs │ │ │ ├── notification │ │ │ │ ├── pre-increment-count-notification-handler.cs │ │ │ │ └── increment-count-notification-handler.cs │ │ │ └── counter-state.debug.cs │ │ ├── base │ │ │ ├── components │ │ │ │ └── ResetButton.razor │ │ │ └── base-action-handler.cs │ │ ├── application │ │ │ ├── application-state │ │ │ │ ├── application-state.cs │ │ │ │ ├── application-state.reset-store.cs │ │ │ │ └── application-state.debug.cs │ │ │ └── notification │ │ │ │ └── application-state.exception-notification-handler.cs │ │ ├── blue │ │ │ ├── blue-state.cs │ │ │ └── actions │ │ │ │ └── blue-state.increment-count.cs │ │ ├── purple │ │ │ ├── purple-state.cs │ │ │ ├── components │ │ │ │ └── PurpleCounter.razor │ │ │ └── actions │ │ │ │ └── purple-state.increment-count.cs │ │ ├── weather-forecast │ │ │ └── weather-forecast-state.cs │ │ ├── clone-test │ │ │ ├── cloneable-state.cs │ │ │ ├── clone-test-state.debug.cs │ │ │ └── actions │ │ │ │ └── cloneable-state.clone-test.cs │ │ └── cacheable-weather │ │ │ └── cacheable-weather-state.cs │ │ ├── wwwroot │ │ ├── appsettings.Development.json │ │ └── appsettings.json │ │ ├── generated │ │ ├── timewarp-source-generators │ │ │ └── TimeWarp.SourceGenerators.HelloWorldGenerator │ │ │ │ └── HelloWorld.g.cs │ │ ├── TimeWarp.State.SourceGenerator │ │ │ └── TimeWarp.State.SourceGenerator.ActionSetMethodSourceGenerator │ │ │ │ ├── Test.App.Client.Features.Blue.BlueState.IncrementCountActionSet_Method.g.cs │ │ │ │ ├── Test.App.Client.Features.CloneTest.CloneableState.CloneTestActionSet_Method.g.cs │ │ │ │ ├── Test.App.Client.Features.Purple.PurpleState.IncrementCountActionSet_Method.g.cs │ │ │ │ ├── Test.App.Client.Features.Application.ApplicationState.ResetStoreActionSet_Method.g.cs │ │ │ │ ├── Test.App.Client.Features.Counter.CounterState.IncrementCountActionSet_Method.g.cs │ │ │ │ ├── Test.App.Client.Features.Application.ApplicationState.TwoSecondTaskActionSet_Method.g.cs │ │ │ │ ├── Test.App.Client.Features.Counter.CounterState.ThrowExceptionActionSet_Method.g.cs │ │ │ │ └── Test.App.Client.Features.EventStream.EventStreamState.AddEventActionSet_Method.g.cs │ │ └── timewarp-state-source-generator │ │ │ └── TimeWarp.State.SourceGenerator.ActionSetMethodSourceGenerator │ │ │ ├── Test.App.Client.Features.Blue.BlueState.IncrementCountActionSet_Method.g.cs │ │ │ ├── Test.App.Client.Features.CloneTest.CloneableState.CloneTestActionSet_Method.g.cs │ │ │ ├── Test.App.Client.Features.Purple.PurpleState.IncrementCountActionSet_Method.g.cs │ │ │ ├── Test.App.Client.Features.Counter.CounterState.IncrementCountActionSet_Method.g.cs │ │ │ ├── Test.App.Client.Features.Application.ApplicationState.ResetStoreActionSet_Method.g.cs │ │ │ ├── Test.App.Client.Features.Application.ApplicationState.TwoSecondTaskActionSet_Method.g.cs │ │ │ ├── Test.App.Client.Features.Counter.CounterState.ThrowExceptionActionSet_Method.g.cs │ │ │ └── Test.App.Client.Features.EventStream.EventStreamState.AddEventActionSet_Method.g.cs │ │ ├── test-objects │ │ ├── test-enum.cs │ │ ├── i-test-interface.cs │ │ ├── custom-collection-object.cs │ │ ├── multi-dimensional2d-array-object.cs │ │ └── multi-dimensional3d-array-object.cs │ │ ├── pipeline │ │ ├── notification-pre-processor │ │ │ ├── pre-pipeline-notification.cs │ │ │ └── pre-pipeline-notification-request-pre-processor.cs │ │ └── notification-post-processor │ │ │ ├── post-pipeline-notification.cs │ │ │ └── post-pipeline-notification-request-post-processor.cs │ │ ├── assembly-marker.cs │ │ ├── _imports.razor │ │ └── components │ │ └── CustomInput.razor ├── timewarp-state-tests │ ├── testing-convention.cs │ ├── global-usings.cs │ ├── timewarp-state-tests.csproj │ └── convention-tests.cs ├── timewarp-state-plus-tests │ ├── testing-convention.cs │ ├── global-usings.cs │ ├── convention-tests.cs │ ├── timewarp-state-plus-tests.csproj │ └── architecture-tests.cs ├── test-app-architecture-tests │ ├── testing-convention.cs │ ├── global-usings.cs │ ├── convention-tests.cs │ ├── test-app-architecture-tests.csproj │ └── architecture-tests.cs ├── test-app-end-to-end-tests │ ├── AssemblyInfo.cs │ ├── global-usings.cs │ ├── render-modes.cs │ ├── configured-render-modes.cs │ ├── configuration.cs │ ├── playwright-settings │ │ ├── webkit.runsettings │ │ ├── chrome.runsettings │ │ ├── firefox.runsettings │ │ └── edge.runsettings │ ├── test-app-end-to-end-tests.csproj │ ├── sample-test.cs │ └── home-page-test.cs ├── timewarp-state-analyzer-tests │ ├── testing-convention.cs │ ├── global-usings.cs │ ├── .editorconfig │ └── timewarp-state-analyzer-tests.csproj └── client-integration-tests │ ├── infrastructure │ ├── client-host.cs │ └── client-host-builder.cs │ ├── clone │ ├── test-state.cs │ └── test-state-clone-tests.cs │ ├── global-usings.cs │ ├── convention-tests.cs │ ├── features │ ├── counter │ │ └── counter-state-clone-tests.cs │ └── application │ │ └── application-state-clone-tests.cs │ └── client-integration-tests.csproj ├── .ai ├── 03-environment.md ├── other │ ├── create-prompt.md │ ├── tools.md │ ├── blog.md │ ├── shell-commands.md │ └── project-structure.md ├── 00-confirmation.md ├── 05-dotnet-conventions.md ├── 01-user.md ├── 02-development-process.md └── Index.md ├── assets └── logo.png ├── aider.instructions.md ├── global.json ├── scripts ├── overview.md └── fix-analyzer-debug.reg ├── samples ├── 01-redux-dev-tools │ ├── images │ │ ├── redux-dev-tools.png │ │ ├── redux-route-state.png │ │ ├── blazor-wasm-hosted-screen-shot.jpeg │ │ └── blazor-wasm-hosted-screen-shot.png │ └── wasm │ │ └── sample-01-wasm │ │ ├── wwwroot │ │ ├── favicon.png │ │ ├── icon-192.png │ │ └── sample-data │ │ │ └── weather.json │ │ ├── pages │ │ ├── Home.razor │ │ └── Counter.razor │ │ ├── features │ │ └── counter │ │ │ └── counter-state.cs │ │ ├── global-usings.cs │ │ ├── layout │ │ └── MainLayout.razor │ │ ├── _imports.razor │ │ ├── sample-01-wasm.csproj │ │ ├── program.cs │ │ └── App.razor ├── 03-routing │ └── wasm │ │ └── sample-03-wasm │ │ ├── wwwroot │ │ ├── favicon.png │ │ ├── icon-192.png │ │ └── sample-data │ │ │ └── weather.json │ │ ├── pages │ │ ├── Home.razor │ │ └── Counter.razor │ │ ├── features │ │ └── counter │ │ │ ├── counter-state.cs │ │ │ └── counter-state.increment-count.cs │ │ ├── global-usings.cs │ │ ├── layout │ │ └── MainLayout.razor │ │ ├── _imports.razor │ │ ├── App.razor │ │ ├── program.cs │ │ └── sample-03-wasm.csproj ├── 02-action-tracking │ └── wasm │ │ └── sample-02-wasm │ │ ├── wwwroot │ │ ├── favicon.png │ │ ├── icon-192.png │ │ └── sample-data │ │ │ └── weather.json │ │ ├── pages │ │ ├── Home.razor │ │ └── Counter.razor │ │ ├── features │ │ └── demo │ │ │ ├── demo-state.cs │ │ │ ├── demo-state.five-second-action.cs │ │ │ └── demo-state.two-second-action.cs │ │ ├── global-usings.cs │ │ ├── _imports.razor │ │ ├── layout │ │ └── MainLayout.razor │ │ ├── App.razor │ │ └── sample-02-wasm.csproj └── 00-state-action-handler │ ├── wasm │ └── sample-00-wasm │ │ ├── wwwroot │ │ ├── favicon.png │ │ ├── icon-192.png │ │ └── sample-data │ │ │ └── weather.json │ │ ├── pages │ │ ├── Home.razor │ │ └── Counter.razor │ │ ├── global-usings.cs │ │ ├── features │ │ └── counter │ │ │ └── counter-state.cs │ │ ├── _imports.razor │ │ ├── program.cs │ │ ├── layout │ │ └── MainLayout.razor │ │ ├── sample-00-wasm.csproj │ │ └── App.razor │ ├── server │ └── sample-00-server │ │ ├── wwwroot │ │ └── favicon.png │ │ ├── appsettings.Development.json │ │ ├── components │ │ ├── pages │ │ │ ├── Home.razor │ │ │ └── Counter.razor │ │ ├── Routes.razor │ │ ├── _imports.razor │ │ ├── App.razor │ │ └── layout │ │ │ └── MainLayout.razor │ │ ├── appsettings.json │ │ ├── global-usings.cs │ │ ├── features │ │ └── counter │ │ │ └── counter-state.cs │ │ └── sample-00-server.csproj │ └── auto │ └── sample-00-auto │ ├── sample-00-auto │ ├── wwwroot │ │ └── favicon.png │ ├── appsettings.Development.json │ ├── components │ │ ├── pages │ │ │ └── Home.razor │ │ ├── Routes.razor │ │ ├── _imports.razor │ │ ├── App.razor │ │ └── layout │ │ │ └── MainLayout.razor │ ├── appsettings.json │ ├── global-usings.cs │ └── sample-00-auto.csproj │ └── sample-00-auto-client │ ├── wwwroot │ ├── appsettings.json │ └── appsettings.Development.json │ ├── global-usings.cs │ ├── features │ └── counter │ │ └── counter-state.cs │ ├── _imports.razor │ ├── program.cs │ ├── sample-00-auto-client.csproj │ └── pages │ └── Counter.razor ├── .devcontainer └── devcontainer.json ├── nuget.config ├── Directory.Build.targets └── .mailmap /.aiderignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /kanban/backlog/_._: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /kanban/done/_._: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /kanban/to-do/-.-: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /documentation/contributing/overview.md: -------------------------------------------------------------------------------- 1 | # Contributing Overview -------------------------------------------------------------------------------- /documentation/index.md: -------------------------------------------------------------------------------- 1 | [!include[Overview](Overview.md)] 2 | -------------------------------------------------------------------------------- /source/timewarp-state/wwwroot/types/redux-dev-tools-types.d.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /kanban/backlog/scratch/overview.md: -------------------------------------------------------------------------------- 1 | # Scratch pad for Kanban board stuff. 2 | -------------------------------------------------------------------------------- /tests/test-app/test-app-server/global-usings.cs: -------------------------------------------------------------------------------- 1 | global using TimeWarp.State; 2 | -------------------------------------------------------------------------------- /.ai/03-environment.md: -------------------------------------------------------------------------------- 1 | ENVIRONMENT: 2 | 3 | COMMAND SHELL: 4 | - Format commands for pwsh 5 | -------------------------------------------------------------------------------- /documentation/dev-ops/toc.yml: -------------------------------------------------------------------------------- 1 | # auto-generated 2 | - name: Dev Ops 3 | href: DevOps.md 4 | -------------------------------------------------------------------------------- /source/timewarp-state-plus/_imports.razor: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Components.Web 2 | -------------------------------------------------------------------------------- /assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimeWarpEngineering/timewarp-state/HEAD/assets/logo.png -------------------------------------------------------------------------------- /documentation/features/toc.yml: -------------------------------------------------------------------------------- 1 | - name: Features Overview 2 | topicUid: TimeWarp.State:Features.md 3 | -------------------------------------------------------------------------------- /documentation/topics/routing.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: TimeWarp.State:Routing.md 3 | title: Enable Routing 4 | --- 5 | -------------------------------------------------------------------------------- /source/timewarp-state/wwwroot/js/redux-dev-tools-types.js: -------------------------------------------------------------------------------- 1 | //# sourceMappingURL=redux-dev-tools-types.js.map -------------------------------------------------------------------------------- /documentation/topics/toc.yml: -------------------------------------------------------------------------------- 1 | - name: Add Redux Dev Tools 2 | topicUid: TimeWarpState:AddReduxDevTools.md 3 | -------------------------------------------------------------------------------- /source/timewarp-state/base/action.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.State; 2 | 3 | public interface IAction : IRequest { } 4 | 5 | -------------------------------------------------------------------------------- /aider.instructions.md: -------------------------------------------------------------------------------- 1 | - line_endings: lf 2 | - do not apologize 3 | 4 | # CSharp 5 | - use explicit types where not obvious 6 | -------------------------------------------------------------------------------- /documentation/model/main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimeWarpEngineering/timewarp-state/HEAD/documentation/model/main.png -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "9.0.203", 4 | "rollForward": "latestMajor", 5 | "allowPrerelease": true 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /scripts/overview.md: -------------------------------------------------------------------------------- 1 | # How to debug analyzer 2 | 3 | https://peterlesliemorris.com/debugging-my-published-rolsyn-source-generator-nuget-package/ -------------------------------------------------------------------------------- /.ai/other/create-prompt.md: -------------------------------------------------------------------------------- 1 | Read this document in full and then generate a prompt with specific instructions to complete this task for a coding LLM to use -------------------------------------------------------------------------------- /documentation/images/redux-dev-tools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimeWarpEngineering/timewarp-state/HEAD/documentation/images/redux-dev-tools.png -------------------------------------------------------------------------------- /documentation/topics/enable-javascript-interop.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: TimeWarp.State:EnableJavascriptInterop.md 3 | title: Enable Javascript Interop 4 | --- 5 | -------------------------------------------------------------------------------- /documentation/images/redux-route-state.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimeWarpEngineering/timewarp-state/HEAD/documentation/images/redux-route-state.png -------------------------------------------------------------------------------- /tests/timewarp-state-tests/testing-convention.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.State.Tests; 2 | 3 | class TestingConvention : TimeWarp.Fixie.TestingConvention { } 4 | -------------------------------------------------------------------------------- /tests/timewarp-state-plus-tests/testing-convention.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.State.Tests; 2 | 3 | class TestingConvention : TimeWarp.Fixie.TestingConvention { } 4 | -------------------------------------------------------------------------------- /tests/test-app-architecture-tests/testing-convention.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.Architecture.Tests; 2 | 3 | class TestingConvention : TimeWarp.Fixie.TestingConvention { } 4 | -------------------------------------------------------------------------------- /tests/test-app/test-app-server/wwwroot/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimeWarpEngineering/timewarp-state/HEAD/tests/test-app/test-app-server/wwwroot/favicon.png -------------------------------------------------------------------------------- /documentation/.gitignore: -------------------------------------------------------------------------------- 1 | ############### 2 | # folder # 3 | ############### 4 | /**/DROP/ 5 | /**/TEMP/ 6 | /**/packages/ 7 | /**/bin/ 8 | /**/obj/ 9 | _site 10 | -------------------------------------------------------------------------------- /samples/01-redux-dev-tools/images/redux-dev-tools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimeWarpEngineering/timewarp-state/HEAD/samples/01-redux-dev-tools/images/redux-dev-tools.png -------------------------------------------------------------------------------- /tests/test-app-end-to-end-tests/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | 3 | [assembly: Parallelize(Scope = ExecutionScope.MethodLevel)] 4 | -------------------------------------------------------------------------------- /tests/timewarp-state-analyzer-tests/testing-convention.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.State.Analyzer.Tests; 2 | 3 | class TestingConvention : TimeWarp.Fixie.TestingConvention { } 4 | -------------------------------------------------------------------------------- /documentation/tutorial/default-template-screen-shot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimeWarpEngineering/timewarp-state/HEAD/documentation/tutorial/default-template-screen-shot.png -------------------------------------------------------------------------------- /samples/01-redux-dev-tools/images/redux-route-state.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimeWarpEngineering/timewarp-state/HEAD/samples/01-redux-dev-tools/images/redux-route-state.png -------------------------------------------------------------------------------- /tests/test-app/test-app-contracts/global-usings.cs: -------------------------------------------------------------------------------- 1 | global using TimeWarp.Mediator; 2 | global using System.Collections.Generic; 3 | global using System.Text.Json.Serialization; 4 | -------------------------------------------------------------------------------- /samples/03-routing/wasm/sample-03-wasm/wwwroot/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimeWarpEngineering/timewarp-state/HEAD/samples/03-routing/wasm/sample-03-wasm/wwwroot/favicon.png -------------------------------------------------------------------------------- /samples/03-routing/wasm/sample-03-wasm/wwwroot/icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimeWarpEngineering/timewarp-state/HEAD/samples/03-routing/wasm/sample-03-wasm/wwwroot/icon-192.png -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "image": "mcr.microsoft.com/devcontainers/universal:2", 3 | "features": { 4 | "ghcr.io/devcontainers/features/powershell:1": {} 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/features/color/actions/color-state.update.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.Client.Features.Counter.Actions; 2 | 3 | public class UpdateColorState 4 | { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /samples/01-redux-dev-tools/wasm/sample-01-wasm/wwwroot/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimeWarpEngineering/timewarp-state/HEAD/samples/01-redux-dev-tools/wasm/sample-01-wasm/wwwroot/favicon.png -------------------------------------------------------------------------------- /samples/02-action-tracking/wasm/sample-02-wasm/wwwroot/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimeWarpEngineering/timewarp-state/HEAD/samples/02-action-tracking/wasm/sample-02-wasm/wwwroot/favicon.png -------------------------------------------------------------------------------- /source/timewarp-state/wwwroot/js/redux-dev-tools-types.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"redux-dev-tools-types.js","sourceRoot":"","sources":["../typescript/redux-dev-tools-types.ts"],"names":[],"mappings":""} -------------------------------------------------------------------------------- /samples/01-redux-dev-tools/images/blazor-wasm-hosted-screen-shot.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimeWarpEngineering/timewarp-state/HEAD/samples/01-redux-dev-tools/images/blazor-wasm-hosted-screen-shot.jpeg -------------------------------------------------------------------------------- /samples/01-redux-dev-tools/images/blazor-wasm-hosted-screen-shot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimeWarpEngineering/timewarp-state/HEAD/samples/01-redux-dev-tools/images/blazor-wasm-hosted-screen-shot.png -------------------------------------------------------------------------------- /samples/01-redux-dev-tools/wasm/sample-01-wasm/wwwroot/icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimeWarpEngineering/timewarp-state/HEAD/samples/01-redux-dev-tools/wasm/sample-01-wasm/wwwroot/icon-192.png -------------------------------------------------------------------------------- /samples/02-action-tracking/wasm/sample-02-wasm/wwwroot/icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimeWarpEngineering/timewarp-state/HEAD/samples/02-action-tracking/wasm/sample-02-wasm/wwwroot/icon-192.png -------------------------------------------------------------------------------- /tests/test-app/test-app-server/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Warning", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/wasm/sample-00-wasm/wwwroot/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimeWarpEngineering/timewarp-state/HEAD/samples/00-state-action-handler/wasm/sample-00-wasm/wwwroot/favicon.png -------------------------------------------------------------------------------- /tests/test-app/test-app-client/wwwroot/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Trace", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /documentation/partials/give-a-star.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: TimeWarp.State.GiveAStar.md 3 | title: Give a Star 4 | --- 5 | 6 | ## Give a Star! :star: 7 | 8 | If you find this project useful, please give it a star. Thanks! 9 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/wasm/sample-00-wasm/wwwroot/icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimeWarpEngineering/timewarp-state/HEAD/samples/00-state-action-handler/wasm/sample-00-wasm/wwwroot/icon-192.png -------------------------------------------------------------------------------- /samples/03-routing/wasm/sample-03-wasm/pages/Home.razor: -------------------------------------------------------------------------------- 1 | @namespace Sample03Wasm.Pages 2 | @page "/" 3 | 4 | Home 5 | 6 |

Hello, world!

7 | 8 | Welcome to your new app. 9 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/server/sample-00-server/wwwroot/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimeWarpEngineering/timewarp-state/HEAD/samples/00-state-action-handler/server/sample-00-server/wwwroot/favicon.png -------------------------------------------------------------------------------- /samples/01-redux-dev-tools/wasm/sample-01-wasm/pages/Home.razor: -------------------------------------------------------------------------------- 1 | @namespace Sample01Wasm.Pages 2 | @page "/" 3 | 4 | Home 5 | 6 |

Hello, world!

7 | 8 | Welcome to your new app. 9 | -------------------------------------------------------------------------------- /samples/02-action-tracking/wasm/sample-02-wasm/pages/Home.razor: -------------------------------------------------------------------------------- 1 | @namespace Sample02Wasm.Pages 2 | @page "/" 3 | 4 | Home 5 | 6 |

Hello, world!

7 | 8 | Welcome to your new app. 9 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/wasm/sample-00-wasm/pages/Home.razor: -------------------------------------------------------------------------------- 1 | @namespace Sample00Wasm.Pages 2 | @page "/" 3 | 4 | Home 5 | 6 |

Hello, world!

7 | 8 | Welcome to your new app. 9 | -------------------------------------------------------------------------------- /source/timewarp-state-analyzer/AnalyzerReleases.Shipped.md: -------------------------------------------------------------------------------- 1 | ; Shipped analyzer releases 2 | ; https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md 3 | 4 | -------------------------------------------------------------------------------- /source/timewarp-state-source-generator/global-usings.cs: -------------------------------------------------------------------------------- 1 | global using Microsoft.CodeAnalysis; 2 | global using Microsoft.CodeAnalysis.CSharp.Syntax; 3 | global using Microsoft.CodeAnalysis.Text; 4 | global using System.Text; 5 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/wwwroot/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Debug", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "UseHttp": true 9 | } 10 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/auto/sample-00-auto/sample-00-auto/wwwroot/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TimeWarpEngineering/timewarp-state/HEAD/samples/00-state-action-handler/auto/sample-00-auto/sample-00-auto/wwwroot/favicon.png -------------------------------------------------------------------------------- /samples/00-state-action-handler/server/sample-00-server/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /samples/02-action-tracking/wasm/sample-02-wasm/features/demo/demo-state.cs: -------------------------------------------------------------------------------- 1 | namespace Sample02Wasm.Features.Demo; 2 | 3 | internal sealed partial class DemoState : State 4 | { 5 | public override void Initialize() { } 6 | } 7 | -------------------------------------------------------------------------------- /tests/test-app/test-app-contracts/features/exception-handling/throw-server-side-exception/throw-server-side-exception-response.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.Contracts.Features.ExceptionHandlings; 2 | 3 | public class ThrowServerSideExceptionResponse; 4 | -------------------------------------------------------------------------------- /documentation/toc.yml: -------------------------------------------------------------------------------- 1 | # auto-generated 2 | - name: Overview 3 | topicUid: TimeWarpState:Overview.md 4 | - name: Topics 5 | href: Topics/ 6 | - name: Release Notes 7 | href: ReleaseNotes/ 8 | - name: Migrations 9 | href: Migrations/ 10 | -------------------------------------------------------------------------------- /source/timewarp-state/features/persistence/persistent-state-method.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.Features.Persistence; 2 | 3 | public enum PersistentStateMethod 4 | { 5 | PreRender, 6 | Server, 7 | SessionStorage, 8 | LocalStorage 9 | } 10 | -------------------------------------------------------------------------------- /tests/test-app-end-to-end-tests/global-usings.cs: -------------------------------------------------------------------------------- 1 | global using Shouldly; 2 | global using Microsoft.Playwright; 3 | global using Microsoft.Playwright.MSTest; 4 | global using System.Text.RegularExpressions; 5 | global using Test.App.EndToEnd.Tests; 6 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/auto/sample-00-auto/sample-00-auto-client/wwwroot/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/auto/sample-00-auto/sample-00-auto/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/server/sample-00-server/components/pages/Home.razor: -------------------------------------------------------------------------------- 1 | @namespace Sample00Server.Components.Pages 2 | @page "/" 3 | 4 | Home 5 | 6 |

Hello, world!

7 | 8 | Welcome to your new app. 9 | -------------------------------------------------------------------------------- /source/timewarp-state-plus/features/timers/timer-config.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.State.Plus.Features.Timers; 2 | 3 | public class TimerConfig 4 | { 5 | public double Duration { get; set; } 6 | public bool ResetOnActivity { get; init; } = true; 7 | } 8 | -------------------------------------------------------------------------------- /source/timewarp-state-plus/features/action-tracking/pipeline/track-action-attribute.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.Features.ActionTracking; 2 | 3 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] 4 | public class TrackActionAttribute : Attribute { } 5 | -------------------------------------------------------------------------------- /source/timewarp-state/store/state-initialized-notification.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.State; 2 | 3 | public class StateInitializedNotification 4 | ( 5 | Type stateType 6 | ) : INotification 7 | { 8 | public Type StateType { get; } = stateType; 9 | } 10 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/auto/sample-00-auto/sample-00-auto/components/pages/Home.razor: -------------------------------------------------------------------------------- 1 | @namespace Sample00Auto.Components.Pages 2 | @page "/" 3 | 4 | Home 5 | 6 |

Hello, world!

7 | 8 | Welcome to your new app. 9 | -------------------------------------------------------------------------------- /documentation/migrations/migration6-7.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: BlazorState:Migration6-7.md 3 | title: Migrate From 6.X to 7.X 4 | --- 5 | 6 | # Migration 7 | 8 | ## From 6.x to 7.x 9 | 10 | ### Update to dotnet 7 11 | 12 | Only change is updating to dotnet 7 is required -------------------------------------------------------------------------------- /samples/00-state-action-handler/auto/sample-00-auto/sample-00-auto-client/wwwroot/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/server/sample-00-server/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /source/timewarp-state-analyzer/global-usings.cs: -------------------------------------------------------------------------------- 1 | global using Microsoft.CodeAnalysis; 2 | global using Microsoft.CodeAnalysis.CSharp.Syntax; 3 | global using Microsoft.CodeAnalysis.Diagnostics; 4 | global using System.Collections.Immutable; 5 | global using System.Linq; 6 | -------------------------------------------------------------------------------- /source/timewarp-state-plus/state/i-timewarp-cacheable-state.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.State.Plus.State; 2 | 3 | public interface ITimeWarpCacheableState 4 | { 5 | string? CacheKey { get; } 6 | DateTime? TimeStamp { get; } 7 | TimeSpan CacheDuration { get;} 8 | } 9 | -------------------------------------------------------------------------------- /source/timewarp-state/features/redux-dev-tools/requests/i-redux-request.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.Features.ReduxDevTools; 2 | 3 | /// 4 | /// Marker Interface to allow for filtering of Devtools Requests 5 | /// 6 | internal interface IReduxRequest { } 7 | -------------------------------------------------------------------------------- /source/timewarp-state/features/persistence/abstractions/i-persistence-service.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.Features.Persistence; 2 | 3 | public interface IPersistenceService 4 | { 5 | Task LoadState(Type stateType, PersistentStateMethod persistentStateMethod); 6 | } 7 | -------------------------------------------------------------------------------- /tests/timewarp-state-plus-tests/global-usings.cs: -------------------------------------------------------------------------------- 1 | global using Shouldly; 2 | global using NetArchTest.Policies; 3 | global using System.Reflection; 4 | global using TimeWarp.Fixie; 5 | global using TimeWarp.State.Policies; 6 | global using TimeWarp.State.Policies.Extensions; 7 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/auto/sample-00-auto/sample-00-auto/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /tests/test-app-architecture-tests/global-usings.cs: -------------------------------------------------------------------------------- 1 | global using Shouldly; 2 | global using NetArchTest.Policies; 3 | global using System.Reflection; 4 | global using TimeWarp.Fixie; 5 | global using TimeWarp.State.Policies; 6 | global using TimeWarp.State.Policies.Extensions; 7 | -------------------------------------------------------------------------------- /tests/test-app/test-app-server/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Warning", 5 | "Microsoft.AspNetCore": "Warning", 6 | "Microsoft.AspNetCore.Components": "Warning" 7 | } 8 | }, 9 | "AllowedHosts": "*" 10 | } 11 | -------------------------------------------------------------------------------- /documentation/partials/releases.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: TimeWarp.State.Releases.md 3 | title: Releases 4 | --- 5 | 6 | ## Releases 7 | 8 | View the [Release Notes](https://timewarpengineering.github.io/timewarp-state/ReleaseNotes/Release11.0.0.html) for detailed information on each release. 9 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/generated/timewarp-source-generators/TimeWarp.SourceGenerators.HelloWorldGenerator/HelloWorld.g.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.Generated; 2 | 3 | public static class HelloWorld 4 | { 5 | public const string Message = "Hello from TimeWarp Source Generator!"; 6 | } -------------------------------------------------------------------------------- /tests/test-app/test-app-client/test-objects/test-enum.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable UnusedType.Global 2 | // ReSharper disable UnusedMember.Global 3 | namespace AnyClone.Tests.TestObjects; 4 | 5 | public enum TestEnum 6 | { 7 | Test1 = 1, 8 | Test2 = 2, 9 | Test3 = 3 10 | } 11 | -------------------------------------------------------------------------------- /nuget.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /source/timewarp-state/wwwroot/typescript/dot-net-reference.d.ts: -------------------------------------------------------------------------------- 1 | export interface DotNetReference { 2 | invokeMethodAsync(methodName: string, requestTypeFullName: string, requestAsJson: string): Promise; 3 | } 4 | 5 | // Optionally, if you have more methods or properties, add them here 6 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/pipeline/notification-pre-processor/pre-pipeline-notification.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.Client.Pipeline.NotificationPreProcessor; 2 | 3 | public class PrePipelineNotification : INotification 4 | { 5 | public required TRequest Request { get; init; } 6 | } 7 | -------------------------------------------------------------------------------- /tests/timewarp-state-tests/global-usings.cs: -------------------------------------------------------------------------------- 1 | global using Shouldly; 2 | global using TimeWarp.Mediator; 3 | global using System.Collections.Concurrent; 4 | global using System.Linq.Expressions; 5 | global using System.Reflection; 6 | global using TimeWarp.Fixie; 7 | global using TimeWarp.State; 8 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/auto/sample-00-auto/sample-00-auto-client/global-usings.cs: -------------------------------------------------------------------------------- 1 | global using Microsoft.AspNetCore.Components; 2 | global using Microsoft.AspNetCore.Components.WebAssembly.Hosting; 3 | global using Microsoft.Extensions.DependencyInjection; 4 | global using TimeWarp.State; 5 | -------------------------------------------------------------------------------- /source/timewarp-state/global-suppressions.cs: -------------------------------------------------------------------------------- 1 | // This file is used by Code Analysis to maintain SuppressMessage 2 | // attributes that are applied to this project. 3 | // Project-level suppressions either have no target or are given 4 | // a specific target and scoped to a namespace, type, member, etc. 5 | -------------------------------------------------------------------------------- /source/timewarp-state-policies/global-usings.cs: -------------------------------------------------------------------------------- 1 | global using Shouldly; 2 | global using Mono.Cecil; 3 | global using NetArchTest.Policies; 4 | global using NetArchTest.Rules; 5 | global using System.Linq; 6 | global using System.Reflection; 7 | global using System.Text; 8 | global using System.Text.Json.Serialization; 9 | -------------------------------------------------------------------------------- /tests/test-app-end-to-end-tests/render-modes.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.EndToEnd.Tests; 2 | 3 | public static class RenderModes 4 | { 5 | public const string Server = "Server"; 6 | public const string Wasm = "Wasm"; 7 | public const string Static = "Static"; 8 | // Add other render modes as needed 9 | } 10 | -------------------------------------------------------------------------------- /tests/client-integration-tests/infrastructure/client-host.cs: -------------------------------------------------------------------------------- 1 | namespace TestApp.Client.Integration.Tests.Infrastructure; 2 | 3 | [NotTest] 4 | public class ClientHost 5 | ( 6 | IServiceProvider serviceProvider 7 | ) 8 | { 9 | 10 | public IServiceProvider ServiceProvider { get; } = serviceProvider; 11 | } 12 | -------------------------------------------------------------------------------- /.ai/other/tools.md: -------------------------------------------------------------------------------- 1 | --- 2 | tools: 3 | - name: Beyond Compare 4 | description: A powerful file and directory comparison tool 5 | - name: PowerGrep 6 | description: A powerful text search tool 7 | --- 8 | 9 | # Tools 10 | 11 | This is a list of tools the user has installed that we want AI to be aware of. 12 | -------------------------------------------------------------------------------- /source/timewarp-state-plus/features/timers/multi-timer-options.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.State.Plus.Features.Timers; 2 | 3 | public class MultiTimerOptions 4 | { 5 | // ReSharper disable once CollectionNeverUpdated.Global Set from Configuration 6 | public Dictionary Timers { get; init; } = new(); 7 | } 8 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/wasm/sample-00-wasm/global-usings.cs: -------------------------------------------------------------------------------- 1 | global using Microsoft.AspNetCore.Components; 2 | global using Microsoft.AspNetCore.Components.Web; 3 | global using Microsoft.AspNetCore.Components.WebAssembly.Hosting; 4 | global using Microsoft.Extensions.DependencyInjection; 5 | global using TimeWarp.State; 6 | -------------------------------------------------------------------------------- /documentation/release-notes/release7.0.0.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: BlazorState:Release.7.0.0.md 3 | title: Release 7.0.0 4 | --- 5 | 6 | ## Release 7.0.0 7 | 8 | ### Breaking Changes 9 | 10 | * Blazor-State now requires dotnet 7 11 | 12 | See [Migrations](xref:BlazorState:Migration6-7.md) for instructions on how to migrate from version 6.0 to 7.0. 13 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/test-objects/i-test-interface.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable UnusedMemberInSuper.Global 2 | namespace AnyClone.Tests.TestObjects; 3 | 4 | public interface ITestInterface 5 | { 6 | bool BoolValue { get; set; } 7 | int IntValue { get; set; } 8 | IDictionary DictionaryValue { get; set; } 9 | } 10 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/features/event-stream/event-stream-state.debug.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.Client.Features.EventStream; 2 | 3 | public partial class EventStreamState 4 | { 5 | internal void Initialize(List events) 6 | { 7 | ThrowIfNotTestAssembly(Assembly.GetCallingAssembly()); 8 | EventList = events; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /documentation/partials/license.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: TimeWarp.State.License.md 3 | title: License 4 | --- 5 | 6 | ## Unlicense 7 | 8 | [![License](https://img.shields.io/github/license/TimeWarpEngineering/timewarp-state.svg?style=flat-square&logo=github)](https://unlicense.org) 9 | This project is licensed under the [Unlicense](https://unlicense.org). 10 | -------------------------------------------------------------------------------- /kanban/backlog/scratch/rejected.md: -------------------------------------------------------------------------------- 1 | - [ ] Implement DevTools Handlers (Currently only Jump works) 2 | See the MobX example for how to implement more ReduxDevTools functionality 3 | https://github.com/zalmoxisus/mobx-remotedev/blob/master/src/monitorActions.js 4 | > I have changed my mind. The fancy stuff in ReduxDevTools I don't really use and is not high ROI 5 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/server/sample-00-server/global-usings.cs: -------------------------------------------------------------------------------- 1 | global using Microsoft.AspNetCore.Builder; 2 | global using Microsoft.AspNetCore.Components; 3 | global using Microsoft.AspNetCore.Components.Web; 4 | global using Microsoft.Extensions.DependencyInjection; 5 | global using Sample00Server.Components; 6 | global using TimeWarp.State; 7 | -------------------------------------------------------------------------------- /samples/03-routing/wasm/sample-03-wasm/features/counter/counter-state.cs: -------------------------------------------------------------------------------- 1 | namespace Sample03Wasm.Features.Counter; 2 | 3 | internal sealed partial class CounterState : State 4 | { 5 | public int Count { get; private set; } 6 | 7 | public override void Initialize() 8 | { 9 | Count = 3; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/features/counter/components/counter.razor.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.Client.Features.Counter.Components; 2 | 3 | using static CounterState; 4 | 5 | public partial class Counter : BaseComponent 6 | { 7 | private async Task ButtonClick() => 8 | await Mediator.Send(new IncrementCountActionSet.Action { Amount = 5 }); 9 | } 10 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/pipeline/notification-post-processor/post-pipeline-notification.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.Client.Pipeline.NotificationPostProcessor; 2 | 3 | public class PostPipelineNotification : INotification 4 | { 5 | public required TRequest Request { get; init; } 6 | public required TResponse Response { get; init; } 7 | } 8 | -------------------------------------------------------------------------------- /.ai/00-confirmation.md: -------------------------------------------------------------------------------- 1 | AI INSTRUCTION SET: 2 | 3 | CONFIRMATION REQUIREMENT: 4 | 5 | To ensure you understand my prompt, I need a piece of confirmation from you. Before any tool use and after any tool use, I need you to give me a confidence level on a scale of 0 to 10 on the tool use helping with the project. Remember to do this every time you are using a tool. 6 | -------------------------------------------------------------------------------- /samples/01-redux-dev-tools/wasm/sample-01-wasm/features/counter/counter-state.cs: -------------------------------------------------------------------------------- 1 | namespace Sample01Wasm.Features.Counter; 2 | 3 | internal sealed partial class CounterState : State 4 | { 5 | public int Count { get; private set; } 6 | 7 | public override void Initialize() 8 | { 9 | Count = 3; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/wasm/sample-00-wasm/features/counter/counter-state.cs: -------------------------------------------------------------------------------- 1 | namespace Sample00Wasm.Features.Counter; 2 | 3 | internal sealed partial class CounterState : State 4 | { 5 | public int Count { get; private set; } 6 | 7 | public override void Initialize() 8 | { 9 | Count = 3; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /source/timewarp-state/base/action-handler.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.State; 2 | 3 | public abstract class ActionHandler 4 | ( 5 | IStore store 6 | ) : IRequestHandler where TAction : IAction 7 | { 8 | protected IStore Store { get; set; } = store; 9 | 10 | public abstract Task Handle(TAction action, CancellationToken cancellationToken); 11 | } 12 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/server/sample-00-server/features/counter/counter-state.cs: -------------------------------------------------------------------------------- 1 | namespace Sample00Server.Features.Counter; 2 | 3 | internal sealed partial class CounterState : State 4 | { 5 | public int Count { get; private set; } 6 | 7 | public override void Initialize() 8 | { 9 | Count = 3; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /source/timewarp-state/features/render-subscriptions/non-nested-class-exception.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.Features.RenderSubscriptions; 2 | 3 | public class NonNestedClassException : ArgumentException 4 | { 5 | public NonNestedClassException(string? message) : base(message) { } 6 | public NonNestedClassException(string? message, string? paramName) : base(message, paramName) { } 7 | } 8 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/features/counter/actions/non-nested-action/non-nested-action.cs: -------------------------------------------------------------------------------- 1 | #if ANALYZER_TEST 2 | // Code examples that the analyzer should fail on 3 | namespace Test.App.Client.Features.Counter; 4 | 5 | public class NonNestedAction : IAction 6 | { 7 | // ReSharper disable once UnusedMember.Global 8 | public int Amount { get; set; } 9 | } 10 | #endif 11 | -------------------------------------------------------------------------------- /documentation/migrations/migration7-8.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: BlazorState:Migration7-8.md 3 | title: Migrate From 7.X to 8.X 4 | --- 5 | 6 | # Migration 7 | 8 | ## From 7.x to 8.x 9 | 10 | ### MediatR 11 to 12 migration 11 | 12 | In this release we migrate from MediatR 11 to 12 see the MediatR migration notes here https://github.com/jbogard/MediatR/wiki/Migration-Guide-11.x-to-12.0 13 | -------------------------------------------------------------------------------- /documentation/partials/contact.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: TimeWarp.State.Contact.md 3 | title: Contact 4 | --- 5 | 6 | ## Contact 7 | 8 | If you have an issue and don't receive a timely response, feel free to reach out on our [Discord server](https://discord.gg/A55JARGKKP). 9 | 10 | [![Discord](https://img.shields.io/discord/715274085940199487?logo=discord)](https://discord.gg/7F4bS2T) 11 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/auto/sample-00-auto/sample-00-auto-client/features/counter/counter-state.cs: -------------------------------------------------------------------------------- 1 | namespace Sample00Auto.Client.Features.Counter; 2 | 3 | internal sealed partial class CounterState : State 4 | { 5 | public int Count { get; private set; } 6 | public override void Initialize() 7 | { 8 | Count = 3; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/features/event-stream/event-stream-state.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.Client.Features.EventStream; 2 | 3 | public sealed partial class EventStreamState : State 4 | { 5 | private List EventList { get; set; } = []; 6 | public IReadOnlyList Events => EventList.AsReadOnly(); 7 | 8 | public override void Initialize() { } 9 | } 10 | -------------------------------------------------------------------------------- /documentation/release-notes/release10.0.0.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: BlazorState:Release.10.0.0.md 3 | title: Release 10.0.0 4 | --- 5 | 6 | ## Release 10.0.0 7 | 8 | ### Breaking Changes 9 | 10 | * IBlazorStateComponent no longer has Mediator or Store properties. 11 | 12 | See [Migrations](xref:BlazorState:Migration9-10.md) for instructions on how to migrate from version 9.0 to 10.0. 13 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/server/sample-00-server/components/Routes.razor: -------------------------------------------------------------------------------- 1 | @namespace Sample00Server.Components 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/server/sample-00-server/sample-00-server.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Sample00Server 5 | Sample00Server 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /samples/02-action-tracking/wasm/sample-02-wasm/global-usings.cs: -------------------------------------------------------------------------------- 1 | global using Microsoft.AspNetCore.Components; 2 | global using Microsoft.AspNetCore.Components.Web; 3 | global using Microsoft.AspNetCore.Components.WebAssembly.Hosting; 4 | global using Microsoft.Extensions.DependencyInjection; 5 | global using TimeWarp.State; 6 | global using TimeWarp.Features.ActionTracking; 7 | global using Sample02Wasm; 8 | -------------------------------------------------------------------------------- /kanban/backlog/scratch/todo.md: -------------------------------------------------------------------------------- 1 | - [ ] Improve usefulness of ILogger. 2 | - [ ] Document all public interfaces 3 | - [ ] Check visibility on classes props etc... private public internal etc.. 4 | - [x] Convert js to ts. See Blazor package for example and Logging. 5 | - [ ] Consider splitting Packages for DevTools as production we will not want to deploy. TimeWarp.State.ReduxDevTools 6 | - [ ] Review TODOs in source 7 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/auto/sample-00-auto/sample-00-auto/global-usings.cs: -------------------------------------------------------------------------------- 1 | global using Microsoft.AspNetCore.Builder; 2 | global using Microsoft.AspNetCore.Components; 3 | global using Microsoft.AspNetCore.Components.Web; 4 | global using Microsoft.Extensions.DependencyInjection; 5 | global using Sample00Auto.Client.Pages; 6 | global using Sample00Auto.Components; 7 | global using TimeWarp.State; 8 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/features/event-stream/components/EventStream.razor: -------------------------------------------------------------------------------- 1 | @namespace Test.App.Client.Features.EventStream.Components 2 | @inherits BaseComponent 3 | 4 |
Events
5 |
    6 | @foreach(string item in Events) 7 | { 8 |
  • @item
  • 9 | } 10 |
11 | 12 | @code 13 | { 14 | private IReadOnlyList Events => EventStreamState.Events; 15 | } 16 | -------------------------------------------------------------------------------- /source/timewarp-state/features/persistence/attributes/persistent-state-attribute.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.Features.Persistence; 2 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] 3 | public class PersistentStateAttribute 4 | ( 5 | PersistentStateMethod PersistentStateMethod 6 | ) : Attribute 7 | { 8 | public readonly PersistentStateMethod PersistentStateMethod = PersistentStateMethod; 9 | } 10 | -------------------------------------------------------------------------------- /tests/client-integration-tests/infrastructure/client-host-builder.cs: -------------------------------------------------------------------------------- 1 | namespace TestApp.Client.Integration.Tests.Infrastructure; 2 | 3 | [NotTest] 4 | public class ClientHostBuilder 5 | { 6 | public IServiceCollection Services { get; } = new ServiceCollection(); 7 | 8 | public static ClientHostBuilder CreateDefault() => new(); 9 | 10 | public ClientHost Build() => new(Services.BuildServiceProvider()); 11 | } 12 | -------------------------------------------------------------------------------- /source/timewarp-state/features/pipeline/invalid-clone-exception.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.Features.StateTransactions; 2 | 3 | public class InvalidCloneException 4 | ( 5 | Type enclosingStateType 6 | ) : Exception($"State of type {enclosingStateType} has an invalid clone. For the default clone to work, a parameterless constructor is required.") 7 | { 8 | public Type EnclosingStateType { get; } = enclosingStateType; 9 | } 10 | -------------------------------------------------------------------------------- /documentation/partials/contributing.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: TimeWarp.State.Contributing.md 3 | title: Contributing 4 | --- 5 | 6 | ## Contributing 7 | 8 | Your contributions are welcome! Before starting any work, please open a [discussion](https://github.com/TimeWarpEngineering/timewarp-state/discussions). 9 | 10 | Help with the [documentation](https://timewarpengineering.github.io/timewarp-state/) is also greatly appreciated. 11 | -------------------------------------------------------------------------------- /source/timewarp-state/wwwroot/types/constants.d.ts: -------------------------------------------------------------------------------- 1 | export declare const TimeWarpStateName: string; 2 | export declare const DevToolsName: string; 3 | export declare const InitializeJavaScriptInteropName: string; 4 | export declare const JsonRequestHandlerMethodName: string; 5 | export declare const ReduxDevToolsFactoryName: string; 6 | export declare const ReduxDevToolsName: string; 7 | export declare const ReduxExtensionName: string; 8 | -------------------------------------------------------------------------------- /source/timewarp-state/wwwroot/types/timewarp-state.d.ts: -------------------------------------------------------------------------------- 1 | import { DotNetReference } from './dot-net-reference'; 2 | import { ReduxDevTools } from "./redux-dev-tools"; 3 | export declare class TimeWarpState { 4 | jsonRequestHandler: DotNetReference; 5 | reduxDevTools: ReduxDevTools; 6 | DispatchRequest(requestTypeFullName: string, request: unknown): Promise; 7 | } 8 | export declare const timeWarpState: TimeWarpState; 9 | -------------------------------------------------------------------------------- /samples/01-redux-dev-tools/wasm/sample-01-wasm/global-usings.cs: -------------------------------------------------------------------------------- 1 | global using Microsoft.AspNetCore.Components; 2 | global using Microsoft.AspNetCore.Components.Web; 3 | global using Microsoft.AspNetCore.Components.WebAssembly.Hosting; 4 | global using Microsoft.Extensions.DependencyInjection; 5 | global using TimeWarp.State; 6 | global using System.Reflection; 7 | global using TimeWarp.Features.Routing; 8 | global using Sample01Wasm; 9 | -------------------------------------------------------------------------------- /source/timewarp-state/features/components/ReduxDevTools.razor: -------------------------------------------------------------------------------- 1 | @namespace TimeWarp.Features.Developer 2 | @code { 3 | 4 | [Inject] private ReduxDevToolsInterop ReduxDevToolsInterop { get; set; } = null!; 5 | 6 | /// 7 | protected override async Task OnAfterRenderAsync(bool firstRender) 8 | { 9 | await ReduxDevToolsInterop.InitAsync(); 10 | await base.OnAfterRenderAsync(firstRender); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /source/timewarp-state/features/pipeline/exception-notification.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.Features.StateTransactions; 2 | 3 | public class ExceptionNotification : INotification 4 | { 5 | public ExceptionNotification(string requestName, Exception exception) 6 | { 7 | RequestName = requestName; 8 | Exception = exception; 9 | } 10 | public string RequestName { get; } 11 | 12 | public Exception Exception { get; } 13 | } 14 | -------------------------------------------------------------------------------- /tests/test-app/test-app-contracts/test-app-contracts.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Test.App.Contracts 5 | Test.App.Contracts 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /tests/timewarp-state-analyzer-tests/global-usings.cs: -------------------------------------------------------------------------------- 1 | global using TimeWarp.State.Analyzer; 2 | global using TimeWarp.State.Analyzer.Tests; 3 | global using Shouldly; 4 | global using Microsoft.CodeAnalysis; 5 | global using Microsoft.CodeAnalysis.CSharp.Testing; 6 | global using Microsoft.CodeAnalysis.Testing; 7 | global using System.Diagnostics.CodeAnalysis; 8 | global using System.Threading.Tasks; 9 | global using TimeWarp.Fixie; 10 | -------------------------------------------------------------------------------- /tests/timewarp-state-tests/timewarp-state-tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /documentation/migrations/migration8-9.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: BlazorState:Migration8-9.md 3 | title: Migrate From 8.X to 9.X 4 | --- 5 | 6 | # Migration 7 | 8 | ## From 8.x to 9.x 9 | 10 | You now have to explicitly register all middleware. 11 | 12 | ### MediatR 12.0 to 12.1 migration 13 | 14 | In this release we migrate from MediatR 11 to 12 see the MediatR migration notes here https://github.com/jbogard/MediatR/wiki/Migration-Guide-12.0-to-12.1 15 | -------------------------------------------------------------------------------- /samples/03-routing/wasm/sample-03-wasm/global-usings.cs: -------------------------------------------------------------------------------- 1 | global using Microsoft.AspNetCore.Components; 2 | global using Microsoft.AspNetCore.Components.Web; 3 | global using Microsoft.AspNetCore.Components.WebAssembly.Hosting; 4 | global using Microsoft.Extensions.DependencyInjection; 5 | global using TimeWarp.State; 6 | global using TimeWarp.Features.Routing; 7 | global using TimeWarp.State.Plus; 8 | global using TimeWarp.State.Plus.Extensions; 9 | -------------------------------------------------------------------------------- /source/timewarp-state-plus/features/timers/timer-elapsed-notification.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.State.Plus.Features.Timers; 2 | 3 | public class TimerElapsedNotification : INotification 4 | { 5 | public string TimerName { get; } 6 | public Action RestartTimer { get; } 7 | 8 | public TimerElapsedNotification(string timerName, Action restartTimer) 9 | { 10 | TimerName = timerName; 11 | RestartTimer = restartTimer; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/client-integration-tests/clone/test-state.cs: -------------------------------------------------------------------------------- 1 | namespace TestApp.Client.Integration.Tests.Clone; 2 | 3 | 4 | [NotTest] 5 | public class TestState 6 | { 7 | // Create an array of strings to sort. 8 | public string[] Fruits { get; set; } = ["apricot", "orange", "banana", "mango", "apple", "grape", "strawberry"]; 9 | public IOrderedEnumerable SortedFruits => Fruits.OrderBy(fruit => fruit.Length).ThenBy(fruit => fruit); 10 | } 11 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/features/base/components/ResetButton.razor: -------------------------------------------------------------------------------- 1 | @namespace Test.App.Client.Features.Base.Components 2 | @inherits BaseComponent 3 | @using static ApplicationState; 4 | 5 | @code { 6 | private async Task ButtonClick() => await Mediator.Send(new ResetStoreActionSet.Action()); 7 | } 8 | 9 |
10 | 11 |
12 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/features/counter/actions/improper-nested-action/improper-nested-action.cs: -------------------------------------------------------------------------------- 1 | #if ANALYZER_TEST 2 | // Code examples that the analyzer should fail on 3 | namespace Test.App.Client.Features.Counter; 4 | 5 | public class WrongNesting 6 | { 7 | public class ImproperNestedAction : IAction 8 | { 9 | // ReSharper disable once UnusedMember.Global 10 | public int Amount { get; set; } 11 | } 12 | } 13 | #endif 14 | -------------------------------------------------------------------------------- /source/timewarp-state-plus/features/feature-flags/feature-flag-state/feature-flag-state.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.State.Plus.Features.FeatureFlags.Actions; 2 | 3 | public sealed class FeatureFlagState : State 4 | { 5 | public FeatureFlagState(ISender sender) : base(sender) {} 6 | 7 | [JsonConstructor] 8 | public FeatureFlagState() {} 9 | 10 | public override void Initialize() => throw new NotImplementedException(); 11 | } 12 | -------------------------------------------------------------------------------- /tests/client-integration-tests/clone/test-state-clone-tests.cs: -------------------------------------------------------------------------------- 1 | namespace TestState_; 2 | 3 | using TestApp.Client.Integration.Tests.Clone; 4 | 5 | public class Clone_Should 6 | { 7 | 8 | public static void Clone() 9 | { 10 | 11 | // Arrange 12 | var testState = new TestState(); 13 | 14 | // Act 15 | TestState clone = testState.Clone(); 16 | 17 | // Assert 18 | clone.SortedFruits.Count().ShouldBe(7); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.ai/other/blog.md: -------------------------------------------------------------------------------- 1 | --- 2 | destination: Documentation/Blogs/ 3 | example post: D:\git\github\TheFreezeTeam\TheFreezeTeamBlog\Source\TheFreezeTeam.com\input\posts\steven-t-cramer\2023\07\2023-07-06.md 4 | --- 5 | 6 | # Blog 7 | 8 | Information needed to generate blog posts. 9 | The destination is the folder where the blog posts will be generated. 10 | The example post is the path to the markdown file that will be used as a template for the blog post. 11 | -------------------------------------------------------------------------------- /source/timewarp-state/wwwroot/js/constants.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"constants.js","sourceRoot":"","sources":["../typescript/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,iBAAiB,GAAW,eAAe,CAAC;AACzD,MAAM,CAAC,MAAM,YAAY,GAAW,UAAU,CAAA;AAC9C,MAAM,CAAC,MAAM,+BAA+B,GAAW,6BAA6B,CAAC;AACrF,MAAM,CAAC,MAAM,4BAA4B,GAAW,QAAQ,CAAC;AAC7D,MAAM,CAAC,MAAM,wBAAwB,GAAW,sBAAsB,CAAC;AACvE,MAAM,CAAC,MAAM,iBAAiB,GAAW,eAAe,CAAC;AACzD,MAAM,CAAC,MAAM,kBAAkB,GAAW,8BAA8B,CAAC"} -------------------------------------------------------------------------------- /source/timewarp-state/features/components/components/TimeWarpJavaScriptInterop.razor: -------------------------------------------------------------------------------- 1 | @namespace TimeWarp.Features.JavaScriptInterop 2 | 3 | @code { 4 | 5 | [Inject] private JsonRequestHandler JsonRequestHandler { get; set; } = null!; 6 | 7 | /// 8 | protected override async Task OnAfterRenderAsync(bool firstRender) 9 | { 10 | await JsonRequestHandler.InitAsync(); 11 | await base.OnAfterRenderAsync(firstRender); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /source/timewarp-state/features/redux-dev-tools/redux-action.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.Features.ReduxDevTools; 2 | 3 | internal class ReduxAction 4 | { 5 | public ReduxAction(object request) 6 | { 7 | ArgumentNullException.ThrowIfNull(request); 8 | 9 | Type = request.GetType().FullName ?? throw new InvalidOperationException(); 10 | Payload = request; 11 | } 12 | 13 | public object Payload { get; set; } 14 | public string Type { get; set; } 15 | } 16 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/auto/sample-00-auto/sample-00-auto/components/Routes.razor: -------------------------------------------------------------------------------- 1 | @namespace Sample00Auto.Components 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /samples/02-action-tracking/wasm/sample-02-wasm/_imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using System.Net.Http.Json 3 | @using Microsoft.AspNetCore.Components.Forms 4 | @using Microsoft.AspNetCore.Components.Routing 5 | @using Microsoft.AspNetCore.Components.Web 6 | @using Microsoft.AspNetCore.Components.Web.Virtualization 7 | @using Microsoft.AspNetCore.Components.WebAssembly.Http 8 | @using Microsoft.JSInterop 9 | @using Sample02Wasm 10 | @using Sample02Wasm.Layout 11 | -------------------------------------------------------------------------------- /source/timewarp-state/wwwroot/types/logger.d.ts: -------------------------------------------------------------------------------- 1 | export interface LogStyles { 2 | info: string; 3 | success: string; 4 | warning: string; 5 | error: string; 6 | function: string; 7 | } 8 | export declare const logStyles: LogStyles; 9 | export type LogLevel = keyof LogStyles; 10 | export declare enum LogAction { 11 | Begin = 0, 12 | End = 1 13 | } 14 | export declare const log: (tag: string, message: string, level?: LogLevel, action?: LogAction) => void; 15 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/auto/sample-00-auto/sample-00-auto-client/_imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using System.Net.Http.Json 3 | @using Microsoft.AspNetCore.Components.Forms 4 | @using Microsoft.AspNetCore.Components.Routing 5 | @using Microsoft.AspNetCore.Components.Web 6 | @using static Microsoft.AspNetCore.Components.Web.RenderMode 7 | @using Microsoft.AspNetCore.Components.Web.Virtualization 8 | @using Microsoft.JSInterop 9 | @using Sample00Auto.Client 10 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/wasm/sample-00-wasm/_imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using System.Net.Http.Json 3 | @using Microsoft.AspNetCore.Components.Forms 4 | @using Microsoft.AspNetCore.Components.Routing 5 | @using Microsoft.AspNetCore.Components.Web 6 | @using Microsoft.AspNetCore.Components.Web.Virtualization 7 | @using Microsoft.AspNetCore.Components.WebAssembly.Http 8 | @using Microsoft.JSInterop 9 | @using Sample00Wasm 10 | @using Sample00Wasm.Layout 11 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/wasm/sample-00-wasm/program.cs: -------------------------------------------------------------------------------- 1 | namespace Sample00Wasm; 2 | 3 | public class Program 4 | { 5 | public static async Task Main(string[] args) 6 | { 7 | var builder = WebAssemblyHostBuilder.CreateDefault(args); 8 | builder.RootComponents.Add("#app"); 9 | builder.RootComponents.Add("head::after"); 10 | 11 | builder.Services.AddTimeWarpState(); 12 | 13 | await builder.Build().RunAsync(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /source/timewarp-state/wwwroot/js/constants.js: -------------------------------------------------------------------------------- 1 | export const TimeWarpStateName = "TimeWarpState"; 2 | export const DevToolsName = "devTools"; 3 | export const InitializeJavaScriptInteropName = "InitializeJavaScriptInterop"; 4 | export const JsonRequestHandlerMethodName = "Handle"; 5 | export const ReduxDevToolsFactoryName = "ReduxDevToolsFactory"; 6 | export const ReduxDevToolsName = "reduxDevTools"; 7 | export const ReduxExtensionName = "__REDUX_DEVTOOLS_EXTENSION__"; 8 | //# sourceMappingURL=constants.js.map -------------------------------------------------------------------------------- /Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | $(Version) 6 | $(Version) 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /samples/02-action-tracking/wasm/sample-02-wasm/pages/Counter.razor: -------------------------------------------------------------------------------- 1 | @namespace Sample02Wasm.Pages 2 | @page "/counter" 3 | 4 | Counter 5 | 6 |

Counter

7 | 8 |

Current count: @currentCount

9 | 10 | 11 | 12 | @code { 13 | private int currentCount = 0; 14 | 15 | private void IncrementCount() 16 | { 17 | currentCount++; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /source/timewarp-state-policies/have-json-constructor.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.State.Policies; 2 | 3 | public class HaveJsonConstructor : ICustomRule 4 | { 5 | public bool MeetsRule(TypeDefinition typeDefinition) 6 | { 7 | var type = typeDefinition.ToType(); 8 | ConstructorInfo[] constructors = type.GetConstructors(BindingFlags.Public | BindingFlags.Instance); 9 | 10 | return constructors.Any(c => c.GetCustomAttributes(typeof(JsonConstructorAttribute), false).Length != 0); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/server/sample-00-server/components/_imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using System.Net.Http.Json 3 | @using Microsoft.AspNetCore.Components.Forms 4 | @using Microsoft.AspNetCore.Components.Routing 5 | @using Microsoft.AspNetCore.Components.Web 6 | @using static Microsoft.AspNetCore.Components.Web.RenderMode 7 | @using Microsoft.AspNetCore.Components.Web.Virtualization 8 | @using Microsoft.JSInterop 9 | @using Sample00Server 10 | @using Sample00Server.Components 11 | -------------------------------------------------------------------------------- /source/timewarp-state-analyzer/timewarp-state-analyzer.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | true 6 | true 7 | false 8 | $(ArtifactsDirectory)analyzers\$(Configuration)\ 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /source/timewarp-state/wwwroot/types/timewarp.state.lib.module.d.ts: -------------------------------------------------------------------------------- 1 | export declare function beforeWebStart(_options: any, _extensions: any): void; 2 | export declare function afterWebStarted(_blazor: any): void; 3 | export declare function beforeWebAssemblyStart(_options: any, _extensions: any): void; 4 | export declare function afterWebAssemblyStarted(_blazor: any): void; 5 | export declare function beforeServerStart(_options: any, _extensions: any): void; 6 | export declare function afterServerStarted(_blazor: any): void; 7 | -------------------------------------------------------------------------------- /tests/test-app-end-to-end-tests/configured-render-modes.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.EndToEnd.Tests; 2 | 3 | public static class ConfiguredRenderModes 4 | { 5 | public const string InteractiveAutoRenderMode = "InteractiveAutoRenderMode"; 6 | public const string InteractiveServerRenderMode = "InteractiveServerRenderMode"; 7 | public const string InteractiveWebAssemblyRenderMode = "InteractiveWebAssemblyRenderMode"; 8 | public const string None = "None"; 9 | // Add other configured render modes as needed 10 | } 11 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/features/application/application-state/application-state.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.Client.Features.Application; 2 | 3 | public sealed partial class ApplicationState : State 4 | { 5 | public string Name { get; private set; } = null!; 6 | public string? ExceptionMessage { get; private set; } 7 | 8 | public string? Version => GetType().Assembly.GetName().Version?.ToString(); 9 | 10 | public override void Initialize() => Name = "TimeWarp.State Test App"; 11 | } 12 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/features/blue/blue-state.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.Client.Features.Blue; 2 | 3 | [PersistentState(PersistentStateMethod.SessionStorage)] 4 | public sealed partial class BlueState : State 5 | { 6 | public int Count { get; private set; } 7 | 8 | public BlueState() { } 9 | 10 | [JsonConstructor] 11 | public BlueState(Guid guid, int count) 12 | { 13 | Guid = guid; 14 | Count = count; 15 | } 16 | 17 | public override void Initialize() => Count = 2; 18 | } 19 | -------------------------------------------------------------------------------- /source/timewarp-state/wwwroot/typescript/constants.ts: -------------------------------------------------------------------------------- 1 | export const TimeWarpStateName: string = "TimeWarpState"; 2 | export const DevToolsName: string = "devTools" 3 | export const InitializeJavaScriptInteropName: string = "InitializeJavaScriptInterop"; 4 | export const JsonRequestHandlerMethodName: string = "Handle"; 5 | export const ReduxDevToolsFactoryName: string = "ReduxDevToolsFactory"; 6 | export const ReduxDevToolsName: string = "reduxDevTools"; 7 | export const ReduxExtensionName: string = "__REDUX_DEVTOOLS_EXTENSION__"; 8 | -------------------------------------------------------------------------------- /documentation/blips/2024-02-time-warp-state-11-release.md: -------------------------------------------------------------------------------- 1 | # TimeWarp.State 11.0.0 Release 2 | 3 | 🚀 Announcing TimeWarp.State 11.0.0! 4 | 5 | Blazor-State has evolved into TimeWarp.State, bringing powerful new features for #Blazor state management: 6 | 7 | ✨ New TimeWarp.State.Plus package 8 | 🛡️ Architecture enforcement with TimeWarp.State.Policies 9 | ⚡ Enhanced performance & developer tools 10 | 🎯 Targeting .NET 8 11 | 12 | Learn more: [Blog Post Link] 13 | 14 | #dotnet #blazor #webdev #opensource 15 | -------------------------------------------------------------------------------- /documentation/migrations/migration9-10.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: BlazorState:Migration9-10.md 3 | title: Migrate From 9.X to 10.X 4 | --- 5 | 6 | # Migration 7 | 8 | ## From 9.x to 10.x 9 | 10 | If you were implementing IBlazorStateComponent in your own component. You no longer need to implement IMediator or IStore. 11 | 12 | If you were accessing either of these properties via the IBlazorStateComponent interface you will need to create your own interface to use that implements IBlazorStateComponent plus the properties you need. 13 | -------------------------------------------------------------------------------- /source/timewarp-state-source-generator/timewarp-state-source-generator.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | true 6 | true 7 | false 8 | $(ArtifactsDirectory)analyzers\$(Configuration)\ 9 | 10 | 11 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/features/purple/purple-state.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.Client.Features.Purple; 2 | 3 | [PersistentState(PersistentStateMethod.LocalStorage)] 4 | public sealed partial class PurpleState : State 5 | { 6 | public int Count { get; private set; } 7 | 8 | public PurpleState() { } 9 | 10 | [JsonConstructor] 11 | public PurpleState(Guid guid, int count) 12 | { 13 | Guid = guid; 14 | Count = count; 15 | } 16 | 17 | public override void Initialize() => Count = 1; 18 | } 19 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/auto/sample-00-auto/sample-00-auto/sample-00-auto.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Sample00Auto 5 | Sample00Auto 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /samples/01-redux-dev-tools/wasm/sample-01-wasm/layout/MainLayout.razor: -------------------------------------------------------------------------------- 1 | @namespace Sample01Wasm.Layout 2 | @inherits LayoutComponentBase 3 |
4 | 7 | 8 |
9 |
10 | About 11 |
12 | 13 |
14 | @Body 15 |
16 |
17 |
18 | -------------------------------------------------------------------------------- /samples/02-action-tracking/wasm/sample-02-wasm/layout/MainLayout.razor: -------------------------------------------------------------------------------- 1 | @namespace Sample02Wasm.Layout 2 | @inherits LayoutComponentBase 3 |
4 | 7 | 8 |
9 |
10 | About 11 |
12 | 13 |
14 | @Body 15 |
16 |
17 |
18 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/wasm/sample-00-wasm/layout/MainLayout.razor: -------------------------------------------------------------------------------- 1 | @namespace Sample00Wasm.Layout 2 | @inherits LayoutComponentBase 3 |
4 | 7 | 8 |
9 |
10 | About 11 |
12 | 13 |
14 | @Body 15 |
16 |
17 |
18 | -------------------------------------------------------------------------------- /source/timewarp-state/features/redux-dev-tools/requests/start/start-request.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.Features.ReduxDevTools; 2 | 3 | /// 4 | /// Request received from Redux Dev Tools when one presses the Start Button. 5 | /// 6 | internal class StartRequest : DispatchRequest, IRequest, IReduxRequest 7 | { 8 | internal class PayloadClass; 9 | public StartRequest(int id, PayloadClass payload, string source, string state, string type) 10 | : base(id, payload, source, state, type) {} 11 | } 12 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/features/color/color-state.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.Client.Features.Counter; 2 | 3 | using System.Drawing; 4 | 5 | public sealed partial class ColorState : State 6 | { 7 | public string MyColorName { get; private set; } = null!; 8 | 9 | public Color FavoriteColor { get; private set; } 10 | 11 | /// 12 | /// Set the Initial State 13 | /// 14 | public override void Initialize() 15 | { 16 | MyColorName = "Fools Gold"; 17 | FavoriteColor = Color.Gold; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.ai/other/shell-commands.md: -------------------------------------------------------------------------------- 1 | --- 2 | shell-commands: 3 | - name: fixie 4 | type: dotnet tool 5 | description: A .NET global tool for running tests with Fixie 6 | command: dotnet fixie 7 | install: dotnet tool install Fixie.Console 8 | - name: timewarp-sync 9 | type: dotnet tool 10 | description: A .NET global tool to synchronize and manage shared files across multiple repositories. 11 | --- 12 | # Shell Commands 13 | Shell commands available that we want AI to be aware of and recommend. Although they may not be in this repo. 14 | -------------------------------------------------------------------------------- /documentation/blips/2024-02-routing-sample.md: -------------------------------------------------------------------------------- 1 | # Routing Sample Released 2 | 3 | 🧭 Announcing the Routing sample for TimeWarp.State! 4 | 5 | Manage complex navigation flows with stack-based routing: 6 | 7 | 📚 Maintain history of visited routes 8 | 🔄 Enable breadcrumb-style navigation 9 | ⬅️ Support multi-step back navigation 10 | 📝 Automatic page title synchronization 11 | 12 | Explore the implementation: https://github.com/TimeWarpEngineering/timewarp-state/tree/main/Samples/03-Routing 13 | 14 | #blazor #dotnet #webdev #opensource 15 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/wasm/sample-00-wasm/sample-00-wasm.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Sample00Wasm 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/features/counter/counter-state.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.Client.Features.Counter; 2 | 3 | public sealed partial class CounterState : State 4 | { 5 | 6 | public int Count { get; private set; } 7 | 8 | public CounterState() { } 9 | 10 | [JsonConstructor] 11 | public CounterState(Guid guid, int count) 12 | { 13 | Guid = guid; 14 | Count = count; 15 | } 16 | 17 | /// 18 | /// Set the Initial State 19 | /// 20 | public override void Initialize() => Count = 3; 21 | } 22 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/auto/sample-00-auto/sample-00-auto-client/program.cs: -------------------------------------------------------------------------------- 1 | namespace Sample00Auto.Client; 2 | 3 | public class Program 4 | { 5 | static async Task Main(string[] args) 6 | { 7 | var builder = WebAssemblyHostBuilder.CreateDefault(args); 8 | ConfigureServices(builder.Services); 9 | await builder.Build().RunAsync(); 10 | } 11 | 12 | public static void ConfigureServices(IServiceCollection serviceCollection) 13 | { 14 | serviceCollection.AddTimeWarpState(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /source/timewarp-state/features/redux-dev-tools/requests/commit/commit-request.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.Features.ReduxDevTools; 2 | 3 | internal class CommitRequest : DispatchRequest, IRequest, IReduxRequest 4 | { 5 | internal class PayloadClass 6 | { 7 | public PayloadClass(string type) 8 | { 9 | Type = type; 10 | } 11 | public string Type { get; } 12 | } 13 | 14 | public CommitRequest(int id, PayloadClass payload, string source, string state, string type) : base(id, payload, source, state, type) {} 15 | } 16 | -------------------------------------------------------------------------------- /.ai/other/project-structure.md: -------------------------------------------------------------------------------- 1 | --- 2 | structure: 3 | - .ai/ 4 | - Assets/ 5 | - DevOps/ 6 | - Documentation/ 7 | - C4/ 8 | - Developer/ 9 | - StarUml/ 10 | - User/ 11 | - Kanban/ 12 | - Backlog/ 13 | - Done/ 14 | - InProgress/ 15 | - ToDo/ 16 | - Samples/ 17 | - Scripts/ 18 | - Git/ 19 | - Postgres/ 20 | - Windows/ 21 | - Source/ 22 | - Tests/ 23 | - Tools/ 24 | --- 25 | 26 | # Project Structure 27 | `.ai` folders can be used to store AI-related files, in any directory as needed to give more specific context. 28 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/test-objects/custom-collection-object.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable ConvertToPrimaryConstructor 2 | // ReSharper disable UnusedAutoPropertyAccessor.Global 3 | namespace AnyClone.Tests.TestObjects; 4 | 5 | using System.Collections.ObjectModel; 6 | 7 | public class CustomCollectionObject : Collection 8 | { 9 | public int CustomId { get; set; } 10 | public string CustomName { get; set; } 11 | public CustomCollectionObject(int customId, string customName) 12 | { 13 | CustomId = customId; 14 | CustomName = customName; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /documentation/blips/2024-02-action-tracking-sample.md: -------------------------------------------------------------------------------- 1 | # Action Tracking Sample Released 2 | 3 | 🎯 Announcing the Action Tracking sample for TimeWarp.State! 4 | 5 | See it in action: https://yoclip.app/share/ejqq4l6k52eca8gth9xnm251?pw=uju1sp3lzuszbfmuffe0c9zk 6 | 7 | The sample demonstrates tracking multiple concurrent actions of varying durations (2s and 5s) with real-time feedback in the UI. 8 | 9 | Explore the implementation: https://github.com/TimeWarpEngineering/timewarp-state/tree/main/Samples/02-ActionTracking 10 | 11 | #blazor #dotnet #webdev #opensource 12 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/features/counter/actions/non-nested-action/non-nested-handler.cs: -------------------------------------------------------------------------------- 1 | #if ANALYZER_TEST 2 | // Code examples that the analyzer should fail on 3 | namespace Test.App.Client.Features.Counter; 4 | 5 | public partial class CounterState 6 | { 7 | internal class NonNestedHandler 8 | ( 9 | IStore store 10 | ) : BaseActionHandler(store) 11 | { 12 | 13 | public override Task Handle 14 | ( 15 | NonNestedAction action, 16 | CancellationToken cancellationToken 17 | ) => Unit.Task; 18 | } 19 | } 20 | #endif 21 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/features/weather-forecast/weather-forecast-state.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.Client.Features.WeatherForecast; 2 | 3 | using static Contracts.Features.WeatherForecast.GetWeatherForecasts; 4 | 5 | public sealed partial class WeatherForecastsState: State 6 | { 7 | private Response? WeatherForecastList; 8 | 9 | public IReadOnlyList? WeatherForecasts => WeatherForecastList?.AsReadOnly(); 10 | 11 | /// 12 | public override void Initialize() 13 | { 14 | WeatherForecastList = null; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "github-actions" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | -------------------------------------------------------------------------------- /samples/03-routing/wasm/sample-03-wasm/layout/MainLayout.razor: -------------------------------------------------------------------------------- 1 | @namespace Sample03Wasm.Layout 2 | @inherits LayoutComponentBase 3 | 4 |
5 | 8 | 9 |
10 |
11 | About 12 |
13 | 14 |
15 | 16 |
17 | 18 |
19 | @Body 20 |
21 |
22 |
23 | 24 | -------------------------------------------------------------------------------- /source/timewarp-state/features/redux-dev-tools/dispatch-request.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.Features.ReduxDevTools; 2 | 3 | internal class DispatchRequest 4 | { 5 | protected DispatchRequest(int id, TPayload payload, string source, string state, string type) 6 | { 7 | Id = id; 8 | Payload = payload; 9 | Source = source; 10 | State = state; 11 | Type = type; 12 | } 13 | public int Id { get; set; } 14 | public TPayload Payload { get; set; } 15 | public string Source { get; set; } 16 | public string State { get; set; } 17 | public string Type { get; set; } 18 | } 19 | -------------------------------------------------------------------------------- /samples/01-redux-dev-tools/wasm/sample-01-wasm/_imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using System.Net.Http.Json 3 | @using Microsoft.AspNetCore.Components.Forms 4 | @using Microsoft.AspNetCore.Components.Routing 5 | @using Microsoft.AspNetCore.Components.Web 6 | @using Microsoft.AspNetCore.Components.Web.Virtualization 7 | @using Microsoft.AspNetCore.Components.WebAssembly.Http 8 | @using Microsoft.JSInterop 9 | @using Sample01Wasm 10 | @using Sample01Wasm.Layout 11 | @using TimeWarp.Features.JavaScriptInterop 12 | @using TimeWarp.Features.Routing 13 | @using TimeWarp.Features.Developer 14 | -------------------------------------------------------------------------------- /samples/01-redux-dev-tools/wasm/sample-01-wasm/sample-01-wasm.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Sample01Wasm 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /samples/02-action-tracking/wasm/sample-02-wasm/App.razor: -------------------------------------------------------------------------------- 1 | @namespace Sample02Wasm 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Not found 10 | 11 |

Sorry, there's nothing at this address.

12 |
13 |
14 |
15 | -------------------------------------------------------------------------------- /samples/02-action-tracking/wasm/sample-02-wasm/sample-02-wasm.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Sample02Wasm 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /tests/client-integration-tests/global-usings.cs: -------------------------------------------------------------------------------- 1 | global using AnyClone; 2 | global using TimeWarp.State; 3 | global using Shouldly; 4 | global using JetBrains.Annotations; 5 | global using TimeWarp.Mediator; 6 | global using Microsoft.AspNetCore.Mvc.Testing; 7 | global using Microsoft.Extensions.DependencyInjection; 8 | global using System.Linq; 9 | global using System.Net.Http; 10 | global using System.Reflection; 11 | global using System.Text.Json; 12 | global using Test.App.Client.Features.Application; 13 | global using TestApp.Client.Integration.Tests.Infrastructure; 14 | global using TimeWarp.Fixie; 15 | -------------------------------------------------------------------------------- /.ai/05-dotnet-conventions.md: -------------------------------------------------------------------------------- 1 | .NET CONVENTIONS: 2 | 3 | FRAMEWORK: 4 | - Target net8.0 5 | 6 | PROJECT CONFIGURATION: 7 | - Use Directory.Build.props for shared project properties 8 | - Use Directory.Packages.props for centralized package versioning 9 | - Enable nullable reference types 10 | 11 | SOLUTION MANAGEMENT: 12 | - Never edit .sln file directly 13 | ✓ `dotnet sln add ./src/MyProject/MyProject.csproj` 14 | ✗ Manual .sln file editing 15 | 16 | TOOLING: 17 | - Initialize local tool manifest 18 | ✓ ```pwsh 19 | dotnet new tool-manifest 20 | ``` 21 | Creates: .config/dotnet-tools.json 22 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/wasm/sample-00-wasm/App.razor: -------------------------------------------------------------------------------- 1 | @namespace Sample00Wasm 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Not found 10 | 11 |

Sorry, there's nothing at this address.

12 |
13 |
14 |
15 | -------------------------------------------------------------------------------- /tests/test-app/test-app-server/components/Routes.razor: -------------------------------------------------------------------------------- 1 | @namespace Test.App.Components 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /documentation/partials/getting-started.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: TimeWarp.State.GettingStarted.md 3 | title: Getting Started 4 | --- 5 | 6 | ## Getting Started 7 | 8 | I recommend the [samples](https://github.com/TimeWarpEngineering/timewarp-state/tree/master/Samples) for step-by-step guides to building Blazor apps with TimeWarp.State. 9 | 10 | 👉 Official [documentation](https://timewarpengineering.github.io/timewarp-state/). 11 | 12 | logo 13 | -------------------------------------------------------------------------------- /samples/01-redux-dev-tools/wasm/sample-01-wasm/program.cs: -------------------------------------------------------------------------------- 1 | namespace Sample01Wasm; 2 | 3 | public class Program 4 | { 5 | public static async Task Main(string[] args) 6 | { 7 | var builder = WebAssemblyHostBuilder.CreateDefault(args); 8 | builder.RootComponents.Add("#app"); 9 | builder.RootComponents.Add("head::after"); 10 | 11 | builder.Services.AddTimeWarpState 12 | ( 13 | options => 14 | { 15 | options.UseReduxDevTools(); // Enable Redux DevTools 16 | } 17 | ); 18 | 19 | await builder.Build().RunAsync(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /samples/03-routing/wasm/sample-03-wasm/_imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using System.Net.Http.Json 3 | @using Microsoft.AspNetCore.Components.Forms 4 | @using Microsoft.AspNetCore.Components.Routing 5 | @using Microsoft.AspNetCore.Components.Web 6 | @using Microsoft.AspNetCore.Components.Web.Virtualization 7 | @using Microsoft.AspNetCore.Components.WebAssembly.Http 8 | @using Microsoft.JSInterop 9 | @using Sample03Wasm 10 | @using Sample03Wasm.Layout 11 | @using TimeWarp.Features.Developer 12 | @using TimeWarp.Features.JavaScriptInterop 13 | @using TimeWarp.Features.Routing 14 | @using TimeWarp.State 15 | -------------------------------------------------------------------------------- /source/timewarp-state/assembly-marker.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.State; 2 | 3 | /// 4 | /// Serves as a marker for the assembly, facilitating easy identification and reflection-based operations. 5 | /// 6 | /// 7 | /// This class is intended to be used as a reference point within the assembly for scenarios such as assembly scanning, 8 | /// where a stable, known type is required to locate the assembly at runtime. The class is sealed to indicate it is not 9 | /// designed for inheritance or extension, reinforcing its role as a simple marker. 10 | /// 11 | public sealed class AssemblyMarker; 12 | -------------------------------------------------------------------------------- /source/timewarp-state/components/timewarp-state-component.render-reasons.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.State; 2 | 3 | public partial class TimeWarpStateComponent 4 | { 5 | public RenderReasonCategory RenderReason { get; private set; } = RenderReasonCategory.None; 6 | public string? RenderReasonDetail { get; private set; } 7 | public string? ShouldRenderWasCalledBy { get; private set; } 8 | 9 | public enum RenderReasonCategory 10 | { 11 | None, 12 | Event, 13 | ParameterChanged, 14 | UntrackedParameter, 15 | Subscription, 16 | RenderTrigger, 17 | StateHasChanged, 18 | Forced, 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/features/counter/components/Counter.razor: -------------------------------------------------------------------------------- 1 | @namespace Test.App.Client.Features.Counter.Components 2 | @inherits BaseComponent 3 | 4 | @code 5 | { 6 | protected override void OnInitialized() 7 | { 8 | //RegisterRenderTrigger(p => p.Count != CounterState.Count); 9 | RegisterRenderTrigger(p => p.Count); 10 | base.OnInitialized(); 11 | } 12 | } 13 | 14 |
15 |

CounterState.Count: @CounterState.Count

16 | 17 | 18 |
19 | -------------------------------------------------------------------------------- /tests/timewarp-state-analyzer-tests/.editorconfig: -------------------------------------------------------------------------------- 1 | # C# files in test projects 2 | [*Tests.cs] 3 | 4 | # Naming styles for test classes 5 | dotnet_naming_rule.test_classes_should_allow_underscore.symbols = test_classes 6 | dotnet_naming_rule.test_classes_should_allow_underscore.style = underscore_allowed_style 7 | dotnet_naming_rule.test_classes_should_allow_underscore.severity = suggestion 8 | 9 | dotnet_naming_symbols.test_classes.applicable_kinds = class 10 | dotnet_naming_symbols.test_classes.applicable_accessibilities = public 11 | 12 | dotnet_naming_style.underscore_allowed_style.capitalization = pascal_case 13 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/auto/sample-00-auto/sample-00-auto/components/_imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using System.Net.Http.Json 3 | @using Microsoft.AspNetCore.Components.Forms 4 | @using Microsoft.AspNetCore.Components.Routing 5 | @using Microsoft.AspNetCore.Components.Web 6 | @using static Microsoft.AspNetCore.Components.Web.RenderMode 7 | @using Microsoft.AspNetCore.Components.Web.Virtualization 8 | @using Microsoft.JSInterop 9 | @using Sample00Auto 10 | @using Sample00Auto.Client 11 | @using Sample00Auto.Components 12 | @using Sample00Auto.Components.Layout 13 | @using Sample00Auto.Components.Pages 14 | -------------------------------------------------------------------------------- /samples/03-routing/wasm/sample-03-wasm/wwwroot/sample-data/weather.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "date": "2022-01-06", 4 | "temperatureC": 1, 5 | "summary": "Freezing" 6 | }, 7 | { 8 | "date": "2022-01-07", 9 | "temperatureC": 14, 10 | "summary": "Bracing" 11 | }, 12 | { 13 | "date": "2022-01-08", 14 | "temperatureC": -13, 15 | "summary": "Freezing" 16 | }, 17 | { 18 | "date": "2022-01-09", 19 | "temperatureC": -16, 20 | "summary": "Balmy" 21 | }, 22 | { 23 | "date": "2022-01-10", 24 | "temperatureC": -2, 25 | "summary": "Chilly" 26 | } 27 | ] 28 | -------------------------------------------------------------------------------- /source/timewarp-state-plus/assembly-marker.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.State.Plus; 2 | 3 | /// 4 | /// Serves as a marker for the assembly, facilitating easy identification and reflection-based operations. 5 | /// 6 | /// 7 | /// This class is intended to be used as a reference point within the assembly for scenarios such as assembly scanning, 8 | /// where a stable, known type is required to locate the assembly at runtime. The class is sealed to indicate it is not 9 | /// designed for inheritance or extension, reinforcing its role as a simple marker. 10 | /// 11 | public sealed class AssemblyMarker; 12 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/assembly-marker.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.Client; 2 | 3 | /// 4 | /// Serves as a marker for the assembly, facilitating easy identification and reflection-based operations. 5 | /// 6 | /// 7 | /// This class is intended to be used as a reference point within the assembly for scenarios such as assembly scanning, 8 | /// where a stable, known type is required to locate the assembly at runtime. The class is sealed to indicate it is not 9 | /// designed for inheritance or extension, reinforcing its role as a simple marker. 10 | /// 11 | public sealed class AssemblyMarker { } 12 | -------------------------------------------------------------------------------- /samples/01-redux-dev-tools/wasm/sample-01-wasm/wwwroot/sample-data/weather.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "date": "2022-01-06", 4 | "temperatureC": 1, 5 | "summary": "Freezing" 6 | }, 7 | { 8 | "date": "2022-01-07", 9 | "temperatureC": 14, 10 | "summary": "Bracing" 11 | }, 12 | { 13 | "date": "2022-01-08", 14 | "temperatureC": -13, 15 | "summary": "Freezing" 16 | }, 17 | { 18 | "date": "2022-01-09", 19 | "temperatureC": -16, 20 | "summary": "Balmy" 21 | }, 22 | { 23 | "date": "2022-01-10", 24 | "temperatureC": -2, 25 | "summary": "Chilly" 26 | } 27 | ] 28 | -------------------------------------------------------------------------------- /samples/02-action-tracking/wasm/sample-02-wasm/wwwroot/sample-data/weather.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "date": "2022-01-06", 4 | "temperatureC": 1, 5 | "summary": "Freezing" 6 | }, 7 | { 8 | "date": "2022-01-07", 9 | "temperatureC": 14, 10 | "summary": "Bracing" 11 | }, 12 | { 13 | "date": "2022-01-08", 14 | "temperatureC": -13, 15 | "summary": "Freezing" 16 | }, 17 | { 18 | "date": "2022-01-09", 19 | "temperatureC": -16, 20 | "summary": "Balmy" 21 | }, 22 | { 23 | "date": "2022-01-10", 24 | "temperatureC": -2, 25 | "summary": "Chilly" 26 | } 27 | ] 28 | -------------------------------------------------------------------------------- /source/timewarp-state-plus/features/theme/theme-state/theme-state.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.Features.Theme; 2 | 3 | public sealed partial class ThemeState : State 4 | { 5 | public Theme CurrentTheme { get; private set; } 6 | 7 | public ThemeState(ISender sender) : base(sender) {} 8 | 9 | [JsonConstructor] 10 | public ThemeState() {} 11 | 12 | public override void Initialize() => CurrentTheme = Theme.System; 13 | 14 | /// 15 | /// Represents the different themes that the app can have. 16 | /// 17 | public enum Theme 18 | { 19 | Light, 20 | Dark, 21 | System 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/features/counter/actions/improper-nested-action/improper-nested-handler.cs: -------------------------------------------------------------------------------- 1 | #if ANALYZER_TEST 2 | // Code examples that the analyzer should fail on 3 | namespace Test.App.Client.Features.Counter; 4 | 5 | using static WrongNesting; 6 | 7 | public partial class CounterState 8 | { 9 | internal class ImproperNestedHandler 10 | ( 11 | IStore store 12 | ) : BaseActionHandler(store) 13 | { 14 | 15 | public override Task Handle 16 | ( 17 | ImproperNestedAction action, 18 | CancellationToken cancellationToken 19 | ) => Unit.Task; 20 | } 21 | } 22 | #endif 23 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/wasm/sample-00-wasm/wwwroot/sample-data/weather.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "date": "2022-01-06", 4 | "temperatureC": 1, 5 | "summary": "Freezing" 6 | }, 7 | { 8 | "date": "2022-01-07", 9 | "temperatureC": 14, 10 | "summary": "Bracing" 11 | }, 12 | { 13 | "date": "2022-01-08", 14 | "temperatureC": -13, 15 | "summary": "Freezing" 16 | }, 17 | { 18 | "date": "2022-01-09", 19 | "temperatureC": -16, 20 | "summary": "Balmy" 21 | }, 22 | { 23 | "date": "2022-01-10", 24 | "temperatureC": -2, 25 | "summary": "Chilly" 26 | } 27 | ] 28 | -------------------------------------------------------------------------------- /source/timewarp-state-plus/global-usings.cs: -------------------------------------------------------------------------------- 1 | global using Blazored.LocalStorage; 2 | global using Blazored.SessionStorage; 3 | global using TimeWarp.State; 4 | global using TimeWarp.Features.Persistence; 5 | global using JetBrains.Annotations; 6 | global using TimeWarp.Mediator; 7 | global using TimeWarp.Mediator.Pipeline; 8 | global using Microsoft.AspNetCore.Components; 9 | global using Microsoft.Extensions.Logging; 10 | global using Microsoft.Extensions.Options; 11 | global using Microsoft.JSInterop; 12 | global using System.Reflection; 13 | global using System.Text.Json; 14 | global using System.Text.Json.Serialization; 15 | global using TimeWarp.State.Plus; 16 | -------------------------------------------------------------------------------- /tests/client-integration-tests/convention-tests.cs: -------------------------------------------------------------------------------- 1 | namespace ConventionTest_; 2 | 3 | [TestTag(TestTags.Fast)] 4 | public class SimpleNoApplicationTest_Should_ 5 | { 6 | public static void AlwaysPass() => true.ShouldBeTrue(); 7 | 8 | [Skip("Demonstrates skip attribute")] 9 | public static void SkipExample() => true.ShouldBeFalse(); 10 | 11 | [TestTag(TestTags.Fast)] 12 | public static void TagExample() => true.ShouldBeTrue(); 13 | 14 | [Input(5, 3, 2)] 15 | [Input(8, 5, 3)] 16 | public static void Subtract(int x, int y, int expectedDifference) 17 | { 18 | int result = x - y; 19 | result.ShouldBe(expectedDifference); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tests/test-app/test-app-contracts/features/exception-handling/throw-server-side-exception/throw-server-side-exception-request.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.Contracts.Features.ExceptionHandlings; 2 | 3 | public class ThrowServerSideExceptionRequest : IRequest 4 | { 5 | private const string RouteTemplate = "api/ExceptionHandlings/ThrowServerSideException"; 6 | 7 | /// 8 | /// Set Properties and Update Docs 9 | /// 10 | /// TODO 11 | public string? SampleProperty { get; set; } 12 | 13 | public string GetRoute() => $"{RouteTemplate}?{nameof(SampleProperty)}={SampleProperty}"; 14 | } 15 | -------------------------------------------------------------------------------- /documentation/blips/2024-02-redux-dev-tools-sample.md: -------------------------------------------------------------------------------- 1 | # Redux DevTools Integration Sample Released 2 | 3 | 🔍 Announcing the Redux DevTools integration sample for TimeWarp.State! 4 | 5 | Enhance your debugging experience with practical tools: 6 | 7 | 📊 Monitor dispatched actions in real-time 8 | 🌳 Inspect your application's state tree 9 | 📝 Examine action payloads and timestamps 10 | 🔄 Track state changes as they happen 11 | 12 | Explore real-world debugging capabilities in our comprehensive sample: https://github.com/TimeWarpEngineering/timewarp-state/tree/main/Samples/01-ReduxDevTools 13 | 14 | #blazor #dotnet #debugging #webdev #opensource 15 | -------------------------------------------------------------------------------- /tests/timewarp-state-tests/convention-tests.cs: -------------------------------------------------------------------------------- 1 | namespace ConventionTest_; 2 | 3 | [TestTag(TestTags.Fast)] 4 | public class SimpleNoApplicationTest_Should_ 5 | { 6 | public static void AlwaysPass() => true.ShouldBeTrue(); 7 | 8 | [Skip("Demonstrates skip attribute")] 9 | public static void SkipExample() => true.ShouldBeFalse(); 10 | 11 | [TestTag(TestTags.Fast)] 12 | public static void TagExample() => true.ShouldBeTrue(); 13 | 14 | [Input(5, 3, 2)] 15 | [Input(8, 5, 3)] 16 | public static void Subtract(int aX, int aY, int aExpectedDifference) 17 | { 18 | int result = aX - aY; 19 | result.ShouldBe(aExpectedDifference); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tests/test-app-architecture-tests/convention-tests.cs: -------------------------------------------------------------------------------- 1 | namespace ConventionTest_; 2 | 3 | [TestTag(TestTags.Fast)] 4 | public class SimpleNoApplicationTest_Should_ 5 | { 6 | public static void AlwaysPass() => true.ShouldBeTrue(); 7 | 8 | [Skip("Demonstrates skip attribute")] 9 | public static void SkipExample() => true.ShouldBeFalse(); 10 | 11 | [TestTag(TestTags.Fast)] 12 | public static void TagExample() => true.ShouldBeTrue(); 13 | 14 | [Input(5, 3, 2)] 15 | [Input(8, 5, 3)] 16 | public static void Subtract(int aX, int aY, int aExpectedDifference) 17 | { 18 | int result = aX - aY; 19 | result.ShouldBe(aExpectedDifference); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tests/timewarp-state-plus-tests/convention-tests.cs: -------------------------------------------------------------------------------- 1 | namespace ConventionTest_; 2 | 3 | [TestTag(TestTags.Fast)] 4 | public class SimpleNoApplicationTest_Should_ 5 | { 6 | public static void AlwaysPass() => true.ShouldBeTrue(); 7 | 8 | [Skip("Demonstrates skip attribute")] 9 | public static void SkipExample() => true.ShouldBeFalse(); 10 | 11 | [TestTag(TestTags.Fast)] 12 | public static void TagExample() => true.ShouldBeTrue(); 13 | 14 | [Input(5, 3, 2)] 15 | [Input(8, 5, 3)] 16 | public static void Subtract(int aX, int aY, int aExpectedDifference) 17 | { 18 | int result = aX - aY; 19 | result.ShouldBe(aExpectedDifference); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /documentation/migrations/migration4-5.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: BlazorState:Migration4-5.md 3 | title: Migrate From 4.X to 5.X 4 | --- 5 | 6 | # Migration 7 | 8 | ## From 4.X to 5.X 9 | 10 | The biggest requirement will be to migrate to dotnet 6. See [Migrate from ASP.NET Core 5.0 to 6.0](https://docs.microsoft.com/en-us/aspnet/core/migration/50-to-60?view=aspnetcore-6.0&tabs=visual-studio) 11 | 12 | After completing that dotnet 6 migration the blazor-state specific changes are as follows: 13 | 14 | ### Remove the script tag in your index.html or _Host.cshtml files 15 | 16 | Delete: 17 | 18 | ```html 19 | 20 | ``` 21 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/auto/sample-00-auto/sample-00-auto-client/sample-00-auto-client.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Sample00Auto.Client 5 | true 6 | Default 7 | Sample00Auto.Client 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /tests/test-app-end-to-end-tests/configuration.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.EndToEnd.Tests; 2 | 3 | public static class Configuration 4 | { 5 | public static string GetSutBaseUrl() 6 | { 7 | string port = Environment.GetEnvironmentVariable("SutPort") ?? "7011"; 8 | string? useHttpEnv = Environment.GetEnvironmentVariable("UseHttp"); 9 | Console.WriteLine($"DEBUG: UseHttp environment variable = '{useHttpEnv}'"); 10 | string protocol = useHttpEnv == "true" ? "http" : "https"; 11 | string sutBaseUrl = $"{protocol}://localhost:{port}"; 12 | Console.WriteLine($"DEBUG: Using base URL = {sutBaseUrl}"); 13 | return sutBaseUrl; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.ai/01-user.md: -------------------------------------------------------------------------------- 1 | USER: 2 | - Name: Steven T. Cramer 3 | - Projects (Author): 4 | - https://github.com/TimeWarpEngineering/timewarp-state 5 | - https://github.com/TimeWarpEngineering/timewarp-architecture 6 | - https://github.com/TimeWarpEngineering/timewarp-fixie 7 | - https://github.com/TimeWarpEngineering/timewarp-options-validation 8 | - https://github.com/TimeWarpEngineering/timewarp-source-generators 9 | - Focus Areas: 10 | - State Management 11 | - Blazor 12 | - Clean Architecture 13 | - Domain-Driven Design 14 | - Test-Driven Development 15 | - Preferred Patterns: 16 | - CQRS 17 | - Language Preferences: 18 | - TypeScript over JavaScript -------------------------------------------------------------------------------- /source/timewarp-state/extensions/method-info-extensions.cs: -------------------------------------------------------------------------------- 1 | namespace System.Reflection; 2 | 3 | /// 4 | /// Use reflection to invoke an Async method. 5 | /// 6 | /// 7 | public static class MethodInfoExtensions 8 | { 9 | public static async Task InvokeAsync(this MethodInfo methodInfo, object @object, params object[] parameters) 10 | { 11 | dynamic awaitable = methodInfo.Invoke(@object, parameters) ?? throw new InvalidOperationException(); 12 | await awaitable; 13 | return awaitable.GetAwaiter().GetResult(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/test-app/test-app-server/components/App.razor: -------------------------------------------------------------------------------- 1 | @namespace Test.App.Components 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /tests/test-app/test-app-server/components/layout/MainLayout.razor: -------------------------------------------------------------------------------- 1 | @namespace Test.App.Components.Layout 2 | @inherits LayoutComponentBase 3 | 4 |
5 | 8 | 9 |
10 |
11 | About 12 |
13 | 14 |
15 | @Body 16 |
17 |
18 |
19 | 20 |
21 | An unhandled error has occurred. 22 | Reload 23 | 🗙 24 |
25 | -------------------------------------------------------------------------------- /tests/test-app-architecture-tests/test-app-architecture-tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/features/clone-test/cloneable-state.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.Client.Features.CloneTest; 2 | 3 | public sealed partial class CloneableState : State, ICloneable 4 | { 5 | public int Count { get; private set; } 6 | 7 | /// 8 | /// Set the Initial State 9 | /// 10 | public override void Initialize() => Count = 3; 11 | 12 | /// 13 | /// 14 | /// 15 | /// We are trying to prove ICloneable is used when available instead of AnyClone. 16 | /// New CloneableState object where Count is always 42 17 | public object Clone() => new CloneableState { Count = 42 }; 18 | } 19 | -------------------------------------------------------------------------------- /samples/01-redux-dev-tools/wasm/sample-01-wasm/pages/Counter.razor: -------------------------------------------------------------------------------- 1 | @namespace Sample01Wasm.Pages 2 | @page "/counter" 3 | @using Sample01Wasm.Features.Counter 4 | @inherits TimeWarp.State.TimeWarpStateComponent 5 | 6 | Counter 7 | 8 |

Counter

9 | 10 |

Current count: @currentCount

11 | 12 | 13 | 14 | @code { 15 | CounterState CounterState => GetState(); 16 | private int currentCount => CounterState.Count; 17 | 18 | private async Task IncrementCount() 19 | { 20 | await CounterState.IncrementCount(amount: 5); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /samples/03-routing/wasm/sample-03-wasm/pages/Counter.razor: -------------------------------------------------------------------------------- 1 | @namespace Sample03Wasm.Pages 2 | @page "/counter" 3 | @using Sample03Wasm.Features.Counter 4 | @inherits TimeWarp.State.TimeWarpStateComponent 5 | 6 | Counter 7 | 8 |

Counter

9 | 10 |

Current count: @currentCount

11 | 12 | 13 | 14 | @code { 15 | CounterState CounterState => GetState(); 16 | private int currentCount => CounterState.Count; 17 | 18 | private async Task IncrementCount() 19 | { 20 | await CounterState.IncrementCount(amount: 5); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/wasm/sample-00-wasm/pages/Counter.razor: -------------------------------------------------------------------------------- 1 | @namespace Sample00Wasm.Pages 2 | @page "/counter" 3 | @using Sample00Wasm.Features.Counter 4 | @inherits TimeWarp.State.TimeWarpStateComponent 5 | 6 | Counter 7 | 8 |

Counter

9 | 10 |

Current count: @currentCount

11 | 12 | 13 | 14 | @code { 15 | CounterState CounterState => GetState(); 16 | private int currentCount => CounterState.Count; 17 | 18 | private async Task IncrementCount() 19 | { 20 | await CounterState.IncrementCount(amount: 5); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/features/purple/components/PurpleCounter.razor: -------------------------------------------------------------------------------- 1 | @namespace Test.App.Client.Features.Purple.Components 2 | @inherits BaseComponent 3 |

Counter

4 | @RenderModeDisplay 5 | 6 | @if (IsPreRendering) 7 | { 8 |
CounterState.Guid:
9 |
Counter 1 count:
10 | } 11 | else 12 | { 13 |
CounterState.Guid: @PurpleState.Guid
14 |
Counter 1 count: @PurpleState.Count
15 | 16 | } 17 | 18 | @code 19 | { 20 | private async Task IncrementCount() => await Mediator.Send(new PurpleState.IncrementCountActionSet.Action { Amount = 5 }); 21 | } 22 | -------------------------------------------------------------------------------- /source/timewarp-state/wwwroot/js/timewarp-state.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"timewarp-state.js","sourceRoot":"","sources":["../typescript/timewarp-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,4BAA4B,EAAC,MAAM,gBAAgB,CAAC;AAE5D,OAAO,EAAC,GAAG,EAAC,MAAM,aAAa,CAAC;AAGhC,MAAM,OAAO,aAAa;IAGxB,kBAAkB,CAAkB;IAGpC,aAAa,CAAgB;IAQ7B,KAAK,CAAC,eAAe,CAAC,mBAA2B,EAAE,OAAgB;QACjE,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;QACjE,CAAC;QAGD,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAE9C,GAAG,CAAC,iBAAiB,EAAE,+BAA+B,mBAAmB,KAAK,aAAa,EAAE,EAAE,UAAU,CAAE,CAAC;QAG5G,MAAM,IAAI,CAAC,kBAAkB,CAAC,iBAAiB,CAAC,4BAA4B,EAAE,mBAAmB,EAAE,aAAa,CAAC,CAAC;IACpH,CAAC;CACF;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,aAAa,EAAE,CAAC"} -------------------------------------------------------------------------------- /documentation/partials/acknowledgements.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: TimeWarp.State.Acknowledgements.md 3 | title: Acknowledgements 4 | --- 5 | 6 | ## Acknowledgements 7 | 8 | Peter Morris and I have been friends for many years. 9 | He is an amazing developer and a person who has taught me a great deal. 10 | Not surprisingly, Pete and I think a lot a like. 11 | We both, independently, started working on our own State Management 12 | components. Although I started first. :P 13 | Pete's component attempts to solve most of the same problems. 14 | TimeWarp.State draws on the strengths of a proven async pipeline in Mediator, where as Fluxor 15 | implements its own middleware. 16 | If TimeWarp.State does not meet your needs be sure to checkout Fluxor. 17 | -------------------------------------------------------------------------------- /tests/test-app/test-app-server/components/_imports.razor: -------------------------------------------------------------------------------- 1 | 2 | @using TimeWarp.State 3 | @using Microsoft.AspNetCore.Components.Forms 4 | @using Microsoft.AspNetCore.Components.Routing 5 | @using Microsoft.AspNetCore.Components.Web 6 | @using Microsoft.AspNetCore.Components.Web.Virtualization 7 | @using Microsoft.JSInterop 8 | @using System.Net.Http 9 | @using System.Net.Http.Json 10 | @using Test.App 11 | @using Test.App.Client 12 | @using Test.App.Client.Components 13 | @using Test.App.Client.Features.Base.Components 14 | @using Test.App.Components 15 | @using TimeWarp.Features.Developer 16 | @using TimeWarp.Features.JavaScriptInterop 17 | @using TimeWarp.Features.Routing 18 | 19 | @using static Microsoft.AspNetCore.Components.Web.RenderMode 20 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/server/sample-00-server/components/App.razor: -------------------------------------------------------------------------------- 1 | @namespace Sample00Server.Components 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/auto/sample-00-auto/sample-00-auto/components/App.razor: -------------------------------------------------------------------------------- 1 | @namespace Sample00Auto.Components 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/server/sample-00-server/components/layout/MainLayout.razor: -------------------------------------------------------------------------------- 1 | @namespace Sample00Server.Components.Layout 2 | @inherits LayoutComponentBase 3 | 4 |
5 | 8 | 9 |
10 |
11 | About 12 |
13 | 14 |
15 | @Body 16 |
17 |
18 |
19 | 20 |
21 | An unhandled error has occurred. 22 | Reload 23 | 🗙 24 |
25 | -------------------------------------------------------------------------------- /source/timewarp-state-analyzer/AnalyzerReleases.Unshipped.md: -------------------------------------------------------------------------------- 1 | ; Unshipped analyzer release 2 | ; https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md 3 | 4 | ### New Rules 5 | 6 | Rule ID | Category | Severity | Notes 7 | --------|----------|----------|------- 8 | StateInheritanceTypeArgumentRule | Design | Error | StateInheritanceAnalyzer 9 | StateReadOnlyPublicPropertiesRule | Design | Error | StateReadOnlyPublicPropertiesAnalyzer 10 | StateSealedClassRule | Design | Warning | StateInheritanceAnalyzer 11 | TW0001 | TimeWarp.State | Error | TimeWarpStateActionAnalyzer 12 | TWD001 | Debug | Info | TimeWarpStateActionAnalyzer 13 | TWS001 | Design | Error | StateImplementationAnalyzer 14 | -------------------------------------------------------------------------------- /.mailmap: -------------------------------------------------------------------------------- 1 | Logan R. Golema 2 | Steven T. Cramer 3 | Steven T. Cramer 4 | Steven T. Cramer 5 | Steven T. Cramer 6 | Steven T. Cramer Steven Cramer 7 | Steven T. Cramer StevenTCramer 8 | Stefan L. Bemelmans 9 | Stefan L. Bemelmans 10 | -------------------------------------------------------------------------------- /documentation/migrations/toc.yml: -------------------------------------------------------------------------------- 1 | - name: From 10.x to 11.x 2 | topicUid: TimeWarpState:Migration10-11.md 3 | - name: From 9.x to 10.x 4 | topicUid: BlazorState:Migration9-10.md 5 | - name: From 8.x to 9.x 6 | topicUid: BlazorState:Migration8-9.md 7 | - name: From 7.x to 8.x 8 | topicUid: BlazorState:Migration7-8.md 9 | - name: From 6.x to 7.x 10 | topicUid: BlazorState:Migration6-7.md 11 | - name: From 5.x to 6.x 12 | topicUid: BlazorState:Migration5-6.md 13 | - name: From 4.x to 5.x 14 | topicUid: BlazorState:Migration4-5.md 15 | - name: From 3.x to 4.x 16 | topicUid: BlazorState:Migration3-4.md 17 | - name: From 2.x to 3.x 18 | topicUid: BlazorState:Migration2-3.md 19 | - name: From 1.x to 2.x 20 | topicUid: BlazorState:Migration1-2.md 21 | -------------------------------------------------------------------------------- /source/timewarp-state-policies/have-injectable-constructor.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.State.Policies; 2 | 3 | public class HaveInjectableConstructor : ICustomRule 4 | { 5 | public bool MeetsRule(TypeDefinition typeDefinition) 6 | { 7 | var type = typeDefinition.ToType(); 8 | ConstructorInfo[] constructors = type.GetConstructors(BindingFlags.Public | BindingFlags.Instance); 9 | 10 | return constructors.Any(IsInjectableConstructor); 11 | } 12 | 13 | private static bool IsInjectableConstructor(ConstructorInfo constructor) 14 | { 15 | ParameterInfo[] parameters = constructor.GetParameters(); 16 | return parameters.Length == 0 || parameters.All(p => !p.ParameterType.IsPrimitive && p.ParameterType != typeof(string)); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /documentation/blips/2024-02-state-action-handler-sample.md: -------------------------------------------------------------------------------- 1 | # StateActionHandler Pattern Samples Released 2 | 3 | 🎓 Announcing comprehensive samples for the StateActionHandler pattern in TimeWarp.State! 4 | 5 | Learn the core pattern through three different Blazor render mode implementations: 6 | 7 | 🔄 Auto render mode 8 | 🖥️ Server render mode 9 | ⚡ WebAssembly render mode 10 | 11 | Each sample demonstrates: 12 | - Immutable state management 13 | - Unidirectional data flow 14 | - Clean separation of concerns 15 | - Best practices for state handling 16 | 17 | Explore the samples: https://github.com/TimeWarpEngineering/timewarp-state/tree/main/Samples/00-StateActionHandler 18 | 19 | #blazor #dotnet #statemanagement #webdev #opensource 20 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/auto/sample-00-auto/sample-00-auto/components/layout/MainLayout.razor: -------------------------------------------------------------------------------- 1 | @namespace Sample00Auto.Components.Layout 2 | @inherits LayoutComponentBase 3 | 4 |
5 | 8 | 9 |
10 |
11 | About 12 |
13 | 14 |
15 | @Body 16 |
17 |
18 |
19 | 20 |
21 | An unhandled error has occurred. 22 | Reload 23 | 🗙 24 |
25 | -------------------------------------------------------------------------------- /source/timewarp-state/store/i-store.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.State; 2 | 3 | public interface IReduxDevToolsStore 4 | { 5 | IDictionary GetSerializableState(); 6 | 7 | void LoadStatesFromJson(string jsonString); 8 | } 9 | 10 | public interface IStore 11 | { 12 | Guid Guid { get; } 13 | 14 | TState GetState() where TState : IState; 15 | 16 | TState? GetPreviousState() where TState : IState; 17 | 18 | object GetState(Type stateType); 19 | 20 | SemaphoreSlim? GetSemaphore(Type stateType); 21 | 22 | void SetState(IState newState); 23 | 24 | void RemoveState() where TState : IState; 25 | 26 | void Reset(); 27 | 28 | ConcurrentDictionary StateInitializationTasks { get; } 29 | } 30 | -------------------------------------------------------------------------------- /tests/client-integration-tests/features/counter/counter-state-clone-tests.cs: -------------------------------------------------------------------------------- 1 | namespace CounterState; 2 | 3 | using Test.App.Client.Features.Counter; 4 | 5 | public class Clone_Should : BaseTest 6 | { 7 | public Clone_Should(ClientHost webAssemblyHost) : base(webAssemblyHost) 8 | { 9 | CounterState = Store.GetState(); 10 | } 11 | 12 | private CounterState CounterState { get; set; } 13 | 14 | public void Clone() 15 | { 16 | //Arrange 17 | CounterState.Initialize(count: 15); 18 | 19 | //Act 20 | CounterState? clone = CounterState.Clone(); 21 | 22 | //Assert 23 | CounterState.ShouldNotBeSameAs(clone); 24 | CounterState.Count.ShouldBe(clone.Count); 25 | CounterState.Guid.ShouldNotBe(clone.Guid); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/features/blue/actions/blue-state.increment-count.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.Client.Features.Blue; 2 | 3 | public partial class BlueState 4 | { 5 | public static class IncrementCountActionSet 6 | { 7 | internal sealed class Action : IAction 8 | { 9 | public int Amount { get; init; } 10 | } 11 | 12 | internal sealed class Handler 13 | ( 14 | IStore store 15 | ) : ActionHandler(store) 16 | { 17 | 18 | BlueState BlueState => Store.GetState(); 19 | 20 | public override Task Handle(Action action, CancellationToken cancellationToken) 21 | { 22 | BlueState.Count += action.Amount; 23 | return Task.CompletedTask; 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/features/application/application-state/application-state.reset-store.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.Client.Features.Application; 2 | 3 | public partial class ApplicationState 4 | { 5 | public static class ResetStoreActionSet 6 | { 7 | internal sealed class Action : IAction; 8 | 9 | internal sealed class Handler : IRequestHandler 10 | { 11 | private readonly IStore Store; 12 | public Handler(IStore store) 13 | { 14 | Store = store; 15 | } 16 | public async Task Handle(Action action, CancellationToken cancellationToken) 17 | { 18 | Store.Reset(); 19 | await Store.GetState().ChangeRoute(newRoute: "/", cancellationToken); 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /documentation/partials/installation.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: TimeWarp.State.Installation.md 3 | title: Installation 4 | --- 5 | 6 | ## Installation 7 | 8 | ```console 9 | dotnet add package TimeWarp.State 10 | dotnet add package TimeWarp.State.Plus 11 | ``` 12 | 13 | Check out the latest NuGet packages on the [TimeWarp Enterprises NuGet page](https://www.nuget.org/profiles/TimeWarp.Enterprises). 14 | 15 | * [TimeWarp.State](https://www.nuget.org/packages/TimeWarp.State/) [![nuget](https://img.shields.io/nuget/v/TimeWarp.State?logo=nuget)](https://www.nuget.org/packages/TimeWarp.State/) 16 | * [TimeWarp.State.Plus](https://www.nuget.org/packages/TimeWarp.State.Plus/) [![nuget](https://img.shields.io/nuget/v/TimeWarp.State.Plus?logo=nuget)](https://www.nuget.org/packages/TimeWarp.State.Plus/) 17 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/server/sample-00-server/components/pages/Counter.razor: -------------------------------------------------------------------------------- 1 | @namespace Sample00Server.Components.Pages 2 | @page "/counter" 3 | @rendermode InteractiveServer 4 | @using Sample00Server.Features.Counter 5 | @inherits TimeWarp.State.TimeWarpStateComponent 6 | 7 | Counter 8 | 9 |

Counter

10 | 11 |

Current count: @currentCount

12 | 13 | 14 | 15 | @code { 16 | CounterState CounterState => GetState(); 17 | private int currentCount => CounterState.Count; 18 | 19 | private async Task IncrementCount() 20 | { 21 | await CounterState.IncrementCount(amount: 5); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /samples/03-routing/wasm/sample-03-wasm/App.razor: -------------------------------------------------------------------------------- 1 | @namespace Sample03Wasm 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Not found 10 | 11 |

Sorry, there's nothing at this address.

12 |
13 |
14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/features/cacheable-weather/cacheable-weather-state.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.Client.Features.WeatherForecast; 2 | 3 | using static Contracts.Features.WeatherForecast.GetWeatherForecasts; 4 | 5 | public sealed partial class CacheableWeatherState: TimeWarpCacheableState 6 | { 7 | private Response? WeatherForecastList; 8 | 9 | public IReadOnlyList? WeatherForecasts => WeatherForecastList?.AsReadOnly(); 10 | 11 | public CacheableWeatherState() 12 | { 13 | CacheDuration = TimeSpan.FromSeconds(10); 14 | } // Set this to short duration for testing 15 | 16 | /// 17 | public override void Initialize() 18 | { 19 | WeatherForecastList = null; 20 | InvalidateCache(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/features/purple/actions/purple-state.increment-count.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.Client.Features.Purple; 2 | 3 | public partial class PurpleState 4 | { 5 | public static class IncrementCountActionSet 6 | { 7 | internal sealed class Action : IAction 8 | { 9 | public int Amount { get; init; } 10 | } 11 | 12 | internal sealed class Handler : ActionHandler 13 | { 14 | public Handler(IStore store) : base(store) {} 15 | PurpleState PurpleState => Store.GetState(); 16 | 17 | public override Task Handle(Action action, CancellationToken cancellationToken) 18 | { 19 | PurpleState.Count += action.Amount; 20 | return Task.CompletedTask; 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/test-app-end-to-end-tests/playwright-settings/webkit.runsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 24 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | webkit 17 | 5000 18 | 19 | true 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /tests/timewarp-state-plus-tests/timewarp-state-plus-tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TimeWarp.State.Plus.Tests 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /samples/01-redux-dev-tools/wasm/sample-01-wasm/App.razor: -------------------------------------------------------------------------------- 1 | @namespace Sample01Wasm 2 | 3 | 4 | 5 | 6 | 7 | 8 | Not found 9 | 10 |

Sorry, there's nothing at this address.

11 |
12 |
13 |
14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /tests/test-app-end-to-end-tests/playwright-settings/chrome.runsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 24 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | chromium 17 | 5000 18 | 19 | true 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /tests/test-app-end-to-end-tests/playwright-settings/firefox.runsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 24 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | firefox 17 | 5000 18 | 19 | true 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /samples/00-state-action-handler/auto/sample-00-auto/sample-00-auto-client/pages/Counter.razor: -------------------------------------------------------------------------------- 1 | @namespace Sample00Auto.Client.Pages 2 | @page "/counter" 3 | @rendermode InteractiveAuto 4 | @using Sample00Auto.Client.Features.Counter 5 | 6 | @inherits TimeWarp.State.TimeWarpStateComponent 7 | 8 | Counter 9 | 10 |

Counter

11 | 12 |

Current count: @currentCount

13 | 14 | 15 | 16 | @code 17 | { 18 | CounterState CounterState => GetState(); 19 | private int currentCount => CounterState.Count; 20 | 21 | private async Task IncrementCount() 22 | { 23 | await CounterState.IncrementCount(amount:5); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /samples/03-routing/wasm/sample-03-wasm/program.cs: -------------------------------------------------------------------------------- 1 | namespace Sample03Wasm; 2 | 3 | public class Program 4 | { 5 | public static async Task Main(string[] args) 6 | { 7 | var builder = WebAssemblyHostBuilder.CreateDefault(args); 8 | builder.RootComponents.Add("#app"); 9 | builder.RootComponents.Add("head::after"); 10 | 11 | builder.Services.AddScoped 12 | ( 13 | sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) } 14 | ); 15 | 16 | builder.Services.AddTimeWarpState 17 | ( 18 | options => 19 | { 20 | options.UseReduxDevTools(); 21 | } 22 | ); 23 | 24 | builder.Services.AddTimeWarpStateRouting(); 25 | 26 | await builder.Build().RunAsync(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /.ai/02-development-process.md: -------------------------------------------------------------------------------- 1 | DEVELOPMENT PROCESS: 2 | 3 | KANBAN STRUCTURE: 4 | - Track work using Kanban tasks 5 | - Folders: 6 | - Kanban/Backlog/ 7 | - Kanban/ToDo/ 8 | - Kanban/InProgress/ 9 | - Kanban/Done/ 10 | 11 | TASK MANAGEMENT: 12 | - Task Template Location: `Kanban\Task-Template.md` 13 | - Task File Format: _.md 14 | ✓ `002_Create-Game-Logic.md` 15 | 16 | COMMIT CONVENTIONS: 17 | - Make git commits between steps 18 | - Format: Task: = 19 | ✓ `Task: 002 = Complete Create Game Logic` 20 | 21 | TASK WORKFLOW: 22 | ✓ Example of proper task movement: 23 | ```pwsh 24 | git mv Kanban/InProgress/002_Create-Game-Logic.md Kanban/Done/002_Create-Game-Logic.md 25 | git commit -m "Task: 002 = Complete Create Game Logic" 26 | ``` 27 | -------------------------------------------------------------------------------- /documentation/release-notes/toc.yml: -------------------------------------------------------------------------------- 1 | - name: Release 11.0.0 2 | topicUid: TimeWarpState:Release.11.0.0.md 3 | - name: Release 10.0.0 4 | topicUid: BlazorState:Release.10.0.0.md 5 | - name: Release 9.0.0 6 | topicUid: BlazorState:Release.9.0.0.md 7 | - name: Release 8.0.0 8 | topicUid: BlazorState:Release.8.0.0.md 9 | - name: Release 7.0.0 10 | topicUid: BlazorState:Release.7.0.0.md 11 | - name: Release 6.0.0 12 | topicUid: BlazorState:Release.6.0.0.md 13 | - name: Release 5.0.0 14 | topicUid: BlazorState:Release.5.0.0.md 15 | - name: Release 4.0.0 16 | topicUid: BlazorState:Release.4.0.0.md 17 | - name: Release 3.0.0 18 | topicUid: BlazorState:Release.3.0.0.md 19 | - name: Release 2.0.0 20 | topicUid: BlazorState:Release.2.0.0.md 21 | - name: Release 1.0.0 22 | topicUid: BlazorState:Release.1.0.0.md 23 | -------------------------------------------------------------------------------- /source/timewarp-state/wwwroot/js/logger.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"logger.js","sourceRoot":"","sources":["../typescript/logger.ts"],"names":[],"mappings":"AASA,MAAM,CAAC,MAAM,SAAS,GAAc;IAClC,IAAI,EAAE,wCAAwC;IAC9C,OAAO,EAAE,sCAAsC;IAC/C,OAAO,EAAE,uCAAuC;IAChD,KAAK,EAAE,oCAAoC;IAC3C,QAAQ,EAAE,yCAAyC;CACpD,CAAC;AAIF,MAAM,CAAN,IAAY,SAGX;AAHD,WAAY,SAAS;IACnB,2CAAK,CAAA;IACL,uCAAG,CAAA;AACL,CAAC,EAHW,SAAS,KAAT,SAAS,QAGpB;AAED,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,GAAW,EAAE,OAAe,EAAE,QAAkB,MAAM,EAAE,MAAkB,EAAQ,EAAE;IACtG,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;IAE/B,IAAI,MAAM,KAAK,SAAS,CAAC,KAAK,EAAE,CAAC;QAC/B,OAAO,CAAC,KAAK,CAAC,KAAK,GAAG,EAAE,EAAE,KAAK,CAAC,CAAC;IACnC,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,KAAK,GAAG,IAAI,OAAO,EAAE,EAAE,KAAK,CAAC,CAAC;IAE1C,IAAI,MAAM,KAAK,SAAS,CAAC,GAAG,EAAE,CAAC;QAC7B,OAAO,CAAC,QAAQ,EAAE,CAAC;IACrB,CAAC;AACH,CAAC,CAAC"} -------------------------------------------------------------------------------- /.ai/Index.md: -------------------------------------------------------------------------------- 1 | # Index 2 | 3 | ## Purpose of the .ai folder 4 | 5 | The `.ai` folder is specifically designed to contain documents intended for Large Language Model (LLM) consumption. These files provide context, guidelines, and structured information about the project, which helps LLMs like myself to better understand and assist with the project. 6 | 7 | The contents of this folder are not typically used directly by the application or developers during normal development. Instead, they serve as a knowledge base for AI assistants, enabling more accurate and context-aware responses when working on the project. 8 | 9 | ## Usage 10 | 11 | When interacting with an AI assistant about this project, you can refer to the contents of the `.ai` folder or ask the AI to consider specific files within this folder for more informed assistance. 12 | -------------------------------------------------------------------------------- /tests/client-integration-tests/client-integration-tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Client.Integration.Tests 5 | $(NoWarn);1591 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /documentation/release-notes/release3.0.0.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: BlazorState:Release.3.0.0.md 3 | title: Release 3.0.0 4 | --- 5 | 6 | ## Release 3.0.0 7 | 8 | ### Breaking Changes 9 | Blazor-State has moved to netstandard 2.1 10 | The BlazorState Javascript location has changed. 11 | 12 | See [Migrations](xref:BlazorState:Migration1-2.md) for how to migrate existing projects from 1.0 to 2.0. 13 | 14 | ## Release 3.0.1 15 | 16 | Update Nuget Dev Dependencies: SourceLink, Fixie 17 | Update Nuget Production Dependency: TypeSupport now supports HashTables. 18 | 19 | ## Release 3.1.0 20 | 21 | AddBlazorState Extention method has been updated to automatically register all classes that inherit from `State<>`. 22 | Thus we no longer need to explicitly register States. 23 | 24 | Updated Mediator to 8.0 https://jimmybogard.com/mediatr-8-0-released/ -------------------------------------------------------------------------------- /tests/test-app-end-to-end-tests/test-app-end-to-end-tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | true 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /source/timewarp-state/state/i-state.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.State; 2 | 3 | public interface IState 4 | { 5 | ISender Sender { get; set; } 6 | Guid Guid { get; } 7 | // string? CacheKey { get; } 8 | // DateTime? TimeStamp { get; } 9 | // TimeSpan CacheDuration { get; } 10 | // bool IsCacheValid(string currentCacheKey); 11 | 12 | void Initialize(); 13 | public void CancelOperations(); 14 | } 15 | 16 | public interface IState : IState 17 | { 18 | /// 19 | /// Set the state from Dictionary 20 | /// Used by ReduxDevTools to support TimeTravel 21 | /// 22 | /// 23 | /// 24 | /// Only needed for time travel which I think is waste anyway. 25 | TState Hydrate(IDictionary keyValuePairs); 26 | } 27 | -------------------------------------------------------------------------------- /documentation/release-notes/release9.0.0.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: BlazorState:Release.9.0.0.md 3 | title: Release 9.0.0 4 | --- 5 | 6 | ## Release 9.0.0 7 | 8 | ### Breaking Changes 9 | 10 | * Blazor-State now requires MediatR version 12.1.1 which actually should have been a breaking change on MediatR. 11 | 12 | See [Migrations](xref:BlazorState:Migration8-9.md) for instructions on how to migrate from version 8.0 to 9.0. 13 | 14 | ### Other Changes 15 | 16 | * Updates to the Sample app and test app to use MediatR version 12.1 17 | * Update Microsoft.CodeAnalysis.Common 4.6.0 -> 4.7.0 18 | * Update Microsoft.CodeAnalysis.CSharp.Workspaces 4.6.0 -> 4.7.0 19 | * Updates other development dependencies 20 | 21 | 22 | ## Release 9.0.1 23 | 24 | * Added InvalidCloneException to assist in detecting when the clone did not work as expected. -------------------------------------------------------------------------------- /source/timewarp-state-policies/be-nested-in-state-custom-rule.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.State.Policies; 2 | 3 | public class BeNestedInStateCustomRule:ICustomRule 4 | { 5 | public bool MeetsRule(TypeDefinition typeDefinition) 6 | { 7 | var type = typeDefinition.ToType(); 8 | 9 | while (type.DeclaringType != null && !typeof(IState).IsAssignableFrom(type)) 10 | { 11 | type = type.DeclaringType; 12 | } 13 | 14 | bool result = typeof(IState).IsAssignableFrom(type); 15 | 16 | return result; 17 | } 18 | } 19 | 20 | public class BeNestedInActionSetCustomRule:ICustomRule 21 | { 22 | public bool MeetsRule(TypeDefinition typeDefinition) 23 | { 24 | var type = typeDefinition.ToType(); 25 | bool result = type?.DeclaringType?.Name.EndsWith("ActionSet") == true; 26 | 27 | return result; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /documentation/release-notes/release1.0.0.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: BlazorState:Release.1.0.0.md 3 | title: Release 1.0.0 4 | --- 5 | 6 | # Migration 7 | 8 | ## From 1.X to 2.X 9 | 10 | > [!WARNING] 11 | > ReduxDevTools should NOT be enabled in production. 12 | 13 | In 1.0 ReduxDevTools were enabled by default, in 2.0 they are disabled by default. 14 | 15 | If your code previously used the default to enabled ReduxDevTools you will now need to explicitly enable it as in the following example `ConfigureServices` method inside `Startup.cs`: 16 | 17 | ```csharp 18 | aServiceCollection.AddBlazorState 19 | ( 20 | (aOptions) => 21 | { 22 | aOptions.UseReduxDevToolsBehavior = true; // Add This Line 23 | aOptions.Assemblies = 24 | new Assembly[] 25 | { 26 | typeof(Startup).GetTypeInfo().Assembly, 27 | }; 28 | } 29 | ); 30 | ``` -------------------------------------------------------------------------------- /source/timewarp-state/wwwroot/js/timewarp-state.js: -------------------------------------------------------------------------------- 1 | import { JsonRequestHandlerMethodName } from './constants.js'; 2 | import { log } from './logger.js'; 3 | export class TimeWarpState { 4 | jsonRequestHandler; 5 | reduxDevTools; 6 | async DispatchRequest(requestTypeFullName, request) { 7 | if (!this.jsonRequestHandler) { 8 | throw new Error('jsonRequestHandler is not initialized. Add '); 9 | } 10 | const requestAsJson = JSON.stringify(request); 11 | log("DispatchRequest", `Dispatching request of Type ${requestTypeFullName}: ${requestAsJson}`, "function"); 12 | await this.jsonRequestHandler.invokeMethodAsync(JsonRequestHandlerMethodName, requestTypeFullName, requestAsJson); 13 | } 14 | } 15 | export const timeWarpState = new TimeWarpState(); 16 | //# sourceMappingURL=timewarp-state.js.map -------------------------------------------------------------------------------- /documentation/migrations/migration1-2.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: BlazorState:Migration1-2.md 3 | title: Migrate From 1.X to 2.X 4 | --- 5 | 6 | # Migration 7 | 8 | ## From 1.X to 2.X 9 | 10 | > [!WARNING] 11 | > ReduxDevTools should NOT be enabled in production. 12 | 13 | In 1.0 ReduxDevTools were enabled by default, in 2.0 they are disabled by default. 14 | 15 | If your code previously used the default to enabled ReduxDevTools you will now need to explicitly enable it as in the following example `ConfigureServices` method inside `Startup.cs`: 16 | 17 | ```csharp 18 | aServiceCollection.AddBlazorState 19 | ( 20 | (aOptions) => 21 | { 22 | aOptions.UseReduxDevToolsBehavior = true; // Add This Line 23 | aOptions.Assemblies = 24 | new Assembly[] 25 | { 26 | typeof(Startup).GetTypeInfo().Assembly, 27 | }; 28 | } 29 | ); 30 | ``` -------------------------------------------------------------------------------- /samples/03-routing/wasm/sample-03-wasm/sample-03-wasm.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Sample03Wasm 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /tests/test-app/test-app-server/test-app-server.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Test.App.Server 5 | Test.App.Server 6 | false 7 | false 8 | false 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/features/counter/actions/counter-state.increment-counter.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.Client.Features.Counter; 2 | 3 | public partial class CounterState 4 | { 5 | public static class IncrementCountActionSet 6 | { 7 | 8 | internal sealed class Action : IAction 9 | { 10 | public int Amount { get; init; } 11 | } 12 | 13 | internal sealed class Handler 14 | ( 15 | IStore store 16 | ) : ActionHandler(store) 17 | { 18 | private CounterState CounterState => Store.GetState(); 19 | 20 | public override Task Handle 21 | ( 22 | Action action, 23 | CancellationToken cancellationToken 24 | ) 25 | { 26 | CounterState.Count += action.Amount; 27 | return Task.CompletedTask; 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /scripts/fix-analyzer-debug.reg: -------------------------------------------------------------------------------- 1 | Windows Registry Editor Version 5.00 2 | 3 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\Notify] 4 | 5 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\Notify\SensLogn] 6 | "DLLName"="WlNotify.dll" 7 | "Lock"="SensLockEvent" 8 | "Logon"="SensLogonEvent" 9 | "Logoff"="SensLogoffEvent" 10 | "Safe"=dword:00000001 11 | "MaxWait"=dword:00000258 12 | "StartScreenSaver"="SensStartScreenSaverEvent" 13 | "StopScreenSaver"="SensStopScreenSaverEvent" 14 | "Startup"="SensStartupEvent" 15 | "Shutdown"="SensShutdownEvent" 16 | "StartShell"="SensStartShellEvent" 17 | "PostShell"="SensPostShellEvent" 18 | "Disconnect"="SensDisconnectEvent" 19 | "Reconnect"="SensReconnectEvent" 20 | "Unlock"="SensUnlockEvent" 21 | "Impersonate"=dword:00000001 22 | "Asynchronous"=dword:00000001 -------------------------------------------------------------------------------- /documentation/release-notes/release2.0.0.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: BlazorState:Release.2.0.0.md 3 | title: Release 2.0.0 4 | --- 5 | 6 | ## Release 2.0.0 7 | 8 | ### Breaking Changes 9 | Since have moved from preview builds to release, and ReduxDevTools should be disabled in production, we are changing the default option setting to be disabled. 10 | 11 | `BlazorStateOptions.UseReduxDevToolsBehavior` now defaults to false; 12 | 13 | See [Migrations](xref:BlazorState:Migration1-2.md) for how to migrate existing projects from 1.0 to 2.0. 14 | 15 | ### Improvements 16 | 17 | `Action`s and their `Handler`s should be nested classes of the `State` they act on. Previously the developer could forget this and it would take some time to figure out the problem (I know I did it.). Now RenderSubscriptionsPostProcessor will throw an exception if the IAction is not nested within an IState. 18 | -------------------------------------------------------------------------------- /kanban/backlog/scratch/done.md: -------------------------------------------------------------------------------- 1 | - [x] Update RouteManager to subscribe to Route Change and update the URL if not already there. 2 | - [x] Search with powergrep for "" 3 | if blazor-state\Directory.Build.props has `preview` then do we need it in all the others? 4 | - [x] Extract common items to Directory.Build.props 5 | - [x] ReduxDevToolsBehavoir uses the pipeline but we probably don't care to log those interaction. 6 | So Maybe we should add a Filter to ignore logging some request IReduxAction marker or something? 7 | - [x] Move ReduxDevToolsBehavoir to top of pipeline. 8 | So when doing time travel we can disable actions from actually being executed. 9 | - [x] Move JavaScriptInterop Folder out of Behaviors (It isn't a behavior) although ReduxDevTools depends on it. 10 | This will let dev tools go back to pages. 11 | -------------------------------------------------------------------------------- /samples/02-action-tracking/wasm/sample-02-wasm/features/demo/demo-state.five-second-action.cs: -------------------------------------------------------------------------------- 1 | namespace Sample02Wasm.Features.Demo; 2 | 3 | partial class DemoState 4 | { 5 | public static class FiveSecondActionSet 6 | { 7 | [TrackAction] 8 | public sealed class Action : IAction { } 9 | 10 | public sealed class Handler : ActionHandler 11 | { 12 | public Handler(IStore store) : base(store) { } 13 | 14 | public override async Task Handle 15 | ( 16 | Action action, 17 | CancellationToken cancellationToken 18 | ) 19 | { 20 | // Simulate a 5-second action 21 | await Task.Delay(TimeSpan.FromSeconds(5), cancellationToken); 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /samples/02-action-tracking/wasm/sample-02-wasm/features/demo/demo-state.two-second-action.cs: -------------------------------------------------------------------------------- 1 | namespace Sample02Wasm.Features.Demo; 2 | 3 | partial class DemoState 4 | { 5 | public static class TwoSecondActionSet 6 | { 7 | [TrackAction] 8 | public sealed class Action : IAction { } 9 | 10 | public sealed class Handler : ActionHandler 11 | { 12 | public Handler(IStore store) : base(store) { } 13 | 14 | public override async Task Handle 15 | ( 16 | Action action, 17 | CancellationToken cancellationToken 18 | ) 19 | { 20 | // Simulate a 2-second action 21 | await Task.Delay(TimeSpan.FromSeconds(2), cancellationToken); 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/test-app-end-to-end-tests/sample-test.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.EndToEnd.Tests; 2 | 3 | [TestClass] 4 | public class ExampleTest : PageTest 5 | { 6 | [TestMethod] 7 | public async Task HasTitle() 8 | { 9 | await Page.GotoAsync("https://playwright.dev"); 10 | 11 | // Expect a title "to contain" a substring. 12 | await Expect(Page).ToHaveTitleAsync(new Regex("Playwright")); 13 | } 14 | 15 | [TestMethod] 16 | public async Task GetStartedLink() 17 | { 18 | await Page.GotoAsync("https://playwright.dev"); 19 | 20 | // Click the get started link. 21 | await Page.GetByRole(AriaRole.Link, new() { Name = "Get started" }).ClickAsync(); 22 | 23 | // Expects page to have a heading with the name of Installation. 24 | await Expect(Page.GetByRole(AriaRole.Heading, new() { Name = "Installation" })).ToBeVisibleAsync(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/timewarp-state-analyzer-tests/timewarp-state-analyzer-tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | $(NoWarn);NU1701 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/features/counter/notification/pre-increment-count-notification-handler.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.Client.Features.Counter; 2 | 3 | internal class PreIncrementCountNotificationHandler 4 | ( 5 | ILogger logger 6 | ) : INotificationHandler> 7 | { 8 | private readonly ILogger Logger = logger; 9 | 10 | public Task Handle 11 | ( 12 | PrePipelineNotification prePipelineNotification, 13 | CancellationToken cancellationToken 14 | ) 15 | { 16 | Logger.LogDebug("{prePipelineNotification_Request_Type_Name}", prePipelineNotification.Request.GetType().Name); 17 | Logger.LogDebug("{methodName} handled", nameof(IncrementCountNotificationHandler)); 18 | return Task.CompletedTask; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/test-app-end-to-end-tests/home-page-test.cs: -------------------------------------------------------------------------------- 1 | namespace HomePage_; 2 | 3 | [TestClass] 4 | public class Should_ : PageTest 5 | { 6 | [TestMethod] 7 | public async Task RenderStaticContent() 8 | { 9 | string sutBaseUrl = Configuration.GetSutBaseUrl() ?? throw new InvalidOperationException("SUT base URL is not configured. Please check your test configuration."); 10 | await Page.GotoAsync(sutBaseUrl); 11 | Console.WriteLine($"Browser: {Page.Context.Browser?.BrowserType.Name}"); 12 | Console.WriteLine($"Browser Version: {Page.Context.Browser?.Version}"); 13 | Console.WriteLine($"User Agent: {await Page.EvaluateAsync("() => navigator.userAgent")}"); 14 | 15 | await Expect(Page).ToHaveTitleAsync("TimeWarp.State Test App"); 16 | await PageUtilities.ValidateRenderModesAsync(this, Page, RenderModes.Static, ConfiguredRenderModes.None); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests/test-app-end-to-end-tests/playwright-settings/edge.runsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 24 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | chromium 17 | 5000 18 | 19 | true 20 | msedge 21 | 22 | --headless=new 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/features/event-stream/actions/add-event/event-stream-state.add-event-action.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.Client.Features.EventStream; 2 | 3 | public partial class EventStreamState 4 | { 5 | public static class AddEventActionSet 6 | { 7 | 8 | internal sealed class Action : IAction 9 | { 10 | public string Message { get; } 11 | public Action(string message) 12 | { 13 | Message = message; 14 | } 15 | } 16 | 17 | internal sealed class AddEventHandler 18 | ( 19 | IStore store 20 | ) : BaseActionHandler(store) 21 | { 22 | 23 | public override Task Handle 24 | ( 25 | Action action, 26 | CancellationToken cancellationToken 27 | ) 28 | { 29 | EventStreamState.EventList.Add(action.Message); 30 | return Task.CompletedTask; 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /source/timewarp-state-plus/features/theme/theme-state/theme-state.update.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.Features.Theme; 2 | 3 | public partial class ThemeState 4 | { 5 | public static class UpdateActionSet 6 | { 7 | internal sealed class Action : IAction 8 | { 9 | public Theme NewTheme { get; } 10 | public Action(Theme newTheme) 11 | { 12 | NewTheme = newTheme; 13 | } 14 | } 15 | 16 | internal sealed class Handler 17 | ( 18 | IStore store 19 | ): ActionHandler(store) 20 | { 21 | private ThemeState ThemeState => Store.GetState(); 22 | 23 | public override Task Handle 24 | ( 25 | Action action, 26 | CancellationToken cancellationToken 27 | ) 28 | { 29 | ThemeState.CurrentTheme = action.NewTheme; 30 | return Task.CompletedTask; 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /source/timewarp-state/extensions/type-extensions.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.State.Extensions; 2 | 3 | public static class TypeExtensions 4 | { 5 | public static Type GetEnclosingStateType(this Type type) 6 | { 7 | string name = type.Name; 8 | while (type.DeclaringType != null && !typeof(IState).IsAssignableFrom(type)) 9 | { 10 | type = type.DeclaringType; 11 | } 12 | 13 | if (!typeof(IState).IsAssignableFrom(type)) 14 | { 15 | throw new NonNestedClassException 16 | ($"{name} must be nested in a class that implements {nameof(IState)}"); 17 | } 18 | 19 | return type; 20 | } 21 | 22 | public static string GetSimpleName(this Type type) 23 | { 24 | ReadOnlySpan nameSpan = type.Name.AsSpan(); 25 | int backtickIndex = nameSpan.IndexOf('`'); 26 | return backtickIndex >= 0 ? nameSpan[..backtickIndex].ToString() : nameSpan.ToString(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /source/timewarp-state/wwwroot/types/redux-dev-tools.d.ts: -------------------------------------------------------------------------------- 1 | import { TimeWarpState } from './timewarp-state.js'; 2 | type Config = any; 3 | type ConnectResponse = any; 4 | type ReduxDevtoolsExtension = any; 5 | export declare class ReduxDevTools { 6 | IsEnabled: boolean; 7 | DevTools: ConnectResponse; 8 | Extension: ReduxDevtoolsExtension; 9 | Config: Config; 10 | TimeWarpState: TimeWarpState; 11 | StackTrace: string | undefined; 12 | private IsInitialized; 13 | constructor(reduxDevToolsOptions: Config); 14 | Init(): void; 15 | GetExtension(): ReduxDevtoolsExtension | undefined; 16 | GetDevTools(): ConnectResponse | undefined; 17 | MapRequestType(message: any): string; 18 | MessageHandler: (message: any) => void; 19 | ReduxDevToolsDispatch(action: any, state: unknown, stackTrace: any): any; 20 | GetStackTraceForAction(_action: any): string; 21 | } 22 | export {}; 23 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/test-objects/multi-dimensional2d-array-object.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable BaseObjectGetHashCodeCallInGetHashCode 2 | // ReSharper disable PropertyCanBeMadeInitOnly.Global 3 | // ReSharper disable MemberCanBePrivate.Global 4 | #pragma warning disable CS8765 // Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes). 5 | namespace AnyClone.Tests.TestObjects; 6 | 7 | public class MultiDimensional2dArrayObject 8 | { 9 | public int[,] Int2DArray { get; set; } = new int[4, 2]; 10 | 11 | public override int GetHashCode() => base.GetHashCode(); 12 | 13 | public override bool Equals(object aObject) 14 | { 15 | var basicObject = (MultiDimensional2dArrayObject)aObject; 16 | return Equals(basicObject); 17 | } 18 | 19 | public bool Equals(MultiDimensional2dArrayObject other) => Int2DArray.EnumerableEqual(other.Int2DArray); 20 | } 21 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/features/application/application-state/application-state.debug.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.Client.Features.Application; 2 | 3 | public partial class ApplicationState 4 | { 5 | public override ApplicationState Hydrate(IDictionary keyValuePairs) => new() 6 | { 7 | Guid = 8 | new Guid 9 | ( 10 | keyValuePairs[CamelCase.MemberNameToCamelCase(nameof(Guid))].ToString() ?? 11 | throw new InvalidOperationException("Guid is required.") 12 | ), 13 | Name = 14 | keyValuePairs[CamelCase.MemberNameToCamelCase(nameof(Name))].ToString() ?? 15 | throw new InvalidOperationException("Name is required.") 16 | }; 17 | 18 | internal void Initialize(string name, string exceptionMessage) 19 | { 20 | ThrowIfNotTestAssembly(Assembly.GetCallingAssembly()); 21 | Name = name; 22 | ExceptionMessage = exceptionMessage; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/test-objects/multi-dimensional3d-array-object.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable PropertyCanBeMadeInitOnly.Global 2 | // ReSharper disable MemberCanBePrivate.Global 3 | // ReSharper disable BaseObjectGetHashCodeCallInGetHashCode 4 | #pragma warning disable CS8765 // Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes). 5 | namespace AnyClone.Tests.TestObjects; 6 | 7 | public class MultiDimensional3dArrayObject 8 | { 9 | public int[,,] Int3DArray { get; set; } = new int[2, 3, 3]; 10 | 11 | public override int GetHashCode() => base.GetHashCode(); 12 | 13 | public override bool Equals(object aObject) 14 | { 15 | var basicObject = (MultiDimensional3dArrayObject)aObject; 16 | return Equals(basicObject); 17 | } 18 | 19 | public bool Equals(MultiDimensional3dArrayObject other) => Int3DArray.EnumerableEqual(other.Int3DArray); 20 | } 21 | -------------------------------------------------------------------------------- /tests/client-integration-tests/features/application/application-state-clone-tests.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable UnusedType.Global 2 | namespace ApplicationState_; 3 | 4 | public class Clone_Should : BaseTest 5 | { 6 | public Clone_Should(ClientHost clientHost) : base(clientHost) 7 | { 8 | ApplicationState = Store.GetState(); 9 | } 10 | 11 | private ApplicationState ApplicationState { get; } 12 | 13 | public void Clone() 14 | { 15 | //Arrange 16 | ApplicationState.Initialize(name: "TestName", exceptionMessage: "Some ExceptionMessage"); 17 | 18 | //Act 19 | ApplicationState clone = ApplicationState.Clone(); 20 | 21 | //Assert 22 | ApplicationState.ShouldNotBeSameAs(clone); 23 | ApplicationState.Name.ShouldBe(clone.Name); 24 | ApplicationState.ExceptionMessage.ShouldBe(clone.ExceptionMessage); 25 | ApplicationState.Guid.ShouldNotBe(clone.Guid); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /source/timewarp-state/wwwroot/js/logger.js: -------------------------------------------------------------------------------- 1 | export const logStyles = { 2 | info: "color: deepskyblue; font-weight: bold;", 3 | success: "color: limegreen; font-weight: bold;", 4 | warning: "color: darkorange; font-weight: bold;", 5 | error: "color: crimson; font-weight: bold;", 6 | function: "color: mediumorchid; font-weight: bold;", 7 | }; 8 | export var LogAction; 9 | (function (LogAction) { 10 | LogAction[LogAction["Begin"] = 0] = "Begin"; 11 | LogAction[LogAction["End"] = 1] = "End"; 12 | })(LogAction || (LogAction = {})); 13 | export const log = (tag, message, level = 'info', action) => { 14 | const style = logStyles[level]; 15 | if (action === LogAction.Begin) { 16 | console.group(`%c${tag}`, style); 17 | } 18 | console.log(`%c${tag} ${message}`, style); 19 | if (action === LogAction.End) { 20 | console.groupEnd(); 21 | } 22 | }; 23 | //# sourceMappingURL=logger.js.map -------------------------------------------------------------------------------- /tests/test-app/test-app-client/features/counter/actions/counter-state.throw-exception.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.Client.Features.Counter; 2 | 3 | public partial class CounterState 4 | { 5 | public static class ThrowExceptionActionSet 6 | { 7 | internal sealed class Action : IAction 8 | { 9 | public string Message { get; } 10 | 11 | public Action(string message) 12 | { 13 | Message = message; 14 | } 15 | } 16 | 17 | internal sealed class Handler : BaseActionHandler 18 | { 19 | public Handler(IStore store) : base(store) {} 20 | 21 | /// 22 | /// Intentionally throw so we can test exception handling. 23 | /// 24 | public override Task Handle 25 | ( 26 | Action action, 27 | CancellationToken cancellationToken 28 | ) => throw new Exception(action.Message); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /source/timewarp-state-plus/features/timers/multi-timer-post-processor.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.State.Plus.Features.Timers; 2 | 3 | public class MultiTimerPostProcessor : IRequestPostProcessor 4 | where TRequest : notnull 5 | { 6 | private readonly ILogger> Logger; 7 | private readonly TimerState TimerState; 8 | 9 | public MultiTimerPostProcessor 10 | ( 11 | ILogger> logger, 12 | TimerState timerState 13 | ) 14 | { 15 | Logger = logger; 16 | TimerState = timerState; 17 | } 18 | 19 | public async Task Process(TRequest request, TResponse response, CancellationToken cancellationToken) 20 | { 21 | Logger.LogDebug(EventIds.MultiTimerPostProcessor_ProcessingRequest, message: "Processing request and checking timers"); 22 | await TimerState.ResetTimersOnActivity(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /source/timewarp-state/features/redux-dev-tools/requests/start/start-handler.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.Features.ReduxDevTools; 2 | 3 | /// 4 | /// Redux Devtools will send the Request once on startup 5 | /// 6 | /// currently we do nothing at start up other than log 7 | internal class StartHandler : IRequestHandler 8 | { 9 | private readonly ILogger Logger; 10 | 11 | public StartHandler 12 | ( 13 | ILogger logger 14 | ) 15 | { 16 | Logger = logger; 17 | Logger.LogDebug(EventIds.JumpToStateHandler_RequestHandled, "constructing"); 18 | } 19 | 20 | /// 21 | /// Currently does nothing 22 | /// 23 | /// 24 | /// 25 | /// 26 | public Task Handle(StartRequest request, CancellationToken cancellationToken) => 27 | Task.CompletedTask; 28 | } 29 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/features/base/base-action-handler.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable UnusedMember.Global 2 | namespace Test.App.Client.Features.Base; 3 | 4 | /// 5 | /// Base Handler that makes it easy to access state 6 | /// 7 | /// The Type of Action to be handled 8 | internal abstract class BaseActionHandler 9 | ( 10 | IStore store 11 | ) : ActionHandler(store) 12 | where TAction : IAction 13 | { 14 | protected ApplicationState ApplicationState => Store.GetState(); 15 | protected CounterState CounterState => Store.GetState(); 16 | protected EventStreamState EventStreamState => Store.GetState(); 17 | protected WeatherForecastsState WeatherForecastsState => Store.GetState(); 18 | protected CacheableWeatherState CacheableWeatherState => Store.GetState(); 19 | } 20 | -------------------------------------------------------------------------------- /source/timewarp-state-plus/features/action-tracking/action-tracking-state/action-tracking-state.debug.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.Features.ActionTracking; 2 | 3 | public partial class ActionTrackingState 4 | { 5 | public override ActionTrackingState Hydrate(IDictionary keyValuePairs) 6 | { 7 | string guidKey = CamelCase.MemberNameToCamelCase(nameof(Guid)); 8 | 9 | if (!keyValuePairs.TryGetValue(guidKey, out object? guidValue)) 10 | { 11 | throw new InvalidOperationException($"Expected key '{guidKey}' not found or value is null."); 12 | } 13 | 14 | var processingState = new ActionTrackingState(this.Sender) 15 | { 16 | Guid = Guid.Parse(guidValue.ToString()!) 17 | }; 18 | return processingState; 19 | } 20 | 21 | internal void Initialize(List processingList) 22 | { 23 | ThrowIfNotTestAssembly(Assembly.GetCallingAssembly()); 24 | ActiveActionList = processingList; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/features/counter/counter-state.debug.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.Client.Features.Counter; 2 | 3 | public partial class CounterState 4 | { 5 | public override CounterState Hydrate(IDictionary keyValuePairs) 6 | { 7 | var counterState = new CounterState 8 | { 9 | Count = Convert.ToInt32(keyValuePairs[CamelCase.MemberNameToCamelCase(nameof(Count))].ToString()), 10 | Guid = 11 | new Guid 12 | ( 13 | keyValuePairs[CamelCase.MemberNameToCamelCase(nameof(Guid))].ToString() ?? 14 | throw new InvalidOperationException() 15 | ) 16 | }; 17 | 18 | return counterState; 19 | } 20 | 21 | /// 22 | /// Use in Tests ONLY, to initialize the State 23 | /// 24 | /// 25 | public void Initialize(int count) 26 | { 27 | ThrowIfNotTestAssembly(Assembly.GetCallingAssembly()); 28 | Count = count; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /documentation/features/features.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: TimeWarp.State:Features.md 3 | title: Features 4 | --- 5 | 6 | * Oneway Data Flow 7 | * Automatic Subscriptions 8 | * Encapsulated State. Each State exposes its API. Like a micro-site 9 | * Extensible Pipeline 10 | * Auto-clone with ability to override 11 | * Precise control of ReRendering 12 | * Async handling of actions 13 | * RouteState management 14 | * BaseCacheableState to simplify client side cache with ability to NOT reRender if using cache. 15 | * A Clean abstraction for Sending of Actions 16 | * BaseComponent that provides handling of Blazors RenderModes. 17 | 18 | # Roadmap 19 | * Action Based Cloning. To reduce the size of the clone based on the action. 20 | * TimeWarp.State DevTools 21 | * Event Stream 22 | * Console and CLI 23 | * Object Inspector 24 | * Middleware Viewer 25 | * Subscriptions Viewer 26 | * IndexedDb/LocalStorage MiddleWare. 27 | * ObjectSpace synchronization with server side Entities. 28 | -------------------------------------------------------------------------------- /documentation/release-notes/release6.0.0.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: BlazorState:Release.6.0.0.md 3 | title: Release 6.0.0 4 | --- 5 | 6 | ## Release 6.0.0 7 | 8 | ### Breaking Changes 9 | 10 | * Blazor-State has moved from MediatR 10 to 11 11 | * UseReduxDevToolsBehavior changes from a boolean to a function that uses the options pattern. 12 | This now gives the ability to enable stack traces in ReduxDevTools. 13 | 14 | See [Migrations](xref:BlazorState:Migration5-6.md) for how to migrate existing projects from 5.0 to 6.0. 15 | 16 | ### Other Changes 17 | 18 | * Remove esproj and add move typescript directly into BlazorState.csproj utilizing `Microsoft.TypeScript.MSBuild` package. 19 | * Fix the tags on the project they should be separated by semicolons. 20 | * Migrate to Fixie 3.2.0 21 | * Use the TimeWarp.Fixie testing convention. 22 | * Update All Nuget packages to the latest 23 | * Add dotnet-cleanup to dotnet-tools.json 24 | * Update Nuget.config to include packageSourceMapping 25 | -------------------------------------------------------------------------------- /source/timewarp-state-plus/features/action-tracking/action-tracking-state/action-tracking-state.start-processing.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.Features.ActionTracking; 2 | 3 | public partial class ActionTrackingState 4 | { 5 | public static class StartProcessingActionSet 6 | { 7 | internal sealed class Action : IAction 8 | { 9 | public Action(IAction theAction) 10 | { 11 | TheAction = theAction; 12 | } 13 | public IAction TheAction { get; } 14 | } 15 | 16 | internal sealed class Handler : ActionHandler 17 | { 18 | public Handler(IStore store) : base(store) {} 19 | private ActionTrackingState ActionTrackingState => Store.GetState(); 20 | 21 | public override Task Handle(Action action, CancellationToken cancellationToken) 22 | { 23 | ActionTrackingState.ActiveActionList.Add(action.TheAction); 24 | return Task.CompletedTask; 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /source/timewarp-state-plus/features/timers/timer-state/timer-state.reset-timers-on-activity.cs: -------------------------------------------------------------------------------- 1 | namespace TimeWarp.State.Plus.Features.Timers; 2 | 3 | using System.Timers; 4 | public partial class TimerState 5 | { 6 | public static class ResetTimersOnActivityActionSet 7 | { 8 | internal sealed class Action : IAction; 9 | 10 | internal sealed class Handler : ActionHandler 11 | { 12 | private TimerState TimerState => Store.GetState(); 13 | public Handler(IStore store) : base(store) { } 14 | 15 | public override Task Handle(Action action, CancellationToken cancellationToken) 16 | { 17 | foreach ((string timerName, (Timer _, TimerConfig timerConfig)) in TimerState.Timers) 18 | { 19 | if (timerConfig.ResetOnActivity) 20 | { 21 | TimerState.RestartTimer(timerName); 22 | } 23 | } 24 | return Task.CompletedTask; 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/_imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Diagnostics.CodeAnalysis 2 | @using System.Net.Http 3 | @using System.Net.Http.Json 4 | @using System.Text.RegularExpressions 5 | @using Microsoft.AspNetCore.Components.Forms 6 | @using Microsoft.AspNetCore.Components.Routing 7 | @using Microsoft.AspNetCore.Components.Web 8 | @using static Microsoft.AspNetCore.Components.Web.RenderMode 9 | @using Microsoft.AspNetCore.Components.Web.Virtualization 10 | @using Microsoft.JSInterop 11 | @using TimeWarp.Features.ActionTracking 12 | @using TimeWarp.Features.Developer 13 | @using TimeWarp.Features.Routing 14 | 15 | @using Test.App.Client 16 | @using Test.App.Client.Components 17 | @using Test.App.Client.Features.Base.Components 18 | @using Test.App.Client.Features.CloneTest.Pages 19 | @using Test.App.Client.Features.Color.Components 20 | @using Test.App.Client.Features.Counter.Components 21 | @using Test.App.Client.Features.EventStream.Components 22 | @using Test.App.Client.Pages 23 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/features/clone-test/clone-test-state.debug.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.Client.Features.CloneTest; 2 | 3 | public partial class CloneableState 4 | { 5 | public override CloneableState Hydrate(IDictionary keyValuePairs) 6 | { 7 | var counterState = new CloneableState 8 | { 9 | Count = Convert.ToInt32(keyValuePairs[CamelCase.MemberNameToCamelCase(nameof(Count))].ToString()), 10 | Guid = 11 | new Guid 12 | ( 13 | keyValuePairs[CamelCase.MemberNameToCamelCase(nameof(Guid))].ToString() ?? 14 | throw new InvalidOperationException() 15 | ) 16 | }; 17 | 18 | return counterState; 19 | } 20 | 21 | /// 22 | /// Use in Tests ONLY, to initialize the State 23 | /// 24 | /// 25 | public void Initialize(int count) 26 | { 27 | ThrowIfNotTestAssembly(Assembly.GetCallingAssembly()); 28 | Count = count; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/generated/TimeWarp.State.SourceGenerator/TimeWarp.State.SourceGenerator.ActionSetMethodSourceGenerator/Test.App.Client.Features.Blue.BlueState.IncrementCountActionSet_Method.g.cs: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | 3 | #pragma warning disable CS1591 4 | namespace Test.App.Client.Features.Blue; 5 | 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | partial class BlueState 10 | { 11 | public async Task IncrementCount(CancellationToken? externalCancellationToken = null) 12 | { 13 | using CancellationTokenSource? linkedCts = externalCancellationToken.HasValue 14 | ? CancellationTokenSource.CreateLinkedTokenSource(externalCancellationToken.Value, CancellationToken) 15 | : null; 16 | 17 | await Sender.Send 18 | ( 19 | new IncrementCountActionSet.Action(), 20 | linkedCts?.Token ?? CancellationToken 21 | ); 22 | } 23 | } 24 | #pragma warning restore CS1591 -------------------------------------------------------------------------------- /tests/test-app/test-app-client/generated/timewarp-state-source-generator/TimeWarp.State.SourceGenerator.ActionSetMethodSourceGenerator/Test.App.Client.Features.Blue.BlueState.IncrementCountActionSet_Method.g.cs: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | 3 | #pragma warning disable CS1591 4 | namespace Test.App.Client.Features.Blue; 5 | 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | partial class BlueState 10 | { 11 | public async Task IncrementCount(CancellationToken? externalCancellationToken = null) 12 | { 13 | using CancellationTokenSource? linkedCts = externalCancellationToken.HasValue 14 | ? CancellationTokenSource.CreateLinkedTokenSource(externalCancellationToken.Value, CancellationToken) 15 | : null; 16 | 17 | await Sender.Send 18 | ( 19 | new IncrementCountActionSet.Action(), 20 | linkedCts?.Token ?? CancellationToken 21 | ); 22 | } 23 | } 24 | #pragma warning restore CS1591 -------------------------------------------------------------------------------- /tests/test-app/test-app-client/pipeline/notification-post-processor/post-pipeline-notification-request-post-processor.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.Client.Pipeline.NotificationPostProcessor; 2 | 3 | internal class PostPipelineNotificationRequestPostProcessor 4 | ( 5 | ILogger> logger, 6 | IPublisher Publisher 7 | ) : 8 | IRequestPostProcessor 9 | where TRequest : notnull 10 | { 11 | private readonly ILogger Logger = logger; 12 | 13 | public Task Process(TRequest request, TResponse response, CancellationToken cancellationToken) 14 | { 15 | var notification = new PostPipelineNotification 16 | { 17 | Request = request, 18 | Response = response 19 | }; 20 | 21 | Logger.LogDebug(nameof(PostPipelineNotificationRequestPostProcessor)); 22 | return Publisher.Publish(notification, cancellationToken); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/features/application/notification/application-state.exception-notification-handler.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.Client.Features.Application; 2 | 3 | public partial class ApplicationState 4 | { 5 | internal class ExceptionNotificationHandler 6 | ( 7 | ILogger Logger, 8 | IStore Store 9 | ) : INotificationHandler 10 | { 11 | private readonly ILogger Logger = Logger; 12 | private ApplicationState ApplicationState => Store.GetState(); 13 | 14 | public Task Handle 15 | ( 16 | ExceptionNotification exceptionNotification, 17 | CancellationToken cancellationToken 18 | ) 19 | { 20 | Logger.LogWarning("exceptionNotification.Exception.Message: {ExceptionMessage}", exceptionNotification.Exception.Message); 21 | ApplicationState.ExceptionMessage = exceptionNotification.Exception.Message; 22 | return Task.CompletedTask; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/generated/TimeWarp.State.SourceGenerator/TimeWarp.State.SourceGenerator.ActionSetMethodSourceGenerator/Test.App.Client.Features.CloneTest.CloneableState.CloneTestActionSet_Method.g.cs: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | 3 | #pragma warning disable CS1591 4 | namespace Test.App.Client.Features.CloneTest; 5 | 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | partial class CloneableState 10 | { 11 | public async Task CloneTest(CancellationToken? externalCancellationToken = null) 12 | { 13 | using CancellationTokenSource? linkedCts = externalCancellationToken.HasValue 14 | ? CancellationTokenSource.CreateLinkedTokenSource(externalCancellationToken.Value, CancellationToken) 15 | : null; 16 | 17 | await Sender.Send 18 | ( 19 | new CloneTestActionSet.Action(), 20 | linkedCts?.Token ?? CancellationToken 21 | ); 22 | } 23 | } 24 | #pragma warning restore CS1591 -------------------------------------------------------------------------------- /tests/test-app/test-app-client/generated/timewarp-state-source-generator/TimeWarp.State.SourceGenerator.ActionSetMethodSourceGenerator/Test.App.Client.Features.CloneTest.CloneableState.CloneTestActionSet_Method.g.cs: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | 3 | #pragma warning disable CS1591 4 | namespace Test.App.Client.Features.CloneTest; 5 | 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | partial class CloneableState 10 | { 11 | public async Task CloneTest(CancellationToken? externalCancellationToken = null) 12 | { 13 | using CancellationTokenSource? linkedCts = externalCancellationToken.HasValue 14 | ? CancellationTokenSource.CreateLinkedTokenSource(externalCancellationToken.Value, CancellationToken) 15 | : null; 16 | 17 | await Sender.Send 18 | ( 19 | new CloneTestActionSet.Action(), 20 | linkedCts?.Token ?? CancellationToken 21 | ); 22 | } 23 | } 24 | #pragma warning restore CS1591 -------------------------------------------------------------------------------- /tests/test-app/test-app-client/generated/TimeWarp.State.SourceGenerator/TimeWarp.State.SourceGenerator.ActionSetMethodSourceGenerator/Test.App.Client.Features.Purple.PurpleState.IncrementCountActionSet_Method.g.cs: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | 3 | #pragma warning disable CS1591 4 | namespace Test.App.Client.Features.Purple; 5 | 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | partial class PurpleState 10 | { 11 | public async Task IncrementCount(CancellationToken? externalCancellationToken = null) 12 | { 13 | using CancellationTokenSource? linkedCts = externalCancellationToken.HasValue 14 | ? CancellationTokenSource.CreateLinkedTokenSource(externalCancellationToken.Value, CancellationToken) 15 | : null; 16 | 17 | await Sender.Send 18 | ( 19 | new IncrementCountActionSet.Action(), 20 | linkedCts?.Token ?? CancellationToken 21 | ); 22 | } 23 | } 24 | #pragma warning restore CS1591 -------------------------------------------------------------------------------- /tests/test-app/test-app-client/generated/timewarp-state-source-generator/TimeWarp.State.SourceGenerator.ActionSetMethodSourceGenerator/Test.App.Client.Features.Purple.PurpleState.IncrementCountActionSet_Method.g.cs: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | 3 | #pragma warning disable CS1591 4 | namespace Test.App.Client.Features.Purple; 5 | 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | partial class PurpleState 10 | { 11 | public async Task IncrementCount(CancellationToken? externalCancellationToken = null) 12 | { 13 | using CancellationTokenSource? linkedCts = externalCancellationToken.HasValue 14 | ? CancellationTokenSource.CreateLinkedTokenSource(externalCancellationToken.Value, CancellationToken) 15 | : null; 16 | 17 | await Sender.Send 18 | ( 19 | new IncrementCountActionSet.Action(), 20 | linkedCts?.Token ?? CancellationToken 21 | ); 22 | } 23 | } 24 | #pragma warning restore CS1591 -------------------------------------------------------------------------------- /tests/test-app/test-app-server/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "profiles": { 4 | "http": { 5 | "commandName": "Project", 6 | "dotnetRunMessages": true, 7 | "launchBrowser": true, 8 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", 9 | "applicationUrl": "http://localhost:5058", 10 | "environmentVariables": { 11 | "ASPNETCORE_ENVIRONMENT": "Development" 12 | } 13 | }, 14 | "https": { 15 | "commandName": "Project", 16 | "dotnetRunMessages": true, 17 | "launchBrowser": true, 18 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", 19 | "applicationUrl": "https://localhost:7011;http://localhost:5058", 20 | "environmentVariables": { 21 | "ASPNETCORE_ENVIRONMENT": "Development" 22 | } 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /tests/test-app/test-app-client/generated/TimeWarp.State.SourceGenerator/TimeWarp.State.SourceGenerator.ActionSetMethodSourceGenerator/Test.App.Client.Features.Application.ApplicationState.ResetStoreActionSet_Method.g.cs: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | 3 | #pragma warning disable CS1591 4 | namespace Test.App.Client.Features.Application; 5 | 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | partial class ApplicationState 10 | { 11 | public async Task ResetStore(CancellationToken? externalCancellationToken = null) 12 | { 13 | using CancellationTokenSource? linkedCts = externalCancellationToken.HasValue 14 | ? CancellationTokenSource.CreateLinkedTokenSource(externalCancellationToken.Value, CancellationToken) 15 | : null; 16 | 17 | await Sender.Send 18 | ( 19 | new ResetStoreActionSet.Action(), 20 | linkedCts?.Token ?? CancellationToken 21 | ); 22 | } 23 | } 24 | #pragma warning restore CS1591 -------------------------------------------------------------------------------- /tests/test-app/test-app-client/generated/TimeWarp.State.SourceGenerator/TimeWarp.State.SourceGenerator.ActionSetMethodSourceGenerator/Test.App.Client.Features.Counter.CounterState.IncrementCountActionSet_Method.g.cs: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | 3 | #pragma warning disable CS1591 4 | namespace Test.App.Client.Features.Counter; 5 | 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | partial class CounterState 10 | { 11 | public async Task IncrementCount(CancellationToken? externalCancellationToken = null) 12 | { 13 | using CancellationTokenSource? linkedCts = externalCancellationToken.HasValue 14 | ? CancellationTokenSource.CreateLinkedTokenSource(externalCancellationToken.Value, CancellationToken) 15 | : null; 16 | 17 | await Sender.Send 18 | ( 19 | new IncrementCountActionSet.Action(), 20 | linkedCts?.Token ?? CancellationToken 21 | ); 22 | } 23 | } 24 | #pragma warning restore CS1591 -------------------------------------------------------------------------------- /tests/test-app/test-app-client/generated/timewarp-state-source-generator/TimeWarp.State.SourceGenerator.ActionSetMethodSourceGenerator/Test.App.Client.Features.Counter.CounterState.IncrementCountActionSet_Method.g.cs: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | 3 | #pragma warning disable CS1591 4 | namespace Test.App.Client.Features.Counter; 5 | 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | partial class CounterState 10 | { 11 | public async Task IncrementCount(CancellationToken? externalCancellationToken = null) 12 | { 13 | using CancellationTokenSource? linkedCts = externalCancellationToken.HasValue 14 | ? CancellationTokenSource.CreateLinkedTokenSource(externalCancellationToken.Value, CancellationToken) 15 | : null; 16 | 17 | await Sender.Send 18 | ( 19 | new IncrementCountActionSet.Action(), 20 | linkedCts?.Token ?? CancellationToken 21 | ); 22 | } 23 | } 24 | #pragma warning restore CS1591 -------------------------------------------------------------------------------- /tests/test-app/test-app-client/generated/timewarp-state-source-generator/TimeWarp.State.SourceGenerator.ActionSetMethodSourceGenerator/Test.App.Client.Features.Application.ApplicationState.ResetStoreActionSet_Method.g.cs: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | 3 | #pragma warning disable CS1591 4 | namespace Test.App.Client.Features.Application; 5 | 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | partial class ApplicationState 10 | { 11 | public async Task ResetStore(CancellationToken? externalCancellationToken = null) 12 | { 13 | using CancellationTokenSource? linkedCts = externalCancellationToken.HasValue 14 | ? CancellationTokenSource.CreateLinkedTokenSource(externalCancellationToken.Value, CancellationToken) 15 | : null; 16 | 17 | await Sender.Send 18 | ( 19 | new ResetStoreActionSet.Action(), 20 | linkedCts?.Token ?? CancellationToken 21 | ); 22 | } 23 | } 24 | #pragma warning restore CS1591 -------------------------------------------------------------------------------- /tests/test-app/test-app-client/features/counter/notification/increment-count-notification-handler.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.Client.Features.Counter; 2 | 3 | internal class IncrementCountNotificationHandler 4 | ( 5 | ILogger logger 6 | ) : INotificationHandler> 7 | { 8 | private readonly ILogger Logger = logger; 9 | 10 | public Task Handle 11 | ( 12 | PostPipelineNotification postPipelineNotification, 13 | CancellationToken cancellationToken 14 | ) 15 | { 16 | Logger.LogDebug("{postPipelineNotification_Request_Type_Name}", postPipelineNotification.Request.GetType().Name); 17 | Logger.LogDebug("{postPipelineNotification_Response_Type_Name}", postPipelineNotification.Response.GetType().Name); 18 | Logger.LogDebug("{methodName} handled", nameof(IncrementCountNotificationHandler)); 19 | return Task.CompletedTask; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/generated/TimeWarp.State.SourceGenerator/TimeWarp.State.SourceGenerator.ActionSetMethodSourceGenerator/Test.App.Client.Features.Application.ApplicationState.TwoSecondTaskActionSet_Method.g.cs: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | 3 | #pragma warning disable CS1591 4 | namespace Test.App.Client.Features.Application; 5 | 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | partial class ApplicationState 10 | { 11 | public async Task TwoSecondTask(CancellationToken? externalCancellationToken = null) 12 | { 13 | using CancellationTokenSource? linkedCts = externalCancellationToken.HasValue 14 | ? CancellationTokenSource.CreateLinkedTokenSource(externalCancellationToken.Value, CancellationToken) 15 | : null; 16 | 17 | await Sender.Send 18 | ( 19 | new TwoSecondTaskActionSet.Action(), 20 | linkedCts?.Token ?? CancellationToken 21 | ); 22 | } 23 | } 24 | #pragma warning restore CS1591 -------------------------------------------------------------------------------- /tests/test-app/test-app-client/generated/timewarp-state-source-generator/TimeWarp.State.SourceGenerator.ActionSetMethodSourceGenerator/Test.App.Client.Features.Application.ApplicationState.TwoSecondTaskActionSet_Method.g.cs: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | 3 | #pragma warning disable CS1591 4 | namespace Test.App.Client.Features.Application; 5 | 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | partial class ApplicationState 10 | { 11 | public async Task TwoSecondTask(CancellationToken? externalCancellationToken = null) 12 | { 13 | using CancellationTokenSource? linkedCts = externalCancellationToken.HasValue 14 | ? CancellationTokenSource.CreateLinkedTokenSource(externalCancellationToken.Value, CancellationToken) 15 | : null; 16 | 17 | await Sender.Send 18 | ( 19 | new TwoSecondTaskActionSet.Action(), 20 | linkedCts?.Token ?? CancellationToken 21 | ); 22 | } 23 | } 24 | #pragma warning restore CS1591 -------------------------------------------------------------------------------- /tests/test-app/test-app-contracts/features/weather-forecast/queries/get-weather-forecasts.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.Contracts.Features.WeatherForecast; 2 | 3 | public static class GetWeatherForecasts 4 | { 5 | public sealed class Query : IRequest 6 | { 7 | public int Days { get; init; } 8 | 9 | public const string RouteTemplate = "api/weather"; 10 | public string GetRoute() => FormattableString.Invariant($"{RouteTemplate}"); 11 | } 12 | 13 | public sealed class Response : List; 14 | 15 | public sealed class WeatherForecastDto 16 | { 17 | public DateOnly Date { get; } 18 | 19 | public string Summary { get; } 20 | 21 | public int TemperatureC { get; } 22 | 23 | 24 | public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); 25 | 26 | public WeatherForecastDto(DateOnly date, string summary, int temperatureC) 27 | { 28 | Date = date; 29 | Summary = summary; 30 | TemperatureC = temperatureC; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tests/test-app-architecture-tests/architecture-tests.cs: -------------------------------------------------------------------------------- 1 | namespace Architecture_; 2 | 3 | public class Should_ 4 | { 5 | public static void FollowActionPolicy() 6 | { 7 | Assembly sut = typeof(Test.App.Client.AssemblyMarker).Assembly; 8 | PolicyDefinition policy = Policies.CreateActionPolicy(sut); 9 | PolicyResults results = policy.Evaluate(); 10 | results.ShouldBeSuccessful(); 11 | } 12 | 13 | public static void FollowActionHandlerPolicy() 14 | { 15 | Assembly sut = typeof(Test.App.Client.AssemblyMarker).Assembly; 16 | PolicyDefinition policy = Policies.CreateActionHandlerPolicy(sut); 17 | PolicyResults results = policy.Evaluate(); 18 | results.ShouldBeSuccessful(); 19 | } 20 | 21 | public static void FollowStatePolicy() 22 | { 23 | Assembly sut = typeof(Test.App.Client.AssemblyMarker).Assembly; 24 | PolicyDefinition policy = Policies.CreateStatePolicy(sut); 25 | PolicyResults results = policy.Evaluate(); 26 | results.ShouldBeSuccessful(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/components/CustomInput.razor: -------------------------------------------------------------------------------- 1 | @namespace Test.App.Client.Components 2 | @typeparam T 3 | @inherits BaseInputComponent 4 | 5 |
6 | @if (!string.IsNullOrWhiteSpace(Label)) 7 | { 8 | 9 | } 10 | 11 |
12 | 13 | 24 | @code 25 | { 26 | // set the CssClass based on the CurrentTheme 27 | private string GetThemeClass() 28 | { 29 | return ThemeState.CurrentTheme switch 30 | { 31 | ThemeState.Theme.Light => "light", 32 | ThemeState.Theme.Dark => "dark", 33 | ThemeState.Theme.System => "dark", 34 | _ => string.Empty 35 | }; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/features/color/color-state.debug.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.Client.Features.Counter; 2 | 3 | using System.Drawing; 4 | 5 | public partial class ColorState 6 | { 7 | public override ColorState Hydrate(IDictionary keyValuePairs) 8 | { 9 | var colorState = new ColorState 10 | { 11 | FavoriteColor = (Color)keyValuePairs[CamelCase.MemberNameToCamelCase(nameof(FavoriteColor))], 12 | MyColorName = (string)keyValuePairs[CamelCase.MemberNameToCamelCase(nameof(FavoriteColor))], 13 | Guid = 14 | new Guid 15 | ( 16 | keyValuePairs[CamelCase.MemberNameToCamelCase(nameof(Guid))].ToString() ?? 17 | throw new InvalidOperationException() 18 | ) 19 | }; 20 | 21 | return colorState; 22 | } 23 | 24 | public void Initialize(Color color, string myColorName) 25 | { 26 | ThrowIfNotTestAssembly(Assembly.GetCallingAssembly()); 27 | FavoriteColor = color; 28 | MyColorName = myColorName; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/generated/TimeWarp.State.SourceGenerator/TimeWarp.State.SourceGenerator.ActionSetMethodSourceGenerator/Test.App.Client.Features.Counter.CounterState.ThrowExceptionActionSet_Method.g.cs: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | 3 | #pragma warning disable CS1591 4 | namespace Test.App.Client.Features.Counter; 5 | 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | partial class CounterState 10 | { 11 | public async Task ThrowException(string message, CancellationToken? externalCancellationToken = null) 12 | { 13 | using CancellationTokenSource? linkedCts = externalCancellationToken.HasValue 14 | ? CancellationTokenSource.CreateLinkedTokenSource(externalCancellationToken.Value, CancellationToken) 15 | : null; 16 | 17 | await Sender.Send 18 | ( 19 | new ThrowExceptionActionSet.Action(message), 20 | linkedCts?.Token ?? CancellationToken 21 | ); 22 | } 23 | } 24 | #pragma warning restore CS1591 -------------------------------------------------------------------------------- /tests/test-app/test-app-client/generated/TimeWarp.State.SourceGenerator/TimeWarp.State.SourceGenerator.ActionSetMethodSourceGenerator/Test.App.Client.Features.EventStream.EventStreamState.AddEventActionSet_Method.g.cs: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | 3 | #pragma warning disable CS1591 4 | namespace Test.App.Client.Features.EventStream; 5 | 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | partial class EventStreamState 10 | { 11 | public async Task AddEvent(string message, CancellationToken? externalCancellationToken = null) 12 | { 13 | using CancellationTokenSource? linkedCts = externalCancellationToken.HasValue 14 | ? CancellationTokenSource.CreateLinkedTokenSource(externalCancellationToken.Value, CancellationToken) 15 | : null; 16 | 17 | await Sender.Send 18 | ( 19 | new AddEventActionSet.Action(message), 20 | linkedCts?.Token ?? CancellationToken 21 | ); 22 | } 23 | } 24 | #pragma warning restore CS1591 -------------------------------------------------------------------------------- /tests/test-app/test-app-client/generated/timewarp-state-source-generator/TimeWarp.State.SourceGenerator.ActionSetMethodSourceGenerator/Test.App.Client.Features.Counter.CounterState.ThrowExceptionActionSet_Method.g.cs: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | 3 | #pragma warning disable CS1591 4 | namespace Test.App.Client.Features.Counter; 5 | 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | partial class CounterState 10 | { 11 | public async Task ThrowException(string message, CancellationToken? externalCancellationToken = null) 12 | { 13 | using CancellationTokenSource? linkedCts = externalCancellationToken.HasValue 14 | ? CancellationTokenSource.CreateLinkedTokenSource(externalCancellationToken.Value, CancellationToken) 15 | : null; 16 | 17 | await Sender.Send 18 | ( 19 | new ThrowExceptionActionSet.Action(message), 20 | linkedCts?.Token ?? CancellationToken 21 | ); 22 | } 23 | } 24 | #pragma warning restore CS1591 -------------------------------------------------------------------------------- /tests/test-app/test-app-client/generated/timewarp-state-source-generator/TimeWarp.State.SourceGenerator.ActionSetMethodSourceGenerator/Test.App.Client.Features.EventStream.EventStreamState.AddEventActionSet_Method.g.cs: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | 3 | #pragma warning disable CS1591 4 | namespace Test.App.Client.Features.EventStream; 5 | 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | partial class EventStreamState 10 | { 11 | public async Task AddEvent(string message, CancellationToken? externalCancellationToken = null) 12 | { 13 | using CancellationTokenSource? linkedCts = externalCancellationToken.HasValue 14 | ? CancellationTokenSource.CreateLinkedTokenSource(externalCancellationToken.Value, CancellationToken) 15 | : null; 16 | 17 | await Sender.Send 18 | ( 19 | new AddEventActionSet.Action(message), 20 | linkedCts?.Token ?? CancellationToken 21 | ); 22 | } 23 | } 24 | #pragma warning restore CS1591 -------------------------------------------------------------------------------- /tests/test-app/test-app-client/features/clone-test/actions/cloneable-state.clone-test.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.Client.Features.CloneTest; 2 | 3 | public partial class CloneableState 4 | { 5 | public static class CloneTestActionSet 6 | { 7 | internal sealed class Action : IAction; 8 | internal sealed class Handler : BaseActionHandler 9 | { 10 | public Handler(IStore store) : base(store) {} 11 | private CloneableState CloneableState => Store.GetState(); 12 | 13 | public override Task Handle 14 | ( 15 | Action action, 16 | CancellationToken cancellationToken 17 | ) 18 | { 19 | // Note: This is a test to verify that the state is cloned. 20 | // It is not an example of any real-world usage. 21 | if ( CloneableState.Count != 42) throw new Exception("Count is not 42 it seems I have failed to clone the state"); 22 | CloneableState.Count++; 23 | return Task.CompletedTask; 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/timewarp-state-plus-tests/architecture-tests.cs: -------------------------------------------------------------------------------- 1 | namespace Architecture_; 2 | 3 | public class Should_ 4 | { 5 | public static void FollowActionPolicy() 6 | { 7 | Assembly sut = typeof(TimeWarp.State.Plus.AssemblyMarker).Assembly; 8 | PolicyDefinition policy = Policies.CreateActionPolicy(sut); 9 | PolicyResults results = policy.Evaluate(); 10 | results.ShouldBeSuccessful(); 11 | } 12 | 13 | public static void FollowActionHandlerPolicy() 14 | { 15 | Assembly sut = typeof(TimeWarp.State.Plus.AssemblyMarker).Assembly; 16 | PolicyDefinition policy = Policies.CreateActionHandlerPolicy(sut); 17 | PolicyResults results = policy.Evaluate(); 18 | results.ShouldBeSuccessful(); 19 | } 20 | 21 | public static void FollowStatePolicy() 22 | { 23 | Assembly sut = typeof(TimeWarp.State.Plus.AssemblyMarker).Assembly; 24 | PolicyDefinition policy = Policies.CreateStatePolicy(sut); 25 | PolicyResults results = policy.Evaluate(); 26 | results.ShouldBeSuccessful(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /source/timewarp-state/features/render-subscriptions/render-subscription-context.md: -------------------------------------------------------------------------------- 1 | # RenderSubscriptionContext 2 | 3 | The `RenderSubscriptionContext` class provides Handlers with control over when subscriptions should be re-rendered. 4 | 5 | ## Purpose 6 | 7 | This class offers a mechanism for Handlers to manage the automatic re-rendering of subscriptions for specific actions, allowing for fine-grained control over the rendering process. 8 | 9 | ## Usage in Action Handlers 10 | 11 | To modify the default re-rendering behavior in your Handler, follow these steps: 12 | 13 | TODO: Insert real example code and maybe a link 14 | 15 | [Link to line 10](./path/to/file.cs:10) 16 | 17 | ## Cross-Middleware Communication 18 | 19 | It's important to note that any middleware or handler within the pipeline can inject the `RenderSubscriptionContext` and thereby affect the re-rendering process. This capability enables cross-middleware communication, allowing different parts of the application to influence when and how subscriptions are re-rendered. 20 | -------------------------------------------------------------------------------- /samples/03-routing/wasm/sample-03-wasm/features/counter/counter-state.increment-count.cs: -------------------------------------------------------------------------------- 1 | namespace Sample03Wasm.Features.Counter; 2 | 3 | partial class CounterState 4 | { 5 | public static class IncrementCountActionSet 6 | { 7 | public sealed class Action : IAction 8 | { 9 | public int Amount { get; } 10 | 11 | public Action(int amount) 12 | { 13 | Amount = amount; 14 | } 15 | } 16 | 17 | public sealed class Handler : ActionHandler 18 | { 19 | public Handler(IStore store) : base(store) { } 20 | 21 | private CounterState CounterState => Store.GetState(); 22 | 23 | public override Task Handle(Action action, CancellationToken cancellationToken) 24 | { 25 | CounterState.Count += action.Amount; 26 | return Task.CompletedTask; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tests/test-app/test-app-client/pipeline/notification-pre-processor/pre-pipeline-notification-request-pre-processor.cs: -------------------------------------------------------------------------------- 1 | namespace Test.App.Client.Pipeline.NotificationPreProcessor; 2 | 3 | internal class PrePipelineNotificationRequestPreProcessor : IRequestPreProcessor 4 | where TRequest : IAction 5 | { 6 | private readonly ILogger Logger; 7 | private readonly IPublisher Publisher; 8 | public PrePipelineNotificationRequestPreProcessor 9 | ( 10 | ILogger> logger, 11 | IPublisher publisher 12 | ) 13 | { 14 | Publisher = publisher; 15 | Logger = logger; 16 | } 17 | 18 | public Task Process(TRequest request, CancellationToken cancellationToken) 19 | { 20 | var notification = new PrePipelineNotification 21 | { 22 | Request = request 23 | }; 24 | 25 | Logger.LogDebug(nameof(PrePipelineNotificationRequestPreProcessor)); 26 | return Publisher.Publish(notification, cancellationToken); 27 | } 28 | } 29 | --------------------------------------------------------------------------------