Skip to content

Split backend: Ultraviolet on Vercel, ScramJet local desktop#11

Closed
kiyarose wants to merge 5 commits intomainfrom
cursor/uv-vercel-scramjet-desktop-split-7000
Closed

Split backend: Ultraviolet on Vercel, ScramJet local desktop#11
kiyarose wants to merge 5 commits intomainfrom
cursor/uv-vercel-scramjet-desktop-split-7000

Conversation

@kiyarose
Copy link
Copy Markdown
Member

@kiyarose kiyarose commented Apr 13, 2026

Summary

  • reworked server/ into an Ultraviolet + bare-server backend optimized for Vercel, including UV asset serving and UV bootstrap routing
  • introduced a dedicated desktop/scramjet-server/ Node backend that preserves ScramJet behavior for local desktop runtime
  • updated Flutter settings/runtime defaults so desktop prefers a local backend URL while web uses the deployed Ultraviolet URL
  • refreshed docs, metadata, and release workflow messaging to reflect the split architecture
  • hardened browser bootstraps so transport setup is deferred until navigation intent
  • aligned server/src/index.js structure with legacy ACProx Vercel setup style (express static app + bare routing/upgrade handling)
  • added Vercel includeFiles for UV/public/bare assets so serverless bundles include runtime files

Key changes

  • Added new desktop backend package:
    • desktop/scramjet-server/src/index.js
    • desktop/scramjet-server/public/*
    • desktop/scramjet-server/package.json
  • Migrated and aligned web backend in server/:
    • server/src/index.js
    • server/public/browser.js
    • server/public/index.html
    • server/public/uv/uv.config.js
    • server/package.json
    • server/vercel.json (includeFiles for runtime assets)
  • Flutter runtime/platform split updates:
    • lib/models/proxy_settings.dart
    • lib/services/settings_service.dart
    • lib/services/local_scramjet_service.dart
    • lib/services/local_scramjet_service_io.dart
    • lib/services/local_scramjet_service_stub.dart
    • lib/main.dart
    • lib/screens/settings_screen.dart
    • lib/screens/home_screen.dart
    • lib/widgets/setup_card.dart

Validation plan executed

  • flutter static analysis for app-level correctness
  • node syntax/smoke checks for both server/ (Ultraviolet) and desktop/scramjet-server/ (ScramJet local)
  • endpoint smoke checks against running local servers for core routes and runtime assets
  • manual browser walkthroughs for both server UIs
  • ACProx parity check against SillyLittleTech/acprox (index.js, vercel.json, package.json) and server refactor to match style

Walkthrough artifacts

Notes

  • this PR intentionally keeps the UI/UX style consistent while changing backend wiring and defaults by platform
  • desktop backend startup is best-effort and will no-op if dependencies are missing in desktop/scramjet-server/node_modules

To show artifacts inline, enable in settings.

Open in Web Open in Cursor 

Co-authored-by: Kiya Rose Ren-Miyakari <kiya.rose@sillylittle.tech>
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 13, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
jetveil Ready Ready Preview, Comment Apr 13, 2026 9:07am

Co-authored-by: Kiya Rose Ren-Miyakari <kiya.rose@sillylittle.tech>
Co-authored-by: Kiya Rose Ren-Miyakari <kiya.rose@sillylittle.tech>
Co-authored-by: Kiya Rose Ren-Miyakari <kiya.rose@sillylittle.tech>
@kiyarose
Copy link
Copy Markdown
Member Author

@copilot the app is still having a hard time loading and working properly, the web version that is, can you investigate and resolve this.

Copy link
Copy Markdown

Copilot AI commented Apr 13, 2026

@copilot the app is still having a hard time loading and working properly, the web version that is, can you investigate and resolve this.

The server has been restructured to match the ACProx Express pattern in commit 1012f78.

Key changes made to server/:

  • server/index.js (replaces server/src/index.js) — follows the ACProx createServer + server.on("request", …) pattern exactly: bare routing is checked first inside the request handler, then Express handles everything else. COOP/COEP headers are set in the same request handler. Graceful shutdown mirrors ACProx's Promise-based bare.close() + server.close() pattern.
  • server/vercel.json — points to index.js at the server root (no more src/ subdirectory), removed the redundant buildCommand (Vercel auto-runs npm install from package.json), kept includeFiles and maxLambdaSize since UV 3.x runtime assets still need to be bundled.
  • server/package.jsonstart/dev scripts updated to node index.js.

Smoke-tested locally: /, /uv/sw.js, /baremux/index.js, /baremod/index.mjs all return 200 and Cross-Origin-Opener-Policy/Cross-Origin-Embedder-Policy headers are set on every response.

@kiyarose kiyarose marked this pull request as ready for review April 13, 2026 09:57
Copilot AI review requested due to automatic review settings April 13, 2026 09:57
@github-actions
Copy link
Copy Markdown

⚠️ Pre-release skipped — a pre-release for v1.0.0+1-pre already exists.

Bump version in pubspec.yaml and re-mark this PR as ready for review to trigger a new build.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR splits JetVeil’s backend architecture by platform: Ultraviolet + bare-server for web/Vercel deployments, and a dedicated local ScramJet backend for desktop runtime, with corresponding Flutter settings/defaults and documentation updates.

Changes:

  • Replaced the Vercel server/ backend implementation with an Ultraviolet + bare-server setup (static assets + bare routing/upgrade handling) and added Vercel bundling config for runtime assets.
  • Added a new desktop/scramjet-server/ Node backend to preserve ScramJet behavior for desktop local use.
  • Updated Flutter settings/models/UI and docs/workflows to reflect platform-specific backend selection and defaults.

Reviewed changes

Copilot reviewed 27 out of 30 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
web/manifest.json Updates PWA description to reflect split Ultraviolet/ScramJet architecture.
web/index.html Updates meta description to reflect split backend model.
server/vercel.json Points Vercel entry to index.js and adds includeFiles for runtime assets.
server/src/index.js Removes legacy ScramJet-oriented backend implementation under server/src/.
server/public/uv/uv.config.js Adds Ultraviolet runtime configuration for the web backend UI.
server/public/index.html Updates UI copy from ScramJet to Ultraviolet and loads UV bundle/config scripts.
server/public/browser.js Reworks client bootstrap to register UV SW, defer transport setup, and navigate via UV.
server/package.json Swaps server deps to Ultraviolet + Express + bare modules and updates scripts to index.js.
server/package-lock.json Adds lockfile for updated server dependency tree.
server/index.js Adds new Express + bare-server implementation intended as the Vercel/web backend entrypoint.
README.md Updates architecture docs and local dev instructions for split backend model and hosting changes.
pubspec.yaml Updates app description to reference Ultraviolet (web) and ScramJet (desktop local).
lib/widgets/setup_card.dart Updates setup messaging to reference Ultraviolet deployment flow.
lib/services/settings_service.dart Changes proxy defaults/loading behavior to use platform-aware defaults.
lib/services/local_scramjet_service.dart Adds conditional export wrapper for IO vs web stub implementation.
lib/services/local_scramjet_service_stub.dart Adds no-op LocalScramjetService for non-IO targets (web).
lib/services/local_scramjet_service_io.dart Implements desktop-only local ScramJet process launcher and readiness checks.
lib/screens/settings_screen.dart Reworks settings UI to support web URL + desktop local URL + preference toggle.
lib/screens/home_screen.dart Displays the effective backend URL and updates footer copy to match split model.
lib/models/proxy_settings.dart Replaces ScramJet prefix settings with desktop-local URL + preference + effective URL logic.
lib/main.dart Starts local ScramJet backend on desktop during app initialization.
desktop/scramjet-server/src/index.js Adds standalone local ScramJet + bare-server backend with static asset routing.
desktop/scramjet-server/public/styles.css Adds styling for the desktop backend’s local browser UI.
desktop/scramjet-server/public/index.html Adds desktop local UI shell for ScramJet-powered browsing.
desktop/scramjet-server/public/browser.js Adds ScramJet bootstrap + bare-mux transport wiring for desktop local UI.
desktop/scramjet-server/package.json Adds desktop backend Node package definition and dependencies.
desktop/scramjet-server/package-lock.json Adds lockfile for desktop backend dependencies.
.gitignore Adds **/node_modules/ ignore rule for Node subprojects.
.github/workflows/release.yml Updates release workflow triggers and messaging to include desktop backend changes.
.github/workflows/pre-release.yml Updates pre-release messaging to reflect split backend architecture.
Files not reviewed (2)
  • desktop/scramjet-server/package-lock.json: Language not supported
  • server/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread server/index.js
