# RecFlare RecFlare is an implementation of RecNet — the Rec Room backend — built on Cloudflare Workers. It implements the network services the Rec Room client talks to — accounts, auth, rooms, matchmaking, economy, chat, notifications, and more — each as an independent Worker on its own subdomain. > **Disclaimer:** This is an unofficial, fan-made project for preservation and > experimentation. It is not affiliated with, endorsed by, or connected to Rec > Room Inc. "Rec Room" is a trademark of its respective owner. ## Client RecFlare is compatible with the [CannedNet client](https://github.com/CannedNet/CannedNet) and the build of Rec Room with manifest `7859140924515540835`. Other client or game versions expect different endpoints and response shapes and are not supported. ## How it works The Rec Room client discovers every service by fetching an _endpoints document_ from the name-server (`ns`) worker at the apex domain. That document maps each service to a host like `https://api.`. Every service runs as a separate Cloudflare Worker attached to its own subdomain, so the client's traffic fans out across the workers in `apps/`. Authentication is a Bearer-JWT flow: the `auth` worker issues tokens from `/connect/token` and owns the shared `accounts` table; every other worker validates that token on its auth-gated routes. New players are placed into the Orientation room on first login. State is persisted with Cloudflare's storage primitives — D1 (SQLite) for accounts and rooms, KV for per-player settings and presence, R2 for images and CDN binaries, and a Durable Object for the real-time notifications hub. Endpoints that aren't backed by storage yet return sensible defaults and are marked `TODO`. ## Services These are every RecNet service the client discovers, taken from the service-discovery map in [`apps/ns/src/endpoints.ts`](apps/ns/src/endpoints.ts). Each is reached at `https://.`. Services with a worker in `apps/` are implemented here; the rest are advertised in the endpoints document but not yet backed by a Worker. | Service | Subdomain | Worker | Notes | | ----------------------- | ----------------------- | ------------------ | ----------------------------------------------------------------- | | Accounts | `accounts` | `accounts` | Player accounts & profile reads/writes (D1) | | AI | `ai` | — | Not yet implemented | | API | `api` | `api` | Core Game API — config, social, avatar, rooms, image uploads (D1, R2) | | Auth | `auth` | `auth` | OAuth token issuance (`/connect/token`); owns the accounts table (D1, KV) | | BugReporting | `bugreporting` | — | Not yet implemented | | Cards | `cards` | — | Not yet implemented | | CDN | `cdn` | `cdn` | Binary CDN — signature blobs & room build data (R2) | | Chat | `chat` | `chat` | Chat service | | Clubs | `clubs` | `clubs` | Clubs | | CMS | `cms` | — | Not yet implemented | | Commerce | `commerce` | `commerce` | Store / purchase endpoints | | Data | `data` | — | Not yet implemented | | DataCollection | `datacollection` | `datacollection` | Client telemetry / analytics sink | | Discovery | `discovery` | — | Not yet implemented | | Econ | `econ` | `econ` | Economy & avatar endpoints (separate from `api`) | | GameLogs | `gamelogs` | — | Not yet implemented | | Geo | `geo` | — | Not yet implemented | | Images | `img` | `img` | Image storage & signed delivery (R2) | | Leaderboard | `leaderboard` | — | Not yet implemented | | Link | `link` | — | Not yet implemented | | Lists | `lists` | — | Not yet implemented | | Matchmaking | `match` | `match` | Matchmaking & per-player presence (D1, KV) | | Moderation | `api` | `api` | Served by the `api` worker (shares the API host) | | Notifications | `notify` | `notify` | Real-time notifications over SignalR/WebSockets (Durable Object) | | PlatformNotifications | `platformnotifications` | — | Not yet implemented | | PlayerSettings | `playersettings` | `playersettings` | Per-player settings (KV) | | RoomComments | `roomcomments` | — | Not yet implemented | | RoomieIntegrations | `roomieintegrations` | — | Not yet implemented | | Rooms | `rooms` | `rooms` | Room storage & queries; seeds the Dorm & Orientation rooms (D1) | | Storage | `storage` | — | Not yet implemented | | Strings | `strings` | — | Not yet implemented | | StringsCDN | `strings-cdn` | — | Not yet implemented | | Studio | `studio` | — | Not yet implemented | | Thorn | `thorn` | — | Not yet implemented | | Videos | `videos` | — | Not yet implemented | | WWW | `www` | — | Website host (not a Worker) | The `ns` worker itself serves this discovery document at the apex/`ns` host and isn't listed within it. Each implemented worker has its own `README.md` under `apps//` documenting its routes. ## Why Cloudflare? - **It's free to run a lot of services.** Cloudflare Workers' free tier is keyed to usage, not to the number of Workers — so whether you deploy 1 service or all 36, the baseline cost is the same. You only start paying once usage crosses the free-tier limits. - **It mirrors RecNet's architecture.** Rec Room's backend is a set of independent microservices, not one monolith. Modeling each service as its own Worker keeps RecFlare's structure close to the real thing — services scale, fail, and deploy independently — instead of collapsing everything into a single giant server. ## Do I have to use Cloudflare? No. The services are plain [Hono](https://hono.dev) apps, so the request-handling code isn't tied to Cloudflare and can be deployed to other hosting providers — AWS (Lambda), Vercel, Netlify, Fly.io, a plain Node/Bun server, and so on. The catch is everything _around_ the code. RecFlare leans on Cloudflare for the deployment and infrastructure layer — custom-domain routing per service, plus the storage bindings (D1, KV, R2, Durable Objects) the workers use. On another provider you'll need to provide equivalents (per-service routing, databases, object storage, a pub/sub or WebSocket layer) and wire up the deployment yourself. ## Prerequisites - node.js v22 or later - pnpm v10 or later - bun 1.2 or later - A Cloudflare account with a zone (domain) you control, for deploying - shfmt / rg (ripgrep) — optional, recommended for shell formatting - mise — optional, recommended for tool management ## Getting Started **Install dependencies:** ```bash just install ``` **Configure your domain:** `env.json` is the single source of truth for your base domain; it is gitignored, so each clone needs its own copy. ```bash cp env.example.json env.json # edit env.json and set "domain" to your domain ``` `just deploy` resolves the base domain at deploy time and passes it to wrangler — each worker is attached to its custom domain via `--domain .`, and the base domain is injected as the `DOMAIN` var so the `ns` service-discovery document and the api share-link base URL are built at runtime. Nothing in version control is rewritten; committed `wrangler.jsonc` files have no routes. The domain is read from the `RECFLARE_DOMAIN` environment variable if set, otherwise from `env.json`. Per-app subdomain overrides come from `RECFLARE_SUBDOMAINS` (a JSON object, e.g. `{"playersettings":"settings"}`) or the `subdomains` key in `env.json`. For CI, set `RECFLARE_DOMAIN` as a secret and skip `env.json` entirely: ```bash RECFLARE_DOMAIN=rec.example.com just deploy ``` **Run the development server:** ```bash just dev ``` **Deploy all workers:** ```bash just deploy ``` Deploying requires `wrangler` to be authenticated against your Cloudflare account (`wrangler login`, or `CLOUDFLARE_API_TOKEN` / `CLOUDFLARE_ACCOUNT_ID` in the environment). Storage resources (D1 databases, KV namespaces, R2 buckets) must be created and their ids set in each worker's `wrangler.jsonc` — see the inline comments in those files for the exact `wrangler` commands. ## Repository Structure - `apps/` - The service workers, one deployable Worker per subdirectory. Each has its own `README.md`, `wrangler.jsonc`, `src/`, and tests. - `packages/` - Shared libraries and configuration used across the workers. - `@repo/hono-helpers` - Hono framework utilities (logging, error handling). - `@repo/tools` - The `runx` CLI and the `bin/` scripts each worker's package.json delegates to, so build/test/deploy stays consistent. - `@repo/typescript-config`, `@repo/oxlint-config` - Shared TS and lint config. - `turbo/generators/` - `turbo gen` templates for scaffolding new workers/packages. - `Justfile` - Convenient aliases for common development tasks. - `pnpm-workspace.yaml` - pnpm workspace definition. - `turbo.jsonc` - Turborepo task graph and caching. - `.syncpackrc.cjs` - Keeps dependency versions consistent across packages. ## Available Commands This repository uses a `Justfile`. Run `just` (or `just --list`) to see every command. Some key ones: - `just install` - Install all dependencies. - `just dev` - Start the dev server (context-aware: runs `bun runx dev`). - `just build` - Build all workers. - `just test` - Run tests (vitest). - `just check` - Check code quality: deps, lint, types, format. - `just fix` - Fix code issues: deps, lint, format, workers-types. - `just deploy` - Deploy all workers to your domain. - `just new-worker` (alias: `just gen`) - Scaffold a new service worker. - `just new-package` - Scaffold a new shared package. - `just cs` - Create a changeset for versioning. - `just update deps` - Update dependencies across the monorepo with syncpack. For a single worker, scope with turbo, e.g. `bun turbo -F api dev`, `bun turbo -F api test`, or `bun turbo -F api deploy`. ## Why a monorepo? The services share types, auth logic, and tooling, so keeping them in one repo keeps those in sync: `pnpm` workspaces share dependencies, `@repo/` packages share code, Turborepo runs build/test/lint with a single cached task graph, and cross-service changes land in one atomic commit.