fix(streams): connect desktop directly to Fly.io streams server#1404
Conversation
The API proxy was causing ERR_CONTENT_DECODING_FAILED in production because Node.js fetch auto-decompresses responses but forwards the original Content-Encoding headers, causing browsers to double-decompress. Instead of patching the proxy, remove it entirely and have the desktop app connect directly to the streams server on Fly.io (streams.superset.sh). This eliminates the Vercel middleman, reduces latency, and avoids serverless timeout limits on long-lived SSE connections.
📝 WalkthroughWalkthroughThis change migrates the streams service from being accessed through an API proxy to direct client access via a new Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
The streams URL needs to be in the renderer's Content Security Policy connect-src directive, and replaced at build time via the HTML env transform plugin. Renamed from STREAMS_URL to NEXT_PUBLIC_STREAMS_URL to follow the convention for renderer-visible env vars.
🧹 Preview Cleanup CompleteThe following preview resources have been cleaned up:
Thank you for your contribution! 🎉 |
Remove STREAMS_URL from API deploy workflows (proxy deleted). Add NEXT_PUBLIC_STREAMS_URL to desktop build workflow.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@apps/streams/fly.toml`:
- Line 13: The CORS_ORIGINS entry currently includes an unnecessary Tauri
origin; update the CORS_ORIGINS value (the CORS_ORIGINS setting string) to
remove "tauri://localhost" so only valid Electron/production origins remain
(e.g., "https://app.superset.sh,https://admin.superset.sh"), ensuring you remove
any extra commas so the CSV string remains well-formed.
In `@apps/streams/src/index.ts`:
- Around line 23-25: After splitting and trimming env.CORS_ORIGINS into
corsOrigins, filter out empty strings so the resulting array contains only valid
origins; update the logic that builds corsOrigins in apps/streams/src/index.ts
(the corsOrigins variable) to remove entries where o === "" (e.g., via a
.filter) so server.ts's allowedOrigins.includes(origin) won't mistakenly match
empty-string or have an array with no real origins.
| STREAMS_INTERNAL_PORT = "8081" | ||
| STREAMS_INTERNAL_URL = "http://127.0.0.1:8081" | ||
| NODE_ENV = "production" | ||
| CORS_ORIGINS = "https://app.superset.sh,https://admin.superset.sh,tauri://localhost" |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check for Tauri configuration files
echo "=== Searching for Tauri configuration ==="
fd -t f "tauri.conf" --max-results 10
# Check for Tauri in TOML files (excluding fly.toml)
echo "=== Tauri references in TOML files ==="
rg "tauri" --type=toml -g '!fly.toml' --max-count=20
# Check for Tauri in package.json files
echo "=== Tauri in package.json files ==="
rg "@tauri" --type=json -g 'package.json' --max-count=20
# Check desktop app structure
echo "=== Desktop app structure ==="
ls -la apps/desktop/ 2>/dev/null | head -20
# Check for Electron in desktop package.json
echo "=== Electron/Tauri in apps/desktop/package.json ==="
cat apps/desktop/package.json 2>/dev/null | grep -A 5 -E '"(electron|tauri)"'Repository: superset-sh/superset
Length of output: 1681
Remove tauri://localhost from CORS_ORIGINS — this is an Electron-only app, not Tauri.
The desktop application uses Electron exclusively (electron-vite, electron-builder). Tauri is not present in the codebase. The tauri://localhost origin is unnecessary and should be removed from the configuration.
🤖 Prompt for AI Agents
In `@apps/streams/fly.toml` at line 13, The CORS_ORIGINS entry currently includes
an unnecessary Tauri origin; update the CORS_ORIGINS value (the CORS_ORIGINS
setting string) to remove "tauri://localhost" so only valid Electron/production
origins remain (e.g., "https://app.superset.sh,https://admin.superset.sh"),
ensuring you remove any extra commas so the CSV string remains well-formed.
| const corsOrigins = env.CORS_ORIGINS | ||
| ? env.CORS_ORIGINS.split(",").map((o) => o.trim()) | ||
| : undefined; |
There was a problem hiding this comment.
Filter out empty strings after splitting CORS_ORIGINS.
A trailing comma (e.g., "https://a.com,https://b.com,") would produce an empty string element after split+trim. In server.ts, allowedOrigins.includes(origin) would then match origin === "", which is the deny sentinel — but more subtly, a bare "," would yield ["", ""], making the array truthy while containing no valid origins.
Proposed fix
const corsOrigins = env.CORS_ORIGINS
- ? env.CORS_ORIGINS.split(",").map((o) => o.trim())
+ ? env.CORS_ORIGINS.split(",").map((o) => o.trim()).filter(Boolean)
: undefined;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const corsOrigins = env.CORS_ORIGINS | |
| ? env.CORS_ORIGINS.split(",").map((o) => o.trim()) | |
| : undefined; | |
| const corsOrigins = env.CORS_ORIGINS | |
| ? env.CORS_ORIGINS.split(",").map((o) => o.trim()).filter(Boolean) | |
| : undefined; |
🤖 Prompt for AI Agents
In `@apps/streams/src/index.ts` around lines 23 - 25, After splitting and trimming
env.CORS_ORIGINS into corsOrigins, filter out empty strings so the resulting
array contains only valid origins; update the logic that builds corsOrigins in
apps/streams/src/index.ts (the corsOrigins variable) to remove entries where o
=== "" (e.g., via a .filter) so server.ts's allowedOrigins.includes(origin)
won't mistakenly match empty-string or have an array with no real origins.
Summary
ERR_CONTENT_DECODING_FAILEDbecause the Vercel API proxy double-encoded response bodiesstreams.superset.sh)Changes
Removed — API proxy (
apps/api)apps/api/src/app/api/streams/[...path]/route.tsSTREAMS_URLfrom API env schema (no longer needed)Updated — Desktop (
apps/desktop)STREAMS_URLenv var with defaulthttps://streams.superset.shgetConfigandChatSessionManagerto useSTREAMS_URLdirectly instead of routing through the API proxyUpdated — Streams server (
apps/streams)CORS_ORIGINSenv var for configurable allowed originscreateServerwith function-based origin checkfile://null-origin requests in CORS middlewarefly.tomlTest Plan
streams.superset.sh→ Fly.io (cert already provisioned)https://streams.superset.sh/healthreturns 200STREAMS_URL=http://localhost:8080)Summary by CodeRabbit
New Features
Improvements