Env-driven dev ports + splash as the front door
vite.config.ts now reads WEB_PORT (Vite) and PORT (API) from .env via loadEnv, with the /api proxy following PORT and strictPort on — so two branch checkouts can each run `npm run dev` on their own ports. Play now always lands on the splash at the bare root instead of silently resuming an active playthrough; a Resume action continues one when present. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,9 +1,18 @@
|
|||||||
DATABASE_URL=postgres://osint:osint_secret@localhost:5433/osint_dev
|
DATABASE_URL=postgres://osint:osint_secret@localhost:5433/osint_dev
|
||||||
|
|
||||||
|
# Dev ports — give each branch checkout distinct values to run them side by side.
|
||||||
|
# PORT is the Express API; WEB_PORT is the Vite dev server, which proxies /api to PORT.
|
||||||
PORT=8787
|
PORT=8787
|
||||||
|
WEB_PORT=5173
|
||||||
CORS_ORIGIN=http://localhost:5173
|
CORS_ORIGIN=http://localhost:5173
|
||||||
LEVEL_EDITING_ENABLED=true
|
LEVEL_EDITING_ENABLED=true
|
||||||
JWT_SECRET=osint-local-dev-secret
|
JWT_SECRET=osint-local-dev-secret
|
||||||
MAX_DOCUMENT_BYTES=26214400
|
MAX_DOCUMENT_BYTES=26214400
|
||||||
|
OCR_ENABLED=true
|
||||||
|
OCR_LANGUAGES=nor+eng
|
||||||
|
OCR_TIMEOUT_MS=20000
|
||||||
|
MAX_OCR_BYTES=15728640
|
||||||
|
MAX_EXTRACTED_TEXT_CHARACTERS=200000
|
||||||
|
|
||||||
# Game asset storage (MinIO). Start it with: docker compose -f docker-compose.dev.yml up -d minio createbuckets
|
# Game asset storage (MinIO). Start it with: docker compose -f docker-compose.dev.yml up -d minio createbuckets
|
||||||
S3_ENDPOINT=http://localhost:9000
|
S3_ENDPOINT=http://localhost:9000
|
||||||
|
|||||||
+7
-3
@@ -7,6 +7,7 @@ import { CutsceneHost, DialoguePlayer, SplashScreen, type PlaythroughState } fro
|
|||||||
// board route (/level/<clone id>), which App renders.
|
// board route (/level/<clone id>), which App renders.
|
||||||
export function Play() {
|
export function Play() {
|
||||||
const [state, setState] = useState<PlaythroughState | null>(null)
|
const [state, setState] = useState<PlaythroughState | null>(null)
|
||||||
|
const [resumable, setResumable] = useState<PlaythroughState | null>(null)
|
||||||
const [splash, setSplash] = useState(false)
|
const [splash, setSplash] = useState(false)
|
||||||
const [busy, setBusy] = useState(false)
|
const [busy, setBusy] = useState(false)
|
||||||
const [status, setStatus] = useState('')
|
const [status, setStatus] = useState('')
|
||||||
@@ -37,10 +38,13 @@ export function Play() {
|
|||||||
if (!cancelled) res.ok ? apply(await res.json()) : setStatus('NODE NOT FOUND')
|
if (!cancelled) res.ok ? apply(await res.json()) : setStatus('NODE NOT FOUND')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// The bare root is always the front door: show the splash, and offer Resume
|
||||||
|
// when a playthrough is already in progress rather than auto-resuming into it.
|
||||||
const res = await fetch('/api/playthroughs/current')
|
const res = await fetch('/api/playthroughs/current')
|
||||||
if (cancelled) return
|
if (cancelled) return
|
||||||
if (res.status === 204) { setSplash(true); setStatus('AWAITING PRINCIPAL INVESTIGATOR'); return }
|
if (res.ok && res.status !== 204) setResumable(await res.json())
|
||||||
res.ok ? apply(await res.json()) : setSplash(true)
|
setSplash(true)
|
||||||
|
setStatus('AWAITING PRINCIPAL INVESTIGATOR')
|
||||||
})()
|
})()
|
||||||
return () => { cancelled = true }
|
return () => { cancelled = true }
|
||||||
}, [apply])
|
}, [apply])
|
||||||
@@ -62,7 +66,7 @@ export function Play() {
|
|||||||
if (res.ok) apply(await res.json())
|
if (res.ok) apply(await res.json())
|
||||||
}
|
}
|
||||||
|
|
||||||
if (splash) return <SplashScreen hasResume={false} busy={busy} status={status} onNewGame={newGame} onResume={() => {}} />
|
if (splash) return <SplashScreen hasResume={!!resumable} busy={busy} status={status} onNewGame={newGame} onResume={() => { if (resumable) apply(resumable) }} />
|
||||||
|
|
||||||
const node = state?.node
|
const node = state?.node
|
||||||
if (!node) return <div className="boot"><div className="seal">GU</div><p>GLITCH UNIVERSITY NETWORK TERMINAL</p><small>{status || 'OPENING CASE FILE…'}</small></div>
|
if (!node) return <div className="boot"><div className="seal">GU</div><p>GLITCH UNIVERSITY NETWORK TERMINAL</p><small>{status || 'OPENING CASE FILE…'}</small></div>
|
||||||
|
|||||||
+13
-4
@@ -1,10 +1,19 @@
|
|||||||
import { defineConfig } from 'vite'
|
import { defineConfig, loadEnv } from 'vite'
|
||||||
import react from '@vitejs/plugin-react'
|
import react from '@vitejs/plugin-react'
|
||||||
|
|
||||||
export default defineConfig({
|
// Ports are read from .env so two branch checkouts can run `npm run dev` side by
|
||||||
|
// side: give each folder its own WEB_PORT (Vite) and PORT (API). The /api proxy
|
||||||
|
// follows PORT so the web server always talks to its own backend.
|
||||||
|
export default defineConfig(({ mode }) => {
|
||||||
|
const env = loadEnv(mode, process.cwd(), '')
|
||||||
|
const webPort = Number(env.WEB_PORT || 5173)
|
||||||
|
const apiPort = Number(env.PORT || 8787)
|
||||||
|
return {
|
||||||
plugins: [react()],
|
plugins: [react()],
|
||||||
server: {
|
server: {
|
||||||
port: 5173,
|
port: webPort,
|
||||||
proxy: { '/api': 'http://127.0.0.1:8787' },
|
strictPort: true, // fail loudly on a clash instead of silently picking another port
|
||||||
|
proxy: { '/api': `http://127.0.0.1:${apiPort}` },
|
||||||
},
|
},
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user