Skip to content

Commit c7c6613

Browse files
Garfield550Copilot
andauthored
docs: add README and MIT license (#15)
* docs: add README and MIT license * docs: update links Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
1 parent e264011 commit c7c6613

2 files changed

Lines changed: 237 additions & 0 deletions

File tree

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 Moeru AI & Garfield550
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
# Eventa for C#
2+
3+
[![Build and Test][build-test-src]][build-test-href]
4+
[![Run Example][run-example-src]][run-example-href]
5+
[![License][license-src]][license-href]
6+
7+
Transport-agnostic, type-safe events for .NET 10, with ergonomic request/response
8+
and streaming invoke flows built on top of event primitives.
9+
10+
Eventa for C# is a source-first preview of the Eventa protocol ideas in idiomatic
11+
.NET. It uses `EventDefinition<T>` for strongly typed events, `EventContext` for
12+
local dispatch and adapter hooks, `Task<T>` for unary invokes, `IAsyncEnumerable<T>`
13+
for streams, `CancellationToken` for cancellation, and `IDisposable` for listener
14+
lifetimes.
15+
16+
## Overview
17+
18+
Eventa treats events as the shared protocol boundary. You define stable event
19+
identities once, subscribe to them through a context, and optionally compose the
20+
same event primitives into RPC-like invoke contracts.
21+
22+
The C# implementation currently focuses on the core protocol layer:
23+
24+
- publish/subscribe event dispatch
25+
- one-shot listeners and explicit unsubscribe support
26+
- match-expression listeners
27+
- unary request/response invokes
28+
- request-stream to unary-response invokes
29+
- server-streaming and bidirectional streaming invokes
30+
- adapter observation hooks for send/receive activity
31+
- fatal event and fatal match-expression hooks that abort pending invokes
32+
33+
## Features
34+
35+
- Type-safe event definitions with stable or generated ids.
36+
- `EventContext` dispatch with direct listeners, one-shot listeners, and match
37+
expressions.
38+
- .NET-native resource cleanup through `IDisposable` subscriptions.
39+
- Unary invoke clients and handlers using `Task<T>`.
40+
- Streaming invoke clients and handlers using `IAsyncEnumerable<T>`.
41+
- Request-stream support for unary and streaming invoke flows.
42+
- Cancellation through `CancellationToken`.
43+
- AOT-oriented API shape with explicit generic payload types.
44+
- Minimal adapter surface through `IEventaAdapter`.
45+
46+
## Requirements
47+
48+
- .NET 10 SDK
49+
- A shell that can run `dotnet`
50+
51+
This repository is source-first right now. There is no NuGet installation step
52+
documented here; clone the repository and work from the solution under this
53+
directory.
54+
55+
## Getting Started
56+
57+
From this directory:
58+
59+
```sh
60+
dotnet restore Eventa.slnx --locked-mode
61+
dotnet build Eventa.slnx --configuration Release --no-restore
62+
dotnet test --project tests/Eventa.Tests/Eventa.Tests.csproj --configuration Release --no-build
63+
dotnet run --project examples/Eventa.Example/Eventa.Example.csproj --configuration Release --no-restore
64+
```
65+
66+
The console example walks through basic events, cross-file event contracts,
67+
dependency injection, unary invokes, streaming invokes, request streams,
68+
match expressions, adapter hooks, cancellation, and fatal abort hooks.
69+
70+
## Event Example
71+
72+
```csharp
73+
using Eventa;
74+
75+
using var context = new EventContext();
76+
var moved = new EventDefinition<MovePayload>("demo:move");
77+
78+
using var subscription = context.Subscribe(
79+
moved,
80+
envelope => Console.WriteLine($"{envelope.Body.X},{envelope.Body.Y}"));
81+
82+
context.Emit(moved, new MovePayload(10, 20));
83+
84+
public sealed record MovePayload(int X, int Y);
85+
```
86+
87+
`EventDefinition<T>` gives an event a stable protocol identity and a payload
88+
shape. `EventContext.Subscribe` returns an `IDisposable`; disposing it removes
89+
the listener.
90+
91+
## Unary Invoke Example
92+
93+
```csharp
94+
using Eventa;
95+
96+
using var context = new EventContext();
97+
var echo = new InvokeEventDefinition<EchoResponse, EchoRequest>("demo:rpc:echo");
98+
99+
using var handler = context.RegisterInvokeHandler(
100+
echo,
101+
static (EchoRequest request, CancellationToken _) =>
102+
Task.FromResult(new EchoResponse(request.Input.ToUpperInvariant())));
103+
104+
var client = context.CreateInvokeClient(echo);
105+
var result = await client.InvokeAsync(new EchoRequest("eventa"));
106+
107+
Console.WriteLine(result.Output); // EVENTA
108+
109+
public sealed record EchoRequest(string Input);
110+
111+
public sealed record EchoResponse(string Output);
112+
```
113+
114+
Invoke definitions derive the protocol event ids used for request payloads,
115+
responses, errors, stream completion, and aborts. Concurrent invokes are
116+
correlated internally so each call receives its own response or failure.
117+
118+
## Streaming Invoke Example
119+
120+
```csharp
121+
using System.Runtime.CompilerServices;
122+
123+
using Eventa;
124+
125+
using var context = new EventContext();
126+
var sync = new InvokeEventDefinition<SyncUpdate, SyncRequest>("demo:rpc:sync");
127+
128+
using var handler = context.RegisterStreamHandler(
129+
sync,
130+
SyncJob);
131+
132+
var client = context.CreateInvokeStreamClient(sync);
133+
134+
await foreach (var update in client.InvokeAsync(new SyncRequest("import", 3)))
135+
{
136+
Console.WriteLine(update);
137+
}
138+
139+
static async IAsyncEnumerable<SyncUpdate> SyncJob(
140+
SyncRequest request,
141+
[EnumeratorCancellation] CancellationToken cancellationToken)
142+
{
143+
for (var step = 1; step <= request.Steps; step++)
144+
{
145+
cancellationToken.ThrowIfCancellationRequested();
146+
await Task.Yield();
147+
yield return new SyncProgress(step * 100 / request.Steps);
148+
}
149+
150+
yield return new SyncCompleted(request.JobId);
151+
}
152+
153+
public sealed record SyncRequest(string JobId, int Steps);
154+
155+
public abstract record SyncUpdate;
156+
157+
public sealed record SyncProgress(int Percent) : SyncUpdate;
158+
159+
public sealed record SyncCompleted(string JobId) : SyncUpdate;
160+
```
161+
162+
Streaming invokes return `IAsyncEnumerable<TResponse>`. Handlers can be written
163+
as async iterators or adapted from callback-style code with
164+
`EventStream.ToStreamHandler`.
165+
166+
## Project Layout
167+
168+
```text
169+
.
170+
+-- Eventa.slnx
171+
+-- src/Eventa/ # Core library
172+
+-- tests/Eventa.Tests/ # xUnit v3 tests on Microsoft.Testing.Platform
173+
+-- examples/Eventa.Example/ # Console examples
174+
+-- docs/ # Design and compatibility notes
175+
```
176+
177+
## Development
178+
179+
Useful commands:
180+
181+
```sh
182+
dotnet restore Eventa.slnx --locked-mode
183+
dotnet build Eventa.slnx --configuration Release --no-restore
184+
dotnet test --project tests/Eventa.Tests/Eventa.Tests.csproj --configuration Release --no-build
185+
dotnet run --project examples/Eventa.Example/Eventa.Example.csproj --configuration Release --no-restore
186+
```
187+
188+
The test project uses xUnit v3 with Microsoft.Testing.Platform. Package lock
189+
files are checked in for restore reproducibility.
190+
191+
## TypeScript Relationship
192+
193+
Eventa started in TypeScript as an event-first way to express local events,
194+
RPC, and streaming RPC across swappable transports. This C# project carries the
195+
same core protocol idea into .NET conventions instead of mirroring the
196+
TypeScript API shape directly.
197+
198+
For example, C# uses `Task<T>`, `IAsyncEnumerable<T>`, `CancellationToken`, and
199+
`IDisposable` where the TypeScript package uses promises, readable streams,
200+
abort signals, and unsubscribe callbacks.
201+
202+
## Security Note
203+
204+
Eventa forwards the payloads you emit. Validate data at process, network, and
205+
trust boundaries before sending it to or accepting it from untrusted peers.
206+
207+
## License
208+
209+
MIT
210+
211+
[build-test-src]: https://github.com/moeru-ai/eventa.net/actions/workflows/build-test.yml/badge.svg
212+
[build-test-href]: https://github.com/moeru-ai/eventa.net/actions/workflows/build-test.yml
213+
[run-example-src]: https://github.com/moeru-ai/eventa.net/actions/workflows/run-example.yml/badge.svg
214+
[run-example-href]: https://github.com/moeru-ai/eventa.net/actions/workflows/run-example.yml
215+
[license-src]: https://img.shields.io/github/license/moeru-ai/eventa.net.svg?style=flat
216+
[license-href]: LICENSE

0 commit comments

Comments
 (0)