Fuaran.UI.ServerDriven
0.3.0
Prefix Reserved
See the version list below for details.
dotnet add package Fuaran.UI.ServerDriven --version 0.3.0
NuGet\Install-Package Fuaran.UI.ServerDriven -Version 0.3.0
<PackageReference Include="Fuaran.UI.ServerDriven" Version="0.3.0" />
<PackageVersion Include="Fuaran.UI.ServerDriven" Version="0.3.0" />
<PackageReference Include="Fuaran.UI.ServerDriven" />
paket add Fuaran.UI.ServerDriven --version 0.3.0
#r "nuget: Fuaran.UI.ServerDriven, 0.3.0"
#:package Fuaran.UI.ServerDriven@0.3.0
#addin nuget:?package=Fuaran.UI.ServerDriven&version=0.3.0
#tool nuget:?package=Fuaran.UI.ServerDriven&version=0.3.0
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.Lowering—TreeOp → DomPatch(Lowering.lower : renderFragment -> newTree -> TreeOp list -> DomPatch list). Structural ops lower directly (RemoveNode/ReorderChildren/MoveNode/InsertChild→InsertFragment); content ops re-render the changed node (looked up in the post-apply tree) into a targetedReplaceFragment;Batchflattens. The HTML renderer is injected (renderFragment : Node<'Msg> -> string) rather than a hardRenderer.Serverdependency — keeps the core Fable-clean + dependency-light and dodges theNode<obj>cast; the host wiresRender.render.content/fuaran-live-patch.js— the generic browser shim (shipped as package content undercontent/). App-agnostic, framework-free vanilla JS (~a few KB): event delegation on[data-fuaran-node-id], a transport adapter (connect/send— the client mirror ofIFuaranLiveChannel, default SSE-push + POST-receive), theDomPatchapplier (addresses by node id;MoveNode/ReorderChildrenrelocate the live element, identity-preserving), and theClientEffectperformer. Auto-starts from<script src="fuaran-live-patch.js" data-fuaran-live-stream="/live/stream" data-fuaran-live-send="/live/event">, or callFuaranLive.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 leakedEventSource, no duplicate sends). Click payloads bridge layout interactivity server-side: a tab-header click carriespayload.index(from the server renderer'sdata-tab-index), a disclosure summary click carriespayload.open(from the<details>state). Browser-verified viasamples/server-driven(tabs + disclosure + repeatedstart()); no headless unit tests.
Roadmap (Phase 152)
- ✅ Track A — the
TreeOp-emitting diff (Fuaran.UI.OpStream.Replay.TreeOpDiff). - Track B (in progress) — ✅ the
DomPatch/ClientEffectwire vocabularies (this package), ✅ theTreeOp → DomPatchlowering (renderer injected), ✅ the generic JS shim. Remaining: the granularSetText/SetAttrlowering follow-on (currently content ops re-render the node viaReplaceFragment— 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 clientrunActiongate server-side), ✅ the per-connection driver (Driver.fs—LiveSession+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-fieldBinding.Local/CommitLocalform-buffer protocol (the floor — client-buffered, server-sees-the-flush — already holds). - Track D ✅ — the
IFuaranLiveChanneltransport 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) andFuaran.UI.ServerDriven.WebSocket(the lower-latency drop-in; its structural identity to the SSE backend proves the seam is transport-neutral). - Track E ✅ —
fuaran/docs/SERVER_DRIVEN.md(architecture + transport analysis + the per-arm tables) andsamples/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 | 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
- Fable.Core (>= 5.0.0)
- FSharp.Core (>= 10.1.300)
- Fuaran.Core.Column (>= 0.1.11)
- Fuaran.Core.DataFrame (>= 0.1.11)
- Fuaran.Core.Function (>= 0.1.11)
- Fuaran.Core.Ops (>= 0.1.11)
- Fuaran.Core.OpStream (>= 0.1.11)
- Fuaran.Core.Tree (>= 0.1.11)
- Fuaran.Core.Wire (>= 0.1.11)
- Fuaran.UI (>= 0.3.0)
- Fuaran.UI.Ops (>= 0.3.0)
- Fuaran.UI.OpStream.Replay (>= 0.3.0)
- Fuaran.UI.Renderer.Core (>= 0.3.0)
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 |