fix(nginx): serve AIUI's absolute /assets/ requests from aiui/assets/

Taking over a parked item from the app-UI work. AIUI's built index.html
emits ABSOLUTE /assets/<hashed> paths, so the browser asks for
/assets/index-BC2fBBaW.js. That lands in the MAIN UI's assets dir, where
it does not exist — the real files are in aiui/assets/. Both of AIUI's
two entry assets 404'd, so the embedded sidebar loaded nothing.

The config already contained a /aiui-assets/ location whose comment names
this exact problem ("AIUI may reference /assets/ without /aiui/ prefix"),
but it only catches requests to /aiui-assets/, a path AIUI never asks
for. It described the bug without fixing it.

/assets/ now falls back to a named location that rewrites into
aiui/assets/ and 404s from there. A fallback rather than copying the two
files up one level, because a frontend deploy replaces web-ui wholesale —
update.rs preserves the aiui/ DIRECTORY, not copies made into assets/ —
so a copy is erased by the very next deploy while this survives one.

Both server blocks (HTTP and HTTPS) are patched; named locations are
per-server, so each needs its own.

Verified on archi-dev-box after reload:
  /assets/index-BC2fBBaW.js   200, 305256 bytes, application/javascript
  /assets/index-BJkaQ2c4.css  200, 150716 bytes, text/css
  /assets/does-not-exist.js   404  (the fallback is not over-broad)
  /assets/index--lyLAgu1.js   200  (real main-UI chunks still come from
  /assets/vendor-CmYeCqL_.js  200   the main dir — try_files hits them
  /assets/index-CiMaoNII.css  200   before the fallback is consulted)
  /  /aiui/  /health          200

Hash collision between the two builds is not a concern: Vite hashes are
content-derived, and any main-UI asset that exists is served by try_files
before the fallback runs.

Noted while doing this, not fixed here: the node's own
/etc/nginx/sites-enabled/archipelago is 378 lines BEHIND this repo file
(984 vs 1362) — it predates the IPv6 listener and the @asset_missing
no-store handling, among others. The node was patched minimally in its
own shape rather than overwritten, since a wholesale copy of a config
this diverged is not a safe unattended action.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
archipelago
2026-08-02 23:40:34 -04:00
co-authored by Claude Opus 5
parent c4aece4883
commit fbec70069f
@@ -125,6 +125,23 @@ server {
# `always` the header applies only to 2xx/3xx; 404s are routed to a
# named location that marks them no-store so the browser retries.
location /assets/ {
try_files $uri @aiui_assets;
add_header Cache-Control "public, max-age=31536000, immutable";
}
# AIUI's built index.html emits ABSOLUTE /assets/<hashed> paths, so they
# land here, in the MAIN UI's assets dir, where they do not exist — the
# real files are in aiui/assets/. The nearby /aiui-assets/ alias names this
# exact problem in its comment but only catches a path AIUI never requests,
# so it never fixed it.
#
# A fallback rather than copying the files up one level: a frontend deploy
# replaces web-ui wholesale (update.rs preserves the aiui/ directory itself,
# not copies made into assets/), so a copy is erased by the very next deploy
# while this survives. Hash collision with a real main-UI asset is not a
# concern — Vite hashes are content-derived, and a main asset that exists is
# served by try_files before this is ever consulted.
location @aiui_assets {
rewrite ^/assets/(.*)$ /aiui/assets/$1 break;
try_files $uri =404;
add_header Cache-Control "public, max-age=31536000, immutable";
error_page 404 = @asset_missing;
@@ -985,6 +1002,23 @@ server {
# HTTP block). No `always` on the immutable header: a transient 404 must
# not be cached for a year — 404s go to @asset_missing (no-store) instead.
location /assets/ {
try_files $uri @aiui_assets;
add_header Cache-Control "public, max-age=31536000, immutable";
}
# AIUI's built index.html emits ABSOLUTE /assets/<hashed> paths, so they
# land here, in the MAIN UI's assets dir, where they do not exist — the
# real files are in aiui/assets/. The nearby /aiui-assets/ alias names this
# exact problem in its comment but only catches a path AIUI never requests,
# so it never fixed it.
#
# A fallback rather than copying the files up one level: a frontend deploy
# replaces web-ui wholesale (update.rs preserves the aiui/ directory itself,
# not copies made into assets/), so a copy is erased by the very next deploy
# while this survives. Hash collision with a real main-UI asset is not a
# concern — Vite hashes are content-derived, and a main asset that exists is
# served by try_files before this is ever consulted.
location @aiui_assets {
rewrite ^/assets/(.*)$ /aiui/assets/$1 break;
try_files $uri =404;
add_header Cache-Control "public, max-age=31536000, immutable";
error_page 404 = @asset_missing;