Aiursoft.AiurEventSyncer.WebExtends
10.0.13
dotnet add package Aiursoft.AiurEventSyncer.WebExtends --version 10.0.13
NuGet\Install-Package Aiursoft.AiurEventSyncer.WebExtends -Version 10.0.13
<PackageReference Include="Aiursoft.AiurEventSyncer.WebExtends" Version="10.0.13" />
<PackageVersion Include="Aiursoft.AiurEventSyncer.WebExtends" Version="10.0.13" />
<PackageReference Include="Aiursoft.AiurEventSyncer.WebExtends" />
paket add Aiursoft.AiurEventSyncer.WebExtends --version 10.0.13
#r "nuget: Aiursoft.AiurEventSyncer.WebExtends, 10.0.13"
#:package Aiursoft.AiurEventSyncer.WebExtends@10.0.13
#addin nuget:?package=Aiursoft.AiurEventSyncer.WebExtends&version=10.0.13
#tool nuget:?package=Aiursoft.AiurEventSyncer.WebExtends&version=10.0.13
AiurVersionControl
A powerful, elegant distributed synchronization framework that brings Git-like version control to any .NET application. Powers Kahla real-time messaging with eventual consistency, automatic conflict resolution, and offline-first capabilities.
๐ Why AiurVersionControl?
Imagine building a multiplayer Snake game where all players see the exact same state in real-time, or a collaborative chat app that works perfectly even when offline. AiurVersionControl makes this trivially easy by treating all data changes as immutable commits that can be synced, merged, and replayed.
Key advantages:
- โ Offline Operations - Commit changes and query your repository without any network connection
- โ Automatic Sync - When connection is available, changes sync automatically
- โ Local-First - All operations work on local data first, perfect for building offline-capable CRUD apps
Key Features
- ๐ Distributed Event Sourcing - Every change is an immutable commit with automatic conflict resolution
- ๐ Offline-First Architecture - Work offline, sync later with guaranteed eventual consistency
- โก Real-time Sync - Bi-directional automatic push/pull between repositories
- ๐ฏ Type-Safe - Fully generic API works with any data type
- ๐งฉ CRUD Operations - High-level abstractions for collection manipulation
- ๐ Multiple Transports - In-memory, WebSocket, HTTP, or custom implementations
- ๐ฎ Production Ready - Battle-tested in Kahla real-time messaging platform
๐ฆ Packages
| Package | Description | Use Case |
|---|---|---|
| Aiursoft.AiurEventSyncer | Core event synchronization engine | Building distributed apps with auto-sync |
| Aiursoft.AiurVersionControl | Event replay & workspace reconstruction | State management with commit history |
| Aiursoft.AiurVersionControl.Crud | High-level CRUD operations | Managing collections with Add/Update/Delete |
| Aiursoft.AiurEventSyncer.WebExtends | WebSocket transport support | Real-time web applications |
| Aiursoft.AiurStore | Immutable storage abstraction | Custom database backends |
๐ Quick Start
Installation
dotnet add package Aiursoft.AiurEventSyncer
Basic Event Syncing
Create two repositories that automatically stay in sync:
using Aiursoft.AiurEventSyncer.Models;
using Aiursoft.AiurEventSyncer.Remotes;
// Create two repositories
var clientRepo = new Repository<string>();
var serverRepo = new Repository<string>();
// Subscribe to observe commits
clientRepo.AppendCommitsHappened.Subscribe(commits =>
{
Console.WriteLine($"[Client] Received: {commits.Last().Item}");
return Task.CompletedTask;
});
serverRepo.AppendCommitsHappened.Subscribe(commits =>
{
Console.WriteLine($"[Server] Received: {commits.Last().Item}");
return Task.CompletedTask;
});
// Attach client to server with bi-directional auto-sync
await new ObjectRemote<string>(serverRepo, autoPush: true, autoPull: true)
.AttachAsync(clientRepo);
// Now they sync automatically!
clientRepo.Commit("Hello from client");
// Output: [Client] Received: Hello from client
// [Server] Received: Hello from client
serverRepo.Commit("Hello from server");
// Output: [Server] Received: Hello from server
// [Client] Received: Hello from server
// Both repositories now have identical commit history
Console.WriteLine($"Client commits: {clientRepo.Commits.Count()}"); // 2
Console.WriteLine($"Server commits: {serverRepo.Commits.Count()}"); // 2
CRUD Operations on Collections
Work with collections using familiar operations:
using Aiursoft.AiurVersionControl.Crud;
using Aiursoft.AiurVersionControl.Remotes;
// Define your model
public class Book
{
public int Id { get; set; }
public string Title { get; set; }
}
// Create a collection repository
var library = new CollectionRepository<Book>
{
new() { Id = 1, Title = "1984" },
new() { Id = 2, Title = "Brave New World" }
};
// CRUD operations
library.Add(new Book { Id = 3, Title = "Fahrenheit 451" });
library.Patch(nameof(Book.Id), 2, nameof(Book.Title), "Updated Title");
library.Drop(nameof(Book.Id), 1);
// Sync with remote
var remoteLibrary = new CollectionRepository<Book>();
var remote = new ObjectRemoteWithWorkSpace<CollectionWorkSpace<Book>>(
library, autoPush: true, autoPull: true);
await remote.AttachAsync(remoteLibrary);
// All changes automatically sync to remoteLibrary!
Advanced: Version-Controlled State
Build stateful applications with full commit history:
using Aiursoft.AiurVersionControl.Models;
using Aiursoft.AiurVersionControl.Remotes;
// Your state model
public class GameState : WorkSpace
{
public int Score { get; set; }
public override object Clone() => new GameState { Score = Score };
}
// Modification actions
public class UpdateScore : IModification<GameState>
{
public int Points { get; set; }
public void Apply(GameState workspace) => workspace.Score += Points;
}
// Create controlled repository
var game = new ControlledRepository<GameState>();
// Apply changes
game.ApplyChange(new UpdateScore { Points = 10 });
game.ApplyChange(new UpdateScore { Points = 5 });
Console.WriteLine(game.WorkSpace.Score); // 15
// Sync with other players
var player2 = new ControlledRepository<GameState>();
await new ObjectRemoteWithWorkSpace<GameState>(player2, true, true)
.AttachAsync(game);
// player2.WorkSpace.Score is now 15!
๐ฎ Real-World Examples
Check out the /demos folder for complete working examples:
Multiplayer Snake Game
A fully functional multiplayer Snake game demonstrating:
- Real-time game state synchronization across multiple clients
- Deterministic conflict resolution
- Immediate visual feedback with no server round-trip delay
- Game state replay and debugging
cd demos/Aiursoft.SnakeGame
dotnet run
WPF Sample Application
Windows desktop app showcasing offline-first data binding.
๐๏ธ Architecture
AiurVersionControl implements a layered architecture inspired by distributed version control systems:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Your Application (CRUD, WorkSpace) โ โ High-level business logic
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ AiurVersionControl (Event Replay) โ โ State reconstruction
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ AiurEventSyncer (Sync Engine) โ โ Distributed syncing
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ AiurStore (Immutable Storage) โ โ Persistence layer
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Core Concepts
- Repository - Immutable commit log, similar to Git
- Commit - Atomic change event with unique ID
- Remote - Connection to another repository for syncing
- WorkSpace - Current state reconstructed from commit history
- Modification - Operation that transforms workspace state
Sync Patterns
Publish-Subscribe: Hub-and-Spoke: Peer-to-Peer:
sender โ server clientโ โ server repoโ โ repoโ
โ clientโ โ server โ โ
subscriberโ clientโ โ server repoโ โ repoโ
subscriberโ
All patterns supported with autoPush and autoPull configurations!
๐ฌ How It Works
Event Sourcing
Instead of storing current state, AiurVersionControl stores all changes as immutable commits:
// Traditional approach
var user = dbContext.Users.Find(123);
user.Name = "Alice"; // Lost: what was the old name? when did it change?
dbContext.SaveChanges();
// AiurVersionControl approach
userRepo.Commit(new UpdateName { UserId = 123, NewName = "Alice" });
// Full history preserved! Can replay, debug, and sync.
Automatic Conflict Resolution
When two repositories diverge and then sync, commits are automatically merged in deterministic order:
// Repo A and B start synchronized
await new ObjectRemote<int>(repoB, autoPush: true, autoPull: true)
.AttachAsync(repoA);
// Both add commits while temporarily disconnected
repoA.Commit(100); // A's timeline: [100]
repoB.Commit(200); // B's timeline: [200]
// When reconnected, both converge to same order
await Task.Delay(100); // Allow sync
// Both now have: [100, 200] or [200, 100] - deterministic based on commit IDs
Offline-First Experience
All operations work without network connection - commits, queries, and CRUD operations are purely local:
// At home with WiFi
var todoApp = new CollectionRepository<Todo>();
todoApp.Add(new Todo { Id = 1, Task = "Buy milk" });
var remote = await ConnectToServer(todoApp);
// Airplane mode! Disconnect from server
await remote.DetachAsync();
// Everything still works - completely offline!
todoApp.Add(new Todo { Id = 2, Task = "Read book" });
todoApp.Add(new Todo { Id = 3, Task = "Exercise" });
todoApp.Patch(nameof(Todo.Id), 2, nameof(Todo.Task), "Read 50 pages");
todoApp.Drop(nameof(Todo.Id), 1);
// Query your local repository - no network needed
var allTodos = todoApp.WorkSpace.ToList();
Console.WriteLine($"Offline todos count: {allTodos.Count}"); // 2
// Back online - reconnect to server
await remote.AttachAsync(todoApp);
// All offline commits automatically sync to server!
// Server now has the same state: todos 2 and 3
This makes AiurVersionControl perfect for building offline-capable CRUD applications - notes apps, todo lists, inventory managers, or any app that needs to work without internet!
๐ Comparison with Alternatives
| Feature | AiurVersionControl | SignalR | Firebase | Event Store |
|---|---|---|---|---|
| Offline Support | โ Full | โ | โ ๏ธ Limited | โ |
| Automatic Sync | โ Bi-directional | โ ๏ธ Manual | โ | โ |
| Conflict Resolution | โ Automatic | โ | โ ๏ธ Manual | โ |
| Type Safety | โ Generic | โ ๏ธ Partial | โ | โ ๏ธ Partial |
| Self-Hosted | โ | โ | โ | โ |
| CRUD Abstraction | โ | โ | โ | โ |
๐งช Testing
The framework includes comprehensive test coverage demonstrating all features:
# Run all tests
dotnet test
# Run specific test suite
dotnet test --filter "FullyQualifiedName~AiurEventSyncer.Tests"
Key test scenarios:
- โ Bi-directional syncing with auto push/pull
- โ Hub-and-spoke distribution patterns
- โ Attach/detach/reattach functionality
- โ CRUD operations with conflict resolution
- โ Merge scenarios with concurrent modifications
๐ Advanced Usage
Custom Storage Backend
// Implement your own storage (SQL, Redis, etc.)
public class SqlCommitStore : InOutDatabase<Commit<MyData>>
{
public override void Add(Commit<MyData> item) => /* SQL INSERT */;
public override IEnumerable<Commit<MyData>> GetAll() => /* SQL SELECT */;
// ... implement other methods
}
var repo = new Repository<MyData>(new SqlCommitStore());
WebSocket Real-Time Sync
// Server side
services.AddAiurEventSyncer();
app.MapWebSocketSyncer<ChatMessage>("/sync");
// Client side
var wsRemote = new WebSocketRemote<ChatMessage>(
"wss://myapp.com/sync", autoPush: true, autoPull: true);
await wsRemote.AttachAsync(localRepo);
Observable State Changes
var game = new ControlledRepository<GameState>();
// React to state changes
game.PropertyChanged += (sender, e) =>
{
if (e.PropertyName == nameof(game.WorkSpace))
{
UI.UpdateDisplay(game.WorkSpace);
}
};
game.ApplyChange(new UpdateScore { Points = 10 });
// UI automatically updates!
๐ ๏ธ Development
Requirements
- .NET 10 SDK
- Any IDE (Visual Studio, VS Code, Rider)
Building
# Restore dependencies
dotnet restore
# Build solution
dotnet build
# Run tests
dotnet test
# Pack NuGet packages
dotnet pack
Project Structure
AiurVersionControl/
โโโ src/
โ โโโ Aiursoft.AiurEventSyncer/ # Core sync engine
โ โโโ Aiursoft.AiurVersionControl/ # Version control layer
โ โโโ Aiursoft.AiurVersionControl.Crud/ # CRUD operations
โ โโโ Aiursoft.AiurEventSyncer.WebExtends/ # WebSocket support
โ โโโ Aiursoft.AiurStore/ # Storage abstraction
โโโ demos/
โ โโโ Aiursoft.SnakeGame/ # Multiplayer game demo
โ โโโ SampleWPF/ # Desktop app demo
โโโ tests/ # Comprehensive tests
๐ค Contributing
We welcome contributions! This project follows a fork-and-pull-request workflow:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to your branch (
git push origin feature/amazing-feature) - Open a Pull Request
Contribution Ideas
- ๐ Additional transport implementations (gRPC, MQTT, etc.)
- ๐ More CRUD operation types
- ๐จ Sample applications
- ๐ Documentation improvements
- ๐ Bug reports with reproduction cases
๐ License
This project is licensed under the MIT License - see the LICENSE file for details.
๐ Acknowledgments
- Inspired by Git, Event Sourcing, and CRDT research
- Powers Kahla - Production-grade real-time messaging
- Built with โค๏ธ by the Aiursoft team
๐ Learn More
- Live Demo: Try the Snake Game to see real-time sync in action
- NuGet Packages: Aiursoft.AiurVersionControl
- GitLab Repository: gitlab.aiursoft.com/aiursoft/aiurversioncontrol
- Kahla Application: kahla.app - See it in production
Made with ๐ฏ precision and โจ elegance by Aiursoft
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Aiursoft.AiurEventSyncer (>= 10.0.2)
- Aiursoft.AiurObserver.WebSocket.Server (>= 10.0.5)
- Aiursoft.WebTools (>= 10.0.8)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 10.0.13 | 0 | 3/13/2026 |
| 10.0.12 | 73 | 3/11/2026 |
| 10.0.11 | 102 | 2/11/2026 |
| 10.0.10 | 104 | 1/28/2026 |
| 10.0.9 | 113 | 1/18/2026 |
| 10.0.8 | 101 | 1/14/2026 |
| 10.0.7 | 112 | 1/12/2026 |
| 10.0.6 | 113 | 1/1/2026 |
| 10.0.5 | 103 | 12/28/2025 |
| 10.0.3 | 448 | 12/11/2025 |
| 10.0.2 | 283 | 11/30/2025 |
| 10.0.1 | 266 | 11/16/2025 |
| 10.0.0 | 318 | 11/13/2025 |
| 9.0.18 | 213 | 11/7/2025 |
| 9.0.17 | 136 | 10/25/2025 |
| 9.0.16 | 339 | 9/17/2025 |
| 9.0.15 | 185 | 9/12/2025 |
| 9.0.14 | 151 | 9/6/2025 |
| 9.0.13 | 304 | 8/7/2025 |
| 9.0.12 | 212 | 7/16/2025 |