Fuaran.UI.ServerDriven 0.6.0

Prefix Reserved
There is a newer version of this package available.
See the version list below for details.
dotnet add package Fuaran.UI.ServerDriven --version 0.6.0
                    
NuGet\Install-Package Fuaran.UI.ServerDriven -Version 0.6.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Fuaran.UI.ServerDriven" Version="0.6.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Fuaran.UI.ServerDriven" Version="0.6.0" />
                    
Directory.Packages.props
<PackageReference Include="Fuaran.UI.ServerDriven" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Fuaran.UI.ServerDriven --version 0.6.0
                    
#r "nuget: Fuaran.UI.ServerDriven, 0.6.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Fuaran.UI.ServerDriven@0.6.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Fuaran.UI.ServerDriven&version=0.6.0
                    
Install as a Cake Addin
#tool nuget:?package=Fuaran.UI.ServerDriven&version=0.6.0
                    
Install as a Cake Tool

Fuaran.UI.ServerDriven

The transport-agnostic core for server-driven interactivity over a Fuaran tree — the third client tier (alongside the Fable client renderer and the Phase 143 hydrateRoot hydration), HTMX / Phoenix-LiveView / Blazor-Server-shaped: keep the Elmish update loop on the server, ship one tiny generic JS shim to the browser, and patch the DOM in place.

The loop: browser event on a [data-fuaran-node-id] element → server runs update → re-renders the tree → diffs old→new into a TreeOp list (Fuaran.UI.OpStream.Replay.TreeOpDiff) → lowers each op to a DomPatch (rendering HTML fragments via Fuaran.UI.Renderer.Server for structure-adding ops) → sends the patch → the shim applies it (targeted, no full re-render, no flash).

