Runbook: deploy Lens (design-gallery) to Cloudflare Pages
Ships packages/design-gallery (Vite + Lit, rendered through
@celestial/lens) as a static SPA to the Cloudflare Pages project
celestial-lens, served from https://lens.celestialintelligence.co/.
Pattern: ADR-018 (cloudflare-pages artifact target). Same shape as marketing-site. No backend, CDN-fronted, free tier.
Prerequisites
Section titled “Prerequisites”ssCLI on PATH (pnpm cli:linkfrom repo root, or installed binary).- Cloudflare credentials in the vault — already provisioned for the
platform; reused as-is:
ss vault list-keys cloudflare# expected: api_bootstrap_token, dns_token, account_id
- DNS already wired. The CNAME for
lensis declared ininfra-domains/infra-domains.ssmod.yaml(servicetooling-co-dns) and is currently live:dig +short lens.celestialintelligence.co# → Cloudflare proxy IPs (104.21.… / 172.67.…) - Project name on CF Pages is
celestial-lens. CF assigned the.pages.devsubdomain ascelestial-lens.pages.devbecause the barecelestial-lenswas already taken in the global subdomain namespace. The CNAME intooling-co-dnspoints to the subdomain (celestial-lens.pages.dev);project_nameinpackages/design-gallery/lens.ssmod.yamlis the project name (celestial-lens). They’re different fields — don’t conflate.
Deploy
Section titled “Deploy”pnpm --filter @celestial/design-gallery build
# 2. Ship the dist/ to Cloudflare Pages.ss artifact deploy lens.site \ --env=prod \ --workspace-file=platform.prod.ssws.yamlThe composed service id is lens.site (module lens, service site).
The artifact target wraps packages/design-gallery/dist with
deploy_to: /packages/design-gallery/dist, so the dist directory
becomes the site root (i.e. dist/index.html → /index.html).
Smoke verification
Section titled “Smoke verification”# Apex returns 200 and serves the SPA shell.curl -sSI https://lens.celestialintelligence.co/ | head -1# → HTTP/2 200
# Response references the Vite module bundle.curl -sS https://lens.celestialintelligence.co/ \ | grep -o '<script type="module"[^>]*>'# → <script type="module" crossorigin src="/assets/index-<hash>.js">
# Bundle itself resolves.curl -sSI "https://lens.celestialintelligence.co/$( curl -sS https://lens.celestialintelligence.co/ \ | grep -oE '/assets/index-[A-Za-z0-9_-]+\.js' | head -1)" | head -1# → HTTP/2 200Open https://lens.celestialintelligence.co/ in a browser — Lens
should render the cel-* story gallery (sidebar + center stage).
Theme switcher in the top-right should swap palettes.
Rollback
Section titled “Rollback”CF Pages keeps every deployment. To roll back:
# List deployments.ss vault get-key cloudflare api_bootstrap_token --raw \ | xargs -I{} curl -sS -H "Authorization: Bearer {}" \ "https://api.cloudflare.com/client/v4/accounts/$(ss vault get-key cloudflare account_id --raw)/pages/projects/celestial-lens/deployments" \ | jq '.result[] | {id, created_on, url}'Or use the CF dashboard → Pages → celestial-lens → Deployments → “Rollback to this deployment”.
DNS check (only if smoke fails with cert / NXDOMAIN)
Section titled “DNS check (only if smoke fails with cert / NXDOMAIN)”dig +short lens.celestialintelligence.co# Expect Cloudflare proxy IPs.
# To re-reconcile the zone if a record drifted:ss deploy --service=infra-domains.tooling-co-dns \ --env=prod --workspace-file=platform.prod.ssws.yamlThe custom domain on the Pages project (lens.celestialintelligence.co)
is added automatically by the cloudflare-pages artifact target on every
deploy — no manual binding needed.