Auto-bust sx.js and body.js via MD5 hash instead of manual version string

Computes file content hash at process startup, cached for lifetime.
Removes manual cache-busting instruction from CLAUDE.md.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-01 23:26:20 +00:00
parent 7ccb463a8b
commit aa5c251a45
2 changed files with 20 additions and 3 deletions

View File

@@ -5,7 +5,6 @@ Cooperative web platform: federated content, commerce, events, and media process
## Deployment
- **Do NOT push** until explicitly told to. Pushes reload code to dev automatically.
- **Cache busting:** After editing `sx.js`, bump the `?v=` query string in `shared/sx/helpers.py` (search for `sx.js?v=`).
## Project Structure

View File

@@ -6,6 +6,8 @@ page elements (headers, search, etc.) from template context.
"""
from __future__ import annotations
import hashlib
from pathlib import Path
from typing import Any
from markupsafe import escape
@@ -482,8 +484,8 @@ details.group{{overflow:hidden}}details.group>summary{{list-style:none}}details.
<body class="bg-stone-50 text-stone-900">
<script type="text/sx" data-components>{component_defs}</script>
<script type="text/sx" data-mount="body">{page_sx}</script>
<script src="{asset_url}/scripts/sx.js?v=20260301d"></script>
<script src="{asset_url}/scripts/body.js"></script>
<script src="{asset_url}/scripts/sx.js?v={sx_js_hash}"></script>
<script src="{asset_url}/scripts/body.js?v={body_js_hash}"></script>
</body>
</html>"""
@@ -544,9 +546,25 @@ def sx_page(ctx: dict, page_sx: str, *,
page_sx=page_sx,
sx_css=sx_css,
sx_css_classes=sx_css_classes,
sx_js_hash=_script_hash("sx.js"),
body_js_hash=_script_hash("body.js"),
)
_SCRIPT_HASH_CACHE: dict[str, str] = {}
def _script_hash(filename: str) -> str:
"""Compute MD5 hash of a static script file, cached for process lifetime."""
if filename not in _SCRIPT_HASH_CACHE:
try:
data = (Path("static") / "scripts" / filename).read_bytes()
_SCRIPT_HASH_CACHE[filename] = hashlib.md5(data).hexdigest()[:8]
except Exception:
_SCRIPT_HASH_CACHE[filename] = "dev"
return _SCRIPT_HASH_CACHE[filename]
def _get_csrf_token() -> str:
"""Get the CSRF token from the current request context."""
try: