Merge PR #597: cross-origin isolation for embedded HermesWorld (threading parity)
Some checks failed
CI / Build & Lint (push) Has been cancelled
CI / Run Tests (push) Has been cancelled
Build & publish Docker image / build-and-push (push) Has been cancelled
Security Scan / Scan for Secrets (push) Has been cancelled

fix(workspace): cross-origin isolation for embedded HermesWorld (threading parity with web client)
This commit is contained in:
Eric
2026-06-05 20:46:46 -04:00
committed by GitHub

View File

@@ -480,6 +480,19 @@ const config = defineConfig(({ mode, command }) => {
],
},
server: {
// Cross-origin isolation so the embedded HermesWorld WebGL client keeps
// SharedArrayBuffer multithreading (matches the standalone web client at
// play.hermes-world.ai). Without these, the iframe silently drops to a
// single thread → render+physics+netcode contend on one thread → inflated
// ping / worse frame pacing even though network RTT is identical.
// COEP 'credentialless' enables isolation WITHOUT requiring CORP headers
// on every cross-origin asset (fonts/images); the web client already sends
// cross-origin-resource-policy: cross-origin so the iframe still embeds.
// Same-origin agent API (/ws-claude, /api/claude-proxy) is unaffected.
headers: {
'Cross-Origin-Opener-Policy': 'same-origin',
'Cross-Origin-Embedder-Policy': 'credentialless',
},
// Force IPv4 — 'localhost' resolves to ::1 (IPv6) on Windows, breaking connectivity
host: '0.0.0.0',
// Port precedence:
@@ -575,6 +588,17 @@ const config = defineConfig(({ mode, command }) => {
if (command !== 'serve') return
},
configureServer(server) {
// Cross-origin isolation headers on EVERY response so the embedded
// HermesWorld WebGL client keeps SharedArrayBuffer multithreading
// (matches play.hermes-world.ai). Injected via middleware because the
// TanStack Start SSR handler owns the HTML response and overrides
// vite's server.headers. COEP 'credentialless' avoids requiring CORP
// on every cross-origin asset; same-origin agent API is unaffected.
server.middlewares.use((_req, res, next) => {
res.setHeader('Cross-Origin-Opener-Policy', 'same-origin')
res.setHeader('Cross-Origin-Embedder-Policy', 'credentialless')
next()
})
server.middlewares.use(async (req, res, next) => {
const requestPath = req.url?.split('?')[0]
if (req.method === 'GET' && requestPath === '/api/healthcheck') {