What's here

  • DomPatch — the lowered, closure-free, browser-applyable patch vocabulary (8 primitives: SetAttr / RemoveAttr / SetText / ReplaceFragment / InsertFragment / RemoveNode / ReorderChildren / MoveNode). The shim's entire instruction set. Tagged-object camelCase JSON.
  • ClientEffect — the parallel channel for client-only effects the server decides but the shim performs (WriteToClipboard / Navigate / Focus / Download / ReadFileBody), because they are inherently browser-side and have no DOM-mutation form.
  • LoweringTreeOp → DomPatch (Lowering.lower : renderFragment -> newTree -> TreeOp list -> DomPatch list). Structural ops lower directly (RemoveNode / ReorderChildren / MoveNode / InsertChildInsertFragment); content ops re-render the changed node (looked up in the post-apply tree) into a targeted ReplaceFragment; Batch flattens. The HTML renderer is injected (renderFragment : Node<'Msg> -> string) rather than a hard Renderer.Server dependency — keeps the core Fable-clean + dependency-light and dodges the Node<obj> cast; the host wires Render.render.
  • content/fuaran-live-patch.js — the generic browser shim (shipped as package content under content/). App-agnostic, framework-free vanilla JS (~a few KB): event delegation on [data-fuaran-node-id], a transport adapter (connect/send — the client mirror of IFuaranLiveChannel, default SSE-push + POST-receive), the DomPatch applier (addresses by node id; MoveNode / ReorderChildren relocate the live element, identity-preserving), and the ClientEffect performer. Auto-starts from <script src="fuaran-live-patch.js" data-fuaran-live-stream="/live/stream" data-fuaran-live-send="/live/event">, or call FuaranLive.start(config, adapterFactory?) explicitly (a WebSocket adapter is a drop-in — only the adapter object changes; the patch/effect/delegation core is transport-identical). start() is restartable — hosts that swap the live tree per page state call it repeatedly: each call closes the previous stream and re-points the once-wired document-level delegation at the new transport (no leaked EventSource, no duplicate sends). Click payloads bridge layout interactivity server-side: a tab-header click carries payload.index (from the server renderer's data-tab-index), a disclosure summary click carries payload.open (from the <details> state). Browser-verified via samples/server-driven (tabs + disclosure + repeated start()); no headless unit tests.

Roadmap (Phase 152)

  • ✅ Track A — the TreeOp-emitting diff (Fuaran.UI.OpStream.Replay.TreeOpDiff).
  • Track B (in progress) — ✅ the DomPatch / ClientEffect wire vocabularies (this package), ✅ the TreeOp → DomPatch lowering (renderer injected), ✅ the generic JS shim. Remaining: the granular SetText / SetAttr lowering follow-on (currently content ops re-render the node via ReplaceFragment — correct + targeted, just not field-level).
  • Track C (in progress) — ✅ the G1 inbound trust boundary (Validation.fs — the non-negotiable default-deny gate: node-exists / event-legitimate-for-kind / payload-in-bounds / dispatch-policy-gated, mirroring the client runAction gate server-side), ✅ the per-connection driver (Driver.fsLiveSession + step: validate → interpret → update → re-view → diff → lower → DomPatch/ClientEffect, with the server-closure win + the server-executable/client-only split). Remaining: the explicit per-field Binding.Local / CommitLocal form-buffer protocol (the floor — client-buffered, server-sees-the-flush — already holds).
  • Track D ✅ — the IFuaranLiveChannel transport seam + Frame + InMemoryChannel + LiveConnection (Channel.fs), transport-agnostic reconnect replay (LiveConnection.Resync), the SSE frame wire encoding (FrameWire.fs), and both backends: Fuaran.UI.ServerDriven.AspNetCore (SSE+POST, the v1 default — verified end-to-end via the sample) and Fuaran.UI.ServerDriven.WebSocket (the lower-latency drop-in; its structural identity to the SSE backend proves the seam is transport-neutral).
  • Track E ✅fuaran-dotnet/docs/SERVER_DRIVEN.md (architecture + transport analysis + the per-arm tables) and samples/server-driven (an SSR counter made live via the shim + the SSE backend, no client bundle).

No platform-SDK dependency appears anywhere here — the SSE framing is implemented here, not depended on.

Apache-2.0 licensed — see the repo LICENSE.

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (5)

Showing the top 5 NuGet packages that depend on Fuaran.UI.ServerDriven:

Package Downloads
Fuaran.UI.ServerDriven.AspNetCore

Fuaran server-driven backend 1 (v1 default) — SSE-push + POST-receive over ASP.NET. The thin transport glue around the Fuaran.UI.ServerDriven core: an SSE IFuaranLiveChannel, the POST inbound parser, the connection registry, and the GET-stream / POST-event endpoint wiring (mapFuaranLive). Default because SSE+POST rides natively through proxies/CDNs/WAFs, gets per-event HTTP governance for free, and maps reconnect 1:1 onto the journal via Last-Event-ID. No platform-SDK dependency (the SSE framing is self-contained). Apache-2.0 licensed.

Fuaran.UI.ServerDriven.WebSocket

Fuaran server-driven backend 2 — one bidirectional WebSocket channel over ASP.NET. The lower-latency transport for measured high-frequency interaction (per-keystroke, drag, live cursors). A first-class second backend whose structural identity to the SSE backend (differing only in channel + endpoint glue) is the architectural-integrity check that IFuaranLiveChannel is genuinely transport-neutral. No platform-SDK dependency. Apache-2.0 licensed.

Fuaran.Program.Bounded

Fuaran.Program.Bounded — the bounded program interpreter: a total fold of the wire-representable action set over a program's state store, with the no-closure-invocation invariant that makes an emitted tree safe to run untrusted. Placement-neutral by construction (the same interpreter drives a server session and a browser client), plus the server placement's loop with its per-interaction resource budget. Apache-2.0 licensed.

Fuaran.Program.Runtime

Fuaran.Program.Runtime — the client placement of the bounded program loop: run a wire-decoded program tree interactively in the browser with no hand-authored update function, no message type and no server. Shares the interpreter with the server placement rather than reimplementing it, so the same tree behaves identically at both. Renderer, effect performer, op sink and live channel are injected seams. Apache-2.0 licensed.

Fuaran.Program.Server

Fuaran.Program.Server — the server-logic placement of the bounded program loop: run a named, host-registered handler as data behind a program tree's call action, with a closed server-effect vocabulary (query, op-apply, host call, patch, notify) behind a default-deny gate. Shares the interpreter, the resource budget and the binding re-resolution pass with the other placements rather than reimplementing them. Carries the codec for the handler declared form, the effect vocabulary and the outcome report, certified against their own conformance corpus. Apache-2.0 licensed.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.39.0 0 8/27/2026
0.35.0 62 8/24/2026
0.32.0 87 8/23/2026
0.31.0 100 8/21/2026
0.30.0 82 8/21/2026
0.29.0 114 8/19/2026
0.28.0 112 8/18/2026
0.27.0 105 8/18/2026
0.26.0 119 8/18/2026
0.18.0 107 8/10/2026
0.15.0 105 8/9/2026
0.12.0 125 7/31/2026
0.11.0 119 7/30/2026
0.10.0 121 7/29/2026
0.6.0 120 7/27/2026
0.4.0 124 7/26/2026
0.3.0 122 7/24/2026