Compare commits

...

1 Commits

Author SHA1 Message Date
Timmy
4cc893874c feat(#1339): Deploy Nexus to proper URL for preview
Some checks failed
CI / test (pull_request) Failing after 46s
Review Approval Gate / verify-review (pull_request) Failing after 7s
CI / validate (pull_request) Failing after 46s
ES module imports fail via file:// or raw Forge URLs (CORS +
missing Content-Type). boot.js already detects this and warns users.

Three deployment options:
  - ./preview.sh — local Python server, correct MIME types
  - docker compose up nexus-preview — nginx + WS proxy on :8080
  - Push to main — GitHub Pages auto-deploy via CI

Files:
  - Dockerfile.preview: nginx preview container
  - preview/nginx.conf: correct MIME types + /api/world/ws proxy
  - preview.sh: Python one-liner preview server
  - PREVIEW.md: deployment documentation
  - .github/workflows/pages.yml: GitHub Pages CI/CD
  - docker-compose.yml: added nexus-preview + nexus-backend
  - deploy.sh: added preview/full modes

Fixes #1339
2026-04-13 21:12:01 -04:00
7 changed files with 260 additions and 4 deletions

47
.github/workflows/pages.yml vendored Normal file
View File

@@ -0,0 +1,47 @@
name: Deploy Nexus Preview to Pages
on:
push:
branches: [main]
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: "pages"
cancel-in-progress: false
jobs:
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Pages
uses: actions/configure-pages@v5
- name: Prepare static assets
run: |
mkdir -p _site
cp index.html app.js style.css boot.js gofai_worker.js _site/
cp service-worker.js manifest.json robots.txt help.html _site/
cp portals.json vision.json _site/
cp -r nexus/ _site/nexus/
cp -r icons/ _site/icons/ 2>/dev/null || true
cp -r assets/ _site/assets/ 2>/dev/null || true
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: '_site'
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4

22
Dockerfile.preview Normal file
View File

@@ -0,0 +1,22 @@
FROM nginx:alpine
RUN rm /etc/nginx/conf.d/default.conf
COPY preview/nginx.conf /etc/nginx/conf.d/default.conf
COPY index.html /usr/share/nginx/html/
COPY app.js /usr/share/nginx/html/
COPY style.css /usr/share/nginx/html/
COPY boot.js /usr/share/nginx/html/
COPY gofai_worker.js /usr/share/nginx/html/
COPY service-worker.js /usr/share/nginx/html/
COPY manifest.json /usr/share/nginx/html/
COPY robots.txt /usr/share/nginx/html/
COPY help.html /usr/share/nginx/html/
COPY portals.json /usr/share/nginx/html/
COPY vision.json /usr/share/nginx/html/
COPY nexus/ /usr/share/nginx/html/nexus/
COPY icons/ /usr/share/nginx/html/icons/
COPY assets/ /usr/share/nginx/html/assets/
EXPOSE 8080

42
PREVIEW.md Normal file
View File

@@ -0,0 +1,42 @@
# Nexus Preview Deployment
Deploy The Nexus to a proper URL so ES module imports work.
## Problem
`file://` and raw Forge URLs break ES module imports (CORS + wrong Content-Type).
`boot.js` already detects this: _"Serve this world over HTTP to initialize Three.js."_
## Quick Start
```bash
./preview.sh # http://localhost:8080 (Python, no deps)
./preview.sh docker # http://localhost:8080 (nginx + WS proxy)
docker compose up -d nexus-preview nexus-backend # full stack
```
## Deploy Options
| Method | Command | URL |
|--------|---------|-----|
| Local Python | `./preview.sh` | http://localhost:8080 |
| Docker nginx | `docker compose up nexus-preview` | http://localhost:8080 |
| GitHub Pages | push to main | auto-deploy |
| VPS nginx | copy files + nginx | your-domain.com |
## Architecture
```
Browser ──► nginx :8080 ──► index.html, app.js, style.css, nexus/
└── /api/world/ws ──► proxy ──► nexus-backend :8765
```
## Files
| File | Purpose |
|------|---------|
| `Dockerfile.preview` | nginx preview container |
| `preview/nginx.conf` | MIME types + WebSocket proxy |
| `preview.sh` | Python preview server |
| `.github/workflows/pages.yml` | GitHub Pages auto-deploy |

View File

