Skip to content

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.

SettingValue
Worker entry pointsrc/server/worker.mjs
Compatibility date2026-07-01, with the Node compatibility flag on
Static assetsthe dist/ directory, bound as ASSETS
Not-found handlingsingle-page application, so client routes resolve
Precedencerequests 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.

EnvironmentWorker nameReached at
staginggrafted-wars-true-stagingits workers.dev address only
productiongrafted-wars-staginggrafted-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.

BindingKindPoints at
UNIVERSEDurable Objectthe Universe class, created under migration tag v1 as a SQLite-backed class
ASSETSstatic assetsthe 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.

VariableSets
SEED_TARGEThow many accounts the universe seeds toward
PLAYER_CAPthe ceiling on accounts
GW_DENSE_SEEDwhether the seed planet is packed to capacity at boot
GW_CLOCK_RATEhow fast virtual time runs against real time
GW_SPEED_ECONOMY, GW_SPEED_FLEET, GW_SPEED_RESEARCHthe three speed multipliers
GW_RETAIN_EVENTS, GW_RETAIN_RECEIPTS, GW_RETAIN_RETURNED_MShow much history is kept
START_DMthe 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-staging

A 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 wantRoute in the dashboard
Live request logsWorkers & Pages → the worker → Logs → Begin log stream
Recent errors and request volumeWorkers & Pages → the worker → Metrics
The secrets a worker holdsWorkers & Pages → the worker → Settings → Variables and Secrets
The Durable Object namespaceWorkers & Pages → the worker → Settings → Bindings
Domain routingWorkers & Pages → the worker → Settings → Domains & Routes
The zone's DNS recordsWebsites → grafted-wars.com → DNS
Account identifierWorkers & 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-staging

The 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.

NameUsed for
CLOUDFLARE_API_TOKENauthenticating deploys and wrangler commands
CLOUDFLARE_ACCOUNT_IDselecting 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.