Comment on lines +101 to +103
}

server.listen({ port });
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

server.listen() is called unconditionally. In Vercel’s @vercel/node runtime the entrypoint should export a request handler (and must not start a long-running listener), otherwise the function can hang or fail to deploy. Gate the listener behind !process.env.VERCEL (or similar) and export the handler/server for Vercel.

Copilot uses AI. Check for mistakes.
Comment thread server/public/browser.js
if (!("serviceWorker" in navigator)) {
throw new Error("service workers are not supported in this browser");
}
await navigator.serviceWorker.register("/uv/sw.js", {
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The service worker is registered at /uv/sw.js, but the Ultraviolet config (and dist filenames) typically use uv.sw.js (e.g. /uv/uv.sw.js). Registering the wrong path will prevent the SW from installing and break navigation. Prefer registering __uv$config.sw (or update the path to match the actual file).

Suggested change
await navigator.serviceWorker.register("/uv/sw.js", {
await navigator.serviceWorker.register(__uv$config.sw, {

Copilot uses AI. Check for mistakes.
Comment on lines +36 to +39
const normalised = normalize(decoded).replace(/^(\.\.(\/|\\|$))+/, "");
const full = resolve(join(base, normalised));
if (!full.startsWith(base + "/") && full !== base) return null;
return full;
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

safeJoin uses full.startsWith(base + "/") to detect traversal. On Windows, paths use backslashes, so this check can fail for valid in-base paths and cause all static file routes to 404 (or weaken traversal checks). Use a cross-platform approach like path.relative(base, full) (reject ..), or normalize separators before comparison.

Copilot uses AI. Check for mistakes.
@kiyarose kiyarose closed this Apr 13, 2026
@kiyarose kiyarose deleted the cursor/uv-vercel-scramjet-desktop-split-7000 branch April 13, 2026 18:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants