From 4d2450e784b99a036d5dc308051fd27c64b723fc Mon Sep 17 00:00:00 2001 From: Natalie Rose Date: Sun, 6 Sep 2026 10:22:34 +1000 Subject: [PATCH] Add tests --- .gitea/workflows/build.yml | 33 + .npmrc | 1 + CLAUDE.md | 91 ++ argumentMap.json | 3016 +++++++++++++++++++++++++++--------- package-lock.json | 8 + package.json | 2 + test/argument-map.test.ts | 149 ++ 7 files changed, 2532 insertions(+), 768 deletions(-) create mode 100644 CLAUDE.md create mode 100644 test/argument-map.test.ts diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml index 8b67406..0f3971b 100644 --- a/.gitea/workflows/build.yml +++ b/.gitea/workflows/build.yml @@ -5,8 +5,41 @@ on: branches: [main] jobs: + test: + runs-on: ubuntu-latest + + container: + options: --cap-add=NET_ADMIN --device=/dev/net/tun + + steps: + - name: Tailscale + uses: tailscale/github-action@v4 + with: + authkey: ${{ secrets.TAILSCALE_AUTHKEY }} + ping: rose-library,gitea + version: latest + use-cache: 'false' + + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version-file: .nvmrc + + - name: Install + run: npm ci + + - name: Check formatting + run: npm run format:check + + - name: Validate argument map + run: npm test + build: runs-on: ubuntu-latest + needs: test container: options: --cap-add=NET_ADMIN --device=/dev/net/tun diff --git a/.npmrc b/.npmrc index ba21d60..c797fc8 100644 --- a/.npmrc +++ b/.npmrc @@ -1,2 +1,3 @@ fund=false engine-strict=true +@tlecommunity:registry=https://gitea.allosaurus-chromatic.ts.net/api/packages/tlecommunity/npm/ diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..af64ce7 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,91 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this +repository. + +## What this is + +An Express 5 proxy that lets clients call the legacy TLE (The Lacuna Expanse) Perl game backend with +modern ergonomics: paths like `POST /v2/empire/is_name_available` and a plain named-argument JSON +body like `{"name": "1vasari"}`, instead of hand-building positional JSON-RPC 2.0 requests. It +translates the request, forwards it to the backend, and passes the backend's response straight back. + +## Commands + +Requires Node >= 22.6.0 and npm >= 10 (`.npmrc` sets `engine-strict=true`). `.nvmrc` pins Node 22. + +- Install: `npm install` +- Run locally: `node --experimental-strip-types index.ts` (Node strips the TS types at runtime; on + Node >= 23.6 the flag is unnecessary). Listens on `PORT` env var, default `5999`. +- Type-check: `npx tsc` (`tsconfig.json` has `noEmit: true` — there is **no build/compile step**; + the `.ts` file is the shipped artifact). +- Test: `npm test` — runs `test/argument-map.test.ts` (built-in `node:test` runner) to cross-check + `argumentMap.json` against the `@tlecommunity/api-spec` OpenAPI spec. +- Format check: `npm run format:check` +- Format fix: `npm run format:fix` +- Docker: `docker build -t v2-api .` (see deployment note below) + +There is **no lint** beyond Prettier. Prettier config: 100-col width, single quotes, semicolons, +`proseWrap: always` (wrap Markdown/prose too). + +### `npm test` / `test/argument-map.test.ts` + +Asserts `argumentMap.json` and the spec stay in sync: every map key is a real spec path; the three +sections are mutually exclusive; every `positional` arg is a spec request-body property (and vice +versa) with matching `required` flags; and **every spec path has a map entry or is listed in +`EXEMPT_PATHS`** in the test. A newly added/renamed spec method fails the test until it is mapped in +`argumentMap.json` (or exempted). CI (`.gitea/workflows/build.yml`) runs this plus `format:check` in +a `test` job that `build` depends on. + +## Architecture + +### Single route + +`POST /v2/:module/:method` (in `index.ts`) is the only endpoint. It builds a JSON-RPC 2.0 request +via `prepareBody()` and forwards it to `http://server:5000/:module` — the backend hostname and port +are **hardcoded** (there's a `TODO pass real port through`); `server` is expected to resolve on the +deploy network (Docker/Tailscale). + +### `prepareBody()` — the core translation + +Given the request body, it produces either an `RPCRequest` or an `RPCError`. It accepts three input +shapes: an already-formed JSON-RPC object (has a `jsonrpc` key — passed through), an array (used as +positional `params` directly), or a plain named object (converted). + +Named -> positional conversion is driven entirely by `argumentMap.json`, which has three top-level +sections keyed by `/module/method`: + +- **`positional`** (~1122 methods): ordered list of `{ name, required }`. The named object's values + are emitted in this order; a missing `required` arg returns an error (code `1002`). +- **`namedOnlyFirstPosition`** (14 methods): backend wants a single hashref wrapped in a one-element + array — `params: [ { ...args } ]`. +- **`namedOnlyArgumentHash`** (2 methods): backend wants a bare hash — `params: { ...args }`. + +A method present in **none** of the three sections is rejected with a loud error rather than +guessing an argument order. Keep `argumentMap.json` exhaustive for every method the proxy is +expected to serve. + +### Auth + +Clients send `Authorization: Token `. The token is injected as the session id: merged in +as `session_id` for hash-style methods, or prepended as the first positional arg for positional +methods. `/empire/login` is exempt (no session yet). + +### Errors + +`errorCodes` in `index.ts` enumerates the legacy game error codes (1000–1200). Validation and +processing failures in the proxy return HTTP 500 with a JSON-RPC error body (usually code `1002`); +backend responses are relayed with the backend's own status code. + +## Regenerating `argumentMap.json` + +It was generated from the server repo's `lib/Lacuna/RPC/**/*.pm` plus the OpenAPI spec (~1157 +methods; ~35 couldn't be auto-resolved — consolidated building names like `beach`, plus spec/backend +drift). There is no generator script in this repo. Edit the file directly as gaps surface through +testing. + +## Deployment + +Pushing to `main` triggers Gitea Actions (`.gitea/workflows/build.yml`): it joins a Tailscale +network, builds a `linux/amd64` image, and pushes +`gitea.allosaurus-chromatic.ts.net/tlecommunity/v2-api:latest` to the private registry. diff --git a/argumentMap.json b/argumentMap.json index 57a1044..aed848e 100644 --- a/argumentMap.json +++ b/argumentMap.json @@ -406,7 +406,7 @@ "required": true } ], - "/bean/build": [ + "/beach1/build": [ { "name": "body_id", "required": true @@ -420,19 +420,19 @@ "required": true } ], - "/bean/demolish": [ + "/beach1/demolish": [ { "name": "building_id", "required": true } ], - "/bean/downgrade": [ + "/beach1/downgrade": [ { "name": "building_id", "required": true } ], - "/bean/get_stats_for_level": [ + "/beach1/get_stats_for_level": [ { "name": "building_id", "required": true @@ -442,25 +442,25 @@ "required": true } ], - "/bean/repair": [ + "/beach1/repair": [ { "name": "building_id", "required": true } ], - "/bean/upgrade": [ + "/beach1/upgrade": [ { "name": "building_id", "required": true } ], - "/bean/view": [ + "/beach1/view": [ { "name": "building_id", "required": true } ], - "/beeldeban/build": [ + "/beach10/build": [ { "name": "body_id", "required": true @@ -474,19 +474,19 @@ "required": true } ], - "/beeldeban/demolish": [ + "/beach10/demolish": [ { "name": "building_id", "required": true } ], - "/beeldeban/downgrade": [ + "/beach10/downgrade": [ { "name": "building_id", "required": true } ], - "/beeldeban/get_stats_for_level": [ + "/beach10/get_stats_for_level": [ { "name": "building_id", "required": true @@ -496,25 +496,25 @@ "required": true } ], - "/beeldeban/repair": [ + "/beach10/repair": [ { "name": "building_id", "required": true } ], - "/beeldeban/upgrade": [ + "/beach10/upgrade": [ { "name": "building_id", "required": true } ], - "/beeldeban/view": [ + "/beach10/view": [ { "name": "building_id", "required": true } ], - "/beeldebannest/build": [ + "/beach11/build": [ { "name": "body_id", "required": true @@ -528,19 +528,19 @@ "required": true } ], - "/beeldebannest/demolish": [ + "/beach11/demolish": [ { "name": "building_id", "required": true } ], - "/beeldebannest/downgrade": [ + "/beach11/downgrade": [ { "name": "building_id", "required": true } ], - "/beeldebannest/get_stats_for_level": [ + "/beach11/get_stats_for_level": [ { "name": "building_id", "required": true @@ -550,25 +550,25 @@ "required": true } ], - "/beeldebannest/repair": [ + "/beach11/repair": [ { "name": "building_id", "required": true } ], - "/beeldebannest/upgrade": [ + "/beach11/upgrade": [ { "name": "building_id", "required": true } ], - "/beeldebannest/view": [ + "/beach11/view": [ { "name": "building_id", "required": true } ], - "/blackholegenerator/build": [ + "/beach12/build": [ { "name": "body_id", "required": true @@ -582,29 +582,19 @@ "required": true } ], - "/blackholegenerator/demolish": [ - { - "name": "building_id", - "required": true - } - ], - "/blackholegenerator/downgrade": [ + "/beach12/demolish": [ { "name": "building_id", "required": true } ], - "/blackholegenerator/get_actions_for": [ + "/beach12/downgrade": [ { "name": "building_id", "required": true - }, - { - "name": "target", - "required": true } ], - "/blackholegenerator/get_stats_for_level": [ + "/beach12/get_stats_for_level": [ { "name": "building_id", "required": true @@ -614,37 +604,25 @@ "required": true } ], - "/blackholegenerator/repair": [ - { - "name": "building_id", - "required": true - } - ], - "/blackholegenerator/subsidize_cooldown": [ + "/beach12/repair": [ { "name": "building_id", "required": true } ], - "/blackholegenerator/upgrade": [ + "/beach12/upgrade": [ { "name": "building_id", "required": true } ], - "/blackholegenerator/view": [ + "/beach12/view": [ { "name": "building_id", "required": true } ], - "/body/abandon": [ - { - "name": "body_id", - "required": true - } - ], - "/body/get_buildable": [ + "/beach13/build": [ { "name": "body_id", "required": true @@ -656,77 +634,49 @@ { "name": "y", "required": true - }, - { - "name": "tag", - "required": true - } - ], - "/body/get_buildings": [ - { - "name": "body_id", - "required": true - } - ], - "/body/get_buildings_resources": [ - { - "name": "body_id", - "required": true } ], - "/body/get_status": [ + "/beach13/demolish": [ { - "name": "body_id", + "name": "building_id", "required": true } ], - "/body/rearrange_buildings": [ - { - "name": "body_id", - "required": true - }, + "/beach13/downgrade": [ { - "name": "arrangement", + "name": "building_id", "required": true } ], - "/body/rename": [ + "/beach13/get_stats_for_level": [ { - "name": "body_id", + "name": "building_id", "required": true }, { - "name": "name", + "name": "level", "required": true } ], - "/body/repair_list": [ - { - "name": "body_id", - "required": true - }, + "/beach13/repair": [ { - "name": "building_ids", + "name": "building_id", "required": true } ], - "/body/set_colony_notes": [ - { - "name": "body_id", - "required": true - }, + "/beach13/upgrade": [ { - "name": "options", + "name": "building_id", "required": true } ], - "/body/view_laws": [ + "/beach13/view": [ { - "name": "body_id", + "name": "building_id", "required": true } ], - "/bread/build": [ + "/beach2/build": [ { "name": "body_id", "required": true @@ -740,19 +690,19 @@ "required": true } ], - "/bread/demolish": [ + "/beach2/demolish": [ { "name": "building_id", "required": true } ], - "/bread/downgrade": [ + "/beach2/downgrade": [ { "name": "building_id", "required": true } ], - "/bread/get_stats_for_level": [ + "/beach2/get_stats_for_level": [ { "name": "building_id", "required": true @@ -762,25 +712,25 @@ "required": true } ], - "/bread/repair": [ + "/beach2/repair": [ { "name": "building_id", "required": true } ], - "/bread/upgrade": [ + "/beach2/upgrade": [ { "name": "building_id", "required": true } ], - "/bread/view": [ + "/beach2/view": [ { "name": "building_id", "required": true } ], - "/burger/build": [ + "/beach3/build": [ { "name": "body_id", "required": true @@ -794,19 +744,19 @@ "required": true } ], - "/burger/demolish": [ + "/beach3/demolish": [ { "name": "building_id", "required": true } ], - "/burger/downgrade": [ + "/beach3/downgrade": [ { "name": "building_id", "required": true } ], - "/burger/get_stats_for_level": [ + "/beach3/get_stats_for_level": [ { "name": "building_id", "required": true @@ -816,25 +766,25 @@ "required": true } ], - "/burger/repair": [ + "/beach3/repair": [ { "name": "building_id", "required": true } ], - "/burger/upgrade": [ + "/beach3/upgrade": [ { "name": "building_id", "required": true } ], - "/burger/view": [ + "/beach3/view": [ { "name": "building_id", "required": true } ], - "/capitol/build": [ + "/beach4/build": [ { "name": "body_id", "required": true @@ -848,19 +798,19 @@ "required": true } ], - "/capitol/demolish": [ + "/beach4/demolish": [ { "name": "building_id", "required": true } ], - "/capitol/downgrade": [ + "/beach4/downgrade": [ { "name": "building_id", "required": true } ], - "/capitol/get_stats_for_level": [ + "/beach4/get_stats_for_level": [ { "name": "building_id", "required": true @@ -870,46 +820,25 @@ "required": true } ], - "/capitol/rename_empire": [ - { - "name": "building_id", - "required": true - }, - { - "name": "name", - "required": true - } - ], - "/capitol/repair": [ + "/beach4/repair": [ { "name": "building_id", "required": true } ], - "/capitol/upgrade": [ + "/beach4/upgrade": [ { "name": "building_id", "required": true } ], - "/capitol/view": [ + "/beach4/view": [ { "name": "building_id", "required": true } ], - "/captcha/fetch": [], - "/captcha/solve": [ - { - "name": "guid", - "required": true - }, - { - "name": "solution", - "required": true - } - ], - "/cheese/build": [ + "/beach5/build": [ { "name": "body_id", "required": true @@ -923,19 +852,19 @@ "required": true } ], - "/cheese/demolish": [ + "/beach5/demolish": [ { "name": "building_id", "required": true } ], - "/cheese/downgrade": [ + "/beach5/downgrade": [ { "name": "building_id", "required": true } ], - "/cheese/get_stats_for_level": [ + "/beach5/get_stats_for_level": [ { "name": "building_id", "required": true @@ -945,25 +874,25 @@ "required": true } ], - "/cheese/repair": [ + "/beach5/repair": [ { "name": "building_id", "required": true } ], - "/cheese/upgrade": [ + "/beach5/upgrade": [ { "name": "building_id", "required": true } ], - "/cheese/view": [ + "/beach5/view": [ { "name": "building_id", "required": true } ], - "/chip/build": [ + "/beach6/build": [ { "name": "body_id", "required": true @@ -977,19 +906,19 @@ "required": true } ], - "/chip/demolish": [ + "/beach6/demolish": [ { "name": "building_id", "required": true } ], - "/chip/downgrade": [ + "/beach6/downgrade": [ { "name": "building_id", "required": true } ], - "/chip/get_stats_for_level": [ + "/beach6/get_stats_for_level": [ { "name": "building_id", "required": true @@ -999,25 +928,25 @@ "required": true } ], - "/chip/repair": [ + "/beach6/repair": [ { "name": "building_id", "required": true } ], - "/chip/upgrade": [ + "/beach6/upgrade": [ { "name": "building_id", "required": true } ], - "/chip/view": [ + "/beach6/view": [ { "name": "building_id", "required": true } ], - "/cider/build": [ + "/beach7/build": [ { "name": "body_id", "required": true @@ -1031,19 +960,19 @@ "required": true } ], - "/cider/demolish": [ + "/beach7/demolish": [ { "name": "building_id", "required": true } ], - "/cider/downgrade": [ + "/beach7/downgrade": [ { "name": "building_id", "required": true } ], - "/cider/get_stats_for_level": [ + "/beach7/get_stats_for_level": [ { "name": "building_id", "required": true @@ -1053,25 +982,25 @@ "required": true } ], - "/cider/repair": [ + "/beach7/repair": [ { "name": "building_id", "required": true } ], - "/cider/upgrade": [ + "/beach7/upgrade": [ { "name": "building_id", "required": true } ], - "/cider/view": [ + "/beach7/view": [ { "name": "building_id", "required": true } ], - "/citadelofknope/build": [ + "/beach8/build": [ { "name": "body_id", "required": true @@ -1085,19 +1014,19 @@ "required": true } ], - "/citadelofknope/demolish": [ + "/beach8/demolish": [ { "name": "building_id", "required": true } ], - "/citadelofknope/downgrade": [ + "/beach8/downgrade": [ { "name": "building_id", "required": true } ], - "/citadelofknope/get_stats_for_level": [ + "/beach8/get_stats_for_level": [ { "name": "building_id", "required": true @@ -1107,25 +1036,25 @@ "required": true } ], - "/citadelofknope/repair": [ + "/beach8/repair": [ { "name": "building_id", "required": true } ], - "/citadelofknope/upgrade": [ + "/beach8/upgrade": [ { "name": "building_id", "required": true } ], - "/citadelofknope/view": [ + "/beach8/view": [ { "name": "building_id", "required": true } ], - "/cloakinglab/build": [ + "/beach9/build": [ { "name": "body_id", "required": true @@ -1139,19 +1068,19 @@ "required": true } ], - "/cloakinglab/demolish": [ + "/beach9/demolish": [ { "name": "building_id", "required": true } ], - "/cloakinglab/downgrade": [ + "/beach9/downgrade": [ { "name": "building_id", "required": true } ], - "/cloakinglab/get_stats_for_level": [ + "/beach9/get_stats_for_level": [ { "name": "building_id", "required": true @@ -1161,25 +1090,25 @@ "required": true } ], - "/cloakinglab/repair": [ + "/beach9/repair": [ { "name": "building_id", "required": true } ], - "/cloakinglab/upgrade": [ + "/beach9/upgrade": [ { "name": "building_id", "required": true } ], - "/cloakinglab/view": [ + "/beach9/view": [ { "name": "building_id", "required": true } ], - "/corn/build": [ + "/bean/build": [ { "name": "body_id", "required": true @@ -1193,19 +1122,19 @@ "required": true } ], - "/corn/demolish": [ + "/bean/demolish": [ { "name": "building_id", "required": true } ], - "/corn/downgrade": [ + "/bean/downgrade": [ { "name": "building_id", "required": true } ], - "/corn/get_stats_for_level": [ + "/bean/get_stats_for_level": [ { "name": "building_id", "required": true @@ -1215,25 +1144,25 @@ "required": true } ], - "/corn/repair": [ + "/bean/repair": [ { "name": "building_id", "required": true } ], - "/corn/upgrade": [ + "/bean/upgrade": [ { "name": "building_id", "required": true } ], - "/corn/view": [ + "/bean/view": [ { "name": "building_id", "required": true } ], - "/cornmeal/build": [ + "/beeldeban/build": [ { "name": "body_id", "required": true @@ -1247,19 +1176,19 @@ "required": true } ], - "/cornmeal/demolish": [ + "/beeldeban/demolish": [ { "name": "building_id", "required": true } ], - "/cornmeal/downgrade": [ + "/beeldeban/downgrade": [ { "name": "building_id", "required": true } ], - "/cornmeal/get_stats_for_level": [ + "/beeldeban/get_stats_for_level": [ { "name": "building_id", "required": true @@ -1269,25 +1198,25 @@ "required": true } ], - "/cornmeal/repair": [ + "/beeldeban/repair": [ { "name": "building_id", "required": true } ], - "/cornmeal/upgrade": [ + "/beeldeban/upgrade": [ { "name": "building_id", "required": true } ], - "/cornmeal/view": [ + "/beeldeban/view": [ { "name": "building_id", "required": true } ], - "/crashedshipsite/build": [ + "/beeldebannest/build": [ { "name": "body_id", "required": true @@ -1301,19 +1230,19 @@ "required": true } ], - "/crashedshipsite/demolish": [ + "/beeldebannest/demolish": [ { "name": "building_id", "required": true } ], - "/crashedshipsite/downgrade": [ + "/beeldebannest/downgrade": [ { "name": "building_id", "required": true } ], - "/crashedshipsite/get_stats_for_level": [ + "/beeldebannest/get_stats_for_level": [ { "name": "building_id", "required": true @@ -1323,25 +1252,25 @@ "required": true } ], - "/crashedshipsite/repair": [ + "/beeldebannest/repair": [ { "name": "building_id", "required": true } ], - "/crashedshipsite/upgrade": [ + "/beeldebannest/upgrade": [ { "name": "building_id", "required": true } ], - "/crashedshipsite/view": [ + "/beeldebannest/view": [ { "name": "building_id", "required": true } ], - "/crater/build": [ + "/blackholegenerator/build": [ { "name": "body_id", "required": true @@ -1355,19 +1284,29 @@ "required": true } ], - "/crater/demolish": [ + "/blackholegenerator/demolish": [ { "name": "building_id", "required": true } ], - "/crater/downgrade": [ + "/blackholegenerator/downgrade": [ { "name": "building_id", "required": true } ], - "/crater/get_stats_for_level": [ + "/blackholegenerator/get_actions_for": [ + { + "name": "building_id", + "required": true + }, + { + "name": "target", + "required": true + } + ], + "/blackholegenerator/get_stats_for_level": [ { "name": "building_id", "required": true @@ -1377,31 +1316,37 @@ "required": true } ], - "/crater/repair": [ + "/blackholegenerator/repair": [ { "name": "building_id", "required": true } ], - "/crater/upgrade": [ + "/blackholegenerator/subsidize_cooldown": [ { "name": "building_id", "required": true } ], - "/crater/view": [ + "/blackholegenerator/upgrade": [ { "name": "building_id", "required": true } ], - "/culinaryinstitute/view": [ + "/blackholegenerator/view": [ { "name": "building_id", "required": true } ], - "/dairy/build": [ + "/body/abandon": [ + { + "name": "body_id", + "required": true + } + ], + "/body/get_buildable": [ { "name": "body_id", "required": true @@ -1413,49 +1358,77 @@ { "name": "y", "required": true + }, + { + "name": "tag", + "required": true } ], - "/dairy/demolish": [ + "/body/get_buildings": [ { - "name": "building_id", + "name": "body_id", "required": true } ], - "/dairy/downgrade": [ + "/body/get_buildings_resources": [ { - "name": "building_id", + "name": "body_id", "required": true } ], - "/dairy/get_stats_for_level": [ + "/body/get_status": [ { - "name": "building_id", + "name": "body_id", + "required": true + } + ], + "/body/rearrange_buildings": [ + { + "name": "body_id", "required": true }, { - "name": "level", + "name": "arrangement", "required": true } ], - "/dairy/repair": [ + "/body/rename": [ { - "name": "building_id", + "name": "body_id", + "required": true + }, + { + "name": "name", "required": true } ], - "/dairy/upgrade": [ + "/body/repair_list": [ { - "name": "building_id", + "name": "body_id", + "required": true + }, + { + "name": "building_ids", "required": true } ], - "/dairy/view": [ + "/body/set_colony_notes": [ { - "name": "building_id", + "name": "body_id", + "required": true + }, + { + "name": "options", "required": true } ], - "/denton/build": [ + "/body/view_laws": [ + { + "name": "body_id", + "required": true + } + ], + "/bread/build": [ { "name": "body_id", "required": true @@ -1469,19 +1442,19 @@ "required": true } ], - "/denton/demolish": [ + "/bread/demolish": [ { "name": "building_id", "required": true } ], - "/denton/downgrade": [ + "/bread/downgrade": [ { "name": "building_id", "required": true } ], - "/denton/get_stats_for_level": [ + "/bread/get_stats_for_level": [ { "name": "building_id", "required": true @@ -1491,25 +1464,25 @@ "required": true } ], - "/denton/repair": [ + "/bread/repair": [ { "name": "building_id", "required": true } ], - "/denton/upgrade": [ + "/bread/upgrade": [ { "name": "building_id", "required": true } ], - "/denton/view": [ + "/bread/view": [ { "name": "building_id", "required": true } ], - "/dentonbrambles/build": [ + "/burger/build": [ { "name": "body_id", "required": true @@ -1523,19 +1496,19 @@ "required": true } ], - "/dentonbrambles/demolish": [ + "/burger/demolish": [ { "name": "building_id", "required": true } ], - "/dentonbrambles/downgrade": [ + "/burger/downgrade": [ { "name": "building_id", "required": true } ], - "/dentonbrambles/get_stats_for_level": [ + "/burger/get_stats_for_level": [ { "name": "building_id", "required": true @@ -1545,25 +1518,25 @@ "required": true } ], - "/dentonbrambles/repair": [ + "/burger/repair": [ { "name": "building_id", "required": true } ], - "/dentonbrambles/upgrade": [ + "/burger/upgrade": [ { "name": "building_id", "required": true } ], - "/dentonbrambles/view": [ + "/burger/view": [ { "name": "building_id", "required": true } ], - "/deployedbleeder/build": [ + "/capitol/build": [ { "name": "body_id", "required": true @@ -1577,19 +1550,19 @@ "required": true } ], - "/deployedbleeder/demolish": [ + "/capitol/demolish": [ { "name": "building_id", "required": true } ], - "/deployedbleeder/downgrade": [ + "/capitol/downgrade": [ { "name": "building_id", "required": true } ], - "/deployedbleeder/get_stats_for_level": [ + "/capitol/get_stats_for_level": [ { "name": "building_id", "required": true @@ -1599,25 +1572,46 @@ "required": true } ], - "/deployedbleeder/repair": [ + "/capitol/rename_empire": [ { "name": "building_id", "required": true + }, + { + "name": "name", + "required": true } ], - "/deployedbleeder/upgrade": [ + "/capitol/repair": [ { "name": "building_id", "required": true } ], - "/deployedbleeder/view": [ + "/capitol/upgrade": [ { "name": "building_id", "required": true } ], - "/development/build": [ + "/capitol/view": [ + { + "name": "building_id", + "required": true + } + ], + "/captcha/fetch": [], + "/captcha/solve": [ + { + "name": "guid", + "required": true + }, + { + "name": "solution", + "required": true + } + ], + "/cheese/build": [ { "name": "body_id", "required": true @@ -1631,19 +1625,19 @@ "required": true } ], - "/development/demolish": [ + "/cheese/demolish": [ { "name": "building_id", "required": true } ], - "/development/downgrade": [ + "/cheese/downgrade": [ { "name": "building_id", "required": true } ], - "/development/get_stats_for_level": [ + "/cheese/get_stats_for_level": [ { "name": "building_id", "required": true @@ -1653,31 +1647,25 @@ "required": true } ], - "/development/repair": [ - { - "name": "building_id", - "required": true - } - ], - "/development/subsidize_build_queue": [ + "/cheese/repair": [ { "name": "building_id", "required": true } ], - "/development/upgrade": [ + "/cheese/upgrade": [ { "name": "building_id", "required": true } ], - "/development/view": [ + "/cheese/view": [ { "name": "building_id", "required": true } ], - "/distributioncenter/build": [ + "/chip/build": [ { "name": "body_id", "required": true @@ -1691,19 +1679,19 @@ "required": true } ], - "/distributioncenter/demolish": [ + "/chip/demolish": [ { "name": "building_id", "required": true } ], - "/distributioncenter/downgrade": [ + "/chip/downgrade": [ { "name": "building_id", "required": true } ], - "/distributioncenter/get_stats_for_level": [ + "/chip/get_stats_for_level": [ { "name": "building_id", "required": true @@ -1713,173 +1701,159 @@ "required": true } ], - "/distributioncenter/get_stored_resources": [ + "/chip/repair": [ { "name": "building_id", "required": true } ], - "/distributioncenter/release_reserve": [ + "/chip/upgrade": [ { "name": "building_id", "required": true } ], - "/distributioncenter/repair": [ + "/chip/view": [ { "name": "building_id", "required": true } ], - "/distributioncenter/reserve": [ + "/cider/build": [ { - "name": "building_id", + "name": "body_id", "required": true }, { - "name": "resources", + "name": "x", + "required": true + }, + { + "name": "y", "required": true } ], - "/distributioncenter/upgrade": [ + "/cider/demolish": [ { "name": "building_id", "required": true } ], - "/distributioncenter/view": [ + "/cider/downgrade": [ { "name": "building_id", "required": true } ], - "/embassy/accept_invite": [ + "/cider/get_stats_for_level": [ { "name": "building_id", "required": true }, { - "name": "invite_id", + "name": "level", "required": true - }, - { - "name": "message", - "required": false } ], - "/embassy/build": [ - { - "name": "body_id", - "required": true - }, + "/cider/repair": [ { - "name": "x", + "name": "building_id", "required": true - }, + } + ], + "/cider/upgrade": [ { - "name": "y", + "name": "building_id", "required": true } ], - "/embassy/cast_vote": [ + "/cider/view": [ { "name": "building_id", "required": true - }, + } + ], + "/citadelofknope/build": [ { - "name": "proposition_id", + "name": "body_id", "required": true }, { - "name": "vote", - "required": true - } - ], - "/embassy/create_alliance": [ - { - "name": "building_id", + "name": "x", "required": true }, { - "name": "name", + "name": "y", "required": true } ], - "/embassy/demolish": [ + "/citadelofknope/demolish": [ { "name": "building_id", "required": true } ], - "/embassy/dissolve_alliance": [ + "/citadelofknope/downgrade": [ { "name": "building_id", "required": true } ], - "/embassy/donate_to_stash": [ + "/citadelofknope/get_stats_for_level": [ { "name": "building_id", "required": true }, { - "name": "donation", + "name": "level", "required": true } ], - "/embassy/downgrade": [ + "/citadelofknope/repair": [ { "name": "building_id", "required": true } ], - "/embassy/exchange_with_stash": [ + "/citadelofknope/upgrade": [ { "name": "building_id", "required": true - }, - { - "name": "donation", - "required": true - }, + } + ], + "/citadelofknope/view": [ { - "name": "request", + "name": "building_id", "required": true } ], - "/embassy/expel_member": [ + "/cloakinglab/build": [ { - "name": "building_id", + "name": "body_id", "required": true }, { - "name": "empire_id", + "name": "x", "required": true }, { - "name": "message", - "required": false - } - ], - "/embassy/get_alliance_status": [ - { - "name": "building_id", + "name": "y", "required": true } ], - "/embassy/get_my_invites": [ + "/cloakinglab/demolish": [ { "name": "building_id", "required": true } ], - "/embassy/get_pending_invites": [ + "/cloakinglab/downgrade": [ { "name": "building_id", "required": true } ], - "/embassy/get_stats_for_level": [ + "/cloakinglab/get_stats_for_level": [ { "name": "building_id", "required": true @@ -1889,247 +1863,187 @@ "required": true } ], - "/embassy/leave_alliance": [ + "/cloakinglab/repair": [ { "name": "building_id", "required": true - }, - { - "name": "message", - "required": false } ], - "/embassy/reject_invite": [ + "/cloakinglab/upgrade": [ { "name": "building_id", "required": true - }, - { - "name": "invite_id", - "required": true - }, - { - "name": "message", - "required": false - } - ], - "/embassy/repair": [ + } + ], + "/cloakinglab/view": [ { "name": "building_id", "required": true } ], - "/embassy/send_invite": [ + "/corn/build": [ { - "name": "building_id", + "name": "body_id", "required": true }, { - "name": "invitee_id", + "name": "x", "required": true }, { - "name": "message", - "required": false + "name": "y", + "required": true } ], - "/embassy/update_alliance": [ + "/corn/demolish": [ { "name": "building_id", "required": true - }, + } + ], + "/corn/downgrade": [ { - "name": "params", + "name": "building_id", "required": true } ], - "/embassy/upgrade": [ + "/corn/get_stats_for_level": [ { "name": "building_id", "required": true + }, + { + "name": "level", + "required": true } ], - "/embassy/view": [ + "/corn/repair": [ { "name": "building_id", "required": true } ], - "/embassy/view_propositions": [ + "/corn/upgrade": [ { "name": "building_id", "required": true } ], - "/embassy/view_stash": [ + "/corn/view": [ { "name": "building_id", "required": true } ], - "/embassy/withdraw_invite": [ + "/cornmeal/build": [ { - "name": "building_id", + "name": "body_id", "required": true }, { - "name": "invite_id", + "name": "x", "required": true }, { - "name": "message", - "required": false - } - ], - "/empire/boost_building": [ - { - "name": "weeks", - "required": false - } - ], - "/empire/boost_energy": [ - { - "name": "weeks", - "required": false - } - ], - "/empire/boost_food": [ - { - "name": "weeks", - "required": false + "name": "y", + "required": true } ], - "/empire/boost_happiness": [ + "/cornmeal/demolish": [ { - "name": "weeks", - "required": false + "name": "building_id", + "required": true } ], - "/empire/boost_ore": [ + "/cornmeal/downgrade": [ { - "name": "weeks", - "required": false + "name": "building_id", + "required": true } ], - "/empire/boost_spy_training": [ + "/cornmeal/get_stats_for_level": [ { - "name": "weeks", - "required": false - } - ], - "/empire/boost_storage": [ + "name": "building_id", + "required": true + }, { - "name": "weeks", - "required": false + "name": "level", + "required": true } ], - "/empire/boost_water": [ + "/cornmeal/repair": [ { - "name": "weeks", - "required": false + "name": "building_id", + "required": true } ], - "/empire/disable_self_destruct": [], - "/empire/edit_profile": [ + "/cornmeal/upgrade": [ { - "name": "profile", + "name": "building_id", "required": true } ], - "/empire/enable_self_destruct": [], - "/empire/fetch_captcha": [], - "/empire/find": [ + "/cornmeal/view": [ { - "name": "name", + "name": "building_id", "required": true } ], - "/empire/found": [ + "/crashedshipsite/build": [ { - "name": "empire_id", + "name": "body_id", "required": true }, { - "name": "api_key", + "name": "x", "required": true }, { - "name": "invite_code", - "required": false - } - ], - "/empire/get_species_templates": [], - "/empire/get_status": [], - "/empire/get_invite_friend_url": [], - "/empire/invite_friend": [ - { - "name": "email", + "name": "y", "required": true - }, - { - "name": "custom_message", - "required": false } ], - "/empire/is_name_available": [ + "/crashedshipsite/demolish": [ { - "name": "name", + "name": "building_id", "required": true } ], - "/empire/logout": [], - "/empire/redeem_essentia_code": [ + "/crashedshipsite/downgrade": [ { - "name": "code", + "name": "building_id", "required": true } ], - "/empire/redefine_species_limits": [], - "/empire/reset_password": [ - { - "name": "reset_key", - "required": true - }, - { - "name": "password1", - "required": true - }, + "/crashedshipsite/get_stats_for_level": [ { - "name": "password2", + "name": "building_id", "required": true }, { - "name": "api_key", + "name": "level", "required": true } ], - "/empire/set_status_message": [ + "/crashedshipsite/repair": [ { - "name": "message", + "name": "building_id", "required": true } ], - "/empire/update_species": [ - { - "name": "empire_id", - "required": true - }, + "/crashedshipsite/upgrade": [ { - "name": "params", + "name": "building_id", "required": true } ], - "/empire/view_authorized_sitters": [], - "/empire/view_boosts": [], - "/empire/view_profile": [], - "/empire/view_public_profile": [ + "/crashedshipsite/view": [ { - "name": "empire_id", + "name": "building_id", "required": true } ], - "/empire/view_species_stats": [], - "/energyreserve/build": [ + "/crater/build": [ { "name": "body_id", "required": true @@ -2143,57 +2057,53 @@ "required": true } ], - "/energyreserve/demolish": [ + "/crater/demolish": [ { "name": "building_id", "required": true } ], - "/energyreserve/downgrade": [ + "/crater/downgrade": [ { "name": "building_id", "required": true } ], - "/energyreserve/dump": [ + "/crater/get_stats_for_level": [ { "name": "building_id", "required": true }, { - "name": "amount", + "name": "level", "required": true } ], - "/energyreserve/get_stats_for_level": [ + "/crater/repair": [ { "name": "building_id", "required": true - }, - { - "name": "level", - "required": true } ], - "/energyreserve/repair": [ + "/crater/upgrade": [ { "name": "building_id", "required": true } ], - "/energyreserve/upgrade": [ + "/crater/view": [ { "name": "building_id", "required": true } ], - "/energyreserve/view": [ + "/culinaryinstitute/view": [ { "name": "building_id", "required": true } ], - "/entertainment/build": [ + "/dairy/build": [ { "name": "body_id", "required": true @@ -2207,31 +2117,19 @@ "required": true } ], - "/entertainment/demolish": [ - { - "name": "building_id", - "required": true - } - ], - "/entertainment/downgrade": [ - { - "name": "building_id", - "required": true - } - ], - "/entertainment/duck_quack": [ + "/dairy/demolish": [ { "name": "building_id", "required": true } ], - "/entertainment/get_lottery_voting_options": [ + "/dairy/downgrade": [ { "name": "building_id", "required": true } ], - "/entertainment/get_stats_for_level": [ + "/dairy/get_stats_for_level": [ { "name": "building_id", "required": true @@ -2241,25 +2139,25 @@ "required": true } ], - "/entertainment/repair": [ + "/dairy/repair": [ { "name": "building_id", "required": true } ], - "/entertainment/upgrade": [ + "/dairy/upgrade": [ { "name": "building_id", "required": true } ], - "/entertainment/view": [ + "/dairy/view": [ { "name": "building_id", "required": true } ], - "/espionage/build": [ + "/denton/build": [ { "name": "body_id", "required": true @@ -2273,19 +2171,19 @@ "required": true } ], - "/espionage/demolish": [ + "/denton/demolish": [ { "name": "building_id", "required": true } ], - "/espionage/downgrade": [ + "/denton/downgrade": [ { "name": "building_id", "required": true } ], - "/espionage/get_stats_for_level": [ + "/denton/get_stats_for_level": [ { "name": "building_id", "required": true @@ -2295,25 +2193,25 @@ "required": true } ], - "/espionage/repair": [ + "/denton/repair": [ { "name": "building_id", "required": true } ], - "/espionage/upgrade": [ + "/denton/upgrade": [ { "name": "building_id", "required": true } ], - "/espionage/view": [ + "/denton/view": [ { "name": "building_id", "required": true } ], - "/essentiavein/build": [ + "/dentonbrambles/build": [ { "name": "body_id", "required": true @@ -2327,29 +2225,1329 @@ "required": true } ], - "/essentiavein/demolish": [ + "/dentonbrambles/demolish": [ { "name": "building_id", "required": true } ], - "/essentiavein/downgrade": [ + "/dentonbrambles/downgrade": [ { "name": "building_id", "required": true } ], - "/essentiavein/drain": [ + "/dentonbrambles/get_stats_for_level": [ { "name": "building_id", "required": true }, { - "name": "times", - "required": false + "name": "level", + "required": true + } + ], + "/dentonbrambles/repair": [ + { + "name": "building_id", + "required": true + } + ], + "/dentonbrambles/upgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/dentonbrambles/view": [ + { + "name": "building_id", + "required": true + } + ], + "/deployedbleeder/build": [ + { + "name": "body_id", + "required": true + }, + { + "name": "x", + "required": true + }, + { + "name": "y", + "required": true + } + ], + "/deployedbleeder/demolish": [ + { + "name": "building_id", + "required": true + } + ], + "/deployedbleeder/downgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/deployedbleeder/get_stats_for_level": [ + { + "name": "building_id", + "required": true + }, + { + "name": "level", + "required": true + } + ], + "/deployedbleeder/repair": [ + { + "name": "building_id", + "required": true + } + ], + "/deployedbleeder/upgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/deployedbleeder/view": [ + { + "name": "building_id", + "required": true + } + ], + "/development/build": [ + { + "name": "body_id", + "required": true + }, + { + "name": "x", + "required": true + }, + { + "name": "y", + "required": true + } + ], + "/development/demolish": [ + { + "name": "building_id", + "required": true + } + ], + "/development/downgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/development/get_stats_for_level": [ + { + "name": "building_id", + "required": true + }, + { + "name": "level", + "required": true + } + ], + "/development/repair": [ + { + "name": "building_id", + "required": true + } + ], + "/development/subsidize_build_queue": [ + { + "name": "building_id", + "required": true + } + ], + "/development/upgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/development/view": [ + { + "name": "building_id", + "required": true + } + ], + "/distributioncenter/build": [ + { + "name": "body_id", + "required": true + }, + { + "name": "x", + "required": true + }, + { + "name": "y", + "required": true + } + ], + "/distributioncenter/demolish": [ + { + "name": "building_id", + "required": true + } + ], + "/distributioncenter/downgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/distributioncenter/get_stats_for_level": [ + { + "name": "building_id", + "required": true + }, + { + "name": "level", + "required": true + } + ], + "/distributioncenter/get_stored_resources": [ + { + "name": "building_id", + "required": true + } + ], + "/distributioncenter/release_reserve": [ + { + "name": "building_id", + "required": true + } + ], + "/distributioncenter/repair": [ + { + "name": "building_id", + "required": true + } + ], + "/distributioncenter/reserve": [ + { + "name": "building_id", + "required": true + }, + { + "name": "resources", + "required": true + } + ], + "/distributioncenter/upgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/distributioncenter/view": [ + { + "name": "building_id", + "required": true + } + ], + "/embassy/accept_invite": [ + { + "name": "building_id", + "required": true + }, + { + "name": "invite_id", + "required": true + }, + { + "name": "message", + "required": false + } + ], + "/embassy/assign_alliance_leader": [ + { + "name": "building_id", + "required": true + }, + { + "name": "new_leader_id", + "required": true + } + ], + "/embassy/build": [ + { + "name": "body_id", + "required": true + }, + { + "name": "x", + "required": true + }, + { + "name": "y", + "required": true + } + ], + "/embassy/cast_vote": [ + { + "name": "building_id", + "required": true + }, + { + "name": "proposition_id", + "required": true + }, + { + "name": "vote", + "required": true + } + ], + "/embassy/create_alliance": [ + { + "name": "building_id", + "required": true + }, + { + "name": "name", + "required": true + } + ], + "/embassy/demolish": [ + { + "name": "building_id", + "required": true + } + ], + "/embassy/dissolve_alliance": [ + { + "name": "building_id", + "required": true + } + ], + "/embassy/donate_to_stash": [ + { + "name": "building_id", + "required": true + }, + { + "name": "donation", + "required": true + } + ], + "/embassy/downgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/embassy/exchange_with_stash": [ + { + "name": "building_id", + "required": true + }, + { + "name": "donation", + "required": true + }, + { + "name": "request", + "required": true + } + ], + "/embassy/expel_member": [ + { + "name": "building_id", + "required": true + }, + { + "name": "empire_id", + "required": true + }, + { + "name": "message", + "required": false + } + ], + "/embassy/get_alliance_status": [ + { + "name": "building_id", + "required": true + } + ], + "/embassy/get_my_invites": [ + { + "name": "building_id", + "required": true + } + ], + "/embassy/get_pending_invites": [ + { + "name": "building_id", + "required": true + } + ], + "/embassy/get_stats_for_level": [ + { + "name": "building_id", + "required": true + }, + { + "name": "level", + "required": true + } + ], + "/embassy/leave_alliance": [ + { + "name": "building_id", + "required": true + }, + { + "name": "message", + "required": false + } + ], + "/embassy/reject_invite": [ + { + "name": "building_id", + "required": true + }, + { + "name": "invite_id", + "required": true + }, + { + "name": "message", + "required": false + } + ], + "/embassy/repair": [ + { + "name": "building_id", + "required": true + } + ], + "/embassy/send_invite": [ + { + "name": "building_id", + "required": true + }, + { + "name": "invitee_id", + "required": true + }, + { + "name": "message", + "required": false + } + ], + "/embassy/update_alliance": [ + { + "name": "building_id", + "required": true + }, + { + "name": "params", + "required": true + } + ], + "/embassy/upgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/embassy/view": [ + { + "name": "building_id", + "required": true + } + ], + "/embassy/view_propositions": [ + { + "name": "building_id", + "required": true + } + ], + "/embassy/view_stash": [ + { + "name": "building_id", + "required": true + } + ], + "/embassy/withdraw_invite": [ + { + "name": "building_id", + "required": true + }, + { + "name": "invite_id", + "required": true + }, + { + "name": "message", + "required": false + } + ], + "/empire/boost_building": [ + { + "name": "weeks", + "required": false + } + ], + "/empire/boost_energy": [ + { + "name": "weeks", + "required": false + } + ], + "/empire/boost_food": [ + { + "name": "weeks", + "required": false + } + ], + "/empire/boost_happiness": [ + { + "name": "weeks", + "required": false + } + ], + "/empire/boost_ore": [ + { + "name": "weeks", + "required": false + } + ], + "/empire/boost_spy_training": [ + { + "name": "weeks", + "required": false + } + ], + "/empire/boost_storage": [ + { + "name": "weeks", + "required": false + } + ], + "/empire/boost_water": [ + { + "name": "weeks", + "required": false + } + ], + "/empire/change_password": [ + { + "name": "password1", + "required": true + }, + { + "name": "password2", + "required": true + } + ], + "/empire/disable_self_destruct": [], + "/empire/edit_profile": [ + { + "name": "profile", + "required": true + } + ], + "/empire/enable_self_destruct": [], + "/empire/fetch_captcha": [], + "/empire/find": [ + { + "name": "name", + "required": true + } + ], + "/empire/found": [ + { + "name": "empire_id", + "required": true + }, + { + "name": "api_key", + "required": true + }, + { + "name": "invite_code", + "required": false + } + ], + "/empire/get_invite_friend_url": [], + "/empire/get_species_templates": [], + "/empire/get_status": [], + "/empire/invite_friend": [ + { + "name": "email", + "required": true + }, + { + "name": "custom_message", + "required": false + } + ], + "/empire/is_name_available": [ + { + "name": "name", + "required": true + } + ], + "/empire/logout": [], + "/empire/redeem_essentia_code": [ + { + "name": "code", + "required": true + } + ], + "/empire/redefine_species_limits": [], + "/empire/reset_password": [ + { + "name": "reset_key", + "required": true + }, + { + "name": "password1", + "required": true + }, + { + "name": "password2", + "required": true + }, + { + "name": "api_key", + "required": true + } + ], + "/empire/set_status_message": [ + { + "name": "message", + "required": true + } + ], + "/empire/update_species": [ + { + "name": "empire_id", + "required": true + }, + { + "name": "params", + "required": true + } + ], + "/empire/view_authorized_sitters": [], + "/empire/view_boosts": [], + "/empire/view_profile": [], + "/empire/view_public_profile": [ + { + "name": "empire_id", + "required": true + } + ], + "/empire/view_species_stats": [], + "/energyreserve/build": [ + { + "name": "body_id", + "required": true + }, + { + "name": "x", + "required": true + }, + { + "name": "y", + "required": true + } + ], + "/energyreserve/demolish": [ + { + "name": "building_id", + "required": true + } + ], + "/energyreserve/downgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/energyreserve/dump": [ + { + "name": "building_id", + "required": true + }, + { + "name": "amount", + "required": true + } + ], + "/energyreserve/get_stats_for_level": [ + { + "name": "building_id", + "required": true + }, + { + "name": "level", + "required": true + } + ], + "/energyreserve/repair": [ + { + "name": "building_id", + "required": true + } + ], + "/energyreserve/upgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/energyreserve/view": [ + { + "name": "building_id", + "required": true + } + ], + "/entertainment/build": [ + { + "name": "body_id", + "required": true + }, + { + "name": "x", + "required": true + }, + { + "name": "y", + "required": true + } + ], + "/entertainment/demolish": [ + { + "name": "building_id", + "required": true + } + ], + "/entertainment/downgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/entertainment/duck_quack": [ + { + "name": "building_id", + "required": true + } + ], + "/entertainment/get_lottery_voting_options": [ + { + "name": "building_id", + "required": true + } + ], + "/entertainment/get_stats_for_level": [ + { + "name": "building_id", + "required": true + }, + { + "name": "level", + "required": true + } + ], + "/entertainment/repair": [ + { + "name": "building_id", + "required": true + } + ], + "/entertainment/upgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/entertainment/view": [ + { + "name": "building_id", + "required": true + } + ], + "/espionage/build": [ + { + "name": "body_id", + "required": true + }, + { + "name": "x", + "required": true + }, + { + "name": "y", + "required": true + } + ], + "/espionage/demolish": [ + { + "name": "building_id", + "required": true + } + ], + "/espionage/downgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/espionage/get_stats_for_level": [ + { + "name": "building_id", + "required": true + }, + { + "name": "level", + "required": true + } + ], + "/espionage/repair": [ + { + "name": "building_id", + "required": true + } + ], + "/espionage/upgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/espionage/view": [ + { + "name": "building_id", + "required": true + } + ], + "/essentiavein/build": [ + { + "name": "body_id", + "required": true + }, + { + "name": "x", + "required": true + }, + { + "name": "y", + "required": true + } + ], + "/essentiavein/demolish": [ + { + "name": "building_id", + "required": true + } + ], + "/essentiavein/downgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/essentiavein/drain": [ + { + "name": "building_id", + "required": true + }, + { + "name": "times", + "required": false + } + ], + "/essentiavein/get_stats_for_level": [ + { + "name": "building_id", + "required": true + }, + { + "name": "level", + "required": true + } + ], + "/essentiavein/repair": [ + { + "name": "building_id", + "required": true + } + ], + "/essentiavein/upgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/essentiavein/view": [ + { + "name": "building_id", + "required": true + } + ], + "/fission/build": [ + { + "name": "body_id", + "required": true + }, + { + "name": "x", + "required": true + }, + { + "name": "y", + "required": true + } + ], + "/fission/demolish": [ + { + "name": "building_id", + "required": true + } + ], + "/fission/downgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/fission/get_stats_for_level": [ + { + "name": "building_id", + "required": true + }, + { + "name": "level", + "required": true + } + ], + "/fission/repair": [ + { + "name": "building_id", + "required": true + } + ], + "/fission/upgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/fission/view": [ + { + "name": "building_id", + "required": true + } + ], + "/fissure/build": [ + { + "name": "body_id", + "required": true + }, + { + "name": "x", + "required": true + }, + { + "name": "y", + "required": true + } + ], + "/fissure/demolish": [ + { + "name": "building_id", + "required": true + } + ], + "/fissure/downgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/fissure/get_stats_for_level": [ + { + "name": "building_id", + "required": true + }, + { + "name": "level", + "required": true + } + ], + "/fissure/repair": [ + { + "name": "building_id", + "required": true + } + ], + "/fissure/upgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/fissure/view": [ + { + "name": "building_id", + "required": true + } + ], + "/foodreserve/build": [ + { + "name": "body_id", + "required": true + }, + { + "name": "x", + "required": true + }, + { + "name": "y", + "required": true + } + ], + "/foodreserve/demolish": [ + { + "name": "building_id", + "required": true + } + ], + "/foodreserve/downgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/foodreserve/dump": [ + { + "name": "building_id", + "required": true + }, + { + "name": "type", + "required": true + }, + { + "name": "amount", + "required": true + } + ], + "/foodreserve/get_stats_for_level": [ + { + "name": "building_id", + "required": true + }, + { + "name": "level", + "required": true + } + ], + "/foodreserve/repair": [ + { + "name": "building_id", + "required": true + } + ], + "/foodreserve/upgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/foodreserve/view": [ + { + "name": "building_id", + "required": true + } + ], + "/fusion/build": [ + { + "name": "body_id", + "required": true + }, + { + "name": "x", + "required": true + }, + { + "name": "y", + "required": true + } + ], + "/fusion/demolish": [ + { + "name": "building_id", + "required": true + } + ], + "/fusion/downgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/fusion/get_stats_for_level": [ + { + "name": "building_id", + "required": true + }, + { + "name": "level", + "required": true + } + ], + "/fusion/repair": [ + { + "name": "building_id", + "required": true + } + ], + "/fusion/upgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/fusion/view": [ + { + "name": "building_id", + "required": true + } + ], + "/gasgiantlab/build": [ + { + "name": "body_id", + "required": true + }, + { + "name": "x", + "required": true + }, + { + "name": "y", + "required": true + } + ], + "/gasgiantlab/demolish": [ + { + "name": "building_id", + "required": true + } + ], + "/gasgiantlab/downgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/gasgiantlab/get_stats_for_level": [ + { + "name": "building_id", + "required": true + }, + { + "name": "level", + "required": true + } + ], + "/gasgiantlab/repair": [ + { + "name": "building_id", + "required": true + } + ], + "/gasgiantlab/upgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/gasgiantlab/view": [ + { + "name": "building_id", + "required": true + } + ], + "/gasgiantplatform/build": [ + { + "name": "body_id", + "required": true + }, + { + "name": "x", + "required": true + }, + { + "name": "y", + "required": true + } + ], + "/gasgiantplatform/demolish": [ + { + "name": "building_id", + "required": true + } + ], + "/gasgiantplatform/downgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/gasgiantplatform/get_stats_for_level": [ + { + "name": "building_id", + "required": true + }, + { + "name": "level", + "required": true + } + ], + "/gasgiantplatform/repair": [ + { + "name": "building_id", + "required": true + } + ], + "/gasgiantplatform/upgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/gasgiantplatform/view": [ + { + "name": "building_id", + "required": true + } + ], + "/geneticslab/build": [ + { + "name": "body_id", + "required": true + }, + { + "name": "x", + "required": true + }, + { + "name": "y", + "required": true + } + ], + "/geneticslab/demolish": [ + { + "name": "building_id", + "required": true + } + ], + "/geneticslab/downgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/geneticslab/get_stats_for_level": [ + { + "name": "building_id", + "required": true + }, + { + "name": "level", + "required": true + } + ], + "/geneticslab/prepare_experiment": [ + { + "name": "building_id", + "required": true + } + ], + "/geneticslab/rename_species": [ + { + "name": "building_id", + "required": true + }, + { + "name": "params", + "required": true + } + ], + "/geneticslab/repair": [ + { + "name": "building_id", + "required": true + } + ], + "/geneticslab/run_experiment": [ + { + "name": "building_id", + "required": true + }, + { + "name": "spy_id", + "required": true + }, + { + "name": "affinity", + "required": true + } + ], + "/geneticslab/upgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/geneticslab/view": [ + { + "name": "building_id", + "required": true + } + ], + "/geo/build": [ + { + "name": "body_id", + "required": true + }, + { + "name": "x", + "required": true + }, + { + "name": "y", + "required": true + } + ], + "/geo/demolish": [ + { + "name": "building_id", + "required": true + } + ], + "/geo/downgrade": [ + { + "name": "building_id", + "required": true } ], - "/essentiavein/get_stats_for_level": [ + "/geo/get_stats_for_level": [ { "name": "building_id", "required": true @@ -2359,25 +3557,25 @@ "required": true } ], - "/essentiavein/repair": [ + "/geo/repair": [ { "name": "building_id", "required": true } ], - "/essentiavein/upgrade": [ + "/geo/upgrade": [ { "name": "building_id", "required": true } ], - "/essentiavein/view": [ + "/geo/view": [ { "name": "building_id", "required": true } ], - "/fission/build": [ + "/geothermalvent/build": [ { "name": "body_id", "required": true @@ -2391,19 +3589,19 @@ "required": true } ], - "/fission/demolish": [ + "/geothermalvent/demolish": [ { "name": "building_id", "required": true } ], - "/fission/downgrade": [ + "/geothermalvent/downgrade": [ { "name": "building_id", "required": true } ], - "/fission/get_stats_for_level": [ + "/geothermalvent/get_stats_for_level": [ { "name": "building_id", "required": true @@ -2413,25 +3611,25 @@ "required": true } ], - "/fission/repair": [ + "/geothermalvent/repair": [ { "name": "building_id", "required": true } ], - "/fission/upgrade": [ + "/geothermalvent/upgrade": [ { "name": "building_id", "required": true } ], - "/fission/view": [ + "/geothermalvent/view": [ { "name": "building_id", "required": true } ], - "/fissure/build": [ + "/gratchsgauntlet/build": [ { "name": "body_id", "required": true @@ -2445,19 +3643,19 @@ "required": true } ], - "/fissure/demolish": [ + "/gratchsgauntlet/demolish": [ { "name": "building_id", "required": true } ], - "/fissure/downgrade": [ + "/gratchsgauntlet/downgrade": [ { "name": "building_id", "required": true } ], - "/fissure/get_stats_for_level": [ + "/gratchsgauntlet/get_stats_for_level": [ { "name": "building_id", "required": true @@ -2467,25 +3665,25 @@ "required": true } ], - "/fissure/repair": [ + "/gratchsgauntlet/repair": [ { "name": "building_id", "required": true } ], - "/fissure/upgrade": [ + "/gratchsgauntlet/upgrade": [ { "name": "building_id", "required": true } ], - "/fissure/view": [ + "/gratchsgauntlet/view": [ { "name": "building_id", "required": true } ], - "/foodreserve/build": [ + "/greatballofjunk/build": [ { "name": "body_id", "required": true @@ -2499,33 +3697,19 @@ "required": true } ], - "/foodreserve/demolish": [ - { - "name": "building_id", - "required": true - } - ], - "/foodreserve/downgrade": [ + "/greatballofjunk/demolish": [ { "name": "building_id", "required": true } ], - "/foodreserve/dump": [ + "/greatballofjunk/downgrade": [ { "name": "building_id", "required": true - }, - { - "name": "type", - "required": true - }, - { - "name": "amount", - "required": true } ], - "/foodreserve/get_stats_for_level": [ + "/greatballofjunk/get_stats_for_level": [ { "name": "building_id", "required": true @@ -2535,25 +3719,25 @@ "required": true } ], - "/foodreserve/repair": [ + "/greatballofjunk/repair": [ { "name": "building_id", "required": true } ], - "/foodreserve/upgrade": [ + "/greatballofjunk/upgrade": [ { "name": "building_id", "required": true } ], - "/foodreserve/view": [ + "/greatballofjunk/view": [ { "name": "building_id", "required": true } ], - "/fusion/build": [ + "/grove/build": [ { "name": "body_id", "required": true @@ -2567,19 +3751,19 @@ "required": true } ], - "/fusion/demolish": [ + "/grove/demolish": [ { "name": "building_id", "required": true } ], - "/fusion/downgrade": [ + "/grove/downgrade": [ { "name": "building_id", "required": true } ], - "/fusion/get_stats_for_level": [ + "/grove/get_stats_for_level": [ { "name": "building_id", "required": true @@ -2589,25 +3773,25 @@ "required": true } ], - "/fusion/repair": [ + "/grove/repair": [ { "name": "building_id", "required": true } ], - "/fusion/upgrade": [ + "/grove/upgrade": [ { "name": "building_id", "required": true } ], - "/fusion/view": [ + "/grove/view": [ { "name": "building_id", "required": true } ], - "/gasgiantlab/build": [ + "/hallsofvrbansk/build": [ { "name": "body_id", "required": true @@ -2621,19 +3805,19 @@ "required": true } ], - "/gasgiantlab/demolish": [ + "/hallsofvrbansk/demolish": [ { "name": "building_id", "required": true } ], - "/gasgiantlab/downgrade": [ + "/hallsofvrbansk/downgrade": [ { "name": "building_id", "required": true } ], - "/gasgiantlab/get_stats_for_level": [ + "/hallsofvrbansk/get_stats_for_level": [ { "name": "building_id", "required": true @@ -2643,25 +3827,25 @@ "required": true } ], - "/gasgiantlab/repair": [ + "/hallsofvrbansk/repair": [ { "name": "building_id", "required": true } ], - "/gasgiantlab/upgrade": [ + "/hallsofvrbansk/upgrade": [ { "name": "building_id", "required": true } ], - "/gasgiantlab/view": [ + "/hallsofvrbansk/view": [ { "name": "building_id", "required": true } ], - "/gasgiantplatform/build": [ + "/hydrocarbon/build": [ { "name": "body_id", "required": true @@ -2675,19 +3859,19 @@ "required": true } ], - "/gasgiantplatform/demolish": [ + "/hydrocarbon/demolish": [ { "name": "building_id", "required": true } ], - "/gasgiantplatform/downgrade": [ + "/hydrocarbon/downgrade": [ { "name": "building_id", "required": true } ], - "/gasgiantplatform/get_stats_for_level": [ + "/hydrocarbon/get_stats_for_level": [ { "name": "building_id", "required": true @@ -2697,83 +3881,125 @@ "required": true } ], - "/gasgiantplatform/repair": [ + "/hydrocarbon/repair": [ { "name": "building_id", "required": true } ], - "/gasgiantplatform/upgrade": [ + "/hydrocarbon/upgrade": [ { "name": "building_id", "required": true } ], - "/gasgiantplatform/view": [ + "/hydrocarbon/view": [ { "name": "building_id", "required": true } ], - "/geneticslab/build": [ + "/ibs/view": [ { - "name": "body_id", + "name": "building_id", + "required": true + } + ], + "/inbox/archive_messages": [ + { + "name": "message_ids", + "required": true + } + ], + "/inbox/read_message": [ + { + "name": "message_id", + "required": true + } + ], + "/inbox/send_message": [ + { + "name": "recipients", "required": true }, { - "name": "x", + "name": "subject", "required": true }, { - "name": "y", + "name": "body", "required": true + }, + { + "name": "options", + "required": false } ], - "/geneticslab/demolish": [ + "/inbox/trash_messages": [ { - "name": "building_id", + "name": "message_ids", "required": true } ], - "/geneticslab/downgrade": [ + "/inbox/view_archived": [ { - "name": "building_id", - "required": true + "name": "options", + "required": false } ], - "/geneticslab/get_stats_for_level": [ + "/inbox/view_inbox": [ { - "name": "building_id", - "required": true - }, + "name": "options", + "required": false + } + ], + "/inbox/view_sent": [ { - "name": "level", - "required": true + "name": "options", + "required": false } ], - "/geneticslab/prepare_experiment": [ + "/inbox/view_trashed": [ { - "name": "building_id", - "required": true + "name": "options", + "required": false } ], - "/geneticslab/rename_species": [ + "/inbox/view_unread": [ + { + "name": "options", + "required": false + } + ], + "/intelligence/assign_spy": [ { "name": "building_id", "required": true }, { - "name": "params", + "name": "spy_id", + "required": true + }, + { + "name": "assignment", "required": true } ], - "/geneticslab/repair": [ + "/intelligence/build": [ { - "name": "building_id", + "name": "body_id", + "required": true + }, + { + "name": "x", + "required": true + }, + { + "name": "y", "required": true } ], - "/geneticslab/run_experiment": [ + "/intelligence/burn_spy": [ { "name": "building_id", "required": true @@ -2781,79 +4007,95 @@ { "name": "spy_id", "required": true - }, + } + ], + "/intelligence/demolish": [ { - "name": "affinity", + "name": "building_id", "required": true } ], - "/geneticslab/upgrade": [ + "/intelligence/downgrade": [ { "name": "building_id", "required": true } ], - "/geneticslab/view": [ + "/intelligence/get_stats_for_level": [ { "name": "building_id", "required": true + }, + { + "name": "level", + "required": true } ], - "/geo/build": [ + "/intelligence/name_spy": [ { - "name": "body_id", + "name": "building_id", "required": true }, { - "name": "x", + "name": "spy_id", "required": true }, { - "name": "y", + "name": "name", "required": true } ], - "/geo/demolish": [ + "/intelligence/repair": [ { "name": "building_id", "required": true } ], - "/geo/downgrade": [ + "/intelligence/subsidize_training": [ { "name": "building_id", "required": true } ], - "/geo/get_stats_for_level": [ + "/intelligence/train_spy": [ { "name": "building_id", "required": true }, { - "name": "level", + "name": "quantity", + "required": false + } + ], + "/intelligence/upgrade": [ + { + "name": "building_id", "required": true } ], - "/geo/repair": [ + "/intelligence/view": [ { "name": "building_id", "required": true } ], - "/geo/upgrade": [ + "/intelligence/view_all_spies": [ { "name": "building_id", "required": true } ], - "/geo/view": [ + "/intelligence/view_spies": [ { "name": "building_id", "required": true + }, + { + "name": "page_number", + "required": false } ], - "/geothermalvent/build": [ + "/inteltraining/build": [ { "name": "body_id", "required": true @@ -2867,19 +4109,19 @@ "required": true } ], - "/geothermalvent/demolish": [ + "/inteltraining/demolish": [ { "name": "building_id", "required": true } ], - "/geothermalvent/downgrade": [ + "/inteltraining/downgrade": [ { "name": "building_id", "required": true } ], - "/geothermalvent/get_stats_for_level": [ + "/inteltraining/get_stats_for_level": [ { "name": "building_id", "required": true @@ -2889,25 +4131,25 @@ "required": true } ], - "/geothermalvent/repair": [ + "/inteltraining/repair": [ { "name": "building_id", "required": true } ], - "/geothermalvent/upgrade": [ + "/inteltraining/upgrade": [ { "name": "building_id", "required": true } ], - "/geothermalvent/view": [ + "/inteltraining/view": [ { "name": "building_id", "required": true } ], - "/gratchsgauntlet/build": [ + "/interdimensionalrift/build": [ { "name": "body_id", "required": true @@ -2921,19 +4163,19 @@ "required": true } ], - "/gratchsgauntlet/demolish": [ + "/interdimensionalrift/demolish": [ { "name": "building_id", "required": true } ], - "/gratchsgauntlet/downgrade": [ + "/interdimensionalrift/downgrade": [ { "name": "building_id", "required": true } ], - "/gratchsgauntlet/get_stats_for_level": [ + "/interdimensionalrift/get_stats_for_level": [ { "name": "building_id", "required": true @@ -2943,25 +4185,25 @@ "required": true } ], - "/gratchsgauntlet/repair": [ + "/interdimensionalrift/repair": [ { "name": "building_id", "required": true } ], - "/gratchsgauntlet/upgrade": [ + "/interdimensionalrift/upgrade": [ { "name": "building_id", "required": true } ], - "/gratchsgauntlet/view": [ + "/interdimensionalrift/view": [ { "name": "building_id", "required": true } ], - "/greatballofjunk/build": [ + "/junkhengesculpture/build": [ { "name": "body_id", "required": true @@ -2975,19 +4217,19 @@ "required": true } ], - "/greatballofjunk/demolish": [ + "/junkhengesculpture/demolish": [ { "name": "building_id", "required": true } ], - "/greatballofjunk/downgrade": [ + "/junkhengesculpture/downgrade": [ { "name": "building_id", "required": true } ], - "/greatballofjunk/get_stats_for_level": [ + "/junkhengesculpture/get_stats_for_level": [ { "name": "building_id", "required": true @@ -2997,25 +4239,25 @@ "required": true } ], - "/greatballofjunk/repair": [ + "/junkhengesculpture/repair": [ { "name": "building_id", "required": true } ], - "/greatballofjunk/upgrade": [ + "/junkhengesculpture/upgrade": [ { "name": "building_id", "required": true } ], - "/greatballofjunk/view": [ + "/junkhengesculpture/view": [ { "name": "building_id", "required": true } ], - "/grove/build": [ + "/kalavianruins/build": [ { "name": "body_id", "required": true @@ -3029,19 +4271,19 @@ "required": true } ], - "/grove/demolish": [ + "/kalavianruins/demolish": [ { "name": "building_id", "required": true } ], - "/grove/downgrade": [ + "/kalavianruins/downgrade": [ { "name": "building_id", "required": true } ], - "/grove/get_stats_for_level": [ + "/kalavianruins/get_stats_for_level": [ { "name": "building_id", "required": true @@ -3051,25 +4293,25 @@ "required": true } ], - "/grove/repair": [ + "/kalavianruins/repair": [ { "name": "building_id", "required": true } ], - "/grove/upgrade": [ + "/kalavianruins/upgrade": [ { "name": "building_id", "required": true } ], - "/grove/view": [ + "/kalavianruins/view": [ { "name": "building_id", "required": true } ], - "/hallsofvrbansk/build": [ + "/kasternskeep/build": [ { "name": "body_id", "required": true @@ -3083,19 +4325,19 @@ "required": true } ], - "/hallsofvrbansk/demolish": [ + "/kasternskeep/demolish": [ { "name": "building_id", "required": true } ], - "/hallsofvrbansk/downgrade": [ + "/kasternskeep/downgrade": [ { "name": "building_id", "required": true } ], - "/hallsofvrbansk/get_stats_for_level": [ + "/kasternskeep/get_stats_for_level": [ { "name": "building_id", "required": true @@ -3105,25 +4347,25 @@ "required": true } ], - "/hallsofvrbansk/repair": [ + "/kasternskeep/repair": [ { "name": "building_id", "required": true } ], - "/hallsofvrbansk/upgrade": [ + "/kasternskeep/upgrade": [ { "name": "building_id", "required": true } ], - "/hallsofvrbansk/view": [ + "/kasternskeep/view": [ { "name": "building_id", "required": true } ], - "/hydrocarbon/build": [ + "/lagoon/build": [ { "name": "body_id", "required": true @@ -3137,19 +4379,19 @@ "required": true } ], - "/hydrocarbon/demolish": [ + "/lagoon/demolish": [ { "name": "building_id", "required": true } ], - "/hydrocarbon/downgrade": [ + "/lagoon/downgrade": [ { "name": "building_id", "required": true } ], - "/hydrocarbon/get_stats_for_level": [ + "/lagoon/get_stats_for_level": [ { "name": "building_id", "required": true @@ -3159,111 +4401,79 @@ "required": true } ], - "/hydrocarbon/repair": [ - { - "name": "building_id", - "required": true - } - ], - "/hydrocarbon/upgrade": [ + "/lagoon/repair": [ { "name": "building_id", "required": true } ], - "/hydrocarbon/view": [ + "/lagoon/upgrade": [ { "name": "building_id", "required": true } ], - "/ibs/view": [ + "/lagoon/view": [ { "name": "building_id", "required": true } ], - "/inbox/archive_messages": [ - { - "name": "message_ids", - "required": true - } - ], - "/inbox/read_message": [ - { - "name": "message_id", - "required": true - } - ], - "/inbox/send_message": [ + "/lake/build": [ { - "name": "recipients", + "name": "body_id", "required": true }, { - "name": "subject", + "name": "x", "required": true }, { - "name": "body", + "name": "y", "required": true - }, - { - "name": "options", - "required": false } ], - "/inbox/trash_messages": [ + "/lake/demolish": [ { - "name": "message_ids", + "name": "building_id", "required": true } ], - "/inbox/view_inbox": [ + "/lake/downgrade": [ { - "name": "options", - "required": false + "name": "building_id", + "required": true } ], - "/inbox/view_archived": [ + "/lake/get_stats_for_level": [ { - "name": "options", - "required": false - } - ], - "/inbox/view_trashed": [ + "name": "building_id", + "required": true + }, { - "name": "options", - "required": false + "name": "level", + "required": true } ], - "/inbox/view_sent": [ + "/lake/repair": [ { - "name": "options", - "required": false + "name": "building_id", + "required": true } ], - "/inbox/view_unread": [ + "/lake/upgrade": [ { - "name": "options", - "required": false + "name": "building_id", + "required": true } ], - "/intelligence/assign_spy": [ + "/lake/view": [ { "name": "building_id", "required": true - }, - { - "name": "spy_id", - "required": true - }, - { - "name": "assignment", - "required": true } ], - "/intelligence/build": [ + "/lapis/build": [ { "name": "body_id", "required": true @@ -3277,19 +4487,19 @@ "required": true } ], - "/intelligence/demolish": [ + "/lapis/demolish": [ { "name": "building_id", "required": true } ], - "/intelligence/downgrade": [ + "/lapis/downgrade": [ { "name": "building_id", "required": true } ], - "/intelligence/get_stats_for_level": [ + "/lapis/get_stats_for_level": [ { "name": "building_id", "required": true @@ -3299,71 +4509,79 @@ "required": true } ], - "/intelligence/name_spy": [ + "/lapis/repair": [ + { + "name": "building_id", + "required": true + } + ], + "/lapis/upgrade": [ { "name": "building_id", "required": true + } + ], + "/lapis/view": [ + { + "name": "building_id", + "required": true + } + ], + "/lapisforest/build": [ + { + "name": "body_id", + "required": true }, { - "name": "spy_id", + "name": "x", "required": true }, { - "name": "name", + "name": "y", "required": true } ], - "/intelligence/repair": [ + "/lapisforest/demolish": [ { "name": "building_id", "required": true } ], - "/intelligence/subsidize_training": [ + "/lapisforest/downgrade": [ { "name": "building_id", "required": true } ], - "/intelligence/train_spy": [ + "/lapisforest/get_stats_for_level": [ { "name": "building_id", "required": true }, { - "name": "quantity", - "required": false - } - ], - "/intelligence/upgrade": [ - { - "name": "building_id", + "name": "level", "required": true } ], - "/intelligence/view": [ + "/lapisforest/repair": [ { "name": "building_id", "required": true } ], - "/intelligence/view_all_spies": [ + "/lapisforest/upgrade": [ { "name": "building_id", "required": true } ], - "/intelligence/view_spies": [ + "/lapisforest/view": [ { "name": "building_id", "required": true - }, - { - "name": "page_number", - "required": false } ], - "/inteltraining/build": [ + "/lcota/build": [ { "name": "body_id", "required": true @@ -3377,19 +4595,19 @@ "required": true } ], - "/inteltraining/demolish": [ + "/lcota/demolish": [ { "name": "building_id", "required": true } ], - "/inteltraining/downgrade": [ + "/lcota/downgrade": [ { "name": "building_id", "required": true } ], - "/inteltraining/get_stats_for_level": [ + "/lcota/get_stats_for_level": [ { "name": "building_id", "required": true @@ -3399,25 +4617,25 @@ "required": true } ], - "/inteltraining/repair": [ + "/lcota/repair": [ { "name": "building_id", "required": true } ], - "/inteltraining/upgrade": [ + "/lcota/upgrade": [ { "name": "building_id", "required": true } ], - "/inteltraining/view": [ + "/lcota/view": [ { "name": "building_id", "required": true } ], - "/interdimensionalrift/build": [ + "/lcotb/build": [ { "name": "body_id", "required": true @@ -3431,19 +4649,19 @@ "required": true } ], - "/interdimensionalrift/demolish": [ + "/lcotb/demolish": [ { "name": "building_id", "required": true } ], - "/interdimensionalrift/downgrade": [ + "/lcotb/downgrade": [ { "name": "building_id", "required": true } ], - "/interdimensionalrift/get_stats_for_level": [ + "/lcotb/get_stats_for_level": [ { "name": "building_id", "required": true @@ -3453,25 +4671,25 @@ "required": true } ], - "/interdimensionalrift/repair": [ + "/lcotb/repair": [ { "name": "building_id", "required": true } ], - "/interdimensionalrift/upgrade": [ + "/lcotb/upgrade": [ { "name": "building_id", "required": true } ], - "/interdimensionalrift/view": [ + "/lcotb/view": [ { "name": "building_id", "required": true } ], - "/junkhengesculpture/build": [ + "/lcotc/build": [ { "name": "body_id", "required": true @@ -3485,19 +4703,19 @@ "required": true } ], - "/junkhengesculpture/demolish": [ + "/lcotc/demolish": [ { "name": "building_id", "required": true } ], - "/junkhengesculpture/downgrade": [ + "/lcotc/downgrade": [ { "name": "building_id", "required": true } ], - "/junkhengesculpture/get_stats_for_level": [ + "/lcotc/get_stats_for_level": [ { "name": "building_id", "required": true @@ -3507,25 +4725,25 @@ "required": true } ], - "/junkhengesculpture/repair": [ + "/lcotc/repair": [ { "name": "building_id", "required": true } ], - "/junkhengesculpture/upgrade": [ + "/lcotc/upgrade": [ { "name": "building_id", "required": true } ], - "/junkhengesculpture/view": [ + "/lcotc/view": [ { "name": "building_id", "required": true } ], - "/kalavianruins/build": [ + "/lcotd/build": [ { "name": "body_id", "required": true @@ -3539,19 +4757,19 @@ "required": true } ], - "/kalavianruins/demolish": [ + "/lcotd/demolish": [ { "name": "building_id", "required": true } ], - "/kalavianruins/downgrade": [ + "/lcotd/downgrade": [ { "name": "building_id", "required": true } ], - "/kalavianruins/get_stats_for_level": [ + "/lcotd/get_stats_for_level": [ { "name": "building_id", "required": true @@ -3561,25 +4779,25 @@ "required": true } ], - "/kalavianruins/repair": [ + "/lcotd/repair": [ { "name": "building_id", "required": true } ], - "/kalavianruins/upgrade": [ + "/lcotd/upgrade": [ { "name": "building_id", "required": true } ], - "/kalavianruins/view": [ + "/lcotd/view": [ { "name": "building_id", "required": true } ], - "/kasternskeep/build": [ + "/lcote/build": [ { "name": "body_id", "required": true @@ -3593,19 +4811,19 @@ "required": true } ], - "/kasternskeep/demolish": [ + "/lcote/demolish": [ { "name": "building_id", "required": true } ], - "/kasternskeep/downgrade": [ + "/lcote/downgrade": [ { "name": "building_id", "required": true } ], - "/kasternskeep/get_stats_for_level": [ + "/lcote/get_stats_for_level": [ { "name": "building_id", "required": true @@ -3615,25 +4833,25 @@ "required": true } ], - "/kasternskeep/repair": [ + "/lcote/repair": [ { "name": "building_id", "required": true } ], - "/kasternskeep/upgrade": [ + "/lcote/upgrade": [ { "name": "building_id", "required": true } ], - "/kasternskeep/view": [ + "/lcote/view": [ { "name": "building_id", "required": true } ], - "/lagoon/build": [ + "/lcotf/build": [ { "name": "body_id", "required": true @@ -3647,19 +4865,19 @@ "required": true } ], - "/lagoon/demolish": [ + "/lcotf/demolish": [ { "name": "building_id", "required": true } ], - "/lagoon/downgrade": [ + "/lcotf/downgrade": [ { "name": "building_id", "required": true } ], - "/lagoon/get_stats_for_level": [ + "/lcotf/get_stats_for_level": [ { "name": "building_id", "required": true @@ -3669,25 +4887,25 @@ "required": true } ], - "/lagoon/repair": [ + "/lcotf/repair": [ { "name": "building_id", "required": true } ], - "/lagoon/upgrade": [ + "/lcotf/upgrade": [ { "name": "building_id", "required": true } ], - "/lagoon/view": [ + "/lcotf/view": [ { "name": "building_id", "required": true } ], - "/lake/build": [ + "/lcotg/build": [ { "name": "body_id", "required": true @@ -3701,19 +4919,19 @@ "required": true } ], - "/lake/demolish": [ + "/lcotg/demolish": [ { "name": "building_id", "required": true } ], - "/lake/downgrade": [ + "/lcotg/downgrade": [ { "name": "building_id", "required": true } ], - "/lake/get_stats_for_level": [ + "/lcotg/get_stats_for_level": [ { "name": "building_id", "required": true @@ -3723,25 +4941,25 @@ "required": true } ], - "/lake/repair": [ + "/lcotg/repair": [ { "name": "building_id", "required": true } ], - "/lake/upgrade": [ + "/lcotg/upgrade": [ { "name": "building_id", "required": true } ], - "/lake/view": [ + "/lcotg/view": [ { "name": "building_id", "required": true } ], - "/lapis/build": [ + "/lcoth/build": [ { "name": "body_id", "required": true @@ -3755,19 +4973,19 @@ "required": true } ], - "/lapis/demolish": [ + "/lcoth/demolish": [ { "name": "building_id", "required": true } ], - "/lapis/downgrade": [ + "/lcoth/downgrade": [ { "name": "building_id", "required": true } ], - "/lapis/get_stats_for_level": [ + "/lcoth/get_stats_for_level": [ { "name": "building_id", "required": true @@ -3777,25 +4995,25 @@ "required": true } ], - "/lapis/repair": [ + "/lcoth/repair": [ { "name": "building_id", "required": true } ], - "/lapis/upgrade": [ + "/lcoth/upgrade": [ { "name": "building_id", "required": true } ], - "/lapis/view": [ + "/lcoth/view": [ { "name": "building_id", "required": true } ], - "/lapisforest/build": [ + "/lcoti/build": [ { "name": "body_id", "required": true @@ -3809,19 +5027,19 @@ "required": true } ], - "/lapisforest/demolish": [ + "/lcoti/demolish": [ { "name": "building_id", "required": true } ], - "/lapisforest/downgrade": [ + "/lcoti/downgrade": [ { "name": "building_id", "required": true } ], - "/lapisforest/get_stats_for_level": [ + "/lcoti/get_stats_for_level": [ { "name": "building_id", "required": true @@ -3831,19 +5049,19 @@ "required": true } ], - "/lapisforest/repair": [ + "/lcoti/repair": [ { "name": "building_id", "required": true } ], - "/lapisforest/upgrade": [ + "/lcoti/upgrade": [ { "name": "building_id", "required": true } ], - "/lapisforest/view": [ + "/lcoti/view": [ { "name": "building_id", "required": true @@ -5357,6 +6575,20 @@ "required": true } ], + "/parliament/cast_vote": [ + { + "name": "building_id", + "required": true + }, + { + "name": "proposition_id", + "required": true + }, + { + "name": "vote", + "required": false + } + ], "/parliament/get_bodies_for_star_in_jurisdiction": [ { "name": "building_id", @@ -5597,6 +6829,12 @@ "required": true } ], + "/parliament/view_propositions": [ + { + "name": "building_id", + "required": true + } + ], "/parliament/view_taxes_collected": [ { "name": "building_id", @@ -5753,6 +6991,12 @@ "required": true } ], + "/planetarycommand/subsidize_pod_cooldown": [ + { + "name": "building_id", + "required": true + } + ], "/planetarycommand/upgrade": [ { "name": "building_id", @@ -6917,16 +8161,6 @@ "required": true } ], - "/spaceport/view_battle_logs": [ - { - "name": "building_id", - "required": true - }, - { - "name": "page_number", - "required": false - } - ], "/spaceport/view_all_ships": [ { "name": "building_id", @@ -6945,6 +8179,16 @@ "required": false } ], + "/spaceport/view_battle_logs": [ + { + "name": "building_id", + "required": true + }, + { + "name": "page_number", + "required": false + } + ], "/spaceport/view_foreign_ships": [ { "name": "building_id", @@ -6975,6 +8219,242 @@ "required": false } ], + "/ssla/build": [ + { + "name": "body_id", + "required": true + }, + { + "name": "x", + "required": true + }, + { + "name": "y", + "required": true + } + ], + "/ssla/demolish": [ + { + "name": "building_id", + "required": true + } + ], + "/ssla/downgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/ssla/get_stats_for_level": [ + { + "name": "building_id", + "required": true + }, + { + "name": "level", + "required": true + } + ], + "/ssla/make_plan": [ + { + "name": "building_id", + "required": true + }, + { + "name": "type", + "required": true + }, + { + "name": "level", + "required": true + } + ], + "/ssla/repair": [ + { + "name": "building_id", + "required": true + } + ], + "/ssla/subsidize_plan": [ + { + "name": "building_id", + "required": true + } + ], + "/ssla/upgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/ssla/view": [ + { + "name": "building_id", + "required": true + } + ], + "/sslb/build": [ + { + "name": "body_id", + "required": true + }, + { + "name": "x", + "required": true + }, + { + "name": "y", + "required": true + } + ], + "/sslb/demolish": [ + { + "name": "building_id", + "required": true + } + ], + "/sslb/downgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/sslb/get_stats_for_level": [ + { + "name": "building_id", + "required": true + }, + { + "name": "level", + "required": true + } + ], + "/sslb/repair": [ + { + "name": "building_id", + "required": true + } + ], + "/sslb/upgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/sslb/view": [ + { + "name": "building_id", + "required": true + } + ], + "/sslc/build": [ + { + "name": "body_id", + "required": true + }, + { + "name": "x", + "required": true + }, + { + "name": "y", + "required": true + } + ], + "/sslc/demolish": [ + { + "name": "building_id", + "required": true + } + ], + "/sslc/downgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/sslc/get_stats_for_level": [ + { + "name": "building_id", + "required": true + }, + { + "name": "level", + "required": true + } + ], + "/sslc/repair": [ + { + "name": "building_id", + "required": true + } + ], + "/sslc/upgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/sslc/view": [ + { + "name": "building_id", + "required": true + } + ], + "/ssld/build": [ + { + "name": "body_id", + "required": true + }, + { + "name": "x", + "required": true + }, + { + "name": "y", + "required": true + } + ], + "/ssld/demolish": [ + { + "name": "building_id", + "required": true + } + ], + "/ssld/downgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/ssld/get_stats_for_level": [ + { + "name": "building_id", + "required": true + }, + { + "name": "level", + "required": true + } + ], + "/ssld/repair": [ + { + "name": "building_id", + "required": true + } + ], + "/ssld/upgrade": [ + { + "name": "building_id", + "required": true + } + ], + "/ssld/view": [ + { + "name": "building_id", + "required": true + } + ], "/stationcommand/view": [ { "name": "building_id", diff --git a/package-lock.json b/package-lock.json index 1b85df9..40c4a3b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "morgan": "^1.10.1" }, "devDependencies": { + "@tlecommunity/api-spec": "^1.6.0", "@types/cors": "^2.8.19", "@types/express": "^5.0.3", "@types/morgan": "^1.9.10", @@ -25,6 +26,13 @@ "npm": ">= 10.0.0" } }, + "node_modules/@tlecommunity/api-spec": { + "version": "1.6.0", + "resolved": "https://gitea.allosaurus-chromatic.ts.net/api/packages/tlecommunity/npm/%40tlecommunity%2Fapi-spec/-/1.6.0/api-spec-1.6.0.tgz", + "integrity": "sha512-ga+QfcosH7Apv44LcCwHu7IRBrD2vvPsIX0y+jo7JixG/faeasEPa4ZFalKd38OgWTcK2dTTiEe+3OZDHpxSgA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/body-parser": { "version": "1.19.6", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", diff --git a/package.json b/package.json index 5cb9c7a..7ba6b5d 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "npm": ">= 10.0.0" }, "scripts": { + "test": "node --experimental-strip-types --test test/argument-map.test.ts", "format:check": "prettier --check .", "format:fix": "prettier --write ." }, @@ -20,6 +21,7 @@ "morgan": "^1.10.1" }, "devDependencies": { + "@tlecommunity/api-spec": "^1.6.0", "@types/cors": "^2.8.19", "@types/express": "^5.0.3", "@types/morgan": "^1.9.10", diff --git a/test/argument-map.test.ts b/test/argument-map.test.ts new file mode 100644 index 0000000..f265795 --- /dev/null +++ b/test/argument-map.test.ts @@ -0,0 +1,149 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import { createRequire } from 'node:module'; + +import argumentMap from '../argumentMap.json' with { type: 'json' }; + +// The spec is ~5MB; load it via require so tsc doesn't try to infer a type from it. +const require = createRequire(import.meta.url); + +type RequestBodySchema = { + properties?: Record; + required?: string[]; +}; + +type SpecDoc = { + paths: Record< + string, + { + post?: { + requestBody?: { + content?: Record; + }; + }; + } + >; +}; + +const spec = require('@tlecommunity/api-spec/build/spec.json') as SpecDoc; + +// Spec paths never need an argument map entry. Entries are `/module/method` refs +// (the spec path with the leading `/v2` stripped), e.g. `/empire/change_password`. +const EXEMPT_PATHS: string[] = []; + +type Argument = { name: string; required: boolean }; + +const positional = argumentMap.positional as Record; +const nofp = new Set(argumentMap.namedOnlyFirstPosition as string[]); +const noah = new Set(argumentMap.namedOnlyArgumentHash as string[]); +const mapKeys = new Set([...Object.keys(positional), ...nofp, ...noah]); + +type SpecEntry = { props: string[]; required: Set; hasBody: boolean }; + +// Build `/module/method` -> request-body shape, validating the spec's own layout as we go. +const specRefs = new Map(); +for (const [path, item] of Object.entries(spec.paths)) { + assert.ok(path.startsWith('/v2/'), `spec path ${path} does not start with /v2/`); + assert.ok(item.post, `spec path ${path} has no POST operation`); + + const ref = path.slice('/v2'.length); + const schema = item.post.requestBody?.content?.['application/json']?.schema; + specRefs.set(ref, { + props: schema?.properties ? Object.keys(schema.properties) : [], + required: new Set(schema?.required ?? []), + hasBody: schema !== undefined, + }); +} + +function assertClean(label: string, violations: string[]) { + assert.equal( + violations.length, + 0, + `${violations.length} ${label}:\n${violations.map((v) => ` - ${v}`).join('\n')}` + ); +} + +test('every argumentMap key exists in the spec', () => { + const violations: string[] = []; + for (const key of mapKeys) { + if (!specRefs.has(key)) violations.push(key); + } + assertClean('argumentMap keys missing from the spec', violations); +}); + +test('argumentMap sections are mutually exclusive', () => { + const violations: string[] = []; + for (const key of mapKeys) { + const sections = [ + key in positional ? 'positional' : null, + nofp.has(key) ? 'namedOnlyFirstPosition' : null, + noah.has(key) ? 'namedOnlyArgumentHash' : null, + ].filter(Boolean); + if (sections.length > 1) violations.push(`${key} in ${sections.join(' + ')}`); + } + assertClean('argumentMap keys in more than one section', violations); +}); + +test('every positional argument is a spec request-body property', () => { + const violations: string[] = []; + for (const [key, args] of Object.entries(positional)) { + const entry = specRefs.get(key); + if (!entry) continue; // covered by "every argumentMap key exists in the spec" + for (const arg of args) { + if (!entry.props.includes(arg.name)) violations.push(`${key} :: ${arg.name}`); + } + } + assertClean('positional arguments absent from the spec request body', violations); +}); + +test('positional required flags match the spec', () => { + const violations: string[] = []; + for (const [key, args] of Object.entries(positional)) { + const entry = specRefs.get(key); + if (!entry) continue; + for (const arg of args) { + if (!entry.props.includes(arg.name)) continue; // covered by the previous test + const specRequired = entry.required.has(arg.name); + if (arg.required !== specRequired) { + violations.push( + `${key} :: ${arg.name} (argumentMap required=${arg.required}, spec required=${specRequired})` + ); + } + } + } + assertClean('positional required flags disagreeing with the spec', violations); +}); + +test('every spec request-body property is covered by the positional map', () => { + const violations: string[] = []; + for (const [key, args] of Object.entries(positional)) { + const entry = specRefs.get(key); + if (!entry || !entry.hasBody) continue; + const argNames = new Set(args.map((a) => a.name)); + for (const prop of entry.props) { + if (!argNames.has(prop)) violations.push(`${key} :: ${prop}`); + } + } + assertClean('spec request-body properties missing from the positional map', violations); +}); + +test('every spec path is mapped or exempt', () => { + const exempt = new Set(EXEMPT_PATHS); + const violations: string[] = []; + for (const key of specRefs.keys()) { + if (!mapKeys.has(key) && !exempt.has(key)) violations.push(key); + } + assertClean( + 'spec paths with no argumentMap entry (add them to argumentMap.json or EXEMPT_PATHS)', + violations + ); +}); + +test('EXEMPT_PATHS entries are real, unmapped spec paths', () => { + const violations: string[] = []; + for (const key of EXEMPT_PATHS) { + if (!specRefs.has(key)) violations.push(`${key} (not a spec path)`); + else if (mapKeys.has(key)) violations.push(`${key} (also present in argumentMap)`); + } + assertClean('stale EXEMPT_PATHS entries', violations); +}); -- 2.51.2