diff --git a/.mailmap b/.mailmap new file mode 100644 index 0000000..9da582a --- /dev/null +++ b/.mailmap @@ -0,0 +1 @@ +Natalie Rose Natalie McCallum diff --git a/README.md b/README.md index 94759a5..462e02e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # API Spec -Open API specification for The Lacuna Expanse +Open API specification for TLE Community # License diff --git a/SPEC-CHANGES-1.4.0.md b/SPEC-CHANGES-1.4.0.md deleted file mode 100644 index a2f7360..0000000 --- a/SPEC-CHANGES-1.4.0.md +++ /dev/null @@ -1,190 +0,0 @@ -# api-spec changes for `@tlecommunity/client` regeneration — v1.3.4 → v1.4.0 - -**Audience:** whoever regenerates `@tlecommunity/client` from `@tlecommunity/api-spec` and then -deletes the now-redundant local types/casts in the `app` repo. - -**What happened:** a pass over `api-spec` to (1) normalize every ID field to a numeric type and -(2) close the still-open correctness gaps listed in `app/api-implementation-status.md` §2/§3 -(and two §1.6 residuals). The `§x.y` references below point at that document. - -**Source of truth:** `api-spec/src/spec/` (hand-authored). `src/spec.ts` `info.version` is now -`1.4.0`. Everything assembles (`node --experimental-strip-types` import of `src/spec.ts` succeeds, -all `$ref`s resolve, `npm start` renders). - -**Not committed** — the working tree holds the changes; commit/tag as normal. - ---- - -## 1. ID fields are now `integer` everywhere (the big one) - -Previously IDs were a mix: ~329 `{ type: 'string' }`, ~17 `{ type: 'number' }`, ~12 -`{ type: 'integer' }`. Every game `*_id` resolves an auto-increment integer PK in the server DB -(`Lacuna::DB::Result`). **All ID fields — request parameters and response fields alike — are now -`{ type: 'integer' }`.** - -This applies to: - -- Every property named `id` or ending in `_id` (`building_id`, `body_id`, `star_id`, - `empire_id`, `leader_id`, `from_id`, `to_id`, `trade_id`, `spy_id`, `prisoner_id`, - `mission_id`, `plan_id`, `law_id`, `proposition_id`, `platform_id`, `site_id`, - `scheduled_id`, `waste_chain_id`, `supply_chain_id`, …). -- Every ID array: `building_ids`, `message_ids`, `ship_ids`, `spy_ids`, and response arrays of - ids (`recipients`, inbox `success` / `failure` / `deleted`, spaceport `spies_sent` / - `spies_not_sent`). -- `in_reply_to` / `forward` (inbox — they carry a message id). -- `oneOf: [{string}, {array of string}]` id shapes → `oneOf: [{integer}, {array of integer}]` - (`development.cancel_build` `scheduled_id`, `shipyard` `building_id`). -- The `stats` nullable alliance id: `{ type: ['string','null'] }` → `{ type: ['integer','null'] }`. -- `components.ts` shared schemas: `body_status.{id,star_id,empire.id,station.id}` - (`number`→`integer`), `building.id` (`string`→`integer`). `empire_status` ids were already - `integer`. -- The reuse helpers in `src/spec/chunks.ts` (`buildingCommonMethods`, `buildingView`) — this is - why ~90 building path files changed with no per-file edit. - -### Effect on generated types - -`openapi-typescript` output for these fields flips from `string` to `number`. In the app that -means: - -- **Request params** — the app already sends `number` for most of these (README #1). Casts like - `message_id: messageId as number`, `util.int(star.id)` before `abandon_probe`, etc. become - unnecessary. -- **Response fields** — fields the app currently receives as `string` and coerces (`int(body.x)` - etc. on status ingest, `alliance.leader_id === String(...)` comparisons, `Prisoner.id`, - `GetProbedStarsResponse.stars[].id`, `GetAllianceStatusResponse` ids, `Observatory` star ids) - are now typed `number`. The app should stop stringifying / coercing and compare as numbers. - -### Exceptions — still `string` (intentionally) - -| Field | Why | -|---|---| -| `session_id` (login / found / reset_password) | UUID v4 auth token, not a DB key | -| `guid` / `captcha_guid` (captcha, empire/create) | 36-char UUID | -| `empire/authorize_sitters` + `deauthorize_sitters` `empires: string[]` | documented as "ids **and/or** names" | -| Object **keys** in id-keyed maps (`empire_status.colonies` / `planets` / `stations`, `buildings_list`, `buildings_resources_list`, medals, `map` `fissures`) | JSON object keys are always strings; described as "stringified integer" | - -### ⚠️ Wire-format caveat — verify before trusting the generator - -The legacy Perl JSON-RPC server frequently serialises integer ids **as JSON strings** (dualvar -scalars). The spec now describes **intent/DB semantics** (`integer`), which is also the direction -`util.fixNumbers` normalises toward. Before deleting the app's coercion helpers wholesale: - -1. Hit a live `/v2` response (e.g. `body/get_status`, `spaceport/view_all_ships`, - `embassy/get_alliance_status`) and check whether ids come back `123` or `"123"`. -2. If still stringified: keep the client's response pipeline running affected fields through - `util.fixNumbers` / `int()`, and treat the spec as the target the server should converge to. -3. Record the finding in `app/api-implementation-status.md` (it currently has no note on the - response side of README #1). - ---- - -## 2. Shared component schema changes (`src/spec/components.ts`) — these ripple widely - -| Schema | Change | Feedback | -|---|---|---| -| `server_status` | added `announcement: { integer, enum [1,0] }` (optional) | §2.2 — app can drop `ServerBlockWithAnnouncement` | -| `body_status` | added `zone: { string }` (optional) | §2.10 — unblocks `@ts-expect-error` on `body?.zone` in `bodyDetailsHeader` | -| **`planet_status`** | **new schema** — the full "own body" shape (a `body_status` + population / happiness / per-resource `*_stored` / `*_hour` / `*_capacity` + `zone`, `notes`, `neutral_entry`, `empire`, `num_incoming_own/ally/enemy`). Lifted from the old inline `stationcommand` `planetSchema`. | §1.6 — see §5 below | -| `building.work` | added `searching: { string }` (optional) — archaeology digs report it | §2.1 residual — `ArchaeologyViewResponse.building.work.searching` | -| `building.downgrade.reason` | `{ string }` → `{ type: 'array', items: {} }`, so it matches `building.upgrade.reason`. Both are now "a `[code, message]` pair; `[0, ""]` when no reason". | §3.6 / README #4 — app can type `reason` as `[number, string]` and drop the `any[]` absorbers | -| `empire_status` | `colonies` / `planets` → `{ type: 'object', additionalProperties: { string } }` (the baked-in `'467647'` sample key + its `required` are gone); `stations` → same shape instead of bare `{ type: 'object' }` | §3.15 — `schema.d.ts` `empire_status` stops being sample-value garbage | -| `buildings_list` entry | added `id: { integer }` (required) and the `repair_costs` block (`food/water/energy/ore`, optional) | §2.8 — `PlanetMapBuilding` no longer needs `id` / `repair_costs` spliced in | -| `buildings_resources_list` entry | added `id: { integer }` (required) | §2.8 — app can reuse `BuildingResourcesSummary` (+ `id`) | - -> Note on `id` in the two `buildings_*` list entries: the **old** captured server payload did NOT -> include `id` inside each row (it existed only as the map key). The spec now asserts the row -> carries `id` too. If the live server still omits it, the client wrapper should splice it from -> the key (as the app does today) rather than treat it as missing. - ---- - -## 3. Response fields added (were missing; forced `as unknown as` casts) - -| Endpoint(s) | Added | Feedback / unblocks | -|---|---|---| -| `security/view_prisoners` **and** `policestation/view_prisoners` | `captured_count: { integer }` (required) | §2.4 — `ViewPrisonersResponse` cast | -| `security/view_foreign_spies` **and** `policestation/view_foreign_spies` | `spy_count: { integer }` (required) | §2.5 — `ViewForeignSpiesResponse` cast | -| `trade/view_market` **and** `trade/view_my_market` | `trade_count: { integer }` (required) | §2.12 — `MarketResponse` cast | -| `map/get_star_map` star items | `zone: { string }`, `influence: { number }` (both required; `influence` may be null) | §2.6 — `StarMapStar` extension, `map.ts` `as unknown as` cast | -| `map` `starDetailSchema` (`get_stars` / `get_star*`) | `influence: { number }` (keeps it consistent with `get_star_map`; already had `zone`) | §2.6 | -| `parliament/get_stars_in_jurisdiction` star rows | `id: { integer }` | §2.7 — `JurisdictionStar` double cast | -| `spaceport` shared `shipSchema` | `combat: { integer }`, `max_occupants: { integer }`, `estimated_travel_time: { integer }`, `details: { payload: string[] }` | §2.9 — the 6+ `@ts-expect-error` in `shipItem.tsx` / `shipDetails.tsx`. **Verify against live `/v2`:** old captured traffic had a top-level `payload` array (not `details.payload`) — if the server still sends it top-level, the app should keep reading `ship.details?.payload ?? ship.payload`. | -| `embassy/view_stash` | `stored: { object, additionalProperties: integer }` (required) | §2.3 — `StashResponse` cast; `stash` was already tightened to `integer` values | -| `archaeology/view_excavators` `excavators[].body` | was bare `{ type: 'object' }`, now `{ id: integer, name, x, y, image }` | §2.11 residual | - ---- - -## 4. Type corrections (field existed, type was wrong) - -| Location | Was | Now | Feedback | -|---|---|---|---| -| `wasterecycling` + `wasteexchanger` `recycle.seconds_per_resource` | `string` | `integer` (block is shared by `view` / `recycle` / `subsidize_recycling`) | §3.2 — `RecycleStatus`, `util.int()` at every call site | -| `empire/create` response | `{ type: 'string' }` | `{ type: 'integer' }` ("The new empire id") | §3.1 — `EmpireCreateResponse` | -| `trade` market row (`view_market` / `view_my_market`) | `{ date, offer: tradeableItemSchema[] }` | `{ date_offered, offer: string[] }` — matches `transporter` / `mercenariesguild`. (`add_to_market` **request** still takes typed `tradeableItemSchema[]` — only the response row changed.) | §3.14 — `MarketTrade` | -| `planetarycommand/view_incoming_supply_chains` `supply_chains[].from_body` | `{ type: 'string' }` | object `{ id, name, x, y, image }` — now identical to `stationcommand`'s version | §3.8 — `IncomingSupplyChain` + `RawSupplyChain` + `toSupplyChain` reshape | -| `planetarycommand` + `stationcommand` `supply_chains[].percent_transferred` | `number` / `integer` (disagreed) | `number` in both | §3.8 | -| `intelligence` spy `assignment` and `possible_assignments[].task` | free `{ string }` | `{ string, enum: ASSIGNMENTS }` (the 26-value list already used by `assign_spy` params) | §3.13 — the hard-coded `ASSIGNMENT_TASKS` fallback in `app/queries/intelligence.ts` | -| `map/view_laws` law item | key misspelled `descripition` | `description` | typo fix | - ---- - -## 5. New / restructured schemas to consume - -- **`components.schemas.planet_status`** — used as `{ $ref }` by: - - `planetarycommand/view` `planet` (was a bare `{ type: 'object' }` — §1.6 residual; - unblocks `PlanetaryCommandViewResponse.planet`) - - `stationcommand/view` `planet` (previously an inline schema local to that file) - Both now point at the one shape. The app's `PlanetaryCommandViewResponse` / - `StationCommand` planet types collapse into it. -- **`components.schemas.server_overview`** — §1.7. The in-game "General"/Server stats tab is fed - by a static `server_overview.json` on the server, **not** a JSON-RPC method, so there is *no - path* for it — just this schema, so the client can export a `ServerOverview` type and the app - can delete its hand-written `ServerOverview*` model in `app/interfaces/stats.ts`. Shape mirrors - that interface (`bodies` / `buildings` / `empires` / `orbits` / `ships` / `spies` / `stars` / - `glyphs`, with the `types` / `orbits` / `glyphs.types` sub-maps as `additionalProperties`). -- **`embassy` `alliance_status`** — the `view` extra was a bare `{ type: 'object' }`; it now has - real properties (`id`, `name`, `members[].{empire_id,name}`, `leader_id`, `forum_uri`, - `description`, `announcements`, `date_created`), shared with the `get_alliance_status` response - via a local `allianceStatusProperties` const. §1.6 residual — unblocks `EmbassyViewResponse` / - `AllianceStatus` / `AllianceMember`. - ---- - -## 6. Deliberately NOT changed (so you don't wait for it) - -- The spec was already well ahead of `api-implementation-status.md` (which was written against - 1.2.0). Already present before this pass, nothing to do: the whole `blackHoleGenerator` - module (§1.1), `body/get_buildable` (§1.2), `body/abandon` · `rename` · `set_colony_notes` - (§1.3–1.5), per-building typed `view`s (§1.6 core), `building.work` block (§2.1), - `building_cost` optionality (§3.5), inbox `tags` as array (§3.11), `network19.restrict_coverage` - as `IntBool` (§3.3), observatory/embassy id primitive choice (§3.4/§3.7 — now unified to - `integer` by §1 here). -- Purely generated-client / app-codegen concerns with nothing to change in the hand-authored - spec: §3.9 (status-block numeric strings — see the wire-format caveat in §1), - §3.10 (`incoming_*_ships: any[]`), §3.11 (`MessageTag` needs a **named** export from the - client — inline enum in the OpenAPI output is unchanged), §3.16 (`SpyTrainingBuilding` - nesting — spec already matches the app's nested model; the divergence is in the convenience - type), `LacunaError` (§6 of the doc). -- The 5 module `view` files (`artmuseum`, `culinaryinstitute`, `ibs`, `operahouse`, - `warehouse`) and `stationcommand` still inline a partial `building` shape instead of - `$ref`-ing `components.schemas.building`. Only their `id` was fixed to `integer`. Converging - them is a later tidy-up. - ---- - -## 7. Suggested order of work on the client / app - -1. Regenerate `dist/lib/types/schema.d.ts` (`npm run generate:types`) from `api-spec` @ 1.4.0. -2. Do the live-payload id spot-check (§1 caveat). Decide whether `util.fixNumbers` stays in the - response pipeline for id/number-string fields. -3. Add the hand-written wrappers that are now backed by real shapes: typed `planet` on the two - command `view`s, `alliance_status`, `stored` on `viewStash`, `captured_count` / `spy_count` / - `trade_count` on the paginated views, `zone` / `influence` on star-map tiles, ship - `combat` / `max_occupants` / `details` / `estimated_travel_time`, `ServerOverview`. -4. Export a **named** `MessageTag` from the client (still a client-only task — the OpenAPI output - inlines the enum). -5. Delete the local types / casts in `app` that these unblock — the `§4` and `§5` tables in - `app/api-implementation-status.md` are the checklist; the "Feedback" column above maps each - spec change to its row(s). -6. Update `app/api-implementation-status.md` to mark the landed items and record the id - wire-format finding. diff --git a/package.json b/package.json index 3eb382e..e670c2f 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "@tlecommunity/api-spec", "type": "module", "version": "1.4.0", - "description": "Open API specification for The Lacuna Expanse", + "description": "Open API specification for TLE Community", "author": "Natalie Rose (https://nataliethistime.com)", "license": "MIT", "files": [ diff --git a/src/spec.ts b/src/spec.ts index 6697cec..005b297 100644 --- a/src/spec.ts +++ b/src/spec.ts @@ -8,7 +8,7 @@ export const spec = { title: 'TLE', version: '1.4.0', description: ` -Open API specification for The Lacuna Expanse. Note that this spec applies not to the original API +Open API specification for TLE Community. Note that this spec applies _not_ to the original API but a new layout of the api which is available on the \`/v2\` subpath of whatever server you are calling. For further context please see the [original API documentation](https://lacuna.allosaurus-chromatic.ts.net/api/).