server {
    listen 3000;
    server_name _;

    root /usr/share/nginx/html;
    index index.html;

    # MIME for WASM streaming compile.
    types {
        application/wasm wasm;
    }

    # Security headers.
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "DENY" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    # WebAssembly + crypto.subtle require secure-context; cross-origin isolation
    # is needed for SharedArrayBuffer used by the signing WASM bundles.
    add_header Cross-Origin-Opener-Policy "same-origin" always;
    add_header Cross-Origin-Embedder-Policy "require-corp" always;

    # Compression.
    gzip on;
    gzip_vary on;
    gzip_min_length 256;
    gzip_types
        application/javascript
        application/json
        application/wasm
        application/xml
        text/css
        text/javascript
        text/plain
        image/svg+xml;

    # Hashed assets (Vite emits /assets/* with content hashes) — cache forever.
    location /assets/ {
        add_header Cache-Control "public, max-age=31536000, immutable" always;
        try_files $uri =404;
    }

    # Never cache the shell HTML.
    location = /index.html {
        add_header Cache-Control "no-cache" always;
    }

    # WISP websocket — must be proxied by an outer reverse proxy or sidecar.
    # Return 502 so the frontend gets a clear signal rather than the SPA shell.
    location /wisp/ {
        return 502;
    }

    # Hash routing (no server-side routes needed) — fall back to index.html.
    location / {
        try_files $uri $uri/ /index.html;
    }
}
