package api import ( "net/http" "os" "path/filepath" "strings" ) // newStaticHandler serves the Astro static build with SPA fallbacks: // /search/ and /tools/ → their respective shell pages. func newStaticHandler(dir string) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { urlPath := r.URL.Path if strings.HasPrefix(urlPath, "/search/") && len(urlPath) > len("/search/") { http.ServeFile(w, r, filepath.Join(dir, "search", "_", "index.html")) return } if strings.HasPrefix(urlPath, "/tools/") { rest := strings.TrimPrefix(urlPath, "/tools/") if rest != "" && !strings.Contains(rest, "/") { http.ServeFile(w, r, filepath.Join(dir, "tools", "_", "index.html")) return } } rel := filepath.FromSlash(strings.TrimPrefix(urlPath, "/")) full := filepath.Join(dir, rel) info, err := os.Stat(full) if err == nil && info.IsDir() { full = filepath.Join(full, "index.html") if _, err2 := os.Stat(full); err2 != nil { serve404(w, r, dir) return } } else if err != nil { serve404(w, r, dir) return } http.ServeFile(w, r, full) }) } func serve404(w http.ResponseWriter, r *http.Request, dir string) { p := filepath.Join(dir, "404.html") if _, err := os.Stat(p); err == nil { w.WriteHeader(http.StatusNotFound) http.ServeFile(w, r, p) return } http.NotFound(w, r) }