From d1cc50622bae8541a19ce990ae4a35b28ed3330d Mon Sep 17 00:00:00 2001 From: Alexa <53471801+Alexa-RR@users.noreply.github.com> Date: Tue, 26 May 2026 01:17:14 +0300 Subject: [PATCH] main: branch-aware README + BRANCHES.md + versions.json MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rewrites main as a docs-only landing branch. Adds: - BRANCHES.md — per-branch chart (client build, status, notes) - versions.json — machine-readable manifest the Easy launcher reads - Branch-picking step + Easy-app/Docker URLs updated in README + docs/advanced-setup.md Drops the per-folder README stubs (server/, admin-ui/, client-mod/, docker/, easy-app/, tools/) — the actual code lives on per-version branches now, not on main. --- BRANCHES.md | 62 +++++++++++++++++++++++ README.md | 76 ++++++++++++++++++++-------- admin-ui/README.md | 36 ------------- client-mod/README.md | 57 --------------------- docker/README.md | 22 -------- docs/README.md | 17 ++++--- docs/advanced-setup.md | 38 +++++++++++--- easy-app/README.md | 112 ----------------------------------------- server/README.md | 57 --------------------- tools/README.md | 10 ---- versions.json | 23 +++++++++ 11 files changed, 178 insertions(+), 332 deletions(-) create mode 100644 BRANCHES.md delete mode 100644 admin-ui/README.md delete mode 100644 client-mod/README.md delete mode 100644 docker/README.md delete mode 100644 easy-app/README.md delete mode 100644 server/README.md delete mode 100644 tools/README.md create mode 100644 versions.json diff --git a/BRANCHES.md b/BRANCHES.md new file mode 100644 index 0000000..76697df --- /dev/null +++ b/BRANCHES.md @@ -0,0 +1,62 @@ +# Branches + +DorkNet maintains a long-lived branch per supported Rec Room client +build. Each branch is an independent fork of the server + client patcher +tuned to that build's wire protocol. Pick the one matching your install. + +## Active branches + +### `december-2020-12-18` + +- **Client build:** Rec Room 2020.12.18 +- **Status:** active +- **Notes:** + - Single EF Initial migration; SQLite + Postgres both work out of the + box. + - Includes the chat-threads, clubs, playlists, weekly-challenge, and + room-keys subsystems added late-2020. + - Server's `Versions/Late2020VersionPlugin` is the active version + plugin; client header `X-DorkNet-Version: december_2020_12_18`. + +### `march-2020-03-10` + +- **Client build:** Rec Room 2020.03.10 +- **Status:** pending import +- **Notes:** + - Earlier wire shape — no clubs, no playlists, simpler store catalog. + - Diverges from `december-2020-12-18` by ~170 files; cannot be + unified with the plugin abstraction alone. + +Setup for either is the same — see [docs/advanced-setup.md](docs/advanced-setup.md) +(starts with a "pick your branch" step). + +## How to pick + +If you don't know which Rec Room build you have, check: + +- **Steam**: right-click *Rec Room* → Properties → Local files → + Browse → look at the `Recroom_Release_Data/StreamingAssets/version.txt` + if present, or note the install timestamp. +- **Manual install** (the typical DorkNet setup path): the build is in + the folder name (`RecRoom-2020.12.18`, `RecRoom-2020.03.10`, etc.). +- **Easy launcher**: auto-detects the build and picks the branch. + +## Machine-readable manifest + +[`versions.json`](versions.json) carries the same information in a +format the Easy launcher and install scripts can consume directly. Add +new versions there too when a new branch lands. + +## Adding a new version branch + +1. Land the server code on a new orphan branch named `-` + (e.g. `august-2021-08-04`). +2. Add a row to the active-branches list above. +3. Add the matching entry to `versions.json`. +4. Add a `docs/-setup.md` setup guide. +5. Tag a release on the new branch so the Easy launcher's + release-fetcher picks it up. + +Branches are intentionally long-lived — once a build is supported, its +branch keeps getting patches against the same wire protocol. Don't +rebase across branches; cherry-pick when a fix applies to multiple. diff --git a/README.md b/README.md index df8afd8..165abca 100644 --- a/README.md +++ b/README.md @@ -1,38 +1,65 @@ # DorkNet -A self-hostable reimplementation of the 2020 Rec Room backend. Bring your own -client; run a private server for yourself and your friends. +A self-hostable reimplementation of the 2020 Rec Room backend. Bring your +own client; run a private server for yourself and your friends. > ⚠️ **Not affiliated with Rec Room Inc. or Against Gravity.** -> See [DISCLAIMER.md](DISCLAIMER.md). DorkNet ships no Rec Room game assets or -> modified binaries — you supply your own legally-acquired Rec Room 2020.12.18 +> See [DISCLAIMER.md](DISCLAIMER.md). DorkNet ships no Rec Room game assets +> or modified binaries — you supply your own legally-acquired Rec Room > install. --- +## Pick your client version + +DorkNet maintains a separate branch for each Rec Room client build it +supports. The server, client patcher, and seed data on each branch are +tuned to that build's wire protocol. + +| Client build | Branch | Status | +|---|---|---| +| **Rec Room 2020.12.18** (December) | [`december-2020-12-18`](../../tree/december-2020-12-18) | Active | +| **Rec Room 2020.03.10** (March) | [`march-2020-03-10`](../../tree/march-2020-03-10) | Pending import | + +See [BRANCHES.md](BRANCHES.md) for the full per-branch breakdown +(supported features, schema notes, plugin compatibility). Programs that +need the mapping in machine-readable form (the Easy launcher, install +scripts) read it from [versions.json](versions.json). + +This `main` branch is **docs-only** — it carries the project README, the +manifest the launcher reads, the per-version setup guides, and the Easy +app source. All actual server / patcher code lives on the per-version +branches above. + +--- + ## Two ways to run it ### 🎮 Easy mode — desktop app -One download. Double-click. Choose "host" or "join" on first launch. +One download. Pick a client version on first launch. Hosts can switch +between supported builds without re-installing the launcher. -- **Host a server** for you and your friends — runs a local server + tunnel, - patches your Rec Room install, and gives you a shareable join code. -- **Join a server** someone shared with you — paste the code, point at your - Rec Room install, hit play. +- **Host a server** — runs a local server + Cloudflare tunnel for the + client version you choose, patches your Rec Room install, and gives + you a shareable join code. +- **Join a server** — paste the code, point at your Rec Room install, + hit play. The launcher fetches the matching client patcher for the + host's server version. -→ **[Easy setup guide](docs/easy-setup.md)** — screenshots, takes 5 minutes. +→ **[Easy setup guide](docs/easy-setup.md)** — screenshots, ~5 minutes. -[Download the latest Easy app →](https://github.com/YOUR_GH_USERNAME/dorknet/releases/latest) +[Download the latest Easy app →](https://github.com/DorkSquadRR/DorkNet/releases/latest) -### 🛠️ Advanced mode — Docker +### 🛠️ Advanced mode — Docker / source -For people running a community server, doing custom modding, or contributing -back. Postgres + Redis + the ASP.NET Core server behind an nginx reverse proxy. +For community-server hosts, modders, and contributors. Pick the branch +matching your client build, clone, run. ```bash -git clone https://github.com/YOUR_GH_USERNAME/dorknet -cd dorknet/docker +# Example: hosting for December 2020.12.18 clients +git clone --branch december-2020-12-18 https://github.com/DorkSquadRR/DorkNet +cd DorkNet/docker cp .env.example .env # fill in 2-3 values docker compose up -d ``` @@ -43,6 +70,9 @@ docker compose up -d ## What works / what doesn't +Feature set varies per branch. The table below is the union — see each +branch's `BRANCHES.md` row for the exact deltas. + | Feature | Status | | -------------------------------- | ------ | | Account creation + login | ✅ | @@ -69,16 +99,18 @@ docker compose up -d - **Code**: [AGPL-3.0](LICENSE). Hosted forks must publish their source. - **"Rec Room"** is a trademark of Rec Room Inc. See [DISCLAIMER.md](DISCLAIMER.md). -- DorkNet is a clean-room reimplementation of the 2020 backend protocol for - educational and personal use. +- DorkNet is a clean-room reimplementation of the 2020 backend protocol + for educational and personal use. --- ## Docs -- [Easy setup](docs/easy-setup.md) -- [Advanced setup](docs/advanced-setup.md) -- [Joining a server](docs/joining-a-server.md) -- [Architecture](docs/architecture.md) +- [Branch chart](BRANCHES.md) — which branch matches your client +- [Easy setup](docs/easy-setup.md) — desktop-launcher path +- [Advanced setup](docs/advanced-setup.md) — Docker / VPS path +- [Joining a server](docs/joining-a-server.md) — for players +- [Architecture](docs/architecture.md) — how the code is laid out - [FAQ](docs/faq.md) +- [Troubleshooting](docs/troubleshooting.md) - [Contributing](CONTRIBUTING.md) diff --git a/admin-ui/README.md b/admin-ui/README.md deleted file mode 100644 index af71836..0000000 --- a/admin-ui/README.md +++ /dev/null @@ -1,36 +0,0 @@ -# admin-ui/ - -React + Vite + Tailwind SPA. Talks to `/api/admin/v1/*` on the server. - -Embedded into: -1. The standalone server's `wwwroot/admin/` (advanced mode), served at - `https://admin./`. -2. The Easy desktop app via a Photino WebView (host mode admin tab). - -## Dev - -```bash -npm install -npm run dev # http://localhost:5173, proxies /api → :5000 -``` - -Start the server first; Vite's proxy doesn't synthesize endpoints. - -## Build - -```bash -npm run build # dist/ — copied into server/wwwroot/admin by the - # server's CI publish step, and into easy-app/Resources/ - # by tools/build-easy-app.ps1 -``` - -## Stack notes - -- React 18 + Vite 5 + TypeScript -- Tailwind 3 with a custom dark `ink/brand` palette in `tailwind.config.js` -- React Router 6 -- No external component library; primitives in `src/components/` -- No state library beyond per-page `useState` + `useApi` - -See [docs/architecture.md](../docs/architecture.md) for how the SPA is -delivered in both modes. diff --git a/client-mod/README.md b/client-mod/README.md deleted file mode 100644 index 1c39188..0000000 --- a/client-mod/README.md +++ /dev/null @@ -1,57 +0,0 @@ -# client-mod/ - -MelonLoader 0.6.x mod that retargets the 2020 Rec Room client at a -DorkNet server. Compiles to `DorkNet.ClientMod.dll`, which the patcher -drops into the user's `Recroom_Release/Mods/` folder. - -## What it does - -Harmony patches applied at boot: - -- **`Uri ctor`** — rewrites every `.rec.net` URL to your configured - server host. Catches every hardcoded API endpoint the watch ships with. -- **`PhotonNetwork.ConnectUsingSettings`** — overrides the baked-in - Photon Cloud AppId with yours. -- **`NetworkingPeer.CallAuthenticate`** — injects `userid` + `LoginLock` - into Photon's CustomAuth so your server can identify the player. -- **`BouncyCastle.Tls.*NotifyServerCertificate`** — bypasses TLS chain - validation. The 2020 client only trusts a baked-in cert set; we replace - the verifier so any cert from your server is accepted. (Mitigated by - also force-routing only to your configured host.) -- **`PlayerEmotes.RemoveInvalidCharactersFromMessage`** — skips the - TMP font-validation step that NREs when the font asset isn't loaded - yet (private servers don't always have it cached at chat-send time). -- **`AccountExtensions.CanLocalPlayerChat`** — forces chat-enabled for - Junior / restricted accounts (single-tenant private server, no chat - moderation needed). - -See `Mod.cs` for the full patch list with citations to the Cpp2IL -disassembly that justifies each one. - -## Config - -The mod reads `MelonLoader/UserData/dorknet-clientmod.json`: - -```json -{ - "ServerHost": "abc-def.trycloudflare.com", - "PhotonAppId": "your-photon-realtime-appid", - "PhotonCloudRegion": "eu", - "InjectAuthValues": true, - "EnableTlsTrustBypass": true -} -``` - -The patcher (desktop app and CLI) writes this file as part of the patch -flow — users don't normally edit it by hand. - -## Building - -```bash -dotnet build -c Release -# → bin/Release/DorkNet.ClientMod.dll -``` - -Requires Il2Cpp interop assemblies from the user's MelonLoader install. -Path defaults to `dist/RecRoom-Clean-2020.03.10/MelonLoader/`; override -with `-p:MelonLoaderDir=`. diff --git a/docker/README.md b/docker/README.md deleted file mode 100644 index 7c317ed..0000000 --- a/docker/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# docker/ - -The Docker Compose stack for advanced mode. See -[docs/advanced-setup.md](../docs/advanced-setup.md) for the full -walkthrough. - -``` -docker/ -├── docker-compose.yml Postgres + Redis + server + nginx -├── docker-compose.cloudflared.yml Optional: replace nginx with CF Tunnel -├── Dockerfile.server Multi-stage: SDK build → admin-ui build → runtime -├── nginx.conf Subdomain routing for *.your-domain -└── .env.example Required environment variables -``` - -Quick start: - -```bash -cp .env.example .env -$EDITOR .env -docker compose up -d -``` diff --git a/docs/README.md b/docs/README.md index 54192c6..37c3dd2 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,10 +1,11 @@ # DorkNet docs -| Doc | For who | -| -------------------------------------- | ---------------------------------------------------- | -| [easy-setup.md](easy-setup.md) | Hosts who want the desktop-app one-click experience | -| [advanced-setup.md](advanced-setup.md) | Hosts running a community server on a VPS | -| [joining-a-server.md](joining-a-server.md) | Players whose friend gave them a join code | -| [architecture.md](architecture.md) | Anyone hacking on the code | -| [faq.md](faq.md) | Common questions before you ask in issues | -| [troubleshooting.md](troubleshooting.md) | Known failure modes + fixes | +| Doc | For who | +| ---------------------------------------------- | ------------------------------------------------------ | +| [../BRANCHES.md](../BRANCHES.md) | Anyone picking which branch matches their Rec Room build | +| [easy-setup.md](easy-setup.md) | Hosts who want the desktop-app one-click experience | +| [advanced-setup.md](advanced-setup.md) | Hosts running a community server on Docker / a VPS | +| [joining-a-server.md](joining-a-server.md) | Players whose friend gave them a join code | +| [architecture.md](architecture.md) | Contributors hacking on the code | +| [faq.md](faq.md) | Common questions before you ask in issues | +| [troubleshooting.md](troubleshooting.md) | Known failure modes + fixes | diff --git a/docs/advanced-setup.md b/docs/advanced-setup.md index 939589a..57a1695 100644 --- a/docs/advanced-setup.md +++ b/docs/advanced-setup.md @@ -29,9 +29,22 @@ Tunnel) this should comfortably run 50+ concurrent players on a $20/mo VPS. ## Setup +### 1. Pick the branch matching your client build + +DorkNet keeps one branch per supported Rec Room build. See +[`../BRANCHES.md`](../BRANCHES.md) for the full chart. Quick map: + +| Your Rec Room install | Branch to clone | +|---|---| +| 2020.12.18 (most common DorkNet target) | `december-2020-12-18` | +| 2020.03.10 (or 2020.03.06) | `march-2020-03-10` | + +### 2. Clone + configure + ```bash -git clone https://github.com/YOUR_GH_USERNAME/dorknet -cd dorknet/docker +# Replace the branch in --branch with the row that matched above. +git clone --branch december-2020-12-18 https://github.com/DorkSquadRR/DorkNet +cd DorkNet/docker cp .env.example .env $EDITOR .env # fill in the values noted below @@ -93,13 +106,15 @@ server is ready at `https://api.your-server.example.com/healthz`. Same patcher as Easy mode, but you'll run it from the command line: ```powershell -.\tools\patch-client.ps1 ` - -RecRoomDir "C:\path\to\Recroom_Release" ` - -ServerHost "your-server.example.com" ` - -PhotonAppId "your-photon-realtime-appid" ` - -PhotonRegion "eu" +.\tools\install-plugin.ps1 ` + -RecRoomPath "C:\path\to\Recroom_Release_Data" ` + -PhotonAppId "" ` + -PhotonVoiceAppId "" ``` +The installer drops the DorkNet BepInEx plugin into the client's +`BepInEx/plugins/` and writes its config under `BepInEx/config/`. + ## Admin UI `https://admin.your-server.example.com` — log in with the first account @@ -119,7 +134,7 @@ docker compose exec postgres pg_dump -U dorknet dorknet > backup.sql ## Updating ```bash -cd dorknet +cd DorkNet git pull docker compose pull docker compose up -d @@ -127,3 +142,10 @@ docker compose up -d The server runs all idempotent migrations on boot, so version upgrades are zero-downtime as long as the schema changes are additive. + +> ⚠️ `git pull` only fetches updates for **your current branch**. +> DorkNet branches are independent — updates on `december-2020-12-18` +> don't flow to `march-2020-03-10` and vice versa. If you've checked +> out the wrong branch for your client, switching is a fresh +> `git clone --branch ...` (the schema and Photon AppId requirements +> differ). diff --git a/easy-app/README.md b/easy-app/README.md deleted file mode 100644 index af6894d..0000000 --- a/easy-app/README.md +++ /dev/null @@ -1,112 +0,0 @@ -# DorkNet Easy App - -The unified desktop app for hosts and guests. One binary, two modes. - -## Project layout - -``` -easy-app/ -├── Shell/ PhotinoNET window host, mode router, settings store, -│ auto-updater, system tray, log viewer. -├── HostMode/ Tunnel manager (cloudflared wrapper), server lifecycle -│ (start/stop the in-process ASP.NET Core), share-code -│ generation. -├── JoinMode/ Join-code parser (dorknet:// URL handler), connection -│ sanity-check, server reachability ping. -├── Shared/ Patcher library (port of tools/patch-client.ps1 to C#), -│ ConfigManager, RecRoomInstallFinder (Steam library scan), -│ ImageSigningKeyManager (auto-generate on first run). -└── Resources/ Icons, admin-ui dist (bundled at build time), - cloudflared.exe, MelonLoader/, mod DLLs. -``` - -## Build flow - -`Resources/admin-ui-dist/` is the production build output from -`../admin-ui/` — copied in by a pre-build task so the Photino webview can -serve it as the host-mode admin tab. - -```pwsh -# One-shot dev build -pwsh tools/build-easy-app.ps1 - -# Release artifact -dotnet publish easy-app -c Release -r win-x64 --self-contained \ - -p:PublishSingleFile=true -p:PublishTrimmed=false -# → bin/Release/net9.0/win-x64/publish/dorknet.exe (~80 MB) -``` - -## Why PhotinoNET - -- The admin UI is already a webview-friendly React SPA. Embedding it in a - Photino window is essentially free. -- Single .NET project. No Node toolchain in the desktop build, no Electron. -- Bundled binary ~50 MB before the runtime, ~80 MB with self-contained - .NET. Acceptable for one-time downloads. - -## Why not Electron / Tauri / Avalonia - -- **Electron**: doubles the binary size, adds Node into the supply chain. -- **Tauri**: Rust dependency we don't otherwise need; mixing it with the - existing .NET server complicates the build matrix. -- **Avalonia**: native, beautiful, but means re-implementing the admin - UI a second time. The point of unified Host mode is *reuse* the admin - SPA verbatim. - -## Modes — first-run decision - -`Shared/ConfigManager` writes `%APPDATA%\DorkNet\mode.json`: - -```json -{ "mode": "host" } -``` - -`Shell` reads this on startup. Missing or `null` → first-run wizard. -Settings → "Switch mode" sets `mode` to the other value, restarts the -process clean (Photino re-init). - -## Host mode lifecycle - -1. User clicks Start server. -2. `HostMode.ServerLauncher` boots the ASP.NET Core host in-process, - wired to a SQLite DB at `%APPDATA%\DorkNet\dorknet.db`. -3. `HostMode.TunnelManager` spawns `cloudflared tunnel --url - http://localhost:5000`, reads the public URL off stderr. -4. UI surfaces the URL + a "Copy join code" button. Join code is - base64(`{host, photonAppId, photonRegion, name}`). - -## Join mode lifecycle - -1. User pastes a join code (or clicks a `dorknet://` URL — the installer - registers the protocol handler). -2. `JoinMode.CodeParser` decodes, ping-checks the host, shows a - "Connecting to X" preview. -3. User points at their Rec Room install (auto-detected via - `RecRoomInstallFinder` if Steam owns it). -4. `Shared.Patcher` patches `global-metadata.dat`, drops MelonLoader, - writes `dorknet-clientmod.json` with the decoded host + Photon AppId. -5. UI offers a "Launch Rec Room" button — runs `Recroom_Release.exe` - directly, no Steam intermediary needed. - -## Auto-updates - -[Velopack](https://velopack.io) is the path of least resistance for .NET -desktop. Drop-in: declare a GitHub Release feed, ship updates as deltas. - -## Testing - -QA matrix to maintain: -- Fresh Windows 10 VM, no Rec Room → install Steam → buy / depot-download - the 2020 build → DorkNet host mode → patch + start + tunnel → connect - from a second VM via Join mode. End-to-end smoke test. -- Mac M1 + Linux: deferred. PhotinoNET supports them but we need separate - cloudflared binaries and a packaging step per OS. - -## Open questions - -- [ ] Code-signing cert. SmartScreen warning is a major adoption friction. - EV cert is ~$200/yr; standard cert is cheaper but takes longer to build - reputation. -- [ ] Crash reporting. Sentry has a generous free tier and a clean .NET SDK. -- [ ] Telemetry — opt-in? Off by default? Right now: no plans, but - document the position so contributors know. diff --git a/server/README.md b/server/README.md deleted file mode 100644 index 2195600..0000000 --- a/server/README.md +++ /dev/null @@ -1,57 +0,0 @@ -# server/ - -The ASP.NET Core backend. - -Built two ways: -- **Standalone Postgres-backed** for advanced mode (Docker), via - `dotnet run` or the `dorknet-server` container. -- **In-process SQLite-backed** for the Easy desktop app, hosted as a - library inside `easy-app/`. - -## Code layout (TBC) - -``` -server/ -├── Controllers/ HTTP endpoints, sliced by subdomain → service -├── Services/ Business logic (presence, notifications, levels, ...) -├── Hubs/ SignalR NotifyHub -├── Data/ DbContext + EntityFramework entity classes -├── Auth/ JWT issuance, Photon CustomAuth handler -├── Middleware/ SubdomainRouter, request logging, error handling -└── Program.cs Boot: migrations, seeds, canonical overrides, DI -``` - -## Building - -```bash -dotnet build -c Release -dotnet run # localhost:5000 -``` - -## Provider switch - -The DbContext is provider-agnostic. `appsettings` picks one: - -```jsonc -{ - "ConnectionStrings": { - // Postgres for advanced mode - "Default": "Host=localhost;Database=dorknet;Username=dorknet;Password=..." - // OR SQLite for easy mode - // "Default": "Data Source=dorknet.db" - }, - "Database": { - "Provider": "Postgres" // or "Sqlite" - } -} -``` - -Easy app boots with `Provider=Sqlite` baked in; standalone defaults to -`Provider=Postgres`. - -## See also - -- [docs/architecture.md](../docs/architecture.md) — request flow, - subdomain routing, Photon relationship -- [docs/advanced-setup.md](../docs/advanced-setup.md) — production setup -- [CONTRIBUTING.md](../CONTRIBUTING.md) — style + PR rules diff --git a/tools/README.md b/tools/README.md deleted file mode 100644 index eebb7a6..0000000 --- a/tools/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# tools/ - -CLI helpers. Most users don't need to touch these — the desktop app -wraps the same logic with a UI. - -| Script | Purpose | -| -------------------- | ------------------------------------------------------ | -| `patch-client.ps1` | Patch a Rec Room install to talk to your DorkNet server. The desktop app wraps this in a UI; CLI path is for advanced-mode hosts. | -| `dump-il2cpp.ps1` | Run Cpp2IL against a Rec Room install to produce the decompiled dumps the project uses for reverse-engineering. Output stays on your machine — never committed. | -| `build-easy-app.ps1` | Build the unified desktop app (`dorknet.exe`). Self-contained .NET single-file publish. | diff --git a/versions.json b/versions.json new file mode 100644 index 0000000..5307ac9 --- /dev/null +++ b/versions.json @@ -0,0 +1,23 @@ +{ + "$schema_version": 1, + "$comment": "Branch-to-client-build manifest. The Easy launcher and install scripts read this to map a detected Rec Room install to the right DorkNet branch + release. When adding a branch, append here AND to BRANCHES.md.", + "branches": [ + { + "branch": "december-2020-12-18", + "client_build": "2020.12.18", + "alt_builds": [], + "version_key": "december_2020_12_18", + "release_tag_prefix": "v1-december", + "supported": true + }, + { + "branch": "march-2020-03-10", + "client_build": "2020.03.10", + "alt_builds": ["2020.03.06"], + "version_key": "march_2020_03_10", + "release_tag_prefix": "v1-march", + "supported": false, + "supported_note": "branch import pending" + } + ] +}