feat(docker-watcher): phase 11 - frontend embed & SSE
Embed SvelteKit static build in Go binary via go:embed. Event bus for pub/sub with deploy log, instance status, and deploy status events. SSE endpoints for real-time streaming. Frontend SSE client with exponential backoff reconnection. Makefile for build pipeline. Update Phase 12 auth plan with OAuth2/OIDC support.
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// StaticHandler serves embedded SPA files with fallback to index.html
|
||||
// for all non-API routes (SPA client-side routing support).
|
||||
func StaticHandler(webFS fs.FS) http.Handler {
|
||||
fileServer := http.FileServer(http.FS(webFS))
|
||||
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// Skip API routes — they are handled by the API router.
|
||||
if strings.HasPrefix(r.URL.Path, "/api") {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// Try to serve the exact file.
|
||||
path := strings.TrimPrefix(r.URL.Path, "/")
|
||||
if path == "" {
|
||||
path = "index.html"
|
||||
}
|
||||
|
||||
// Check if file exists in the embedded FS.
|
||||
f, err := webFS.Open(path)
|
||||
if err == nil {
|
||||
f.Close()
|
||||
// Clear the JSON content-type set by middleware — let file server decide.
|
||||
w.Header().Del("Content-Type")
|
||||
fileServer.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// File not found: serve index.html for SPA client-side routing.
|
||||
r.URL.Path = "/"
|
||||
w.Header().Del("Content-Type")
|
||||
fileServer.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user