# Base domain all service hosts are derived from, e.g. accounts.. RECFLARE_DOMAIN=rec.example.com # Optional per-service subdomain overrides, as a compact JSON object keyed by the # service's default subdomain (which, for a service backed by a worker, is that # worker's directory name). Unlisted services keep their default. # # One entry moves both sides: it decides which host `just deploy` puts the worker on # AND which host the `ns` discovery document advertises to the client, so the two can't # drift apart. Redeploy `ns` (`just deploy -F ns`) after changing this. # # {"playersettings":"settings"} the playersettings worker moves to settings. # {"moderation":"api"} Moderation has no worker of its own, so this is a pure # client-side redirect: it points the client's Moderation # calls at the api worker, which is where the # /api/PlayerReporting/… routes actually live # # Keep it compact — no spaces. Services are listed in SERVICES.md. # RECFLARE_SUBDOMAINS='{"moderation":"api"}' # Id of the shared `recflare` D1 database (create it manually with # `wrangler d1 create recflare`). All D1-backed workers bind this one database. # Kept out of the committed wrangler.jsonc (which uses a "local" placeholder) and # spliced in at deploy time. Required to deploy any worker that uses D1. # RECFLARE_D1=d44083e1-5bfe-4467-aa9a-f13c5c2496d5 # KV namespace ids, as a compact JSON object keyed by binding name. Each namespace # is distinct (create with `wrangler kv namespace create `). Kept out of # the committed wrangler.jsonc (which uses "local" placeholders) and spliced in at # deploy time. Required to deploy any worker with the matching KV binding. # RECFLARE_KV='{"RECFLARE_MATCH_PRESENCE":"9f53f04b7dd244658d59f515a14748b6","RECFLARE_PLAYER_SETTINGS":"d33a90014e904b0eac720bddcbe0b036"}' # Id of the shared Secrets Store that holds the `JWT_SECRET` signing key (create it # with `wrangler secrets-store store create recflare --scopes workers`). Every # worker binds this one store as JWT_SECRET so auth-signed tokens verify everywhere. # Kept out of the committed wrangler.jsonc (which uses a "local" placeholder) and # spliced in at deploy time. Required to deploy any worker. # RECFLARE_SECRETS_STORE=00000000-0000-0000-0000-000000000000 # --- Server tuning (all optional; the shown value is the built-in default) --- # Everything below is passed to the workers as a variable, named without the RECFLARE_ # prefix: RECFLARE_STARTING_TOKENS becomes STARTING_TOKENS. Every worker gets every knob — # the ones that don't read a knob just ignore it — so nothing here has to be routed to a # particular service, and two services reading the same knob agree on it for free. (The five # settings above are the exception: they configure the deploy itself, not the workers.) # # The same values are used by `just deploy` and by `just dev`, so a knob is set in exactly # one place. Change one and re-deploy the worker that reads it (e.g. `just deploy -F auth`) # for it to take effect. Leave a line commented out and the worker uses its built-in # default — and deleting a line you'd set really does restore that default on the next # deploy. # # Don't set these in the Cloudflare dashboard — a deploy replaces a worker's variables # wholesale, so a dashboard-set value is wiped by your next `just deploy`. This file is the # durable place. (Actual secrets don't go here either: they live in the Cloudflare Secrets # Store, like the shared JWT signing key above.) # How many accounts one signup source may create (`auth`). Enforced on signup only, # never on login: an existing account always stays reachable. Set either to 0 to turn # that cap off entirely. # ...PER_PLATFORM_ID counts accounts per Steam-verified identity — unspoofable. # ...PER_IP counts accounts per signup IP — coarse, since a household, NAT or campus # network shares one address. This is the one to raise (or zero out) if real players # report being locked out. # RECFLARE_MAX_ACCOUNTS_PER_PLATFORM_ID=3 # RECFLARE_MAX_ACCOUNTS_PER_IP=3 # How far a ban reaches beyond the account it was handed to (`match` and `auth`), as a # comma-separated list out of `ip` and `platform` — or `off` for neither. Unset means # BOTH, so a ban also blocks accounts sharing a proven platform identity or an IP with a # banned one, and refuses a signup from either. Without that, an evader is back in the # game with a new account in under a minute. # ...`platform` matches a Steam/Meta identity the player PROVED — sharp, no false # positives worth the name. # ...`ip` matches the signup/last-login address — coarse. A household, dorm, campus or # mobile carrier shares one address, so this arm bans the banned player's housemates # along with them, and locks them out of signing up at all. Set BAN_EVASION_MATCH=platform # to keep the sharp arm only, or off to make a ban apply to just the banned account. # A ban ALWAYS applies to the account it was handed to, whatever this is set to. # RECFLARE_BAN_EVASION_MATCH=ip,platform # How many rooms one account may create (`rooms`) and how many clubs (`clubs`). # Enforced on creation only — lowering either never touches what players already have, # it just stops new ones. Set either to 0 to turn that cap off. # ...ROOMS counts rooms the account created, minus their auto-provisioned dorm. # ...CLUBS counts clubs the account created (subscription clubs don't count). # RECFLARE_MAX_ROOMS_PER_ACCOUNT=10 # RECFLARE_MAX_CLUBS_PER_ACCOUNT=10 # Rooms to switch out at matchmake time (`match`), as comma-separated = # pairs, where is a room id or room name. This is how a stock RRO room is replaced # with your own: 2=MyHub sends everyone who matchmakes into the Rec Center (room 2) to the # room named MyHub instead, whether the client asked for it by id or by name, and whether # it came through the room list, a club's clubhouse, or a party. Substitution is a single # hop (2=3,3=2 swaps the two rooms), a requested subroom is dropped in favour of the # substitute's default one, and a target that doesn't exist leaves the original room in # place. Following a friend or joining a specific instance is unaffected — those join a # live instance, which is already in whichever room it was created in. # RECFLARE_ROOM_REDIRECTS=2=MyHub # The Photon applications the client connects to (`match`, GET /player/connection-info). # EMPTY unless you set them: recflare ships no Photon application, so until these name # yours the client is handed empty ids and connects to nothing. Create the three apps in # the Photon dashboard (Realtime, Voice, Chat) and paste their app ids here. They are not # secrets — the client is handed all three in the clear — which is why they are vars and # not Secrets Store entries. # RECFLARE_PHOTON_REALTIME_APP_ID= # RECFLARE_PHOTON_VOICE_APP_ID= # RECFLARE_PHOTON_CHAT_APP_ID= # The Tachyon voice server (`match`, GET /player/connection-info): the `host:port` the # client is handed as `voiceConnectionInfo`, and its id as `voiceServerId`. EMPTY unless # you set them — no separate voice server. Set both or neither; like the Photon ids they # are not secrets (the client receives them in the clear). # RECFLARE_TACHYON_HOST_PORT=127.0.0.1:7777 # RECFLARE_TACHYON_NAME=server-1 # The Photon region every session is pinned to (`match`). Unlike the app ids above this # does default, to `us` (us-east1) — an instance stamped with an empty region is one the # client cannot connect to, so there is no "unset" state for it to have. It is # named in the connection info AND stamped on every room instance, and one var feeds both: # the client authenticates against the app above and connects to the region on its # instance, so the two disagreeing is a session nobody can join. The QoS pings the client # reports are ranked but never acted on — one deployment runs in one region. # RECFLARE_PHOTON_REGION=us # RecCenterTokens a new player is granted, the first time their balance is read (`econ`). # 0 means players start broke. Applies only to players who haven't been granted yet — # raising it later does NOT top up existing players. # RECFLARE_STARTING_TOKENS=10000 # Signup on the website is configured OUTSIDE this file: it's guarded by a Cloudflare # Turnstile widget, and both of that widget's keys live in the shared Secrets Store # (RECFLARE_SECRETS_STORE above), alongside JWT_SECRET — not as vars, not as worker secrets. # # wrangler secrets-store secret create --name TURNSTILE_SITE_KEY \ # --scopes workers --remote # wrangler secrets-store secret create --name TURNSTILE_SECRET_KEY \ # --scopes workers --remote # # Setting them both is what opens web signup; with either missing it stays closed. See # DEPLOYING.md. Accounts are still created by the game either way, and both `auth` account # caps above apply regardless. # The website's benefits claim (www `/claim`): a player proves a role in your Discord and # gets Rec Room Plus. FOUR settings, and ALL FOUR are required — with any missing, the claim # stays closed, `/api/config` reports `benefitsEnabled: false`, and the page and its nav link # never appear. That is the usual reason "I set the secrets and nothing shows up". # # The two CREDENTIALS live in the Secrets Store, like the Turnstile pair above: # # wrangler secrets-store secret create --name DISCORD_CLIENT_ID \ # --scopes workers --remote # wrangler secrets-store secret create --name DISCORD_CLIENT_SECRET \ # --scopes workers --remote # # The two IDS are plain vars, and go HERE — they are not secrets, and setting the secrets # alone is not enough. Both are Discord snowflakes: all digits, no letters, copied with # Developer Mode on (right-click the server or role -> Copy ID). Ids, not names. # # ROLE_IDS is a list and ANY one of them qualifies, so several tiers can share the benefit. # SEPARATE THEM WITH COMMAS AND NO SPACES: these knobs are passed to wrangler as `--var` # flags that are word-split, so a value containing a space silently breaks the deploy. (The # worker itself also accepts whitespace, which is fine in wrangler.jsonc but not here.) # RECFLARE_DISCORD_GUILD_ID=1077000000000000000 # RECFLARE_DISCORD_BENEFITS_ROLE_IDS=1077000000000000001,1077000000000000002 # # Also add https:///claim to the app's Redirects in the Discord developer # portal, or the exchange is refused. Granting Plus takes effect on the player's NEXT # sign-in. `runx admin grant-plus` sets it directly, with no Discord involved.