From 14c183b992e90fa0aed49f06856740fcb2591a2f Mon Sep 17 00:00:00 2001 From: Jeff Emmett Date: Mon, 16 Mar 2026 17:02:10 -0700 Subject: [PATCH] fix(rsplat): use request Host header for staged image URLs fal.ai needs to download the staged image. Using hardcoded PUBLIC_ORIGIN (rspace.online) fails because Cloudflare redirects /data/ paths and the subdomain (jeff.rspace.online) isn't matched. Now derives the public URL from the request's Host header. Added logging for staged image URLs. Co-Authored-By: Claude Opus 4.6 --- server/index.ts | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/server/index.ts b/server/index.ts index 4385e07..113d25d 100644 --- a/server/index.ts +++ b/server/index.ts @@ -1201,6 +1201,14 @@ app.post("/api/video-gen/i2v", async (c) => { // Stage image for 3D generation (binary upload → HTTPS URL for fal.ai) const PUBLIC_ORIGIN = process.env.PUBLIC_ORIGIN || "https://rspace.online"; + +/** Build public URL using the request's Host header so subdomains (jeff.rspace.online) work */ +function publicUrl(c: any, path: string): string { + const host = c.req.header("host") || new URL(PUBLIC_ORIGIN).host; + const proto = c.req.header("x-forwarded-proto") || "https"; + return `${proto}://${host}${path}`; +} + app.post("/api/image-stage", async (c) => { const ct = c.req.header("content-type") || ""; console.log("[image-stage] Content-Type:", ct); @@ -1217,7 +1225,9 @@ app.post("/api/image-stage", async (c) => { const dir = resolve(process.env.FILES_DIR || "./data/files", "generated"); const filename = `stage-${Date.now()}-${Math.random().toString(36).slice(2, 6)}.jpg`; await Bun.write(resolve(dir, filename), buf); - return c.json({ url: `${PUBLIC_ORIGIN}/api/files/generated/${filename}` }); + const url = publicUrl(c, `/api/files/generated/${filename}`); + console.log("[image-stage] Staged (binary fallback):", url); + return c.json({ url }); } return c.json({ error: "Invalid upload format. Expected multipart/form-data." }, 400); } @@ -1249,7 +1259,9 @@ app.post("/api/image-stage", async (c) => { const buf = Buffer.from(await file.arrayBuffer()); await Bun.write(resolve(dir, filename), buf); - return c.json({ url: `${PUBLIC_ORIGIN}/api/files/generated/${filename}` }); + const url = publicUrl(c, `/api/files/generated/${filename}`); + console.log("[image-stage] Staged:", url, `(${buf.length} bytes)`); + return c.json({ url }); }); // Image-to-3D via fal.ai Hunyuan3D v2.1 (async job queue)