@@ -1,7 +1,9 @@
#!/usr/bin/env bash
# deploy.sh — spin up (or update) the Nexus staging environment
# Usage: ./deploy.sh — rebuild and restart nexus-main (port 4200)
# ./deploy.sh staging — rebuild and restart nexus-staging (port 4201)
# deploy.sh — spin up (or update) the Nexus environment
# Usage: ./deploy.sh — rebuild nexus-main (port 8765)
# ./deploy.sh staging — rebuild nexus-staging (port 8766)
# ./deploy.sh preview — deploy static preview (port 8080)
# ./deploy.sh full — deploy preview + backend
set -euo pipefail
SERVICE="${1:-nexus-main}"
@@ -9,6 +11,21 @@ SERVICE="${1:-nexus-main}"
case "$SERVICE" in
staging) SERVICE="nexus-staging" ;;
main) SERVICE="nexus-main" ;;
preview)
echo "==> Deploying Nexus preview on http://localhost:8080"
docker compose build nexus-preview
docker compose up -d --force-recreate nexus-preview
echo "==> Preview at http://localhost:8080"
exit 0
;;
full)
echo "==> Deploying full Nexus stack (preview + backend)"
docker compose build nexus-preview nexus-backend
docker compose up -d --force-recreate nexus-preview nexus-backend
echo "==> Preview: http://localhost:8080"
echo "==> Backend WS: nexus-backend:8765"
exit 0
;;
esac
echo "==> Deploying $SERVICE"

View File

@@ -7,9 +7,28 @@ services:
restart: unless-stopped
ports:
- "8765:8765"
nexus-staging:
build: .
container_name: nexus-staging
restart: unless-stopped
ports:
- "8766:8765"
- "8766:8765"
nexus-backend:
build: .
container_name: nexus-backend
restart: unless-stopped
expose:
- "8765"
nexus-preview:
build:
context: .
dockerfile: Dockerfile.preview
container_name: nexus-preview
restart: unless-stopped
ports:
- "8080:8080"
depends_on:
- nexus-backend

52
preview.sh Executable file
View File

@@ -0,0 +1,52 @@
#!/usr/bin/env bash
# preview.sh — One-command preview server for The Nexus
# Serves static files with correct MIME types so ES modules load.
#
# Usage:
# ./preview.sh — http://localhost:8080
# ./preview.sh 3000 — http://localhost:3000
# ./preview.sh docker — Docker/nginx instead
set -euo pipefail
PORT="${1:-8080}"
if [ "$PORT" = "docker" ]; then
echo "==> Starting Nexus preview via Docker/nginx..."
docker compose up -d nexus-preview
echo "==> Preview at http://localhost:8080"
exit 0
fi
if ! command -v python3 &> /dev/null; then
echo "Error: python3 not found. Use './preview.sh docker' instead."
exit 1
fi
echo "==> Nexus preview on http://localhost:$PORT"
echo "==> Ctrl+C to stop"
echo ""
python3 -c "
import http.server, socketserver
PORT = $PORT
class Handler(http.server.SimpleHTTPRequestHandler):
def end_headers(self):
self.send_header('Access-Control-Allow-Origin', '*')
super().end_headers()
def guess_type(self, path):
if path.endswith('.js') or path.endswith('.mjs'):
return 'application/javascript'
if path.endswith('.css'):
return 'text/css'
if path.endswith('.json'):
return 'application/json'
return super().guess_type(path)
with socketserver.TCPServer(('', PORT), Handler) as httpd:
print(f'Serving at http://localhost:{PORT}')
httpd.serve_forever()
"

57
preview/nginx.conf Normal file
View File

@@ -0,0 +1,57 @@
server {
listen 8080;
server_name _;
root /usr/share/nginx/html;
index index.html;
# Serve static assets with correct MIME types
location / {
try_files $uri $uri/ /index.html;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
}
# ES modules need correct Content-Type
location ~* \.js$ {
types { application/javascript js; }
add_header Cache-Control "public, max-age=3600";
}
location ~* \.css$ {
types { text/css css; }
add_header Cache-Control "public, max-age=3600";
}
location ~* \.json$ {
types { application/json json; }
add_header Cache-Control "no-cache";
}
# Proxy WebSocket to backend (app.js connects to /api/world/ws)
location /api/world/ws {
proxy_pass http://nexus-backend:8765;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 86400;
}
# Direct WebSocket proxy
location /ws {
proxy_pass http://nexus-backend:8765;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 86400;
}
# Health check
location /health {
return 200 '{"status":"ok","service":"nexus-preview"}';
add_header Content-Type application/json;
}
}