fix(documents): a PDF added to a workflow never loaded #634
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |