Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .dev.vars.example
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Copy to .dev.vars (gitignored) for local development.
# These override [vars] in wrangler.toml when running `wrangler dev`.
# These override [vars] in cloudflare.config.ts when running `cf dev`.

# Local dev overrides — production uses the values in wrangler.toml.
# Local dev overrides — production uses the values in cloudflare.config.ts.
PUBLIC_URL="http://localhost:8787"

# Random 32+ char string. Generate with: openssl rand -hex 32
Expand All @@ -18,5 +18,5 @@ GITHUB_CLIENT_SECRET="dev-mock"
# Sentry observability. Optional in dev. When unset, both the Worker
# wrapper and the browser /sentry.js route no-op. DSN is public — Sentry
# expects it in client code. Set in production via:
# wrangler secret put SENTRY_DSN
# cf workers secrets update SENTRY_DSN --worker htmlbin --type secret_text --text <dsn>
# SENTRY_DSN="https://<publicKey>@oXXXXX.ingest.sentry.io/<project>"
40 changes: 19 additions & 21 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:

- uses: actions/setup-node@v4
with:
node-version: "20"
node-version: "22"
cache: "npm"

- run: npm ci
Expand All @@ -41,34 +41,32 @@ jobs:
- name: Deploy to production
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
id: prod
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
command: deploy
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
run: npx cf deploy

# ───── PR → versioned preview ──────────────────────────────────
# `versions upload` ships a new version of the existing Worker
# without changing the live deployment. Cloudflare returns a
# unique workers.dev preview URL for that version. The action's
# `deployment-url` output isn't reliably populated for
# `versions upload`, so we parse the URL out of command-output.
# `workers versions create` ships a new version of the existing
# Worker without changing the live deployment. Cloudflare returns
# a unique workers.dev preview URL for that version; we parse it
# out of the command output.
- name: Upload preview version
if: github.event_name == 'pull_request'
id: preview
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
command: versions upload --message "PR #${{ github.event.pull_request.number }} — ${{ github.event.pull_request.head.sha }}"
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
# pipefail so a failed upload fails the step instead of tee's exit 0.
run: |
set -o pipefail
npx cf workers versions create \
--message "PR #${{ github.event.pull_request.number }} — ${{ github.event.pull_request.head.sha }}" \
2>&1 | tee "$RUNNER_TEMP/cf-preview.log"

- name: Extract preview URL from wrangler output
- name: Extract preview URL from cf output
if: github.event_name == 'pull_request'
id: extract_url
env:
WRANGLER_STDOUT: ${{ steps.preview.outputs.command-output }}
WRANGLER_STDERR: ${{ steps.preview.outputs.command-stderr }}
run: |
combined="$WRANGLER_STDOUT
$WRANGLER_STDERR"
combined=$(cat "$RUNNER_TEMP/cf-preview.log")
url=$(printf '%s' "$combined" | grep -oE 'https://[a-z0-9-]+\.[a-z0-9-]+\.workers\.dev' | head -1)
if [ -z "$url" ]; then
url=$(printf '%s' "$combined" | grep -oE 'https://[a-z0-9-]+\.workers\.dev' | head -1)
Expand All @@ -84,7 +82,7 @@ jobs:
message: |
### 🚀 Cloudflare preview

${{ steps.extract_url.outputs.url && format('**URL:** {0}', steps.extract_url.outputs.url) || '⚠️ Preview URL not found in wrangler output. Check the **Upload preview version** step logs for the actual URL.' }}
${{ steps.extract_url.outputs.url && format('**URL:** {0}', steps.extract_url.outputs.url) || '⚠️ Preview URL not found in cf output. Check the **Upload preview version** step logs for the actual URL.' }}

Built from commit `${{ github.event.pull_request.head.sha }}`.

Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ build/
.parcel-cache/
*.tsbuildinfo

# --- Cloudflare / Wrangler ---
# --- Cloudflare ---
.wrangler/
.cloudflare/
worker-configuration.d.ts
.dev.vars
.dev.vars.*
!.dev.vars.example
Expand Down
8 changes: 4 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ reference-only and must not ship in the public version.
5. Do not introduce a new format keyword or relitigate the old HTMD
naming. Product is `htmlbin`; artifacts are "drops".
6. Keep the aesthetic aligned with `DESIGN.md`.
7. Never deploy production directly. No local `wrangler deploy`. No
7. Never deploy production directly. No local `cf deploy` or `wrangler deploy`. No
`git push origin main`. Ship through branch -> PR -> preview URL ->
user approval -> merge to `main`.

Expand Down Expand Up @@ -87,7 +87,7 @@ The only production path is `.github/workflows/deploy.yml`:
5. Test the preview URL and wait for explicit user approval.
6. Merge to `main`; the workflow deploys production.

Do not bypass this with local Wrangler deploys or direct pushes.
Do not bypass this with local `cf`/Wrangler deploys or direct pushes.

## API Conventions

Expand Down Expand Up @@ -157,7 +157,7 @@ callback with a synthesized identity.

## Asset Gotchas

Wrangler 4 + ES module Workers has been unreliable for importing
The bundler (Wrangler 4, which cf builds with) has been unreliable for importing
non-JS files outside `src/` through `[[rules]]`.

Use established patterns:
Expand All @@ -184,7 +184,7 @@ src/views/ landing, verify, viewer, favicon, OG views
skills/htmlbin/SKILL.md human-browsable mirror of src/skill.ts
schema.sql D1 schema
migrations/ D1 migrations
wrangler.toml Cloudflare config
cloudflare.config.ts Cloudflare config read by cf (all commands go through cf)
scripts/setup.mjs provisioning
scripts/agent-e2e.sh full functional test
scripts/stats.mjs text-based stats snapshot (npm run stats)
Expand Down
Loading
Loading