Skip to content

Deploy docs through Cloudflare Pages#1342

Merged
TabishB merged 3 commits into
mainfrom
agent/deploy-docs-cloudflare-pages
Jul 10, 2026
Merged

Deploy docs through Cloudflare Pages#1342
TabishB merged 3 commits into
mainfrom
agent/deploy-docs-cloudflare-pages

Conversation

@TabishB

@TabishB TabishB commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Summary

  • codify the Cloudflare Worker that mounts the separate docs Pages project at openspec.dev/docs and proxies its supporting asset/search/OG/LLM routes
  • document the Git-connected openspec-docs Pages build and deployment setup
  • remove the redundant GitHub Actions docs workflow and its no-longer-needed secrets/variable instructions

Why

The Fumadocs site is a static export and now deploys directly through Cloudflare Pages' Git integration. The existing landing page remains in its separate Astro project, so a small Worker provides path-based routing on the shared openspec.dev hostname without requiring Enterprise-only Origin Rule host/DNS overrides.

Deployment behavior

  • pushes to main rebuild production only when docs/** or website/** changes
  • pull requests that touch those paths receive Pages preview builds
  • unrelated monorepo changes do not trigger a docs deployment
  • the landing page continues to serve all non-docs paths

Validation

  • NEXT_PUBLIC_SITE_URL=https://openspec.dev pnpm run build (87 static routes)
  • node --check cloudflare/router/worker.js
  • wrangler deploy --dry-run --config cloudflare/router/wrangler.jsonc
  • live smoke tests returned 200 for /, /docs, /docs/core-concepts, /api/search, and /llms.txt

Summary by CodeRabbit

  • New Features

    • Added a Cloudflare routing layer to serve documentation routes and related endpoints from the main site, including proper handling of redirects and preserved URLs.
    • Restricted proxied methods to GET/HEAD for routed documentation paths.
  • Documentation

    • Updated Cloudflare Pages deployment guidance to use Node.js 22 and provided an explicit NEXT_PUBLIC_SITE_URL example.
    • Reworked instructions for automated builds and preview deployments, including routing worker setup and project structure.
  • Chores

    • Removed the previous GitHub Actions-based documentation deployment workflow and updated the Cloudflare worker configuration for routing.

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Cloudflare Pages deployment documentation is updated, a routing Worker and Wrangler configuration are added for documentation paths, and the previous GitHub Actions deployment workflow is removed.

Changes

Docs hosting and routing

Layer / File(s) Summary
Cloudflare routing Worker
website/cloudflare/router/worker.js, website/cloudflare/router/wrangler.jsonc
Adds configured openspec.dev routes and proxies eligible GET/HEAD requests to the documentation Pages site, forwarding selected headers and rewriting same-site redirects.
Pages deployment documentation
website/README.md
Documents Node 22, NEXT_PUBLIC_SITE_URL, Git-connected Pages deployments, previews, routing Worker deployment, and project structure changes.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Browser
  participant RouterWorker
  participant DocsPages
  Browser->>RouterWorker: Request documentation path
  RouterWorker->>DocsPages: Proxy eligible GET or HEAD request
  DocsPages-->>RouterWorker: Return response or redirect
  RouterWorker-->>Browser: Return response with rewritten location
Loading

Possibly related PRs

Suggested reviewers: alfred-openspec

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly captures the main change: moving docs deployment to Cloudflare Pages.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch agent/deploy-docs-cloudflare-pages

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 10, 2026

Copy link
Copy Markdown

Deploying openspec-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: 461953e
Status: ✅  Deploy successful!
Preview URL: https://494f3a89.openspec-docs.pages.dev
Branch Preview URL: https://agent-deploy-docs-cloudflare.openspec-docs.pages.dev

View logs

@TabishB TabishB marked this pull request as ready for review July 10, 2026 14:51

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@website/cloudflare/router/worker.js`:
- Around line 12-23: Update the proxy request construction in the worker to
allow only an explicit safe-header allowlist, excluding sensitive headers such
as Cookie and Authorization, rather than copying all request headers. Reject
non-GET/HEAD requests before creating the proxy request, and remove the
init.body assignment and write-path handling.

In `@website/cloudflare/router/wrangler.jsonc`:
- Around line 7-14: Update the route handling in worker.js to gate proxying by
exact pathname allowlists for the docs, api/search, and llms route groups.
Preserve query-string support while rejecting unexpected path prefixes that
match the broad Wrangler patterns, and apply the same validation consistently
before forwarding requests to Pages.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: aa54cabc-98d5-4fd9-9ca5-fd055e0d8cca

📥 Commits

Reviewing files that changed from the base of the PR and between e1b51d1 and 2aa54cd.

📒 Files selected for processing (4)
  • .github/workflows/deploy-docs.yml
  • website/README.md
  • website/cloudflare/router/worker.js
  • website/cloudflare/router/wrangler.jsonc
💤 Files with no reviewable changes (1)
  • .github/workflows/deploy-docs.yml

Comment thread website/cloudflare/router/worker.js Outdated
Comment thread website/cloudflare/router/wrangler.jsonc

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
website/cloudflare/router/worker.js (1)

52-69: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Wrap the upstream fetch in error handling.

If openspec-docs.pages.dev is unreachable or returns a network error, the await fetch on line 52 will throw and Cloudflare will return an opaque 1101/500 to the client. A try/catch returning a 502 with a short message would give users a clearer signal and prevent confusing error pages.

🛡️ Suggested error handling
-  const response = await fetch(upstream.toString(), init);
-  const responseHeaders = new Headers(response.headers);
-  const location = responseHeaders.get('location');
-
-  if (location) {
-    const redirected = new URL(location, upstream);
-    if (redirected.hostname === 'openspec-docs.pages.dev') {
-      redirected.protocol = incoming.protocol;
-      redirected.host = incoming.host;
-      responseHeaders.set('location', redirected.toString());
-    }
-  }
-
-  return new Response(response.body, {
-    status: response.status,
-    statusText: response.statusText,
-    headers: responseHeaders,
-  });
+  let response;
+  try {
+    response = await fetch(upstream.toString(), init);
+  } catch {
+    return new Response('Documentation is temporarily unavailable.', {
+      status: 502,
+      headers: { 'content-type': 'text/plain' },
+    });
+  }
+  const responseHeaders = new Headers(response.headers);
+  const location = responseHeaders.get('location');
+
+  if (location) {
+    const redirected = new URL(location, upstream);
+    if (redirected.hostname === 'openspec-docs.pages.dev') {
+      redirected.protocol = incoming.protocol;
+      redirected.host = incoming.host;
+      responseHeaders.set('location', redirected.toString());
+    }
+  }
+
+  return new Response(response.body, {
+    status: response.status,
+    statusText: response.statusText,
+    headers: responseHeaders,
+  });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@website/cloudflare/router/worker.js` around lines 52 - 69, Wrap the upstream
request and response-processing logic in the worker’s fetch handler with
try/catch, including the existing fetch call and redirect rewriting. On fetch
failure, return a 502 Response with a concise plain-text error message instead
of allowing the exception to propagate.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@website/cloudflare/router/worker.js`:
- Around line 79-80: The router condition for the exact “/og/docs” path requires
a matching exact deployment route. Update
website/cloudflare/router/wrangler.jsonc to add “openspec.dev/og/docs” alongside
the existing wildcard route, preserving the “/og/docs/*” coverage.

---

Nitpick comments:
In `@website/cloudflare/router/worker.js`:
- Around line 52-69: Wrap the upstream request and response-processing logic in
the worker’s fetch handler with try/catch, including the existing fetch call and
redirect rewriting. On fetch failure, return a 502 Response with a concise
plain-text error message instead of allowing the exception to propagate.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b6f3334d-82f6-4ed1-acf6-8a668429bed6

📥 Commits

Reviewing files that changed from the base of the PR and between 2aa54cd and 25d3525.

📒 Files selected for processing (1)
  • website/cloudflare/router/worker.js

Comment on lines +79 to +80
pathname === '/og/docs' ||
pathname.startsWith('/og/docs/') ||

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check whether /og/docs (without trailing slash) is expected to be served by the Worker
rg -n 'og/docs' website/cloudflare/router/

Repository: Fission-AI/OpenSpec

Length of output: 424


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== wrangler.jsonc =="
cat -n website/cloudflare/router/wrangler.jsonc

echo
echo "== worker.js around isDocsRoute =="
sed -n '60,100p' website/cloudflare/router/worker.js

echo
echo "== any other og/docs references =="
rg -n --context 2 'og/docs' website/cloudflare/router/

Repository: Fission-AI/OpenSpec

Length of output: 2890


🌐 Web query:

Cloudflare Workers route pattern "/path/*" match exact "/path" without trailing slash

💡 Result:

In Cloudflare Workers, a route pattern with a trailing asterisk, such as /path/*, does not match an exact path without a trailing slash (e.g., /path) [1]. The wildcard operator (*) in Cloudflare route patterns matches zero or more characters [1]. For the pattern /path/* to trigger, there must be content after the /path/ prefix. Consequently: - /path/* matches /path/ and any path starting with /path/ (e.g., /path/something). - /path/* does not match the exact path /path because the wildcard expects a subsequent character (or a trailing slash) to satisfy the pattern [1]. To match both the exact path /path and any sub-paths under it, you must define two separate route patterns: 1. /path 2. /path/* Cloudflare routing is deterministic: if multiple patterns match, the system selects the most specific one [1][2]. By explicitly defining both, you ensure all variations of that path are covered [1].

Citations:


Add openspec.dev/og/docs for the bare path. openspec.dev/og/docs/* doesn’t cover /og/docs, so pathname === '/og/docs' in website/cloudflare/router/worker.js is unreachable unless website/cloudflare/router/wrangler.jsonc adds the exact route.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@website/cloudflare/router/worker.js` around lines 79 - 80, The router
condition for the exact “/og/docs” path requires a matching exact deployment
route. Update website/cloudflare/router/wrangler.jsonc to add
“openspec.dev/og/docs” alongside the existing wildcard route, preserving the
“/og/docs/*” coverage.

@alfred-openspec alfred-openspec left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the Cloudflare Pages deployment and routing changes. The route scoping, request-header allowlist, method restrictions, redirect handling, and deployment documentation look good, and all checks are passing.

@TabishB TabishB added this pull request to the merge queue Jul 10, 2026
Merged via the queue into main with commit 0a99f41 Jul 10, 2026
13 checks passed
@TabishB TabishB deleted the agent/deploy-docs-cloudflare-pages branch July 10, 2026 15:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants