Skip to content

fix(documents): a PDF added to a workflow never loaded #634

fix(documents): a PDF added to a workflow never loaded

fix(documents): a PDF added to a workflow never loaded #634

Workflow file for this run

name: Web Deploy (Cloudflare Pages)
# Deploys the web app (web/, a Vite SPA) to Cloudflare Pages from GitHub Actions
# instead of Cloudflare's git integration, which built on every push with no
# control over the toolchain or build state. This builds on the pinned Node
# version and ships only after the build succeeds.
#
# The web bundle inlines @nodetool-ai/* package SOURCE (the `nodetool-dev` Vite
# resolve condition) and reads generated pricing JSONs produced by
# `build:packages`, so package changes affect the bundle — hence this runs on
# every push to main except changes that can't reach the bundle.
#
# Required GitHub config (Settings → Secrets and variables → Actions):
# Secrets:
# CLOUDFLARE_API_TOKEN — token with "Cloudflare Pages: Edit" on the account
# CLOUDFLARE_ACCOUNT_ID — account that owns the Pages project
# Variables:
# CLOUDFLARE_WEB_PAGES_PROJECT — the Cloudflare Pages project name to deploy to
# VITE_API_URL — API base URL (e.g. https://api.nodetool.ai)
# VITE_SUPABASE_URL — Supabase project URL
# VITE_SUPABASE_ANON_KEY — Supabase anon (publishable) key baked into the
# build. It's a Variable, not a Secret: the key is
# public by design (RLS-protected) and is shipped in
# the client bundle anyway, so a Secret would only
# hide it from this workflow, not from users.
# VITE_AUTH_REDIRECT_URL — optional OAuth redirect URL
#
# This job runs in the `web-production` environment, so the secrets/variables
# above must be visible to it: set them either at the repository level or on the
# `web-production` environment itself (Settings → Environments → web-production).
# An env-scoped secret defined only on a DIFFERENT environment (e.g. the
# marketing deploy's `marketing-production`) is NOT available here — it expands to
# an empty string. For the Cloudflare creds, wrangler then fails with error 9106
# ("Authentication error" / missing Authorization header); for the Supabase build
# vars, the bundle silently falls back to localhost placeholders and breaks auth
# in production. The preflight step below catches both before the deploy runs.
#
# Disconnect the repo from the Cloudflare Pages git integration so the site is
# only deployed from here.
on:
push:
branches:
- main
paths-ignore:
- "marketing/**"
- "docs/**"
- "mobile/**"
- "electron/**"
- "**/*.md"
workflow_dispatch:
# Least-privilege token: the build only reads the repo; the Pages deploy
# authenticates with its own Cloudflare API token, not GITHUB_TOKEN.
permissions:
contents: read
# One deploy at a time; let an in-flight upload finish rather than cancelling it.
concurrency:
group: web-deploy
cancel-in-progress: false
jobs:
deploy:
name: Build & deploy to Cloudflare Pages
runs-on: ubuntu-latest
timeout-minutes: 30
environment:
name: web-production
steps:
- name: Checkout code
uses: actions/checkout@v7
with:
fetch-depth: 1
# Fail fast with an actionable message if the Cloudflare credentials, the
# Pages project name, or the Supabase build vars are missing, rather than
# letting wrangler fail late with a cryptic "Must specify a project name" or
# 9106 auth error — or, worse, shipping a bundle that silently falls back to
# the `http://localhost` / `public-anon-key` Supabase placeholders in
# web/src/lib/supabaseClient.ts and breaks auth in production with no error.
# Secrets/vars must be visible to the `web-production` environment (see the
# header note); they expand to empty strings when they are not.
- name: Check Cloudflare deploy config
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
CLOUDFLARE_WEB_PAGES_PROJECT: ${{ vars.CLOUDFLARE_WEB_PAGES_PROJECT }}
VITE_SUPABASE_URL: ${{ vars.VITE_SUPABASE_URL }}
VITE_SUPABASE_ANON_KEY: ${{ vars.VITE_SUPABASE_ANON_KEY }}
run: |
missing=()
[ -n "$CLOUDFLARE_API_TOKEN" ] || missing+=("secret CLOUDFLARE_API_TOKEN")
[ -n "$CLOUDFLARE_ACCOUNT_ID" ] || missing+=("secret CLOUDFLARE_ACCOUNT_ID")
[ -n "$CLOUDFLARE_WEB_PAGES_PROJECT" ] || missing+=("variable CLOUDFLARE_WEB_PAGES_PROJECT")
[ -n "$VITE_SUPABASE_URL" ] || missing+=("variable VITE_SUPABASE_URL")
[ -n "$VITE_SUPABASE_ANON_KEY" ] || missing+=("variable VITE_SUPABASE_ANON_KEY")
if [ ${#missing[@]} -ne 0 ]; then
echo "::error::Missing required deploy config: ${missing[*]}"
echo "Set these at the repository level (Settings → Secrets and variables → Actions)"
echo "or on the 'web-production' environment (Settings → Environments → web-production)."
echo "An env-scoped secret on a different environment is NOT visible to this job."
exit 1
fi
echo "Deploy config present (project: $CLOUDFLARE_WEB_PAGES_PROJECT, Supabase URL: $VITE_SUPABASE_URL)."
# Installs the workspace and builds the backend packages, which generates
# the fal/kie pricing JSONs the Vite build aliases resolve.
- name: Set up Node, install deps, build packages
uses: ./.github/actions/setup-build
with:
build-packages: "true"
- name: Build (Vite)
working-directory: web
run: npx vite build
env:
VITE_API_URL: ${{ vars.VITE_API_URL }}
VITE_SUPABASE_URL: ${{ vars.VITE_SUPABASE_URL }}
VITE_SUPABASE_ANON_KEY: ${{ vars.VITE_SUPABASE_ANON_KEY }}
VITE_AUTH_REDIRECT_URL: ${{ vars.VITE_AUTH_REDIRECT_URL }}
- name: Deploy to Cloudflare Pages
uses: cloudflare/wrangler-action@v4
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
wranglerVersion: "4.85.0"
workingDirectory: web
command: pages deploy dist --project-name=${{ vars.CLOUDFLARE_WEB_PAGES_PROJECT }} --branch=main