{ "$schema": "node_modules/wrangler/config-schema.json", "name": "www", "main": "src/www.app.ts", "compatibility_date": "2026-06-16", "compatibility_flags": ["nodejs_compat"], "routes": [], // React SPA client build (Vite emits it to dist/www/client). Static assets are // served directly; any non-asset request falls through to the Worker, which // serves API routes and returns index.html for client-side routes (SPA). // // `run_worker_first` (an ARRAY) is an EXCLUSIVE allowlist: it replaces the default // routing entirely, so the Worker runs ONLY for the listed patterns and every other // path is served assets-first (with the SPA fallback → index.html). It must therefore // list EVERY route the Worker handles, not just the new ones — otherwise `/api/*` // falls through to index.html and the whole BFF breaks. Why it's needed at all: with // SPA `not_found_handling`, a top-level *navigation* to a non-asset path (browsers // send `Sec-Fetch-Mode: navigate`) is served index.html WITHOUT invoking the Worker, // so a browser hitting `/docs` got the homepage. Keep this in sync with the Worker's // routes (`/api/*`, `/docs*` and `/privacy`). `/docs/scalar.standalone.js` is // deliberately excluded so it's served directly as the static asset it is. // // `/privacy` is here for the same reason `/docs` is, and it matters more: the Meta // Horizon Store re-fetches the privacy policy URL to confirm it's live, and dropping // it from this list would serve that fetch the SPA shell instead of the policy. "assets": { "binding": "ASSETS", "not_found_handling": "single-page-application", "run_worker_first": ["/api/*", "/docs", "/docs/openapi/*", "/privacy"] }, // The Turnstile keypair guarding web signup, out of the same account-level Secrets // Store every other worker binds for JWT_SECRET — values live there, never in this // file. The "local" store_id placeholder is replaced with RECFLARE_SECRETS_STORE at // deploy time, exactly as it is for the other workers. // // wrangler secrets-store secret create --name TURNSTILE_SITE_KEY \ // --scopes workers --remote // wrangler secrets-store secret create --name TURNSTILE_SECRET_KEY \ // --scopes workers --remote // // Creating both is what OPENS signup; if either can't be resolved it stays closed, so // an operator who skips this gets no signup rather than an unprotected one. The SITE // key is public (it ships to the browser to render the widget) and is kept here beside // its secret so one place configures signup. See src/turnstile.ts. "secrets_store_secrets": [ { "binding": "TURNSTILE_SITE_KEY", "store_id": "local", "secret_name": "TURNSTILE_SITE_KEY" }, { "binding": "TURNSTILE_SECRET_KEY", "store_id": "local", "secret_name": "TURNSTILE_SECRET_KEY" } ], "upload_source_maps": true, "observability": { "logs": { "enabled": true, "head_sampling_rate": 1 // 100% } }, "vars": { "ENVIRONMENT": "development", // overridden during deployment "SENTRY_RELEASE": "unknown", // overridden during deployment // Base domain the auth/accounts hosts are derived from (auth., // accounts.). Overridden at deploy time with the real RECFLARE_DOMAIN // (see run-wrangler-deploy). For local dev, point this at a deployed domain so // the BFF proxy can reach the auth/accounts workers. "DOMAIN": "rec.example.com" } }