Recently Written · git

subplz-web

git clone https://github.com/equwal/subplz-web

Log | Files | Refs


commit 2925a3853d109ab3fec04c5cd559a23d0ce7c0b8
equwal <truex@equwal.com>
2026-09-21 16:48:03 -0700

Make the browser revalidate the engine scripts

engine/job.js imports ./asr.js by bare path, so a browser could keep an
old asr.js and run it with a new app.js. The old asr.js fetched the
model from huggingface.co. The page, app.js and the engine modules now
answer with Cache-Control: no-cache, and the ETag makes the check one
round trip. The pinned files under /vendor/ may stay for a day.

 backend/main.py              |  8 ++++++++
 tests/test_static_headers.py | 25 +++++++++++++++++++++++++
 2 files changed, 33 insertions(+)
diff --git a/backend/main.py b/backend/main.py
index 80063b7..a6ee76e 100644
--- a/backend/main.py
+++ b/backend/main.py
@@ -137,6 +137,14 @@ async def cross_origin_isolation(request, call_next):
     response = await call_next(request)
     response.headers["Cross-Origin-Opener-Policy"] = "same-origin"
     response.headers["Cross-Origin-Embedder-Policy"] = "credentialless"
+    # The engine's modules import each other by bare path, so a browser that
+    # kept an old engine/asr.js would run it with a new app.js. Make each of
+    # them ask the server first (an ETag answers in one round trip); the
+    # pinned libraries and weights under /vendor/ may stay a day.
+    if request.url.path.startswith("/vendor/"):
+        response.headers["Cache-Control"] = "public, max-age=86400"
+    elif response.headers.get("content-type", "").startswith(("text/javascript", "text/html")):
+        response.headers["Cache-Control"] = "no-cache"
     return response
 
 
diff --git a/tests/test_static_headers.py b/tests/test_static_headers.py
new file mode 100644
index 0000000..4810d5d
--- /dev/null
+++ b/tests/test_static_headers.py
@@ -0,0 +1,25 @@
+"""The headers on the static files: cross-origin isolation, and how long a
+browser may keep each file."""
+
+from __future__ import annotations
+
+
+def test_page_is_cross_origin_isolated(client):
+    r = client.get("/")
+    assert r.headers["cross-origin-opener-policy"] == "same-origin"
+    assert r.headers["cross-origin-embedder-policy"] == "credentialless"
+
+
+def test_engine_modules_are_revalidated_every_time(client):
+    # engine/job.js imports ./asr.js by bare path. A kept copy of one with a
+    # new copy of the other is a broken engine, so each must ask the server.
+    for path in ("/", "/app.js", "/engine/asr.js", "/engine/job.js"):
+        r = client.get(path)
+        assert r.status_code == 200, path
+        assert r.headers["cache-control"] == "no-cache", path
+
+
+def test_vendor_files_may_be_kept(client):
+    r = client.get("/vendor/versions.json")
+    assert r.status_code == 200
+    assert r.headers["cache-control"] == "public, max-age=86400"