From 6da518d9907d8424519de6ba97cf82dce44e575c Mon Sep 17 00:00:00 2001 From: Gerard Webb <183988205+joeblew999@users.noreply.github.com> Date: Thu, 11 Dec 2025 16:51:16 +0700 Subject: [PATCH] feat: Add Handler() method and fix SSE closed pipe errors (#24) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add Handler() method for testing and custom server integration Exposes the underlying http.Handler to enable: - Integration testing with gost-dom/browser for SSE/Datastar testing - Custom server setups (e.g., embedding Via in existing applications) - Standard Go httptest patterns 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 * fix: Suppress closed pipe errors when SSE connection closes Don't log error when SSE fails to send patches if the connection was already closed. This reduces noise in logs during shutdown and testing, where browsers/clients close connections before server handlers finish. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --------- Co-authored-by: joeblew999 Co-authored-by: Claude Opus 4.5 --- via.go | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/via.go b/via.go index 6b37ad6..94fb510 100644 --- a/via.go +++ b/via.go @@ -243,6 +243,12 @@ func (v *V) Start() { log.Fatalf("[fatal] %v", http.ListenAndServe(v.cfg.ServerAddress, v.mux)) } +// Handler returns the underlying http.Handler for use with custom servers or testing. +// This enables integration with test frameworks like gost-dom/browser for SSE/Datastar testing. +func (v *V) Handler() http.Handler { + return v.mux +} + func (v *V) devModePersist(c *Context) { p := filepath.Join(".via", "devmode", "ctx.json") if err := os.MkdirAll(filepath.Dir(p), 0755); err != nil { @@ -413,17 +419,24 @@ func New() *V { switch patch.typ { case patchTypeElements: if err := sse.PatchElements(patch.content); err != nil { - v.logErr(c, "PatchElements failed: %v", err) + // Only log if connection wasn't closed (avoids noise during shutdown/tests) + if sse.Context().Err() == nil { + v.logErr(c, "PatchElements failed: %v", err) + } continue } case patchTypeSignals: if err := sse.PatchSignals([]byte(patch.content)); err != nil { - v.logErr(c, "PatchSignals failed: %v", err) + if sse.Context().Err() == nil { + v.logErr(c, "PatchSignals failed: %v", err) + } continue } case patchTypeScript: if err := sse.ExecuteScript(patch.content, datastar.WithExecuteScriptAutoRemove(true)); err != nil { - v.logErr(c, "ExecuteScript failed: %v", err) + if sse.Context().Err() == nil { + v.logErr(c, "ExecuteScript failed: %v", err) + } continue } }