---
package: "@webjsdev/server"
version: 0.8.11
date: 2026-06-03T04:57:15.789Z
commit_count: 4
---
## Features

- **add access logging, request id, an error hook, and a version probe** ([#285](https://github.com/webjsdev/webjs/pull/285)) [`b3540a7d`](https://github.com/webjsdev/webjs/commit/b3540a7d)

  Each handled request emits one structured access log line (method, path, status, durationMs, requestId) via the pluggable logger. A per-request id is minted with native crypto (or an inbound `X-Request-Id` honored after a charset/length check), stored on the request ALS, set on `X-Request-Id`, and exposed via `requestId()`. `createRequestHandler({ onError })` is a best-effort APM sink called on a 500 / middleware / ssr / action throw with the original error + request id. `GET /__webjs/version` returns `{ version, build, node, uptime }` so a deploy can verify the live build.

- **honor If-None-Match with a 304 on cacheable pages, assets, and modules** ([#286](https://github.com/webjsdev/webjs/pull/286)) [`7df66c67`](https://github.com/webjsdev/webjs/commit/7df66c67)

  A shared RFC 7232 helper at the response funnel sets a weak content-hash ETag on cacheable buffered GET/HEAD responses (a page with a public `metadata.cacheControl`, static assets, app + runtime modules) and returns 304 Not Modified when `If-None-Match` matches, so a repeat request no longer re-transfers an identical body. `no-store` / `private` pages and streamed responses are excluded; an internal buffered marker gates which responses are hashed so a streaming route or SSE never hangs.

- **cache static-route HTML with a revalidate window and revalidatePath** ([#287](https://github.com/webjsdev/webjs/pull/287)) [`3aabec25`](https://github.com/webjsdev/webjs/commit/3aabec25)

  A page opts into server-side HTML caching with `export const revalidate = N` (the no-build equivalent of ISR): a GET within the window serves the cached body from the pluggable store without re-running the page function, with the CSRF cookie re-minted per response. It is safe by construction: a page that reads per-user state via `cookies()` / `headers()` / `getSession()` / `auth()` is auto-excluded (Next's auto-dynamic model), and CSP / non-framework-Set-Cookie / partial-nav responses are never cached. `revalidatePath(path)` / `revalidateAll()` evict on demand.

- **add tag-based and action-driven invalidation for server cache()** ([#288](https://github.com/webjsdev/webjs/pull/288)) [`fd029d5e`](https://github.com/webjsdev/webjs/commit/fd029d5e)

  `cache(fn, { key, ttl, tags })` records a thin tag-to-key index in the store; `tags` can be a static array or a function `(...args) => string[]` so a per-arg read tags with the entity id. `revalidateTag(tag)` / `revalidateTags(tags)` evict every cached key under a tag across modules, so a mutation in one module invalidates a related read in another without importing its wrapper. Pairs with `revalidatePath` as the server cache invalidation surface.
