From aa5c251a45c7935379576119cb3ebbaa311cc7ad Mon Sep 17 00:00:00 2001 From: giles Date: Sun, 1 Mar 2026 23:26:20 +0000 Subject: [PATCH] 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 --- CLAUDE.md | 1 - shared/sx/helpers.py | 22 ++++++++++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index fa4ca3a..438bd41 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -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 diff --git a/shared/sx/helpers.py b/shared/sx/helpers.py index 4304d73..ddb2b7b 100644 --- a/shared/sx/helpers.py +++ b/shared/sx/helpers.py @@ -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. - - + + """ @@ -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: