From 520cac386dfe20a967f57cc5e47d693868ad58f0 Mon Sep 17 00:00:00 2001 From: Chew Date: Tue, 3 Feb 2026 20:59:35 -0600 Subject: [PATCH 1/2] initial openapi spec integration --- docs/.vitepress/theme/index.ts | 10 + docs/v2/achievements.md | 6 + docs/v2/profile.md | 84 ++ docs/v2/retroachievements.json | 2053 ++++++++++++++++++++++++++++++++ docs/v2/systems.md | 6 + package.json | 2 + pnpm-lock.yaml | 204 ++++ 7 files changed, 2365 insertions(+) create mode 100644 docs/v2/achievements.md create mode 100644 docs/v2/profile.md create mode 100644 docs/v2/retroachievements.json create mode 100644 docs/v2/systems.md diff --git a/docs/.vitepress/theme/index.ts b/docs/.vitepress/theme/index.ts index c86b19c..71b8aed 100644 --- a/docs/.vitepress/theme/index.ts +++ b/docs/.vitepress/theme/index.ts @@ -3,10 +3,20 @@ import "./styles.css"; import DefaultTheme from "vitepress/theme"; import type { Theme } from "vitepress"; import ConditionalCopyButtons from "./ConditionalCopyButtons.vue"; +import { theme, useOpenapi } from "vitepress-openapi/client"; +import "vitepress-openapi/dist/style.css"; + +import spec from "../../v2/retroachievements.json" with { type: "json" }; export default { extends: DefaultTheme, enhanceApp({ app }) { + useOpenapi({ + spec, + }); + + theme.enhanceApp({ app }); + app.component("CopyOrDownloadAsMarkdownButtons", ConditionalCopyButtons); }, } satisfies Theme; diff --git a/docs/v2/achievements.md b/docs/v2/achievements.md new file mode 100644 index 0000000..7d840ef --- /dev/null +++ b/docs/v2/achievements.md @@ -0,0 +1,6 @@ + + + diff --git a/docs/v2/profile.md b/docs/v2/profile.md new file mode 100644 index 0000000..351234f --- /dev/null +++ b/docs/v2/profile.md @@ -0,0 +1,84 @@ + + +# User Profile + +A call to this endpoint will retrieve user profile information, such as their ID, motto, most recent game ID, avatar, and points. + +[[toc]] + +## On-site Representation + +This information can be found near the top of [any user page](https://retroachievements.org/user/MaxMilyin): + +![User Profile](/user-profile.png) + +## HTTP Request + +https://retroachievements.org/api/v2/profile/MaxMilyin + +### Parameters + +You must query the user by either their username or their ULID. +Please note the username is not considered a stable value. As of 2025, users can change their usernames. Initially querying by username is a good way to fetch a ULID. + +| Name | Required? | Description | +| :--- | :-------- | :--------------------------- | +| `u` | Yes | The target username or ULID. | + +## Response + +::: code-group + +```json [HTTP Response] +{ + "User": "MaxMilyin", + "ULID": "00003EMFWR7XB8SDPEHB3K56ZQ", + "UserPic": "/UserPic/MaxMilyin.png", + "MemberSince": "2016-01-02 00:43:04", + "RichPresenceMsg": "Playing ~Hack~ 11th Annual Vanilla Level Design Contest, The", + "LastGameID": 19504, + "ContribCount": 0, + "ContribYield": 0, + "TotalPoints": 399597, + "TotalSoftcorePoints": 0, + "TotalTruePoints": 1599212, + "Permissions": 1, + "Untracked": 0, + "ID": 16446, + "UserWallActive": true, + "Motto": "Join me on Twitch! GameSquadSquad for live RA" +} +``` + +```json [NodeJS] +{ + "user": "MaxMilyin", + "ulid": "00003EMFWR7XB8SDPEHB3K56ZQ", + "userPic": "/UserPic/MaxMilyin.png", + "memberSince": "2016-01-02 00:43:04", + "richPresenceMsg": "Playing ~Hack~ 11th Annual Vanilla Level Design Contest, The", + "lastGameId": 19504, + "contribCount": 0, + "contribYield": 0, + "totalPoints": 399597, + "totalSoftcorePoints": 0, + "totalTruePoints": 1599212, + "permissions": 1, + "untracked": false, + "id": 16446, + "userWallActive": true, + "motto": "Join me on Twitch! GameSquadSquad for live RA" +} +``` + +::: + +## Source + +| Repo | URL | +| :--------- | :------------------------------------------------------------------------------------------------------------------- | +| RAWeb | https://github.com/RetroAchievements/RAWeb/blob/master/public/API/API_GetUserProfile.php | +| api-js | https://github.com/RetroAchievements/api-js/blob/main/src/user/getUserProfile.ts | +| api-kotlin | https://github.com/RetroAchievements/api-kotlin/blob/main/src/main/kotlin/org/retroachivements/api/RetroInterface.kt | diff --git a/docs/v2/retroachievements.json b/docs/v2/retroachievements.json new file mode 100644 index 0000000..ef27eee --- /dev/null +++ b/docs/v2/retroachievements.json @@ -0,0 +1,2053 @@ +{ + "openapi": "3.0.2", + "info": { + "title": "RetroAchievements", + "description": "JSON:API built using Laravel", + "version": "2.0" + }, + "servers": [ + { + "url": "https://api.retroachievements.org/v2", + "description": "Primary server" + } + ], + "paths": { + "/achievements": { + "get": { + "tags": ["Achievements"], + "summary": "Get all achievements", + "description": "", + "operationId": "achievements.index", + "parameters": [ + { + "name": "page[size]", + "in": "query", + "description": "The page size for paginated results", + "required": false, + "allowEmptyValue": false, + "schema": { + "type": "integer" + } + }, + { + "name": "page[number]", + "in": "query", + "description": "The page number for paginated results", + "required": false, + "allowEmptyValue": false, + "schema": { + "type": "integer" + } + }, + { + "name": "sort", + "in": "query", + "required": false, + "allowEmptyValue": false, + "schema": { + "type": "array", + "items": { + "enum": [ + "id", + "-id", + "title", + "-title", + "points", + "-points", + "pointsWeighted", + "-pointsWeighted", + "type", + "-type", + "orderColumn", + "-orderColumn", + "unlocksTotal", + "-unlocksTotal", + "unlocksHardcore", + "-unlocksHardcore", + "unlockPercentage", + "-unlockPercentage", + "unlockHardcorePercentage", + "-unlockHardcorePercentage" + ], + "type": "string" + } + } + }, + { + "name": "filter[id]", + "in": "query", + "description": "A list of ids to filter by.", + "required": false, + "allowEmptyValue": false, + "style": "form", + "explode": false, + "schema": { + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "examples": { + "empty": { + "value": [] + }, + "1": { + "value": ["1"] + }, + "2": { + "value": ["2"] + }, + "3": { + "value": ["3"] + } + } + }, + { + "name": "filter[state]", + "in": "query", + "description": "Applies the state scope.", + "required": false, + "allowEmptyValue": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "filter[gameId]", + "in": "query", + "description": "Applies the gameId scope.", + "required": false, + "allowEmptyValue": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "filter[type]", + "in": "query", + "description": "A list of types to filter by.", + "required": false, + "allowEmptyValue": false, + "style": "form", + "explode": false, + "schema": { + "default": { + "value": [] + }, + "type": "array", + "items": { + "type": "string" + } + }, + "examples": { + "progression": { + "value": "progression" + }, + "missable": { + "value": "missable" + } + } + } + ], + "responses": { + "200": { + "description": "Index achievements", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "required": ["jsonapi", "data"], + "properties": { + "jsonapi": { + "type": "object", + "properties": { + "version": { + "title": "version", + "type": "string", + "example": "1.0" + } + } + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/resources.achievements.resource.fetch" + } + } + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + } + } + } + }, + "/achievements/{achievement}": { + "get": { + "tags": ["Achievements"], + "summary": "Show one achievement", + "description": "", + "operationId": "achievements.show", + "parameters": [ + { + "name": "achievement", + "in": "path", + "required": true, + "allowEmptyValue": false, + "schema": { + "type": "string" + }, + "examples": { + "1": { + "value": "1" + }, + "2": { + "value": "2" + }, + "3": { + "value": "3" + } + } + } + ], + "responses": { + "200": { + "description": "Show achievements", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "required": ["jsonapi", "data"], + "properties": { + "jsonapi": { + "type": "object", + "properties": { + "version": { + "title": "version", + "type": "string", + "example": "1.0" + } + } + }, + "data": { + "$ref": "#/components/schemas/resources.achievements.resource.fetch" + } + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + } + } + } + }, + "/achievement-sets/{achievement_set}": { + "get": { + "tags": ["Achievement-sets"], + "summary": "Show one achievement-set", + "description": "", + "operationId": "achievement-sets.show", + "parameters": [ + { + "name": "achievement_set", + "in": "path", + "required": true, + "allowEmptyValue": false, + "schema": { + "type": "string" + }, + "examples": { + "1": { + "value": "1" + }, + "2": { + "value": "2" + }, + "3": { + "value": "3" + } + } + } + ], + "responses": { + "200": { + "description": "Show achievement-sets", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "required": ["jsonapi", "data"], + "properties": { + "jsonapi": { + "type": "object", + "properties": { + "version": { + "title": "version", + "type": "string", + "example": "1.0" + } + } + }, + "data": { + "$ref": "#/components/schemas/resources.achievement-sets.resource.fetch" + } + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + } + } + } + }, + "/games": { + "get": { + "tags": ["Games"], + "summary": "Get all games", + "description": "", + "operationId": "games.index", + "parameters": [ + { + "name": "page[size]", + "in": "query", + "description": "The page size for paginated results", + "required": false, + "allowEmptyValue": false, + "schema": { + "type": "integer" + } + }, + { + "name": "page[number]", + "in": "query", + "description": "The page number for paginated results", + "required": false, + "allowEmptyValue": false, + "schema": { + "type": "integer" + } + }, + { + "name": "sort", + "in": "query", + "required": false, + "allowEmptyValue": false, + "schema": { + "type": "array", + "items": { + "enum": [ + "id", + "-id", + "title", + "-title", + "sortTitle", + "-sortTitle", + "releasedAt", + "-releasedAt", + "playersTotal", + "-playersTotal", + "playersHardcore", + "-playersHardcore", + "achievementsPublished", + "-achievementsPublished", + "pointsTotal", + "-pointsTotal", + "pointsWeighted", + "-pointsWeighted" + ], + "type": "string" + } + } + }, + { + "name": "filter[id]", + "in": "query", + "description": "A list of ids to filter by.", + "required": false, + "allowEmptyValue": false, + "style": "form", + "explode": false, + "schema": { + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "examples": { + "empty": { + "value": [] + }, + "1": { + "value": ["1"] + }, + "2": { + "value": ["2"] + }, + "3": { + "value": ["3"] + } + } + }, + { + "name": "filter[systemId]", + "in": "query", + "description": "Filters the records", + "required": false, + "allowEmptyValue": false, + "schema": { + "default": "", + "type": "string" + }, + "examples": { + "1": { + "value": 1 + } + } + } + ], + "responses": { + "200": { + "description": "Index games", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "required": ["jsonapi", "data"], + "properties": { + "jsonapi": { + "type": "object", + "properties": { + "version": { + "title": "version", + "type": "string", + "example": "1.0" + } + } + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/resources.games.resource.fetch" + } + } + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + } + } + } + }, + "/games/{game}": { + "get": { + "tags": ["Games"], + "summary": "Show one game", + "description": "", + "operationId": "games.show", + "parameters": [ + { + "name": "game", + "in": "path", + "required": true, + "allowEmptyValue": false, + "schema": { + "type": "string" + }, + "examples": { + "1": { + "value": "1" + }, + "2": { + "value": "2" + }, + "3": { + "value": "3" + } + } + } + ], + "responses": { + "200": { + "description": "Show games", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "required": ["jsonapi", "data"], + "properties": { + "jsonapi": { + "type": "object", + "properties": { + "version": { + "title": "version", + "type": "string", + "example": "1.0" + } + } + }, + "data": { + "$ref": "#/components/schemas/resources.games.resource.fetch" + } + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + } + } + } + }, + "/leaderboards": { + "get": { + "tags": ["Leaderboards"], + "summary": "Get all leaderboards", + "description": "", + "operationId": "leaderboards.index", + "parameters": [ + { + "name": "page[size]", + "in": "query", + "description": "The page size for paginated results", + "required": false, + "allowEmptyValue": false, + "schema": { + "type": "integer" + } + }, + { + "name": "page[number]", + "in": "query", + "description": "The page number for paginated results", + "required": false, + "allowEmptyValue": false, + "schema": { + "type": "integer" + } + }, + { + "name": "sort", + "in": "query", + "required": false, + "allowEmptyValue": false, + "schema": { + "type": "array", + "items": { + "enum": [ + "id", + "-id", + "title", + "-title", + "orderColumn", + "-orderColumn", + "createdAt", + "-createdAt", + "updatedAt", + "-updatedAt" + ], + "type": "string" + } + } + }, + { + "name": "filter[id]", + "in": "query", + "description": "A list of ids to filter by.", + "required": false, + "allowEmptyValue": false, + "style": "form", + "explode": false, + "schema": { + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "examples": { + "empty": { + "value": [] + }, + "1": { + "value": ["1"] + }, + "2": { + "value": ["2"] + }, + "3": { + "value": ["3"] + } + } + }, + { + "name": "filter[gameId]", + "in": "query", + "description": "Filters the records", + "required": false, + "allowEmptyValue": false, + "schema": { + "default": "", + "type": "string" + }, + "examples": { + "1": { + "value": 1 + } + } + }, + { + "name": "filter[state]", + "in": "query", + "description": "Applies the state scope.", + "required": false, + "allowEmptyValue": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "Index leaderboards", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "required": ["jsonapi", "data"], + "properties": { + "jsonapi": { + "type": "object", + "properties": { + "version": { + "title": "version", + "type": "string", + "example": "1.0" + } + } + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/resources.leaderboards.resource.fetch" + } + } + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + } + } + } + }, + "/leaderboards/{leaderboard}": { + "get": { + "tags": ["Leaderboards"], + "summary": "Show one leaderboard", + "description": "", + "operationId": "leaderboards.show", + "parameters": [ + { + "name": "leaderboard", + "in": "path", + "required": true, + "allowEmptyValue": false, + "schema": { + "type": "string" + }, + "examples": { + "1": { + "value": "1" + }, + "2": { + "value": "2" + }, + "3": { + "value": "3" + } + } + } + ], + "responses": { + "200": { + "description": "Show leaderboards", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "required": ["jsonapi", "data"], + "properties": { + "jsonapi": { + "type": "object", + "properties": { + "version": { + "title": "version", + "type": "string", + "example": "1.0" + } + } + }, + "data": { + "$ref": "#/components/schemas/resources.leaderboards.resource.fetch" + } + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + } + } + } + }, + "/systems": { + "get": { + "tags": ["Systems"], + "summary": "Get All Systems", + "description": "Views a list of all systems on the site", + "operationId": "systems.index", + "parameters": [ + { + "name": "page[size]", + "in": "query", + "description": "The page size for paginated results", + "required": false, + "allowEmptyValue": false, + "schema": { + "type": "integer" + } + }, + { + "name": "page[number]", + "in": "query", + "description": "The page number for paginated results", + "required": false, + "allowEmptyValue": false, + "schema": { + "type": "integer" + } + }, + { + "name": "sort", + "in": "query", + "required": false, + "allowEmptyValue": false, + "schema": { + "type": "array", + "items": { + "enum": [ + "id", + "-id", + "name", + "-name", + "nameFull", + "-nameFull", + "nameShort", + "-nameShort" + ], + "type": "string" + } + } + }, + { + "name": "filter[id]", + "in": "query", + "description": "A list of ids to filter by.", + "required": false, + "allowEmptyValue": false, + "style": "form", + "explode": false, + "schema": { + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "examples": { + "empty": { + "value": [] + }, + "1": { + "value": ["1"] + }, + "2": { + "value": ["2"] + }, + "3": { + "value": ["3"] + } + } + }, + { + "name": "filter[active]", + "in": "query", + "description": "Filters the records", + "required": false, + "allowEmptyValue": false, + "schema": { + "default": "", + "type": "string" + }, + "examples": { + "1": { + "value": true + } + } + } + ], + "responses": { + "200": { + "description": "Index systems", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "required": ["jsonapi", "data"], + "properties": { + "jsonapi": { + "type": "object", + "properties": { + "version": { + "title": "version", + "type": "string", + "example": "1.0" + } + } + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/resources.systems.resource.fetch" + } + } + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + } + } + } + }, + "/systems/{system}": { + "get": { + "tags": ["Systems"], + "summary": "Show one system", + "description": "", + "operationId": "systems.show", + "parameters": [ + { + "name": "system", + "in": "path", + "required": true, + "allowEmptyValue": false, + "schema": { + "type": "string" + }, + "examples": { + "1": { + "value": "1" + }, + "2": { + "value": "2" + }, + "3": { + "value": "3" + } + } + } + ], + "responses": { + "200": { + "description": "Show systems", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "required": ["jsonapi", "data"], + "properties": { + "jsonapi": { + "type": "object", + "properties": { + "version": { + "title": "version", + "type": "string", + "example": "1.0" + } + } + }, + "data": { + "$ref": "#/components/schemas/resources.systems.resource.fetch" + } + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + } + } + } + }, + "/users": { + "get": { + "tags": ["Users"], + "summary": "Get all users", + "description": "", + "operationId": "users.index", + "parameters": [ + { + "name": "page[size]", + "in": "query", + "description": "The page size for paginated results", + "required": false, + "allowEmptyValue": false, + "schema": { + "type": "integer" + } + }, + { + "name": "page[number]", + "in": "query", + "description": "The page number for paginated results", + "required": false, + "allowEmptyValue": false, + "schema": { + "type": "integer" + } + }, + { + "name": "sort", + "in": "query", + "required": false, + "allowEmptyValue": false, + "schema": { + "type": "array", + "items": { + "enum": [ + "id", + "-id", + "points", + "-points", + "pointsHardcore", + "-pointsHardcore", + "pointsWeighted", + "-pointsWeighted", + "yieldUnlocks", + "-yieldUnlocks", + "yieldPoints", + "-yieldPoints", + "joinedAt", + "-joinedAt", + "lastActivityAt", + "-lastActivityAt" + ], + "type": "string" + } + } + }, + { + "name": "filter[role]", + "in": "query", + "description": "Applies the role scope.", + "required": false, + "allowEmptyValue": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "Index users", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "required": ["jsonapi", "data"], + "properties": { + "jsonapi": { + "type": "object", + "properties": { + "version": { + "title": "version", + "type": "string", + "example": "1.0" + } + } + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/resources.users.resource.fetch" + } + } + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + } + } + } + }, + "/users/{user}": { + "get": { + "tags": ["Users"], + "summary": "Show one user", + "description": "", + "operationId": "users.show", + "parameters": [ + { + "name": "user", + "in": "path", + "required": true, + "allowEmptyValue": false, + "schema": { + "type": "string" + }, + "examples": { + "01K4Y87MWZ3Q9WC9EFFT6JKSNP": { + "value": "01K4Y87MWZ3Q9WC9EFFT6JKSNP" + }, + "01K4Y87VCKZ0HCW9M95BPVZ2T8": { + "value": "01K4Y87VCKZ0HCW9M95BPVZ2T8" + }, + "01K4Y87BXTWJWX795ZTVS0FQBF": { + "value": "01K4Y87BXTWJWX795ZTVS0FQBF" + } + } + } + ], + "responses": { + "200": { + "description": "Show users", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "required": ["jsonapi", "data"], + "properties": { + "jsonapi": { + "type": "object", + "properties": { + "version": { + "title": "version", + "type": "string", + "example": "1.0" + } + } + }, + "data": { + "$ref": "#/components/schemas/resources.users.resource.fetch" + } + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + } + } + } + } + }, + "components": { + "schemas": { + "helper.errors": { + "title": "Helper/Errors", + "type": "array", + "items": { + "title": "Error", + "type": "object", + "required": ["status", "title"], + "properties": { + "detail": { + "type": "string" + }, + "status": { + "type": "string" + }, + "title": { + "type": "string" + }, + "source": { + "type": "object", + "properties": { + "pointer": { + "type": "string" + } + } + } + } + } + }, + "helper.jsonapi": { + "title": "Helper/JSONAPI", + "type": "object", + "required": ["version"], + "properties": { + "version": { + "title": "version", + "type": "string", + "example": "1.0" + } + } + }, + "resources.achievement-sets.resource.fetch": { + "title": "Resource/Achievement-set/Fetch", + "type": "object", + "required": ["type", "id", "attributes"], + "properties": { + "type": { + "title": "type", + "default": "achievement-sets", + "type": "string" + }, + "id": { + "type": "string", + "example": "1" + }, + "attributes": { + "type": "object", + "properties": { + "title": { + "title": "title", + "type": "string", + "readOnly": true, + "example": "Quia Impedit Libero Quam" + }, + "pointsTotal": { + "title": "pointsTotal", + "type": "number", + "readOnly": true, + "example": 189 + }, + "pointsWeighted": { + "title": "pointsWeighted", + "type": "number", + "readOnly": true, + "example": 341 + }, + "achievementsPublished": { + "title": "achievementsPublished", + "type": "number", + "readOnly": true, + "example": 20 + }, + "achievementsUnpublished": { + "title": "achievementsUnpublished", + "type": "number", + "readOnly": true, + "example": 0 + }, + "badgeUrl": { + "title": "badgeUrl", + "type": "string", + "readOnly": true + }, + "achievementsFirstPublishedAt": { + "title": "achievementsFirstPublishedAt", + "type": "string", + "readOnly": true, + "example": "2025-09-03T07:20:03.000000Z" + }, + "types": { + "title": "types", + "type": "array", + "readOnly": true + }, + "createdAt": { + "title": "createdAt", + "type": "string", + "readOnly": true, + "example": "2025-09-12T06:01:58.000000Z" + }, + "updatedAt": { + "title": "updatedAt", + "type": "string", + "readOnly": true, + "example": "2026-01-09T02:06:22.000000Z" + } + } + }, + "relationships": { + "type": "object", + "properties": { + "games": { + "title": "games", + "type": "object", + "properties": { + "links": { + "type": "object", + "properties": { + "related": { + "title": "related", + "type": "string", + "example": "https://retroachievements.org/api/v2/games/1" + }, + "self": { + "title": "self", + "type": "string", + "example": "https://retroachievements.org/api/v2/games/1" + } + }, + "readOnly": true + } + } + } + } + } + } + }, + "resources.achievements.resource.fetch": { + "title": "Resource/Achievement/Fetch", + "type": "object", + "required": ["type", "id", "attributes"], + "properties": { + "type": { + "title": "type", + "default": "achievements", + "type": "string" + }, + "id": { + "type": "string", + "example": "1" + }, + "attributes": { + "type": "object", + "properties": { + "title": { + "title": "title", + "type": "string", + "readOnly": true, + "example": "Soluta Quasi!" + }, + "description": { + "title": "description", + "type": "string", + "readOnly": true, + "example": "Nisi et sit labore reprehenderit aliquam aspernatur explicabo. True." + }, + "points": { + "title": "points", + "type": "number", + "readOnly": true, + "example": 1 + }, + "pointsWeighted": { + "title": "pointsWeighted", + "type": "number", + "readOnly": true, + "example": 1 + }, + "badgeUrl": { + "title": "badgeUrl", + "type": "string", + "readOnly": true, + "example": "https://retroachievements.org/media/Badge/00001.png" + }, + "badgeLockedUrl": { + "title": "badgeLockedUrl", + "type": "string", + "readOnly": true, + "example": "https://retroachievements.org/media/Badge/00001_lock.png" + }, + "type": { + "title": "type", + "type": "string", + "readOnly": true + }, + "state": { + "title": "state", + "type": "string", + "readOnly": true + }, + "orderColumn": { + "title": "orderColumn", + "type": "number", + "readOnly": true, + "example": 1 + }, + "unlocksTotal": { + "title": "unlocksTotal", + "type": "number", + "readOnly": true, + "example": 81 + }, + "unlocksHardcore": { + "title": "unlocksHardcore", + "type": "number", + "readOnly": true, + "example": 81 + }, + "unlockPercentage": { + "title": "unlockPercentage", + "type": "number", + "readOnly": true, + "example": 0.987804878 + }, + "unlockHardcorePercentage": { + "title": "unlockHardcorePercentage", + "type": "number", + "readOnly": true, + "example": 0.987804878 + }, + "createdAt": { + "title": "createdAt", + "type": "string", + "readOnly": true, + "example": "2025-09-12T06:01:58.000000Z" + }, + "modifiedAt": { + "title": "modifiedAt", + "type": "string", + "readOnly": true, + "example": "2025-09-12T06:01:58.000000Z" + } + } + }, + "relationships": { + "type": "object", + "properties": { + "developer": { + "title": "developer", + "type": "object", + "properties": { + "links": { + "type": "object", + "properties": { + "related": { + "title": "related", + "type": "string", + "example": "https://retroachievements.org/api/v2/developers/1" + }, + "self": { + "title": "self", + "type": "string", + "example": "https://retroachievements.org/api/v2/developers/1" + } + }, + "readOnly": true + } + } + }, + "achievementSet": { + "title": "achievementSet", + "type": "object", + "properties": { + "links": { + "type": "object", + "properties": { + "related": { + "title": "related", + "type": "string", + "example": "https://retroachievements.org/api/v2/achievement-sets/1" + }, + "self": { + "title": "self", + "type": "string", + "example": "https://retroachievements.org/api/v2/achievement-sets/1" + } + }, + "readOnly": true + } + } + }, + "games": { + "title": "games", + "type": "object", + "properties": { + "links": { + "type": "object", + "properties": { + "related": { + "title": "related", + "type": "string", + "example": "https://retroachievements.org/api/v2/games/1" + }, + "self": { + "title": "self", + "type": "string", + "example": "https://retroachievements.org/api/v2/games/1" + } + }, + "readOnly": true + } + } + } + } + } + } + }, + "resources.games.resource.fetch": { + "title": "Resource/Game/Fetch", + "type": "object", + "required": ["type", "id", "attributes"], + "properties": { + "type": { + "title": "type", + "default": "games", + "type": "string" + }, + "id": { + "type": "string", + "example": "1" + }, + "attributes": { + "type": "object", + "properties": { + "title": { + "title": "title", + "type": "string", + "example": "Quia Impedit Libero Quam" + }, + "sortTitle": { + "title": "sortTitle", + "type": "string", + "example": "quia impedit libero quam" + }, + "badgeUrl": { + "title": "badgeUrl", + "type": "string", + "readOnly": true, + "example": "https://retroachievements.org/media/Images/000002.png" + }, + "imageBoxArtUrl": { + "title": "imageBoxArtUrl", + "type": "string", + "readOnly": true, + "example": "https://retroachievements.org/media/Images/000002.png" + }, + "imageTitleUrl": { + "title": "imageTitleUrl", + "type": "string", + "readOnly": true, + "example": "https://retroachievements.org/media/Images/000002.png" + }, + "imageIngameUrl": { + "title": "imageIngameUrl", + "type": "string", + "readOnly": true, + "example": "https://retroachievements.org/media/Images/000002.png" + }, + "releasedAt": { + "title": "releasedAt", + "type": "string" + }, + "releasedAtGranularity": { + "title": "releasedAtGranularity", + "type": "string" + }, + "playersTotal": { + "title": "playersTotal", + "type": "number", + "example": 82 + }, + "playersHardcore": { + "title": "playersHardcore", + "type": "number", + "example": 82 + }, + "achievementsPublished": { + "title": "achievementsPublished", + "type": "number", + "example": 20 + }, + "achievementsUnpublished": { + "title": "achievementsUnpublished", + "type": "number", + "example": 0 + }, + "pointsTotal": { + "title": "pointsTotal", + "type": "number", + "example": 189 + }, + "pointsWeighted": { + "title": "pointsWeighted", + "type": "number", + "example": 341 + }, + "timesBeaten": { + "title": "timesBeaten", + "type": "number", + "example": 0 + }, + "timesBeatenHardcore": { + "title": "timesBeatenHardcore", + "type": "number", + "example": 1 + }, + "medianTimeToBeatMinutes": { + "title": "medianTimeToBeatMinutes", + "type": "number" + }, + "medianTimeToBeatHardcoreMinutes": { + "title": "medianTimeToBeatHardcoreMinutes", + "type": "number", + "example": 5153 + } + } + }, + "relationships": { + "type": "object", + "properties": { + "system": { + "title": "system", + "type": "object", + "properties": { + "links": { + "type": "object", + "properties": { + "related": { + "title": "related", + "type": "string", + "example": "https://retroachievements.org/api/v2/systems/1" + }, + "self": { + "title": "self", + "type": "string", + "example": "https://retroachievements.org/api/v2/systems/1" + } + }, + "readOnly": true + } + } + }, + "achievementSets": { + "title": "achievementSets", + "type": "object", + "properties": { + "links": { + "type": "object", + "properties": { + "related": { + "title": "related", + "type": "string", + "example": "https://retroachievements.org/api/v2/achievement-sets/1" + }, + "self": { + "title": "self", + "type": "string", + "example": "https://retroachievements.org/api/v2/achievement-sets/1" + } + }, + "readOnly": true + } + } + } + } + } + } + }, + "resources.leaderboards.resource.fetch": { + "title": "Resource/Leaderboard/Fetch", + "type": "object", + "required": ["type", "id", "attributes"], + "properties": { + "type": { + "title": "type", + "default": "leaderboards", + "type": "string" + }, + "id": { + "type": "string", + "example": "1" + }, + "attributes": { + "type": "object", + "properties": { + "title": { + "title": "title", + "type": "string", + "readOnly": true, + "example": "Totam Unde" + }, + "description": { + "title": "description", + "type": "string", + "readOnly": true, + "example": "Modi vitae commodi possimus animi." + }, + "format": { + "title": "format", + "type": "string", + "readOnly": true, + "example": "VALUE" + }, + "rankAsc": { + "title": "rankAsc", + "type": "boolean", + "readOnly": true, + "example": false + }, + "state": { + "title": "state", + "type": "string", + "readOnly": true, + "example": "active" + }, + "orderColumn": { + "title": "orderColumn", + "type": "number", + "readOnly": true, + "example": 64 + }, + "createdAt": { + "title": "createdAt", + "type": "string", + "readOnly": true, + "example": "2025-09-12T06:04:12.000000Z" + }, + "updatedAt": { + "title": "updatedAt", + "type": "string", + "readOnly": true, + "example": "2025-09-12T06:04:12.000000Z" + } + } + }, + "relationships": { + "type": "object", + "properties": { + "games": { + "title": "games", + "type": "object", + "properties": { + "links": { + "type": "object", + "properties": { + "related": { + "title": "related", + "type": "string", + "example": "https://retroachievements.org/api/v2/games/1" + }, + "self": { + "title": "self", + "type": "string", + "example": "https://retroachievements.org/api/v2/games/1" + } + }, + "readOnly": true + } + } + }, + "developer": { + "title": "developer", + "type": "object", + "properties": { + "links": { + "type": "object", + "properties": { + "related": { + "title": "related", + "type": "string", + "example": "https://retroachievements.org/api/v2/developers/1" + }, + "self": { + "title": "self", + "type": "string", + "example": "https://retroachievements.org/api/v2/developers/1" + } + }, + "readOnly": true + } + } + } + } + } + } + }, + "resources.systems.resource.fetch": { + "title": "Resource/System/Fetch", + "type": "object", + "required": ["type", "id", "attributes"], + "properties": { + "type": { + "title": "type", + "default": "systems", + "type": "string" + }, + "id": { + "type": "string", + "example": "1" + }, + "attributes": { + "type": "object", + "properties": { + "name": { + "title": "name", + "type": "string", + "example": "Genesis/Mega Drive" + }, + "nameFull": { + "title": "nameFull", + "type": "string", + "example": "Sega Genesis/Mega Drive" + }, + "nameShort": { + "title": "nameShort", + "type": "string", + "example": "MD" + }, + "manufacturer": { + "title": "manufacturer", + "type": "string", + "example": "Sega" + }, + "iconUrl": { + "title": "iconUrl", + "type": "string", + "readOnly": true, + "example": "https://retroachievements.org/assets/images/system/md.png" + }, + "active": { + "title": "active", + "type": "boolean", + "example": true + } + } + } + } + }, + "resources.users.resource.fetch": { + "title": "Resource/User/Fetch", + "type": "object", + "required": ["type", "id", "attributes"], + "properties": { + "type": { + "title": "type", + "default": "users", + "type": "string" + }, + "id": { + "type": "string", + "example": "01K4Y87MWZ3Q9WC9EFFT6JKSNP" + }, + "attributes": { + "type": "object", + "properties": { + "displayName": { + "title": "displayName", + "type": "string", + "readOnly": true, + "example": "claireboehm" + }, + "avatarUrl": { + "title": "avatarUrl", + "type": "string", + "readOnly": true, + "example": "https://retroachievements.org/media/UserPic/claireboehm.png" + }, + "motto": { + "title": "motto", + "type": "string", + "readOnly": true, + "example": "" + }, + "points": { + "title": "points", + "type": "number", + "readOnly": true, + "example": 1250 + }, + "pointsHardcore": { + "title": "pointsHardcore", + "type": "number", + "readOnly": true, + "example": 9019 + }, + "pointsWeighted": { + "title": "pointsWeighted", + "type": "number", + "readOnly": true, + "example": 19902 + }, + "yieldUnlocks": { + "title": "yieldUnlocks", + "type": "number", + "readOnly": true, + "example": 0 + }, + "yieldPoints": { + "title": "yieldPoints", + "type": "number", + "readOnly": true, + "example": 0 + }, + "joinedAt": { + "title": "joinedAt", + "type": "string", + "readOnly": true, + "example": "2025-09-12T06:01:51.000000Z" + }, + "lastActivityAt": { + "title": "lastActivityAt", + "type": "string", + "readOnly": true, + "example": "2025-09-12T06:24:12.000000Z" + }, + "deletedAt": { + "title": "deletedAt", + "type": "string", + "readOnly": true + }, + "isUnranked": { + "title": "isUnranked", + "type": "boolean", + "readOnly": true, + "example": false + }, + "isUserWallActive": { + "title": "isUserWallActive", + "type": "boolean", + "readOnly": true, + "example": true + }, + "richPresence": { + "title": "richPresence", + "type": "string", + "readOnly": true, + "example": "Playing Alias Et" + }, + "richPresenceUpdatedAt": { + "title": "richPresenceUpdatedAt", + "type": "string", + "readOnly": true, + "example": "2025-09-12T06:24:12.000000Z" + }, + "visibleRole": { + "title": "visibleRole", + "type": "string", + "readOnly": true + }, + "displayableRoles": { + "title": "displayableRoles", + "type": "array", + "readOnly": true + } + } + } + } + } + }, + "responses": { + "400": { + "description": "Bad request", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "properties": { + "helper.jsonapi": { + "$ref": "#/components/schemas/helper.jsonapi" + }, + "helper.errors": { + "$ref": "#/components/schemas/helper.errors" + } + } + }, + "examples": { + "-": { + "value": { + "jsonapi": { + "version": "1.0" + }, + "errors": [ + { + "detail": "The member id is required.", + "source": { + "pointer": "/data" + }, + "status": "400", + "title": "Non-Compliant JSON:API Document" + } + ] + } + } + } + } + } + }, + "401": { + "description": "Unauthorized Action", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "properties": { + "helper.jsonapi": { + "$ref": "#/components/schemas/helper.jsonapi" + }, + "helper.errors": { + "$ref": "#/components/schemas/helper.errors" + } + } + }, + "examples": { + "-": { + "value": { + "jsonapi": { + "version": "1.0" + }, + "errors": [ + { + "title": "Unauthorized.", + "status": "401", + "detail": "Unauthenticated." + } + ] + } + } + } + } + } + }, + "404": { + "description": "Content Not Found", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "properties": { + "helper.jsonapi": { + "$ref": "#/components/schemas/helper.jsonapi" + }, + "helper.errors": { + "$ref": "#/components/schemas/helper.errors" + } + } + }, + "examples": { + "-": { + "value": { + "jsonapi": { + "version": "1.0" + }, + "errors": [ + { + "title": "Not Found", + "status": "404" + } + ] + } + } + } + } + } + }, + "422": { + "description": "Unprocessable Entity", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "properties": { + "helper.jsonapi": { + "$ref": "#/components/schemas/helper.jsonapi" + }, + "helper.errors": { + "$ref": "#/components/schemas/helper.errors" + } + } + }, + "examples": { + "-": { + "value": { + "jsonapi": { + "version": "1.0" + }, + "errors": [ + { + "detail": "Lorem Ipsum", + "source": { + "pointer": "/data/attributes/lorem" + }, + "title": "Unprocessable Entity", + "status": "422" + } + ] + } + } + } + } + } + } + } + } +} diff --git a/docs/v2/systems.md b/docs/v2/systems.md new file mode 100644 index 0000000..a680df8 --- /dev/null +++ b/docs/v2/systems.md @@ -0,0 +1,6 @@ + + + diff --git a/package.json b/package.json index 2170c22..fe5102c 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "engines": { "node": ">=20" }, + "type": "module", "scripts": { "dev": "vitepress dev docs", "build": "vitepress build docs", @@ -17,6 +18,7 @@ "license": "MIT", "dependencies": { "vitepress": "^1.6.4", + "vitepress-openapi": "^0.1.13", "vitepress-plugin-llms": "^1.7.3", "vue": "3.5.18" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 50e3405..3ce06f3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,6 +11,9 @@ importers: vitepress: specifier: ^1.6.4 version: 1.6.4(@algolia/client-search@5.35.0)(postcss@8.4.38)(search-insights@2.14.0) + vitepress-openapi: + specifier: ^0.1.13 + version: 0.1.13(vitepress@1.6.4(@algolia/client-search@5.35.0)(postcss@8.4.38)(search-insights@2.14.0))(vue@3.5.18) vitepress-plugin-llms: specifier: ^1.7.3 version: 1.7.3 @@ -375,12 +378,30 @@ packages: cpu: [x64] os: [win32] + '@floating-ui/core@1.7.4': + resolution: {integrity: sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg==} + + '@floating-ui/dom@1.7.5': + resolution: {integrity: sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg==} + + '@floating-ui/utils@0.2.10': + resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + + '@floating-ui/vue@1.1.10': + resolution: {integrity: sha512-vdf8f6rHnFPPLRsmL4p12wYl+Ux4mOJOkjzKEMYVnwdf7UFdvBtHlLvQyx8iKG5vhPRbDRgZxdtpmyigDPjzYg==} + '@iconify-json/simple-icons@1.2.48': resolution: {integrity: sha512-EACOtZMoPJtERiAbX1De0asrrCtlwI27+03c9OJlYWsly9w1O5vcD8rTzh+kDPjo+K8FOVnq2Qy+h/CzljSKDA==} '@iconify/types@2.0.0': resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} + '@internationalized/date@3.10.1': + resolution: {integrity: sha512-oJrXtQiAXLvT9clCf1K4kxp3eKsQhIaZqxEyowkBcsvZDdZkbWrVmnGknxs5flTD0VGsxrxKgBCZty1EzoiMzA==} + + '@internationalized/number@3.6.5': + resolution: {integrity: sha512-6hY4Kl4HPBvtfS62asS/R22JzNNy8vi/Ssev7x6EobfCp+9QIB2hKvI2EtbdJ0VSQacxVNtqhE/NmF/NZ0gm6g==} + '@isaacs/balanced-match@4.0.1': resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} engines: {node: 20 || >=22} @@ -554,6 +575,17 @@ packages: '@shikijs/vscode-textmate@10.0.2': resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} + '@swc/helpers@0.5.18': + resolution: {integrity: sha512-TXTnIcNJQEKwThMMqBXsZ4VGAza6bvN4pa41Rkqoio6QBKMvo+5lexeTMScGCIxtzgQJzElcvIltani+adC5PQ==} + + '@tanstack/virtual-core@3.13.18': + resolution: {integrity: sha512-Mx86Hqu1k39icq2Zusq+Ey2J6dDWTjDvEv43PJtRCoEYTLyfaPnxIQ6iy7YAOK0NV/qOEmZQ/uCufrppZxTgcg==} + + '@tanstack/vue-virtual@3.13.18': + resolution: {integrity: sha512-6pT8HdHtTU5Z+t906cGdCroUNA5wHjFXsNss9gwk7QAr1VNZtz9IQCs2Nhx0gABK48c+OocHl2As+TMg8+Hy4A==} + peerDependencies: + vue: ^2.7.0 || ^3.0.0 + '@types/debug@4.1.12': resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} @@ -635,6 +667,11 @@ packages: '@vueuse/core@12.8.2': resolution: {integrity: sha512-HbvCmZdzAu3VGi/pWYm5Ut+Kd9mn1ZHnn4L5G8kOQTPs/IwIAmJoBrmYk2ckLArgMXZj0AW3n5CAejLUO+PhdQ==} + '@vueuse/core@13.9.0': + resolution: {integrity: sha512-ts3regBQyURfCE2BcytLqzm8+MmLlo5Ln/KLoxDVcsZ2gzIwVNnQpQOL/UKV8alUqjSZOlpFZcRNsLRqj+OzyA==} + peerDependencies: + vue: ^3.5.0 + '@vueuse/integrations@12.8.2': resolution: {integrity: sha512-fbGYivgK5uBTRt7p5F3zy6VrETlV9RtZjBqd1/HxGdjdckBgBM4ugP8LHpjolqTj14TXTxSK1ZfgPbHYyGuH7g==} peerDependencies: @@ -679,9 +716,17 @@ packages: '@vueuse/metadata@12.8.2': resolution: {integrity: sha512-rAyLGEuoBJ/Il5AmFHiziCPdQzRt88VxR+Y/A/QhJ1EWtWqPBBAxTAFaSkviwEuOEZNtW8pvkPgoCZQ+HxqW1A==} + '@vueuse/metadata@13.9.0': + resolution: {integrity: sha512-1AFRvuiGphfF7yWixZa0KwjYH8ulyjDCC0aFgrGRz8+P4kvDFSdXLVfTk5xAN9wEuD1J6z4/myMoYbnHoX07zg==} + '@vueuse/shared@12.8.2': resolution: {integrity: sha512-dznP38YzxZoNloI0qpEfpkms8knDtaoQ6Y/sfS0L7Yki4zh40LFHEhur0odJC6xTHG5dxWVPiUWBXn+wCG2s5w==} + '@vueuse/shared@13.9.0': + resolution: {integrity: sha512-e89uuTLMh0U5cZ9iDpEI2senqPGfbPRTHM/0AaQkcxnpqjkZqDYP8rpfm7edOz8s+pOCOROEy1PIveSW8+fL5g==} + peerDependencies: + vue: ^3.5.0 + algoliasearch@5.35.0: resolution: {integrity: sha512-Y+moNhsqgLmvJdgTsO4GZNgsaDWv8AOGAaPeIeHKlDn/XunoAqYbA+XNpBd1dW8GOXAUDyxC9Rxc7AV4kpFcIg==} engines: {node: '>= 14.0.0'} @@ -722,6 +767,10 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + aria-hidden@1.2.6: + resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} + engines: {node: '>=10'} + autoprefixer@10.4.19: resolution: {integrity: sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==} engines: {node: ^10 || ^12 || >=14} @@ -790,6 +839,9 @@ packages: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} + class-variance-authority@0.7.1: + resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} + cli-cursor@4.0.0: resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -802,6 +854,10 @@ packages: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -875,6 +931,9 @@ packages: decode-named-character-reference@1.2.0: resolution: {integrity: sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==} + defu@6.1.4: + resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} @@ -1139,12 +1198,20 @@ packages: resolution: {integrity: sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==} engines: {node: 14 || >=16.14} + lucide-vue-next@0.503.0: + resolution: {integrity: sha512-3MrtHIBdh4dPCUZDLxQnvmQ17UzUnBYgezUSIo87Laais8hOz6qIPllp0iG/uS/UIzk7bJxyZRzoZTW/gLSr4A==} + peerDependencies: + vue: '>=3.0.1' + magic-string@0.30.17: resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} mark.js@8.11.1: resolution: {integrity: sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==} + markdown-it-link-attributes@4.0.1: + resolution: {integrity: sha512-pg5OK0jPLg62H4k7M9mRJLT61gUp9nvG0XveKYHMOOluASo9OEF13WlXrpAp2aj35LbedAy3QOCgQCw0tkLKAQ==} + markdown-it@14.1.0: resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==} hasBin: true @@ -1324,6 +1391,9 @@ packages: resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} engines: {node: '>= 6'} + ohash@2.0.11: + resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} + onetime@5.1.2: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} @@ -1634,6 +1704,11 @@ packages: regex@6.0.1: resolution: {integrity: sha512-uorlqlzAKjKQZ5P+kTJr3eeJGSVroLKoHmquUj4zHWuR+hEyNqlXsSKlYYF5F4NI6nl7tWCs0apKJ0lmfsXAPA==} + reka-ui@2.7.0: + resolution: {integrity: sha512-m+XmxQN2xtFzBP3OAdIafKq7C8OETo2fqfxcIIxYmNN2Ch3r5oAf6yEYCIJg5tL/yJU2mHqF70dCCekUkrAnXA==} + peerDependencies: + vue: '>= 3.2.0' + remark-frontmatter@5.0.0: resolution: {integrity: sha512-XTFYvNASMe5iPN0719nPrdItC9aU0ssC4v14mH1BCi1u0n1gAocqcujWUrByftZTbLhRtiKRyjYTSIOcr69UVQ==} @@ -1806,6 +1881,9 @@ packages: ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + uc.micro@2.1.0: resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} @@ -1876,6 +1954,12 @@ packages: terser: optional: true + vitepress-openapi@0.1.13: + resolution: {integrity: sha512-cu0d07Gn6NCtWCNWtNI91bM41OeLBX5wdKRSCxaC1wZv9RSBNZ35KKT9GW5+Eb0qDx0wBtGeXZ9fIGf5QT3xGA==} + peerDependencies: + vitepress: '>=1.0.0' + vue: ^3.0.0 + vitepress-plugin-llms@1.7.3: resolution: {integrity: sha512-XhTVbUrKwrzrwlRKd/zT2owvjwi5cdB21HgDRcHqp9PYK4Fy+mBYJUoTcLaJ5IKD1DDrJZMo0DuJeyC5RSDI9Q==} @@ -1891,6 +1975,17 @@ packages: postcss: optional: true + vue-demi@0.14.10: + resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} + engines: {node: '>=12'} + hasBin: true + peerDependencies: + '@vue/composition-api': ^1.0.0-rc.1 + vue: ^3.0.0-0 || ^2.6.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + vue@3.5.18: resolution: {integrity: sha512-7W4Y4ZbMiQ3SEo+m9lnoNpV9xG7QVMLa+/0RFwwiAVkeYoyGXqWE85jabU4pllJNUzqfLShJ5YLptewhCWUgNA==} peerDependencies: @@ -2230,12 +2325,40 @@ snapshots: '@esbuild/win32-x64@0.21.5': optional: true + '@floating-ui/core@1.7.4': + dependencies: + '@floating-ui/utils': 0.2.10 + + '@floating-ui/dom@1.7.5': + dependencies: + '@floating-ui/core': 1.7.4 + '@floating-ui/utils': 0.2.10 + + '@floating-ui/utils@0.2.10': {} + + '@floating-ui/vue@1.1.10(vue@3.5.18)': + dependencies: + '@floating-ui/dom': 1.7.5 + '@floating-ui/utils': 0.2.10 + vue-demi: 0.14.10(vue@3.5.18) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + '@iconify-json/simple-icons@1.2.48': dependencies: '@iconify/types': 2.0.0 '@iconify/types@2.0.0': {} + '@internationalized/date@3.10.1': + dependencies: + '@swc/helpers': 0.5.18 + + '@internationalized/number@3.6.5': + dependencies: + '@swc/helpers': 0.5.18 + '@isaacs/balanced-match@4.0.1': {} '@isaacs/brace-expansion@5.0.0': @@ -2385,6 +2508,17 @@ snapshots: '@shikijs/vscode-textmate@10.0.2': {} + '@swc/helpers@0.5.18': + dependencies: + tslib: 2.8.1 + + '@tanstack/virtual-core@3.13.18': {} + + '@tanstack/vue-virtual@3.13.18(vue@3.5.18)': + dependencies: + '@tanstack/virtual-core': 3.13.18 + vue: 3.5.18 + '@types/debug@4.1.12': dependencies: '@types/ms': 2.1.0 @@ -2502,6 +2636,13 @@ snapshots: transitivePeerDependencies: - typescript + '@vueuse/core@13.9.0(vue@3.5.18)': + dependencies: + '@types/web-bluetooth': 0.0.21 + '@vueuse/metadata': 13.9.0 + '@vueuse/shared': 13.9.0(vue@3.5.18) + vue: 3.5.18 + '@vueuse/integrations@12.8.2(focus-trap@7.6.5)': dependencies: '@vueuse/core': 12.8.2 @@ -2514,12 +2655,18 @@ snapshots: '@vueuse/metadata@12.8.2': {} + '@vueuse/metadata@13.9.0': {} + '@vueuse/shared@12.8.2': dependencies: vue: 3.5.18 transitivePeerDependencies: - typescript + '@vueuse/shared@13.9.0(vue@3.5.18)': + dependencies: + vue: 3.5.18 + algoliasearch@5.35.0: dependencies: '@algolia/abtesting': 1.1.0 @@ -2564,6 +2711,10 @@ snapshots: argparse@2.0.1: {} + aria-hidden@1.2.6: + dependencies: + tslib: 2.8.1 + autoprefixer@10.4.19(postcss@8.4.38): dependencies: browserslist: 4.23.0 @@ -2625,6 +2776,10 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + class-variance-authority@0.7.1: + dependencies: + clsx: 2.1.1 + cli-cursor@4.0.0: dependencies: restore-cursor: 4.0.0 @@ -2640,6 +2795,8 @@ snapshots: strip-ansi: 6.0.1 wrap-ansi: 7.0.0 + clsx@2.1.1: {} + color-convert@2.0.1: dependencies: color-name: 1.1.4 @@ -2692,6 +2849,8 @@ snapshots: dependencies: character-entities: 2.0.2 + defu@6.1.4: {} + dequal@2.0.3: {} devlop@1.1.0: @@ -2964,12 +3123,18 @@ snapshots: lru-cache@10.2.2: {} + lucide-vue-next@0.503.0(vue@3.5.18): + dependencies: + vue: 3.5.18 + magic-string@0.30.17: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 mark.js@8.11.1: {} + markdown-it-link-attributes@4.0.1: {} + markdown-it@14.1.0: dependencies: argparse: 2.0.1 @@ -3246,6 +3411,8 @@ snapshots: object-hash@3.0.0: {} + ohash@2.0.11: {} + onetime@5.1.2: dependencies: mimic-fn: 2.1.0 @@ -3548,6 +3715,23 @@ snapshots: dependencies: regex-utilities: 2.3.0 + reka-ui@2.7.0(vue@3.5.18): + dependencies: + '@floating-ui/dom': 1.7.5 + '@floating-ui/vue': 1.1.10(vue@3.5.18) + '@internationalized/date': 3.10.1 + '@internationalized/number': 3.6.5 + '@tanstack/vue-virtual': 3.13.18(vue@3.5.18) + '@vueuse/core': 12.8.2 + '@vueuse/shared': 12.8.2 + aria-hidden: 1.2.6 + defu: 6.1.4 + ohash: 2.0.11 + vue: 3.5.18 + transitivePeerDependencies: + - '@vue/composition-api' + - typescript + remark-frontmatter@5.0.0: dependencies: '@types/mdast': 4.0.4 @@ -3780,6 +3964,8 @@ snapshots: ts-interface-checker@0.1.13: {} + tslib@2.8.1: {} + uc.micro@2.1.0: {} unified@11.0.5: @@ -3847,6 +4033,20 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + vitepress-openapi@0.1.13(vitepress@1.6.4(@algolia/client-search@5.35.0)(postcss@8.4.38)(search-insights@2.14.0))(vue@3.5.18): + dependencies: + '@vueuse/core': 13.9.0(vue@3.5.18) + class-variance-authority: 0.7.1 + clsx: 2.1.1 + lucide-vue-next: 0.503.0(vue@3.5.18) + markdown-it-link-attributes: 4.0.1 + reka-ui: 2.7.0(vue@3.5.18) + vitepress: 1.6.4(@algolia/client-search@5.35.0)(postcss@8.4.38)(search-insights@2.14.0) + vue: 3.5.18 + transitivePeerDependencies: + - '@vue/composition-api' + - typescript + vitepress-plugin-llms@1.7.3: dependencies: byte-size: 9.0.1 @@ -3915,6 +4115,10 @@ snapshots: - typescript - universal-cookie + vue-demi@0.14.10(vue@3.5.18): + dependencies: + vue: 3.5.18 + vue@3.5.18: dependencies: '@vue/compiler-dom': 3.5.18 From 5b115bfc01a64b0287794299e8392f6634e22ba8 Mon Sep 17 00:00:00 2001 From: Chew Date: Tue, 3 Feb 2026 21:23:47 -0600 Subject: [PATCH 2/2] update spec, add sidebar --- docs/.vitepress/config.mts | 500 ++++++++-------- docs/v2/achievement.md | 6 + docs/v2/retroachievements.json | 1010 ++++++++++++++++++++++++++++++-- 3 files changed, 1238 insertions(+), 278 deletions(-) create mode 100644 docs/v2/achievement.md diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index 9a19f17..c77616c 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -1,6 +1,8 @@ import { defineConfig } from "vitepress"; import llmstxt from "vitepress-plugin-llms"; import { copyOrDownloadAsMarkdownButtons } from "vitepress-plugin-llms"; +import { useSidebar } from 'vitepress-openapi' +import spec from '../v2/retroachievements.json' with { type: "json" }; /** * Try your best not to have any sidebar page titles wrap to a 2nd line. @@ -47,243 +49,273 @@ export default defineConfig({ }, ], - nav: [{ text: "Quick Start", link: "/getting-started" }], + nav: [ + { text: "Quick Start", link: "/getting-started" }, + { text: "Version 1", link: "/v1" }, + { text: "Version 2", link: "/v2" }, + ], - sidebar: [ - { - text: "About", - link: "/", - }, - { - text: "Getting Started", - link: "/getting-started", - }, - { - text: "User", - collapsible: true, - items: [ - { - text: "Profile", - link: "/v1/get-user-profile", - }, - { - text: "Unlocks (most recent)", - link: "/v1/get-user-recent-achievements", - }, - { - text: "Unlocks (by date range)", - link: "/v1/get-achievements-earned-between", - }, - { - text: "Unlocks (on date)", - link: "/v1/get-achievements-earned-on-day", - }, - { - text: "Game Progress", - link: "/v1/get-game-info-and-user-progress", - }, - { - text: "All Completion Progress", - link: "/v1/get-user-completion-progress", - }, - { - text: "Awards / Badges", - link: "/v1/get-user-awards", - }, - { - text: "Set Development Claims", - link: "/v1/get-user-claims", - }, - { - text: "Game Rank and Score", - link: "/v1/get-user-game-rank-and-score", - }, - { - text: "Point Totals", - link: "/v1/get-user-points", - }, - { - text: "Specific Games Progress", - link: "/v1/get-user-progress", - }, - { - text: "Recently Played Games", - link: "/v1/get-user-recently-played-games", - }, - { - text: "Summary", - link: "/v1/get-user-summary", - }, - { - text: "Completed Games", - link: "/v1/get-user-completed-games", - }, - { - text: "Want to Play Games List", - link: "/v1/get-user-want-to-play-list", - }, - { - text: "Users I Follow", - link: "/v1/get-users-i-follow", - }, - { - text: "Users Following Me", - link: "/v1/get-users-following-me", - }, - { - text: "User Set Requests", - link: "/v1/get-user-set-requests", - }, - ], - }, - { - text: "Game", - collapsible: true, - items: [ - { - text: "Summary", - link: "/v1/get-game", - }, - { - text: "Extended Details", - link: "/v1/get-game-extended", - }, - { - text: "Hashes", - link: "/v1/get-game-hashes", - }, - { - text: "Achievement IDs", - link: "/v1/get-achievement-count", - }, - { - text: "Unlocks Distribution", - link: "/v1/get-achievement-distribution", - }, - { - text: "High Scores", - link: "/v1/get-game-rank-and-score", - }, - { - text: "Progression", - link: "/v1/get-game-progression", - }, - ], - }, - { - text: "Leaderboards", - collapsible: true, - items: [ - { - text: "Leaderboards (by gameID)", - link: "/v1/get-game-leaderboards", - }, - { - text: "Entries", - link: "/v1/get-leaderboard-entries", - }, - { - text: "User Leaderboards (by gameID)", - link: "/v1/get-user-game-leaderboards", - }, - ], - }, - { - text: "System", - collapsible: true, - items: [ - { - text: "All Systems", - link: "/v1/get-console-ids", - }, - { - text: "All Games and Hashes", - link: "/v1/get-game-list", - }, - ], - }, - { - text: "Achievement", - collapsible: true, - items: [ - { - text: "All Unlocks", - link: "/v1/get-achievement-unlocks", - }, + sidebar: { + '/': [ + { + text: "Home", + items: [ + { + text: "About", + link: "/", + }, + { + text: "Getting Started", + link: "/getting-started", + }, + ] + } ], - }, - { - text: "Comment", - collapsible: true, - items: [ - { - text: "Comments", - link: "/v1/get-comments", - }, - ], - }, - { - text: "Feed", - collapsible: true, - items: [ - { - text: "All Recent Game Awards", - link: "/v1/get-recent-game-awards", - }, - { - text: "Active Claims", - link: "/v1/get-active-claims", - }, - { - text: "Inactive Claims", - link: "/v1/get-claims", - }, - { - text: "Top Ten Ranked Users", - link: "/v1/get-top-ten-users", - }, - ], - }, - { - text: "Event", - items: [ - { - text: "Achievement of the Week", - link: "/v1/get-achievement-of-the-week", - }, + '/v1/': [ + { + text: 'v1', + items: [{ + text: "API v2", + link: "/v2" + }, + { + text: "User", + collapsible: true, + items: [ + { + text: "Profile", + link: "/v1/get-user-profile", + }, + { + text: "Unlocks (most recent)", + link: "/v1/get-user-recent-achievements", + }, + { + text: "Unlocks (by date range)", + link: "/v1/get-achievements-earned-between", + }, + { + text: "Unlocks (on date)", + link: "/v1/get-achievements-earned-on-day", + }, + { + text: "Game Progress", + link: "/v1/get-game-info-and-user-progress", + }, + { + text: "All Completion Progress", + link: "/v1/get-user-completion-progress", + }, + { + text: "Awards / Badges", + link: "/v1/get-user-awards", + }, + { + text: "Set Development Claims", + link: "/v1/get-user-claims", + }, + { + text: "Game Rank and Score", + link: "/v1/get-user-game-rank-and-score", + }, + { + text: "Point Totals", + link: "/v1/get-user-points", + }, + { + text: "Specific Games Progress", + link: "/v1/get-user-progress", + }, + { + text: "Recently Played Games", + link: "/v1/get-user-recently-played-games", + }, + { + text: "Summary", + link: "/v1/get-user-summary", + }, + { + text: "Completed Games", + link: "/v1/get-user-completed-games", + }, + { + text: "Want to Play Games List", + link: "/v1/get-user-want-to-play-list", + }, + { + text: "Users I Follow", + link: "/v1/get-users-i-follow", + }, + { + text: "Users Following Me", + link: "/v1/get-users-following-me", + }, + { + text: "User Set Requests", + link: "/v1/get-user-set-requests", + }, + ], + }, + { + text: "Game", + collapsible: true, + items: [ + { + text: "Summary", + link: "/v1/get-game", + }, + { + text: "Extended Details", + link: "/v1/get-game-extended", + }, + { + text: "Hashes", + link: "/v1/get-game-hashes", + }, + { + text: "Achievement IDs", + link: "/v1/get-achievement-count", + }, + { + text: "Unlocks Distribution", + link: "/v1/get-achievement-distribution", + }, + { + text: "High Scores", + link: "/v1/get-game-rank-and-score", + }, + { + text: "Progression", + link: "/v1/get-game-progression", + }, + ], + }, + { + text: "Leaderboards", + collapsible: true, + items: [ + { + text: "Leaderboards (by gameID)", + link: "/v1/get-game-leaderboards", + }, + { + text: "Entries", + link: "/v1/get-leaderboard-entries", + }, + { + text: "User Leaderboards (by gameID)", + link: "/v1/get-user-game-leaderboards", + }, + ], + }, + { + text: "System", + collapsible: true, + items: [ + { + text: "All Systems", + link: "/v1/get-console-ids", + }, + { + text: "All Games and Hashes", + link: "/v1/get-game-list", + }, + ], + }, + { + text: "Achievement", + collapsible: true, + items: [ + { + text: "All Unlocks", + link: "/v1/get-achievement-unlocks", + }, + ], + }, + { + text: "Comment", + collapsible: true, + items: [ + { + text: "Comments", + link: "/v1/get-comments", + }, + ], + }, + { + text: "Feed", + collapsible: true, + items: [ + { + text: "All Recent Game Awards", + link: "/v1/get-recent-game-awards", + }, + { + text: "Active Claims", + link: "/v1/get-active-claims", + }, + { + text: "Inactive Claims", + link: "/v1/get-claims", + }, + { + text: "Top Ten Ranked Users", + link: "/v1/get-top-ten-users", + }, + ], + }, + { + text: "Event", + items: [ + { + text: "Achievement of the Week", + link: "/v1/get-achievement-of-the-week", + }, + ], + }, + { + text: "Ticket", + collapsible: true, + items: [ + { + text: "Get Ticket by ID", + link: "/v1/get-ticket-data/get-ticket-by-id", + }, + { + text: "Get Most Ticketed Games", + link: "/v1/get-ticket-data/get-most-ticketed-games", + }, + { + text: "Get Most Recent Tickets", + link: "/v1/get-ticket-data/get-most-recent-tickets", + }, + { + text: "Get Game Ticket Stats", + link: "/v1/get-ticket-data/get-game-ticket-stats", + }, + { + text: "Get Developer Ticket Stats", + link: "/v1/get-ticket-data/get-developer-ticket-stats", + }, + { + text: "Get Achievement Ticket Stats", + link: "/v1/get-ticket-data/get-achievement-ticket-stats", + }, + ], + }] + } ], - }, - { - text: "Ticket", - collapsible: true, - items: [ - { - text: "Get Ticket by ID", - link: "/v1/get-ticket-data/get-ticket-by-id", - }, - { - text: "Get Most Ticketed Games", - link: "/v1/get-ticket-data/get-most-ticketed-games", - }, - { - text: "Get Most Recent Tickets", - link: "/v1/get-ticket-data/get-most-recent-tickets", - }, - { - text: "Get Game Ticket Stats", - link: "/v1/get-ticket-data/get-game-ticket-stats", - }, - { - text: "Get Developer Ticket Stats", - link: "/v1/get-ticket-data/get-developer-ticket-stats", - }, - { - text: "Get Achievement Ticket Stats", - link: "/v1/get-ticket-data/get-achievement-ticket-stats", - }, - ], - }, - ], + '/v2/': useSidebar({spec}).generateSidebarGroups({ + linkPrefix: "/v2/", + sidebarItemTemplate: ({ + title + }) => { + + return title; + } + }), + }, + editLink: { pattern: diff --git a/docs/v2/achievement.md b/docs/v2/achievement.md new file mode 100644 index 0000000..a7a7274 --- /dev/null +++ b/docs/v2/achievement.md @@ -0,0 +1,6 @@ + + + diff --git a/docs/v2/retroachievements.json b/docs/v2/retroachievements.json index ef27eee..06a7bad 100644 --- a/docs/v2/retroachievements.json +++ b/docs/v2/retroachievements.json @@ -7,8 +7,7 @@ }, "servers": [ { - "url": "https://api.retroachievements.org/v2", - "description": "Primary server" + "url": "https://api.retroachievements.org/v2" } ], "paths": { @@ -535,6 +534,502 @@ } } }, + "/hubs": { + "get": { + "tags": ["Hubs"], + "summary": "Get all hubs", + "description": "", + "operationId": "hubs.index", + "parameters": [ + { + "name": "page[size]", + "in": "query", + "description": "The page size for paginated results", + "required": false, + "allowEmptyValue": false, + "schema": { + "type": "integer" + } + }, + { + "name": "page[number]", + "in": "query", + "description": "The page number for paginated results", + "required": false, + "allowEmptyValue": false, + "schema": { + "type": "integer" + } + }, + { + "name": "sort", + "in": "query", + "required": false, + "allowEmptyValue": false, + "schema": { + "type": "array", + "items": { + "enum": [ + "id", + "-id", + "title", + "-title", + "sortTitle", + "-sortTitle", + "createdAt", + "-createdAt", + "updatedAt", + "-updatedAt", + "gamesCount", + "-gamesCount", + "linkedHubsCount", + "-linkedHubsCount", + "gamesCount", + "-gamesCount", + "linkedHubsCount", + "-linkedHubsCount" + ], + "type": "string" + } + } + }, + { + "name": "filter[id]", + "in": "query", + "description": "A list of ids to filter by.", + "required": false, + "allowEmptyValue": false, + "style": "form", + "explode": false, + "schema": { + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "examples": { + "empty": { + "value": [] + }, + "1": { + "value": ["1"] + }, + "2": { + "value": ["2"] + }, + "3": { + "value": ["3"] + } + } + }, + { + "name": "filter[parentId]", + "in": "query", + "description": "Applies the parentId scope.", + "required": false, + "allowEmptyValue": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "filter[title]", + "in": "query", + "description": "Applies the title scope.", + "required": false, + "allowEmptyValue": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "Index hubs", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "required": ["jsonapi", "data"], + "properties": { + "jsonapi": { + "type": "object", + "properties": { + "version": { + "title": "version", + "type": "string", + "example": "1.0" + } + } + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/resources.hubs.resource.fetch" + } + } + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + } + } + } + }, + "/hubs/{hub}": { + "get": { + "tags": ["Hubs"], + "summary": "Show one hub", + "description": "", + "operationId": "hubs.show", + "parameters": [ + { + "name": "hub", + "in": "path", + "required": true, + "allowEmptyValue": false, + "schema": { + "type": "string" + }, + "examples": { + "1": { + "value": "1" + }, + "2": { + "value": "2" + }, + "3": { + "value": "3" + } + } + } + ], + "responses": { + "200": { + "description": "Show hubs", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "required": ["jsonapi", "data"], + "properties": { + "jsonapi": { + "type": "object", + "properties": { + "version": { + "title": "version", + "type": "string", + "example": "1.0" + } + } + }, + "data": { + "$ref": "#/components/schemas/resources.hubs.resource.fetch" + } + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + } + } + } + }, + "/hubs/{hub}/games": { + "get": { + "tags": ["Hubs"], + "summary": "Show games", + "description": "", + "operationId": "hubs.games", + "parameters": [ + { + "name": "hub", + "in": "path", + "required": true, + "allowEmptyValue": false, + "schema": { + "type": "string" + }, + "examples": { + "1": { + "value": "1" + }, + "2": { + "value": "2" + }, + "3": { + "value": "3" + } + } + } + ], + "responses": { + "200": { + "description": "ShowRelated hubs", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "required": ["jsonapi", "data"], + "properties": { + "jsonapi": { + "type": "object", + "properties": { + "version": { + "title": "version", + "type": "string", + "example": "1.0" + } + } + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/resources.games.resource.fetch" + } + } + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + } + } + } + }, + "/hubs/{hub}/relationships/games": { + "get": { + "tags": ["Hubs"], + "summary": "Show games relation", + "description": "", + "operationId": "hubs.games.show", + "parameters": [ + { + "name": "hub", + "in": "path", + "required": true, + "allowEmptyValue": false, + "schema": { + "type": "string" + }, + "examples": { + "1": { + "value": "1" + }, + "2": { + "value": "2" + }, + "3": { + "value": "3" + } + } + } + ], + "responses": { + "200": { + "description": "Show hubs", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "required": ["jsonapi", "data"], + "properties": { + "jsonapi": { + "type": "object", + "properties": { + "version": { + "title": "version", + "type": "string", + "example": "1.0" + } + } + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/resources.hubs.relationship.games.fetch" + } + } + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + } + } + } + }, + "/hubs/{hub}/links": { + "get": { + "tags": ["Hubs"], + "summary": "Show links", + "description": "", + "operationId": "hubs.links", + "parameters": [ + { + "name": "hub", + "in": "path", + "required": true, + "allowEmptyValue": false, + "schema": { + "type": "string" + }, + "examples": { + "1": { + "value": "1" + }, + "2": { + "value": "2" + }, + "3": { + "value": "3" + } + } + } + ], + "responses": { + "200": { + "description": "ShowRelated hubs", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "required": ["jsonapi", "data"], + "properties": { + "jsonapi": { + "type": "object", + "properties": { + "version": { + "title": "version", + "type": "string", + "example": "1.0" + } + } + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/resources.hubs.resource.fetch" + } + } + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + } + } + } + }, + "/hubs/{hub}/relationships/links": { + "get": { + "tags": ["Hubs"], + "summary": "Show links relation", + "description": "", + "operationId": "hubs.links.show", + "parameters": [ + { + "name": "hub", + "in": "path", + "required": true, + "allowEmptyValue": false, + "schema": { + "type": "string" + }, + "examples": { + "1": { + "value": "1" + }, + "2": { + "value": "2" + }, + "3": { + "value": "3" + } + } + } + ], + "responses": { + "200": { + "description": "Show hubs", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "required": ["jsonapi", "data"], + "properties": { + "jsonapi": { + "type": "object", + "properties": { + "version": { + "title": "version", + "type": "string", + "example": "1.0" + } + } + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/resources.hubs.relationship.links.fetch" + } + } + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + } + } + } + }, "/leaderboards": { "get": { "tags": ["Leaderboards"], @@ -631,21 +1126,155 @@ "value": 1 } } - }, - { - "name": "filter[state]", - "in": "query", - "description": "Applies the state scope.", - "required": false, - "allowEmptyValue": false, - "schema": { - "type": "boolean" - } + }, + { + "name": "filter[state]", + "in": "query", + "description": "Applies the state scope.", + "required": false, + "allowEmptyValue": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "Index leaderboards", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "required": ["jsonapi", "data"], + "properties": { + "jsonapi": { + "type": "object", + "properties": { + "version": { + "title": "version", + "type": "string", + "example": "1.0" + } + } + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/resources.leaderboards.resource.fetch" + } + } + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + } + } + } + }, + "/leaderboards/{leaderboard}": { + "get": { + "tags": ["Leaderboards"], + "summary": "Show one leaderboard", + "description": "", + "operationId": "leaderboards.show", + "parameters": [ + { + "name": "leaderboard", + "in": "path", + "required": true, + "allowEmptyValue": false, + "schema": { + "type": "string" + }, + "examples": { + "1": { + "value": "1" + }, + "2": { + "value": "2" + }, + "3": { + "value": "3" + } + } + } + ], + "responses": { + "200": { + "description": "Show leaderboards", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "required": ["jsonapi", "data"], + "properties": { + "jsonapi": { + "type": "object", + "properties": { + "version": { + "title": "version", + "type": "string", + "example": "1.0" + } + } + }, + "data": { + "$ref": "#/components/schemas/resources.leaderboards.resource.fetch" + } + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + } + } + } + }, + "/leaderboards/{leaderboard}/entries": { + "get": { + "tags": ["Leaderboards"], + "summary": "Show entries", + "description": "", + "operationId": "leaderboards.entries", + "parameters": [ + { + "name": "leaderboard", + "in": "path", + "required": true, + "allowEmptyValue": false, + "schema": { + "type": "string" + }, + "examples": { + "1": { + "value": "1" + }, + "2": { + "value": "2" + }, + "3": { + "value": "3" + } + } } ], "responses": { "200": { - "description": "Index leaderboards", + "description": "ShowRelated leaderboards", "content": { "application/vnd.api+json": { "schema": { @@ -665,7 +1294,7 @@ "data": { "type": "array", "items": { - "$ref": "#/components/schemas/resources.leaderboards.resource.fetch" + "$ref": "#/components/schemas/resources.leaderboard-entries.resource.fetch" } } } @@ -678,16 +1307,19 @@ }, "401": { "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" } } } }, - "/leaderboards/{leaderboard}": { + "/leaderboards/{leaderboard}/relationships/entries": { "get": { "tags": ["Leaderboards"], - "summary": "Show one leaderboard", + "summary": "Show entries relation", "description": "", - "operationId": "leaderboards.show", + "operationId": "leaderboards.entries.show", "parameters": [ { "name": "leaderboard", @@ -730,7 +1362,10 @@ } }, "data": { - "$ref": "#/components/schemas/resources.leaderboards.resource.fetch" + "type": "array", + "items": { + "$ref": "#/components/schemas/resources.leaderboards.relationship.entries.fetch" + } } } } @@ -752,8 +1387,8 @@ "/systems": { "get": { "tags": ["Systems"], - "summary": "Get All Systems", - "description": "Views a list of all systems on the site", + "summary": "Get all systems", + "description": "", "operationId": "systems.index", "parameters": [ { @@ -1258,12 +1893,12 @@ "related": { "title": "related", "type": "string", - "example": "https://retroachievements.org/api/v2/games/1" + "example": "https://raweb.test/api/v2/games/1" }, "self": { "title": "self", "type": "string", - "example": "https://retroachievements.org/api/v2/games/1" + "example": "https://raweb.test/api/v2/games/1" } }, "readOnly": true @@ -1319,13 +1954,13 @@ "title": "badgeUrl", "type": "string", "readOnly": true, - "example": "https://retroachievements.org/media/Badge/00001.png" + "example": "https://raweb.test/media/Badge/00001.png" }, "badgeLockedUrl": { "title": "badgeLockedUrl", "type": "string", "readOnly": true, - "example": "https://retroachievements.org/media/Badge/00001_lock.png" + "example": "https://raweb.test/media/Badge/00001_lock.png" }, "type": { "title": "type", @@ -1394,12 +2029,12 @@ "related": { "title": "related", "type": "string", - "example": "https://retroachievements.org/api/v2/developers/1" + "example": "https://raweb.test/api/v2/developers/1" }, "self": { "title": "self", "type": "string", - "example": "https://retroachievements.org/api/v2/developers/1" + "example": "https://raweb.test/api/v2/developers/1" } }, "readOnly": true @@ -1416,12 +2051,12 @@ "related": { "title": "related", "type": "string", - "example": "https://retroachievements.org/api/v2/achievement-sets/1" + "example": "https://raweb.test/api/v2/achievement-sets/1" }, "self": { "title": "self", "type": "string", - "example": "https://retroachievements.org/api/v2/achievement-sets/1" + "example": "https://raweb.test/api/v2/achievement-sets/1" } }, "readOnly": true @@ -1438,12 +2073,12 @@ "related": { "title": "related", "type": "string", - "example": "https://retroachievements.org/api/v2/games/1" + "example": "https://raweb.test/api/v2/games/1" }, "self": { "title": "self", "type": "string", - "example": "https://retroachievements.org/api/v2/games/1" + "example": "https://raweb.test/api/v2/games/1" } }, "readOnly": true @@ -1485,25 +2120,25 @@ "title": "badgeUrl", "type": "string", "readOnly": true, - "example": "https://retroachievements.org/media/Images/000002.png" + "example": "https://raweb.test/media/Images/000002.png" }, "imageBoxArtUrl": { "title": "imageBoxArtUrl", "type": "string", "readOnly": true, - "example": "https://retroachievements.org/media/Images/000002.png" + "example": "https://raweb.test/media/Images/000002.png" }, "imageTitleUrl": { "title": "imageTitleUrl", "type": "string", "readOnly": true, - "example": "https://retroachievements.org/media/Images/000002.png" + "example": "https://raweb.test/media/Images/000002.png" }, "imageIngameUrl": { "title": "imageIngameUrl", "type": "string", "readOnly": true, - "example": "https://retroachievements.org/media/Images/000002.png" + "example": "https://raweb.test/media/Images/000002.png" }, "releasedAt": { "title": "releasedAt", @@ -1577,12 +2212,12 @@ "related": { "title": "related", "type": "string", - "example": "https://retroachievements.org/api/v2/systems/1" + "example": "https://raweb.test/api/v2/systems/1" }, "self": { "title": "self", "type": "string", - "example": "https://retroachievements.org/api/v2/systems/1" + "example": "https://raweb.test/api/v2/systems/1" } }, "readOnly": true @@ -1599,12 +2234,260 @@ "related": { "title": "related", "type": "string", - "example": "https://retroachievements.org/api/v2/achievement-sets/1" + "example": "https://raweb.test/api/v2/achievement-sets/1" + }, + "self": { + "title": "self", + "type": "string", + "example": "https://raweb.test/api/v2/achievement-sets/1" + } + }, + "readOnly": true + } + } + } + } + } + } + }, + "resources.hubs.relationship.games.fetch": { + "title": "Resource/Hub/Relationship/Games/Fetch", + "type": "object", + "required": ["type", "id"], + "properties": { + "type": { + "title": "type", + "default": "games", + "type": "string" + }, + "id": { + "title": "id", + "type": "string", + "example": "1" + } + } + }, + "resources.hubs.relationship.links.fetch": { + "title": "Resource/Hub/Relationship/Links/Fetch", + "type": "object", + "required": ["type", "id"], + "properties": { + "type": { + "title": "type", + "default": "hubs", + "type": "string" + }, + "id": { + "title": "id", + "type": "string", + "example": "1" + } + } + }, + "resources.hubs.resource.fetch": { + "title": "Resource/Hub/Fetch", + "type": "object", + "required": ["type", "id", "attributes"], + "properties": { + "type": { + "title": "type", + "default": "hubs", + "type": "string" + }, + "id": { + "type": "string", + "example": "1" + }, + "attributes": { + "type": "object", + "properties": { + "title": { + "title": "title", + "type": "string", + "readOnly": true, + "example": "[Central]" + }, + "sortTitle": { + "title": "sortTitle", + "type": "string", + "readOnly": true + }, + "badgeUrl": { + "title": "badgeUrl", + "type": "string", + "readOnly": true, + "example": "https://raweb.test/media/Images/000001.png" + }, + "hasMatureContent": { + "title": "hasMatureContent", + "type": "boolean", + "readOnly": true, + "example": false + }, + "gamesCount": { + "title": "gamesCount", + "type": "number", + "readOnly": true, + "example": 0 + }, + "linkedHubsCount": { + "title": "linkedHubsCount", + "type": "number", + "readOnly": true, + "example": 0 + }, + "isEventHub": { + "title": "isEventHub", + "type": "boolean", + "readOnly": true, + "example": false + }, + "createdAt": { + "title": "createdAt", + "type": "string", + "readOnly": true, + "example": "2025-09-12T06:04:29.000000Z" + }, + "updatedAt": { + "title": "updatedAt", + "type": "string", + "readOnly": true, + "example": "2025-09-12T06:04:29.000000Z" + } + } + }, + "relationships": { + "type": "object", + "properties": { + "games": { + "title": "games", + "type": "object", + "properties": { + "links": { + "type": "object", + "properties": { + "related": { + "title": "related", + "type": "string", + "example": "https://raweb.test/api/v2/games/1" + }, + "self": { + "title": "self", + "type": "string", + "example": "https://raweb.test/api/v2/games/1" + } + }, + "readOnly": true + } + } + }, + "links": { + "title": "links", + "type": "object", + "properties": { + "links": { + "type": "object", + "properties": { + "related": { + "title": "related", + "type": "string", + "example": "https://raweb.test/api/v2/links/1" + }, + "self": { + "title": "self", + "type": "string", + "example": "https://raweb.test/api/v2/links/1" + } + }, + "readOnly": true + } + } + } + } + } + } + }, + "resources.leaderboard-entries.resource.fetch": { + "title": "Resource/Leaderboard-entry/Fetch", + "type": "object", + "required": ["type", "id", "attributes"], + "properties": { + "type": { + "title": "type", + "default": "leaderboard-entries", + "type": "string" + }, + "id": { + "type": "string", + "example": "1" + }, + "attributes": { + "type": "object", + "properties": { + "score": { + "title": "score", + "type": "number", + "readOnly": true, + "example": 1 + }, + "rank": { + "title": "rank", + "type": "number", + "readOnly": true + }, + "createdAt": { + "title": "createdAt", + "type": "string", + "readOnly": true + }, + "updatedAt": { + "title": "updatedAt", + "type": "string", + "readOnly": true + } + } + }, + "relationships": { + "type": "object", + "properties": { + "user": { + "title": "user", + "type": "object", + "properties": { + "links": { + "type": "object", + "properties": { + "related": { + "title": "related", + "type": "string", + "example": "https://raweb.test/api/v2/users/1" + }, + "self": { + "title": "self", + "type": "string", + "example": "https://raweb.test/api/v2/users/1" + } + }, + "readOnly": true + } + } + }, + "leaderboard": { + "title": "leaderboard", + "type": "object", + "properties": { + "links": { + "type": "object", + "properties": { + "related": { + "title": "related", + "type": "string", + "example": "https://raweb.test/api/v2/leaderboards/1" }, "self": { "title": "self", "type": "string", - "example": "https://retroachievements.org/api/v2/achievement-sets/1" + "example": "https://raweb.test/api/v2/leaderboards/1" } }, "readOnly": true @@ -1615,6 +2498,23 @@ } } }, + "resources.leaderboards.relationship.entries.fetch": { + "title": "Resource/Leaderboard/Relationship/Entries/Fetch", + "type": "object", + "required": ["type", "id"], + "properties": { + "type": { + "title": "type", + "default": "leaderboard-entries", + "type": "string" + }, + "id": { + "title": "id", + "type": "string", + "example": "1" + } + } + }, "resources.leaderboards.resource.fetch": { "title": "Resource/Leaderboard/Fetch", "type": "object", @@ -1695,12 +2595,12 @@ "related": { "title": "related", "type": "string", - "example": "https://retroachievements.org/api/v2/games/1" + "example": "https://raweb.test/api/v2/games/1" }, "self": { "title": "self", "type": "string", - "example": "https://retroachievements.org/api/v2/games/1" + "example": "https://raweb.test/api/v2/games/1" } }, "readOnly": true @@ -1717,12 +2617,34 @@ "related": { "title": "related", "type": "string", - "example": "https://retroachievements.org/api/v2/developers/1" + "example": "https://raweb.test/api/v2/developers/1" + }, + "self": { + "title": "self", + "type": "string", + "example": "https://raweb.test/api/v2/developers/1" + } + }, + "readOnly": true + } + } + }, + "entries": { + "title": "entries", + "type": "object", + "properties": { + "links": { + "type": "object", + "properties": { + "related": { + "title": "related", + "type": "string", + "example": "https://raweb.test/api/v2/entries/1" }, "self": { "title": "self", "type": "string", - "example": "https://retroachievements.org/api/v2/developers/1" + "example": "https://raweb.test/api/v2/entries/1" } }, "readOnly": true @@ -1774,7 +2696,7 @@ "title": "iconUrl", "type": "string", "readOnly": true, - "example": "https://retroachievements.org/assets/images/system/md.png" + "example": "https://raweb.test/assets/images/system/md.png" }, "active": { "title": "active", @@ -1812,7 +2734,7 @@ "title": "avatarUrl", "type": "string", "readOnly": true, - "example": "https://retroachievements.org/media/UserPic/claireboehm.png" + "example": "https://raweb.test/media/UserPic/claireboehm.png" }, "motto": { "title": "motto",