Appearance
Cloudflare
For: knowing what exists in the Cloudflare account, which piece is which, and where to click when something needs looking at.
What is deployed
The whole product is one Cloudflare Worker. It serves the built client as static assets and answers the API itself, and it holds all game state in a Durable Object.
The configuration is a single file at the repository root, wrangler.jsonc. There are no environment blocks in it: staging and production differ by the flags their deploy scripts pass, not by separate config sections.
| Setting | Value |
|---|---|
| Worker entry point | src/server/worker.mjs |
| Compatibility date | 2026-07-01, with the Node compatibility flag on |
| Static assets | the dist/ directory, bound as ASSETS |
| Not-found handling | single-page application, so client routes resolve |
| Precedence | requests to /api/* run the Worker before assets are considered |
The two workers
There are two deployed Workers, and their names are confusable at a glance. Read this table before typing a worker name into any command.
| Environment | Worker name | Reached at |
|---|---|---|
| staging | grafted-wars-true-staging | its workers.dev address only |
| production | grafted-wars-staging | grafted-wars.com and www.grafted-wars.com |
The production worker is the one called grafted-wars-staging. That naming is a trap worth reading twice, because a secret or a tail attached to the wrong one looks like it worked and changes nothing.
Bindings
One binding carries state, and one carries the built client.
| Binding | Kind | Points at |
|---|---|---|
UNIVERSE | Durable Object | the Universe class, created under migration tag v1 as a SQLite-backed class |
ASSETS | static assets | the built dist/ directory uploaded with the Worker |
There is no D1 database, no KV namespace, no R2 bucket and no queue. Every piece of game state lives inside the Durable Object. Data and stores is the page that covers reaching it.
Variables and secrets
Plain variables live in the configuration file and are visible in the repository. They set the universe's shape rather than anything sensitive.
| Variable | Sets |
|---|---|
SEED_TARGET | how many accounts the universe seeds toward |
PLAYER_CAP | the ceiling on accounts |
GW_DENSE_SEED | whether the seed planet is packed to capacity at boot |
GW_CLOCK_RATE | how fast virtual time runs against real time |
GW_SPEED_ECONOMY, GW_SPEED_FLEET, GW_SPEED_RESEARCH | the three speed multipliers |
GW_RETAIN_EVENTS, GW_RETAIN_RECEIPTS, GW_RETAIN_RETURNED_MS | how much history is kept |
START_DM | the dark matter an account begins with |
One value is a secret rather than a variable, and it is set per worker:
bash
npx wrangler secret put ADMIN_EMAIL --name grafted-wars-true-stagingA worker with no ADMIN_EMAIL refuses every request. A freshly deployed worker that answers nothing but refusals has almost always never been given this secret, and that is worth checking before suspecting the deploy.
Each worker holds its own copy. Setting it on staging does nothing for production.
Where to click
Everything below starts at the Cloudflare dashboard, signed in to the account that owns the Workers.
| You want | Route in the dashboard |
|---|---|
| Live request logs | Workers & Pages → the worker → Logs → Begin log stream |
| Recent errors and request volume | Workers & Pages → the worker → Metrics |
| The secrets a worker holds | Workers & Pages → the worker → Settings → Variables and Secrets |
| The Durable Object namespace | Workers & Pages → the worker → Settings → Bindings |
| Domain routing | Workers & Pages → the worker → Settings → Domains & Routes |
| The zone's DNS records | Websites → grafted-wars.com → DNS |
| Account identifier | Workers & Pages → Overview, in the right-hand column |
The same log stream is available from the terminal, which is often faster than the dashboard:
bash
npx wrangler tail --name grafted-wars-true-stagingThe credentials this needs
Two values authenticate any deploy or wrangler command, and both are named on Credentials and access together with where each is obtained.
| Name | Used for |
|---|---|
CLOUDFLARE_API_TOKEN | authenticating deploys and wrangler commands |
CLOUDFLARE_ACCOUNT_ID | selecting which account those act on |
Both are read from the environment, or from the repository's gitignored .env file. Neither belongs in a commit.
The domain
Production binds grafted-wars.com and its www alias through the Cloudflare API as part of the deploy, rather than by hand in the dashboard. The deploy script reports the bindings it made in its closing summary.
Staging binds no custom domain and is reached at its workers.dev address.