Repository navigation
feat(infra): demo.pywire.dev DNS record - #18
Merged
Merged
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NUEPGc2SgMUHxx4Z28HS8v
Terraform plan — 📝 changescloudflare_r2_bucket.cdn: Refreshing state... [id=pywire-cdn]
cloudflare_email_routing_address.destinations["[email]"]: Refreshing state... [id=ba2224a5004345f19ad66c5a71343976]
cloudflare_dns_record.vscode_verification: Refreshing state... [id=8ac56f7d47b8d2401df848706ad88cdd]
cloudflare_email_routing_address.destinations["[email]"]: Refreshing state... [id=b465118aef02490e9f584146ce54f65b]
cloudflare_dns_record.docs_cname: Refreshing state... [id=e562a5382eacb08985eaba0d4907fb2c]
cloudflare_ruleset.allow_llm_crawlers: Refreshing state... [id=375241922de4405a8b77b812e6e25730]
cloudflare_pages_project.docs: Refreshing state... [id=pywire-docs]
cloudflare_email_routing_settings.main: Refreshing state... [id=9f1c5e8c997d29163e81a24f7b26dc35]
cloudflare_pages_project.landing: Refreshing state... [id=pywire-landing]
cloudflare_email_routing_rule.individual_aliases["hello"]: Refreshing state... [id=1ff2a9d2add740089d4c7952455e4b56]
cloudflare_email_routing_rule.maintainers_group: Refreshing state... [id=2f20558a55f04e10959ead934f397730]
cloudflare_email_routing_rule.individual_aliases["reece"]: Refreshing state... [id=d14078e65aea4106adf662dc46d54710]
cloudflare_pages_domain.docs: Refreshing state... [id=docs.pywire.dev]
cloudflare_workers_script.router: Refreshing state... [id=pywire-router]
cloudflare_pages_domain.landing: Refreshing state... [id=pywire.dev]
cloudflare_dns_record.nightly: Refreshing state... [id=6a2d6b6878cc8452e1e29dd1f30c6dd1]
cloudflare_workers_route.nightly: Refreshing state... [id=874d0be239a04de79226d64cd941e9bf]
cloudflare_workers_route.catch_all: Refreshing state... [id=a70946d772474786ada02b87b9fd05cf]
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# cloudflare_dns_record.demo will be created
+ resource "cloudflare_dns_record" "demo" {
+ content = "100::"
+ created_on = (known after apply)
+ id = (known after apply)
+ meta = (known after apply)
+ modified_on = (known after apply)
+ name = "demo"
+ proxiable = (known after apply)
+ proxied = true
+ settings = (known after apply)
+ tags = (known after apply)
+ tags_modified_on = (known after apply)
+ ttl = 1
+ type = "AAAA"
+ zone_id = "9f1c5e8c997d29163e81a24f7b26dc35"
}
# cloudflare_worker.demo["edge-stateless"] will be created
+ resource "cloudflare_worker" "demo" {
+ account_id = "abd8226d8d910afcfa1d370097e6336a"
+ created_on = (known after apply)
+ id = (known after apply)
+ logpush = false
+ name = "pywire-demo-edge-stateless"
+ observability = {
+ enabled = false
+ head_sampling_rate = 1
+ logs = {
+ enabled = false
+ head_sampling_rate = 1
+ invocation_logs = true
}
}
+ references = (known after apply)
+ subdomain = {
+ enabled = false
+ previews_enabled = false
}
+ tags = []
+ tail_consumers = []
+ updated_on = (known after apply)
}
# cloudflare_worker.demo["form-builder"] will be created
+ resource "cloudflare_worker" "demo" {
+ account_id = "abd8226d8d910afcfa1d370097e6336a"
+ created_on = (known after apply)
+ id = (known after apply)
+ logpush = false
+ name = "pywire-demo-form-builder"
+ observability = {
+ enabled = false
+ head_sampling_rate = 1
+ logs = {
+ enabled = false
+ head_sampling_rate = 1
+ invocation_logs = true
}
}
+ references = (known after apply)
+ subdomain = {
+ enabled = false
+ previews_enabled = false
}
+ tags = []
+ tail_consumers = []
+ updated_on = (known after apply)
}
# cloudflare_worker.demo["site"] will be created
+ resource "cloudflare_worker" "demo" {
+ account_id = "abd8226d8d910afcfa1d370097e6336a"
+ created_on = (known after apply)
+ id = (known after apply)
+ logpush = false
+ name = "pywire-demo"
+ observability = {
+ enabled = false
+ head_sampling_rate = 1
+ logs = {
+ enabled = false
+ head_sampling_rate = 1
+ invocation_logs = true
}
}
+ references = (known after apply)
+ subdomain = {
+ enabled = false
+ previews_enabled = false
}
+ tags = []
+ tail_consumers = []
+ updated_on = (known after apply)
}
# cloudflare_workers_route.demo["edge-stateless"] will be created
+ resource "cloudflare_workers_route" "demo" {
+ id = (known after apply)
+ pattern = "demo.pywire.dev/edge-stateless"
+ script = "pywire-demo-edge-stateless"
+ zone_id = "9f1c5e8c997d29163e81a24f7b26dc35"
}
# cloudflare_workers_route.demo["edge-stateless/*"] will be created
+ resource "cloudflare_workers_route" "demo" {
+ id = (known after apply)
+ pattern = "demo.pywire.dev/edge-stateless/*"
+ script = "pywire-demo-edge-stateless"
+ zone_id = "9f1c5e8c997d29163e81a24f7b26dc35"
}
# cloudflare_workers_route.demo["form-builder"] will be created
+ resource "cloudflare_workers_route" "demo" {
+ id = (known after apply)
+ pattern = "demo.pywire.dev/form-builder"
+ script = "pywire-demo-form-builder"
+ zone_id = "9f1c5e8c997d29163e81a24f7b26dc35"
}
# cloudflare_workers_route.demo["form-builder/*"] will be created
+ resource "cloudflare_workers_route" "demo" {
+ id = (known after apply)
+ pattern = "demo.pywire.dev/form-builder/*"
+ script = "pywire-demo-form-builder"
+ zone_id = "9f1c5e8c997d29163e81a24f7b26dc35"
}
# cloudflare_workers_route.demo["site"] will be created
+ resource "cloudflare_workers_route" "demo" {
+ id = (known after apply)
+ pattern = "demo.pywire.dev/*"
+ script = "pywire-demo"
+ zone_id = "9f1c5e8c997d29163e81a24f7b26dc35"
}
Plan: 9 to add, 0 to change, 0 to destroy. |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NUEPGc2SgMUHxx4Z28HS8v
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NUEPGc2SgMUHxx4Z28HS8v
reecelikesramen
marked this pull request as ready for review
September 30, 2026 00:59
reecelikesramen
added a commit
to pywire/pywire
that referenced
this pull request
Sep 30, 2026
Needs #400 (merged): the example Workers use `main = "src/entry.py"`, which #400 teaches `pywire build` to keep. The Workers themselves, their routes and DNS are created by pywire/pywire.dev#18. Before: none of the examples ran anywhere public. After: demo.pywire.dev has a landing page listing the demos, the form builder at demo.pywire.dev/form-builder/, and the stateless demo at demo.pywire.dev/edge-stateless/. Every push to main that touches those examples or pywire itself redeploys them, so the demos always run main. Each example deploys from its own folder, the same way a create-pywire-app project would. There is no staging step. Examples aren't released, so release-please isn't involved. How: - Each example has a committed `wrangler.toml` (Worker `pywire-demo-<name>`, `main = "src/entry.py"`, `PYWIRE_BASE_PATH=/<name>`) with code and vars only. Terraform in pywire.dev creates the Worker and its routes, the way it creates the docs Pages project. - `pywire[cli]` sits in each example's dev group, so the Worker bundle holds only runtime dependencies. - `.github/workflows/deploy-examples.yml` runs on pushes to main (paths filtered) and by hand. It deploys `examples/demo-site` with wrangler. For each example it builds the client bundle, runs `uv run pywire build --platform cloudflare-edge`, then `uv run --with workers-py pywrangler deploy`. - `UV_NO_EDITABLE=1` makes pywrangler vendor a real copy of the workspace's pywire rather than an editable link, so the demos run main's source. - The form builder gets `CLIENT_IP_HEADER=cf-connecting-ip`, which Cloudflare sets itself. - realtime waits for the shared Durable Object target (#393). taskboard needs a database, so it's left out. Order: 1. Merge pywire.dev#18 and run Infra apply. That creates the Workers, routes and DNS. 2. Reece gives this repo's `CLOUDFLARE_API_TOKEN` the account-level Workers permission at Editor. 3. Merge this. The first run uploads the code. 4. Reece sets the Worker secrets: `PYWIRE_SECRET_KEY` on both example Workers, plus `GROQ_API_KEY` and `TYPESAFE_API_KEY` on `pywire-demo-form-builder` (commands in `examples/README.md`). The examples return errors until then. Worth knowing: the form builder's rate limiter keeps its counts in memory. On Workers each isolate has its own memory, so a visitor can get more than 10 builds per 10 minutes. The out-of-usage message still covers the case where the keys run dry. Tests: in examples/form-builder I ran the build and `UV_NO_EDITABLE=1 uv run --with workers-py pywrangler dev` in local workerd. The page, CSS and client loaded under `/form-builder/`, stateless POSTs returned 200, and a build with a fake key showed the out-of-usage message. A dry-run upload is 2.5 MB gzipped. The Examples check passes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Signed-off-by: reecelikesramen <3149587+reecelikesramen@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Before: demo.pywire.dev doesn't exist. There's no DNS record, no Workers and no routes.
After: Terraform creates the demo Workers (
pywire-demofor the landing page,pywire-demo-edge-statelessandpywire-demo-form-builder), their routes, and demo.pywire.dev's DNS record. The record is a proxied AAAA 100::, Cloudflare's placeholder for a Worker-only hostname.demo.pywire.dev/*goes to the landing page, anddemo.pywire.dev/<name>and/<name>/*go to that example's Worker.How:
cloudflare_workeris a Worker without code, the same way the Pages projects here exist without their deployments. pywire/pywire's Deploy Examples workflow (pywire/pywire#392) uploads each Worker's code and vars. Secrets are set withwrangler secret putso they stay out of state. workers.dev and preview URLs are off, matching eachwrangler.toml. Cloudflare picks the most specific route, so the example routes win over the landing page's catch-all. Adding an example later means adding its name tolocal.demo_examples.Order: apply this first, then merge pywire/pywire#392 (its first run uploads the code), then set the secrets.
🤖 Generated with Claude Code