djust 0.8.2rc1

Pre-releaseSecurityReleased

Added

  • {% theme_css_link %} cache-busting helper tag (v0.8.2 drain — Group T, closes #1012) — Chrome's Vary: Cookie handling is unreliable for per-cookie dynamic CSS; after a pack switch the browser often serves the prior pack's stylesheet from its own HTTP cache and the page renders with stale palette. The new {% theme_css_link %} tag in djust.theming.templatetags.theme_tags emits <link href="/_theming/theme.css?p=<pack>&m=<mode>&r=<preset>"> with cache-busting query params derived from the same ThemeManager.get_state() the view itself reads. Different pack/mode = different URL = guaranteed fresh fetch. Usage: <link rel="stylesheet" href="{% theme_css_link %}">.

  • prose.css for @tailwindcss/typography ↔ pack bridge (v0.8.2 drain — Group T, closes #1009) — new djust_theming/static/djust_theming/css/prose.css ships pack-aware overrides for the typography plugin's --tw-prose-* variables. Opt in by adding prose-djust alongside prose on your <article>. Reads --color-brand-* tokens the active pack emits, so flipping packs at runtime updates prose without a stylesheet swap. Includes both light-mode and dark-mode invert variables. Pulled from docs.djust.org's reference implementation. ~95 lines.

  • enable_client_override flag for LIVEVIEW_CONFIG['theme'] (v0.8.2 drain — Group T, closes #1013)ThemeManager.get_state() reads djust_theme_pack / djust_theme_preset cookies with priority over config defaults. Default behavior unchanged (back-compat True). Sites without a user-facing theme switcher can set LIVEVIEW_CONFIG['theme']['enable_client_override']: False to ignore cookie reads — prevents cross-project bleed on localhost where multiple djust apps share a cookie jar.

Fixed

  • .card / .alert overflow:hidden for clean rounded corners (v0.8.2 drain — Group T, closes #1011)djust_theming/static/djust_theming/css/components.css .card and .alert selectors now set overflow: hidden. Without this, child borders (e.g. .card-header { border-bottom: ... }) cross the parent's rounded arc and produce a visible 1-2 px notch at the corners. Affects every theme pack.

  • mount_batch fallback for old-server compat (v0.8.1 reconcile drain — Group F, closes #1031) — the mount_batch WebSocket frame was added in v0.6.0 (PR #970) for lazy- hydration efficiency. A v0.6.0+ client talking to a pre-v0.6.0 server previously got a generic "Unknown message type: mount_batch" error and the lazy-hydrated views never mounted. Now the client tracks the in-flight batch in lazyHydrationManager.inFlightBatch; if the websocket error handler sees mount_batch or Unknown message type in the error string, it invokes handleMountBatchFallback() which iterates the stashed mounts and falls back to per-view mount calls. Idempotent (clears inFlightBatch before iterating) so a late-arriving successful response can't double-trigger. 7 new JSDOM tests under tests/js/mount-batch-fallback.test.js.

Security

  • Drop exception text from JSON-parse error responses (v0.8.1 reconcile drain — Group B, closes #1026)python/djust/api/dispatch.py (two sites at the API event-dispatch and server-function paths) was returning f"Malformed JSON body: {exc}" — a small but real stack-trace-style leak that could surface parser internals (offsets, snippets of the malformed input) to the client. Aligned to match observability/views.py:401's existing pattern: log the exception server-side via logger.exception(...), return a generic "Malformed JSON body — see server logs" message. The invalid_json error code is unchanged, so callers that branch on error keep working.

Changed

  • WebSocket cache-write failures now log under djustDebug (v0.8.1 reconcile drain — Group B, closes #1030)python/djust/static/djust/src/03-websocket.js:386 previously swallowed cache-put exceptions with a bare catch (_e) {}. Now logs the failure via if (globalThis.djustDebug) console.log(...) so developers can diagnose cache-write misses without polluting production console output.

  • Test infrastructure cleanup (v0.8.1 reconcile drain — Group A, closes #1027, #1028, #1034, #1036) — four small test-quality refactors bundled in one PR:

    • #1036: _assert_benchmark_under and the per-segment budget constants (TARGET_PER_EVENT_S, TARGET_LIST_UPDATE_S, TARGET_WS_MOUNT_S) moved from tests/benchmarks/test_request_path.py into tests/benchmarks/conftest.py for shared scope across benchmark files.
    • #1034: replaced the TARGET_LIST_UPDATE_S * 20 magic-number budget for the WS-mount benchmark with a named TARGET_WS_MOUNT_S = 0.1 constant — rationale lives in the constant name, not the multiplier.
    • #1028: extracted the duplicated _make_user factory into python/djust/tests/conftest.py as make_staff_user(...). Two test files (test_admin_widgets_per_page.py, test_bulk_progress.py) now import the shared factory.
    • #1027: replaced the inspect.getsource-based regression test in test_stack_trace_exposure.py with a behavior-level test that triggers a serialize-error via a sentinel-laden RuntimeError and asserts neither the sentinel nor the exception class name reach the response body. Defends against regressions even if the leak vector moves.

Added

  • make roadmap-lint — mechanical ROADMAP-vs-codebase drift check (Action #142, closes #1057)scripts/roadmap-lint.py parses the "Not started" entries in ROADMAP.md, extracts grep-able tokens from each feature name, and reports entries whose tokens have zero hits in code paths (python/, crates/, static/, scripts/, tests/, Makefile). Pure mechanical check — for semantic auditing (LLM reads each entry, decides if the cited feature actually ships) use the pipeline-roadmap-audit skill instead. Exit code 0 unless drift exceeds threshold (25 suspect entries). Run via make roadmap-lint or make roadmap-lint VERBOSE=1.

  • Pre-push hook for # noqa: F822 in __all__ patterns (Action #146, closes #1061)scripts/check-noqa-f822.sh flags new noqa: F822 annotations introduced in python/**/*.py or tests/**/*.py since the last push. Ruff silences py/undefined-export with noqa: F822, but CodeQL flags it as a security alert later — the canonical fix is a TYPE_CHECKING-conditional import (PR #924 pattern). Hook fires only on changed files (incremental); pass --all to scan the whole tree manually.

All releases · Atom feed