Skip to content

v0.4.3

Choose a tag to compare

@shivamsn97 shivamsn97 released this 12 Jun 08:16
· 6 commits to main since this release
fd17c46
  • Security: hardened HEAD sanitisation (XSS). Dynamic HEAD values/callables that interpolate loader data into raw head strings — the documented dynamic-meta-tags recipe — could previously inject markup because attribute values weren't escaped (a " in a <meta content> broke out of the attribute). Head elements are now parsed and rebuilt from a strict tag allowlist with every attribute value HTML-escaped, on* handlers dropped, javascript:/vbscript:/data: URLs neutralised, <meta http-equiv="refresh"> and non-head tags rejected, and any markup injected after a breakout discarded. Inline <script>/<style> head content remains supported as trusted author code. Self-closing head tags now serialise canonically as />.
  • Security: CSRF exempt paths match on segment boundaries. csrf.exemptPaths previously used a bare string prefix, so exempting /api/webhooks also exempted an adjacently-named sibling like /api/webhooks-admin. Exemptions now match a path exactly or at a / boundary.
  • Security: oversized no-JS form POSTs fail loud. A form-encoded POST whose body exceeded the CSRF buffer cap (1 MB) was silently truncated and replayed to your handler. Such requests now return 413 and ask for the token via the X-CSRF-Token header instead of corrupting the payload.
  • Fix: <Script>/<Image> boolean attributes written as strings. defer="false", async="no", priority="0", lazy="false" and similar quoted-falsy forms were coerced to True (the opposite of the source). They now coerce correctly.
  • Fix: custom csrf.cookieName / csrf.headerName now reach the client runtime. Configuring either name made every action POST fail with 403 — the middleware set and validated the cookie under the configured name while useAction/<Form> kept reading a literal pyxle-csrf cookie and sending a literal x-csrf-token header. Non-default names are now injected into the document shell as window.__PYXLE_CSRF_COOKIE__ / window.__PYXLE_CSRF_HEADER__ and the client runtime resolves them with the defaults as fallback, in both dev and production builds.
  • Fix: no double loader run on hover-then-click navigation. When a <Link> was prefetched on hover/viewport and then clicked, the click raced a second request and ran the page's @server loader twice. The click now reuses the in-flight prefetch, and a navigation-sequence token discards a superseded prefetch so a slow one can't render a stale page over a newer click.
  • Multi-core serving: pyxle serve --workers N. Production serving can now run N independent server processes on one port (each with its own SSR pool and event loop) — throughput scales with cores, no load balancer or shared state to configure. See Deployment → Multi-core (worker processes).
  • Sync API endpoints. A plain def endpoint(request) in pages/api/ now runs in Starlette's threadpool instead of failing at request time — blocking database drivers and sync SDKs no longer require manual asyncio.to_thread wrapping. Sync get/post/… methods on HTTPEndpoint classes are threadpooled too, and HTTPEndpoint classes dispatch correctly alongside route hooks. See API Routes → Sync endpoints and blocking calls.
  • In-memory static asset cache. When serving a production build, small static files (≤1 MB each, 32 MB total per process) are loaded into memory at startup and served without filesystem I/O or threadpool hops — several-fold higher static throughput. Conditional requests (ETag/If-Modified-Since → 304) and cache headers behave exactly as before; larger files keep streaming from disk.

Full changelog: https://pyxle.dev/docs/changelog