From 4cc570db35bfd0b55eb83e3b5b804d6f3d4db65c Mon Sep 17 00:00:00 2001 From: Pablo Stanley Date: Sun, 19 Apr 2026 19:08:19 -0700 Subject: [PATCH] Docs: refresh cache semantics after PR #166 (1d fresh + 7d SWR) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR #166 swapped the deterministic cache header from 1-year immutable to 1-day fresh + 7-day stale-while-revalidate. The ?v= versioning story we shipped in PRs #164–#165 assumed the old immutable headers, so the docs overclaimed how long stale animations linger. Updates: - api.mdx intro / embedding blurb / caching section reflect the SWR window (≤ 1 day fresh, up to 8 days long-tail). - Animation-versioning section frames ?v=N as the escape hatch for instant propagation rather than "the only way out of an immutable trap." - openapi.json descriptions match. - Root CLAUDE.md points agents at DETERMINISTIC_CACHE in app/src/lib/api.ts. No code changes — /frames route was already switched to DETERMINISTIC_CACHE in PR #168. Co-Authored-By: Claude Opus 4.7 (1M context) --- CLAUDE.md | 2 +- app/content/docs/api.mdx | 8 ++++---- app/public/openapi.json | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 31251cb..00144f4 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -74,7 +74,7 @@ Body sub-animations aren't wired yet (the feet-planted split needs per-frame top - `GET /api/pixabot/random` — 302 redirect to random pixabot (or `?format=json`) - JSON responses include `png` and `gif` URLs - OpenAPI 3.1 spec at `/openapi.json` -- CORS enabled, immutable caching on deterministic endpoints +- CORS enabled, 1-day fresh + 7-day stale-while-revalidate caching on deterministic endpoints (see `DETERMINISTIC_CACHE` in `app/src/lib/api.ts`) ## Deployment diff --git a/app/content/docs/api.mdx b/app/content/docs/api.mdx index c6dc52a..7b1d469 100644 --- a/app/content/docs/api.mdx +++ b/app/content/docs/api.mdx @@ -3,7 +3,7 @@ title: API description: REST API for fetching pixabot images, animations, and metadata --- -All endpoints are **CORS-enabled** (`Access-Control-Allow-Origin: *`) and return immutable cache headers for deterministic URLs. You can embed pixabots directly from any site — no proxy, no key, no auth. +All endpoints are **CORS-enabled** (`Access-Control-Allow-Origin: *`) and return cache-friendly headers (1-day fresh + 7-day stale-while-revalidate) for deterministic URLs. You can embed pixabots directly from any site — no proxy, no key, no auth. ## GET /api/pixabot/\{id\} @@ -231,7 +231,7 @@ curl https://pixabots.com/api/pixabot/random?format=json ## Embedding -Drop a pixabot anywhere — any site, any framework. CORS is wide open and images cache on the CDN forever. +Drop a pixabot anywhere — any site, any framework. CORS is wide open and images cache on the CDN for a day (with 7 more days of stale-while-revalidate) so repeat loads stay instant. ### HTML @@ -300,11 +300,11 @@ Always use `image-rendering: pixelated` in CSS so browsers don't antialias the p ## Caching -Deterministic endpoints return `Cache-Control: public, max-age=31536000, immutable`. Same ID + size + flags always produces the same image, so CDNs cache it forever. The `/random` endpoint never caches (302 redirect, target cached normally). +Deterministic endpoints return `Cache-Control: public, max-age=86400, stale-while-revalidate=604800`. Same ID + size + flags always produces the same image for a given animation version, so the CDN keeps it fresh for a day and can serve stale for another 7 days while re-fetching in the background. That gives sprite / animation changes a natural rollout window (≤ 1 day for fresh traffic, ≤ 8 days for the long tail). The `/random` endpoint never caches (302 redirect, target cached normally). ## Animation versioning -Animated output (`?animated=true`) is deterministic and immutably cached by the CDN for a year. That means if we change the animation — new frame timing, new blink schedule, new bounce curve — already-cached URLs keep serving the old render until the cache evicts. +Animated output (`?animated=true`) is deterministic and CDN-cached for 1 day + 7 days of stale-while-revalidate. If we change the animation — new frame timing, new blink schedule, new bounce curve — fresh traffic picks up the new render within a day, and the long-tail (CDN SWR + consumer HTTP cache) can linger up to 8 days. Use `?v=N` when you need instant propagation. To opt into the latest render, add `?v=N` to the URL. `N` is the `ANIM_VERSION` integer exported by `@pixabots/core`: diff --git a/app/public/openapi.json b/app/public/openapi.json index 30df8bc..9f46146 100644 --- a/app/public/openapi.json +++ b/app/public/openapi.json @@ -15,7 +15,7 @@ "get": { "operationId": "getPixabot", "summary": "Get a pixabot by ID", - "description": "Returns a pixel-perfect PNG image by default, or JSON metadata with `?format=json`. PNGs are cached with immutable headers.", + "description": "Returns a pixel-perfect PNG image by default, or JSON metadata with `?format=json`. PNGs are CDN-cached (1-day fresh + 7-day stale-while-revalidate).", "parameters": [ { "name": "id", @@ -84,7 +84,7 @@ "name": "v", "in": "query", "required": false, - "description": "Cache-bust key. Pass an integer matching `ANIM_VERSION` from `@pixabots/core`; the value is ignored by the renderer, so any change forces a new immutable CDN cache entry. `@pixabots/react` appends this automatically for animated output.", + "description": "Cache-bust key. Pass an integer matching `ANIM_VERSION` from `@pixabots/core`; the value is ignored by the renderer, so any change forces a new CDN cache entry and sidesteps the 1-day fresh / 8-day stale-while-revalidate window. `@pixabots/react` appends this automatically for animated output.", "schema": { "type": "integer", "minimum": 1 } } ],