controller: .fab browser download — the existing export pipeline staged under the data dir + a guarded streaming exit (estimate-first, io.Copy, post-stream cleanup, 1h TTL sweep); portability framing (decision 3); traversal guard red-proven, export→import round-trip + corrupt-bundle refusal unit-proven

Claude-Session: https://claude.ai/code/session_01GzammAMzsJTgpQHqxwM2bC
This commit is contained in:
2026-07-13 09:47:10 +02:00
parent aa967fbf69
commit 753cd83456
6 changed files with 607 additions and 0 deletions
@@ -43,6 +43,15 @@ func (s *Server) ServeExportAPI(w http.ResponseWriter, r *http.Request) {
case path == "/api/export/status" && r.Method == http.MethodGet:
s.apiExportStatus(w, r)
// .fab browser download (v0.124.0): estimate → start (existing pipeline, staging dest) →
// guarded stream. Portability exit only — no scheduling, no status surface.
case path == "/api/export/download/estimate" && r.Method == http.MethodGet:
s.apiExportDownloadEstimate(w, r)
case path == "/api/export/download/start" && r.Method == http.MethodPost:
s.apiExportDownloadStart(w, r)
case path == "/api/export/download" && r.Method == http.MethodGet:
s.apiExportDownloadFetch(w, r)
// GET /api/export/bundles — scan for .fab files on all drives
case path == "/api/export/bundles" && r.Method == http.MethodGet:
s.apiExportBundles(w, r)