diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 54f9ccb53..5672678eb 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -7,10 +7,13 @@ on: paths: - "docs/**" - "scripts/docs-site/**" + - "workers/**" - "package.json" - "package-lock.json" - ".github/workflows/pages.yml" + - "wrangler.toml" - "README.md" + - "CLOUDFLARE.md" workflow_dispatch: permissions: diff --git a/CLOUDFLARE.md b/CLOUDFLARE.md index a45f6e26c..58ce1011d 100644 --- a/CLOUDFLARE.md +++ b/CLOUDFLARE.md @@ -33,6 +33,7 @@ Production is still on the safe Worker Static Assets fallback until the Cloudfla - Route: `documentation.openclaw.ai/*` - Static assets binding: `env.ASSETS` - Header: `X-OpenClaw-Docs-Origin: cloudflare-static-assets` +- Cache-Control follows the same policy as the R2 manifest. The fallback exists because the Services@openclaw.org Cloudflare token currently cannot access R2. Local verification against account `91b59577e757131d68d55a471fe32aca` fails before bucket operations with Cloudflare API auth error `10000`. @@ -170,6 +171,7 @@ Expected before R2 cutover: - the same URLs work through the Worker Static Assets fallback. - docs responses include `X-OpenClaw-Docs-Origin: cloudflare-static-assets`. +- repeated requests should show Cloudflare `cf-cache-status: HIT`. ## Rollback diff --git a/workers/docs-router.ts b/workers/docs-router.ts index 27aa548f8..4fe496f65 100644 --- a/workers/docs-router.ts +++ b/workers/docs-router.ts @@ -87,6 +87,7 @@ async function assetResponse(env: Env, request: Request, pathname: string): Prom })); const responseHeaders = new Headers(response.headers); responseHeaders.set("X-OpenClaw-Docs-Origin", "cloudflare-static-assets"); + if (response.ok) responseHeaders.set("Cache-Control", cacheControlFor(pathname)); return new Response(request.method === "HEAD" ? null : response.body, { status: response.status, statusText: response.statusText, @@ -94,6 +95,16 @@ async function assetResponse(env: Env, request: Request, pathname: string): Prom }); } +function cacheControlFor(pathname: string): string { + if (pathname.endsWith(".html")) { + return "public, max-age=60, s-maxage=86400, stale-while-revalidate=604800"; + } + if (pathname.endsWith(".md") || pathname.endsWith(".txt") || pathname.endsWith(".json") || pathname.endsWith(".jsonl")) { + return "public, max-age=300, s-maxage=3600, stale-while-revalidate=86400"; + } + return "public, max-age=31536000, immutable"; +} + function appendVary(current: string | null, value: string): string { const parts = new Set((current ?? "").split(",").map((part) => part.trim()).filter(Boolean)); parts.add(value);