{"id":49925296,"url":"https://github.com/cocoar-dev/cocoar.signalarrr","last_synced_at":"2026-05-16T23:17:12.350Z","repository":{"id":346376489,"uuid":"1168835437","full_name":"cocoar-dev/Cocoar.SignalARRR","owner":"cocoar-dev","description":null,"archived":false,"fork":false,"pushed_at":"2026-05-16T15:53:07.000Z","size":828,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"develop","last_synced_at":"2026-05-16T15:53:53.866Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cocoar-dev.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":"NOTICE","maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-27T21:16:11.000Z","updated_at":"2026-05-16T15:53:10.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/cocoar-dev/Cocoar.SignalARRR","commit_stats":null,"previous_names":["cocoar-dev/cocoar.signalarrr"],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/cocoar-dev/Cocoar.SignalARRR","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cocoar-dev%2FCocoar.SignalARRR","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cocoar-dev%2FCocoar.SignalARRR/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cocoar-dev%2FCocoar.SignalARRR/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cocoar-dev%2FCocoar.SignalARRR/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cocoar-dev","download_url":"https://codeload.github.com/cocoar-dev/Cocoar.SignalARRR/tar.gz/refs/heads/develop","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cocoar-dev%2FCocoar.SignalARRR/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33121912,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-16T18:38:32.183Z","status":"ssl_error","status_checked_at":"2026-05-16T18:38:29.903Z","response_time":115,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-05-16T23:17:10.888Z","updated_at":"2026-05-16T23:17:12.337Z","avatar_url":"https://github.com/cocoar-dev.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SignalARRR\n\n[![CI](https://github.com/cocoar-dev/Cocoar.SignalARRR/actions/workflows/ci-pr-validation.yml/badge.svg)](https://github.com/cocoar-dev/Cocoar.SignalARRR/actions/workflows/ci-pr-validation.yml)\n[![NuGet](https://img.shields.io/nuget/v/Cocoar.SignalARRR.Server?label=NuGet)](https://www.nuget.org/packages/Cocoar.SignalARRR.Server)\n[![npm](https://img.shields.io/npm/v/@cocoar/signalarrr?label=npm)](https://www.npmjs.com/package/@cocoar/signalarrr)\n[![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)\n\nTyped bidirectional RPC over ASP.NET Core SignalR.\n\nServer and client call each other's methods through shared interfaces — with compile-time proxy generation, streaming, cancellation propagation, and ASP.NET Core authorization. Clients available for **.NET**, **TypeScript/JavaScript**, and **Swift**.\n\n\u003e **[Read the full documentation](https://docs.cocoar.dev/signalarrr/)**\n\n## Packages\n\n### .NET\n\n| Package | Purpose |\n|---|---|\n| [`Cocoar.SignalARRR.Contracts`](https://www.nuget.org/packages/Cocoar.SignalARRR.Contracts) | `[SignalARRRContract]` attribute + source generator — reference from shared interface projects |\n| [`Cocoar.SignalARRR.Server`](https://www.nuget.org/packages/Cocoar.SignalARRR.Server) | Server-side: HARRR hub, ServerMethods, authorization, ClientManager |\n| [`Cocoar.SignalARRR.Client`](https://www.nuget.org/packages/Cocoar.SignalARRR.Client) | Client-side: HARRRConnection, typed proxies, event handlers |\n| [`Cocoar.SignalARRR.DynamicProxy`](https://www.nuget.org/packages/Cocoar.SignalARRR.DynamicProxy) | Opt-in runtime proxy fallback via DispatchProxy |\n| [`Cocoar.SignalARRR.Client.FullFramework`](https://www.nuget.org/packages/Cocoar.SignalARRR.Client.FullFramework) | Client for .NET Framework 4.6.2+ — typed proxies, streaming, file transfer |\n\n### TypeScript / JavaScript\n\n```\nnpm install @cocoar/signalarrr\n```\n\n### Swift (iOS / macOS)\n\n```swift\n.package(url: \"https://github.com/cocoar-dev/Cocoar.SignalARRR.git\", from: \"4.0.0\")\n```\n\n## Quick Start\n\nDefine shared interfaces, set up the server, and call methods with full type safety:\n\n```csharp\n// Shared interface\n[SignalARRRContract]\npublic interface IChatHub {\n    Task SendMessage(string user, string message);\n    Task\u003cList\u003cstring\u003e\u003e GetHistory();\n}\n\n// Client usage — one line to get a typed proxy\nvar chat = connection.GetTypedMethods\u003cIChatHub\u003e();\nawait chat.SendMessage(\"Alice\", \"Hello!\");\n```\n\n```typescript\n// TypeScript client\nconst history = await connection.invoke\u003cstring[]\u003e('ChatMethods.GetHistory');\n```\n\n```swift\n// Swift client — @HubProxy macro generates the proxy\n@HubProxy protocol IChatHub { ... }\nlet chat = connection.getTypedMethods(IChatHubProxy.self)\n```\n\nFor full setup guides, streaming, authorization, and server-to-client calls, see the **[documentation](https://docs.cocoar.dev/signalarrr/)**.\n\n## Features\n\n- **Typed bidirectional RPC** — server and client call each other through shared interfaces\n- **Compile-time proxy generation** — Roslyn source generator (zero reflection)\n- **Organized hub methods** — split logic across `ServerMethods\u003cT\u003e` classes with full DI\n- **Streaming** — `IAsyncEnumerable\u003cT\u003e`, `IObservable\u003cT\u003e`, `ChannelReader\u003cT\u003e` in both directions\n- **HTTP stream references** — file download/upload through SignalR hub methods\n- **CancellationToken propagation** — server can cancel client operations remotely\n- **Authorization** — method-level, class-level, and hub-level `[Authorize]`\n- **Server-to-client calls from anywhere** — inject `ClientManager` in controllers, background services, etc.\n- **Four clients** — .NET, .NET Framework, TypeScript/JavaScript, Swift\n- **Typed broadcasts** — `WithHub\u003cT\u003e().WithGroup().SendAsync\u003cT\u003e()` for groups and filtered clients\n- **Redis-compatible multi-node backplane** — opt-in scale-out with Redis, Valkey, or Garnet\n\n## Redis-compatible backplane\n\nSignalARRR stays pure in-memory by default. If you do **not** configure a backplane, behavior remains single-node and process-local exactly as before.\n\nFor multi-node scale-out, opt in with the built-in Redis-compatible backplane:\n\n```csharp\nbuilder.Services.AddSignalARRR(b =\u003e\n    b.AddServerMethodsFrom(typeof(ChatHub).Assembly));\n\nbuilder.Services.AddSignalARRRRedisBackplane(options =\u003e options\n    .WithConnectionString(\"localhost:6379,abortConnect=false\")\n    .WithChannelPrefix(\"my-app\")\n    .WithNodeId($\"{Environment.MachineName}-api-1\"));\n```\n\nThis works with **Redis**, **Valkey**, and **Garnet** because SignalARRR talks to a Redis-compatible backend via `StackExchange.Redis`.\n\n### What becomes cluster-aware\n\n- `GetTypedMethods\u003cT\u003e(connectionId)` send/invoke across nodes\n- `WithHub\u003cT\u003e().SendAsync(...)` across all nodes\n- `WithGroup(...)`, `WithUser(...)`, and `WithAttribute(...)` across nodes\n- `InvokeAllAsync(...)` and `InvokeOneAsync(...)` across nodes\n- `AddToGroupAsync(...)` / `RemoveFromGroupAsync(...)` for remote connections\n- Presence APIs on `ClientManager`:\n  - `GetConnectionsAsync\u003cTHub\u003e()`\n  - `GetConnectionsByUserAsync\u003cTHub\u003e(...)`\n  - `GetConnectionsInGroupAsync\u003cTHub\u003e(...)`\n  - `GetConnectionsByAttributeAsync\u003cTHub\u003e(...)`\n  - `GetOnlineUsersAsync\u003cTHub\u003e()`\n  - `IsUserOnlineAsync\u003cTHub\u003e(...)`\n\n### Cluster semantics\n\n- **Transient transport**: the backplane distributes live messages; it is not a durable queue or event store.\n- **Eventual convergence**: connection, group, user, and attribute metadata propagate quickly, but not atomically across all nodes. Right after connect/disconnect/group changes there can be a short convergence window.\n- **Crash cleanup**: dead nodes are removed by heartbeat + timeout sweep. Tune `WithHeartbeatInterval(...)` and `WithNodeTimeout(...)` if you want faster stale-node cleanup.\n- **Safe fallback**: without `AddSignalARRRRedisBackplane(...)`, all APIs continue to use the old in-memory single-node path.\n\n## Framework Support\n\n| Target | Version |\n|---|---|\n| .NET (server + client) | .NET 8 / .NET 9 / .NET 10 |\n| .NET Framework (client) | 4.6.2+ (via `Cocoar.SignalARRR.Client.FullFramework`) |\n| TypeScript / JavaScript | Node.js 22 / modern browsers |\n| Swift (iOS / macOS) | Swift 5.10+, iOS 14+ / macOS 11+ |\n\n## Building from Source\n\n```bash\n# .NET\ndotnet build src/Cocoar.SignalARRR.slnx\ndotnet test src/Cocoar.SignalARRR.slnx\n\n# TypeScript\ncd src/Cocoar.SignalARRR.Typescript \u0026\u0026 npm install \u0026\u0026 npm run build\n\n# Swift\nswift build \u0026\u0026 swift test\n```\n\n## License\n\nApache License 2.0 — see [LICENSE](LICENSE) for details.\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcocoar-dev%2Fcocoar.signalarrr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcocoar-dev%2Fcocoar.signalarrr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcocoar-dev%2Fcocoar.signalarrr/lists"}