From e11e24e8989e96a82cf09d5018a7b683ea17c2af Mon Sep 17 00:00:00 2001 From: vivianh_dev Date: Fri, 27 Mar 2026 23:37:14 -0500 Subject: [PATCH] Create dynamic openapi specs --- .gitignore | 1 + assets/scripts/objects.js | 163 ++++ index.html | 412 +-------- openapi.yaml | 1576 +++++++++++++++++++++++++++++++++++ package-lock.json | 31 + package.json | 10 + scripts/generate-openapi.js | 426 ++++++++++ scripts/objects.js | 180 ++++ 8 files changed, 2396 insertions(+), 403 deletions(-) create mode 100644 .gitignore create mode 100644 assets/scripts/objects.js create mode 100644 openapi.yaml create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 scripts/generate-openapi.js create mode 100644 scripts/objects.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c2658d7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules/ diff --git a/assets/scripts/objects.js b/assets/scripts/objects.js new file mode 100644 index 0000000..62b13ed --- /dev/null +++ b/assets/scripts/objects.js @@ -0,0 +1,163 @@ +const objects = { + UserProfile: { + kind: 'Class', + fields: [ + { name: 'uuid', type: 'String', description: "User's UUID" }, + { name: 'nickname', type: 'String', description: "User's nickname" }, + { name: 'roleType', type: 'Integer', description: "User's role type" }, + { name: 'eloRate', type: 'Integer?', description: "User's Elo rate. It is null if the user hasn't finished placement matches." }, + { name: 'eloRank', type: 'Integer?', description: "User's Elo rank" }, + { name: 'country', type: 'String?', description: 'User\'s country code in lowercased ISO 3166-1 alpha-2 format.' }, + ] + }, + Achievement: { + kind: 'Class', + fields: [ + { name: 'id', type: 'String', description: 'Achievement Identifier' }, + { name: 'date', type: 'Date', description: 'Timestamp of when the achievement was earned' }, + { name: 'data', type: 'String[]', description: 'Additional data array' }, + { name: 'level', type: 'Integer', description: 'Level of achievement' }, + { name: 'value', type: 'Integer?', description: "Contains the current player's progression of the achievement. It is null if the achievement is not a leveling one." }, + { name: 'goal', type: 'Integer?', description: 'Next level goal of the achievement. It is null if the achievement is at max level or not a leveling one.' }, + ] + }, + MatchInfo: { + kind: 'Class', + note: 'Advanced parameters are only available with /matches/{match_id} endpoint.', + fields: [ + { name: 'id', type: 'String' }, + { name: 'type', type: 'MatchType' }, + { name: 'season', type: 'Integer' }, + { name: 'category', type: 'String?', description: 'Match completions category. Default is ANY' }, + { name: 'date', type: 'Date' }, + { name: 'players', type: 'UserProfile[]' }, + { name: 'spectators', type: 'UserProfile[]' }, + { name: 'seed', type: 'MatchSeed?', description: "Seed ID if it's a ranked filtered seed. This is not the seed number. It is null if the seed is not filtered." }, + { name: 'result.uuid', type: 'String?', description: "Winner's UUID. It is null if the match was a draw." }, + { name: 'result.time', type: 'Time' }, + { name: 'forfeited', type: 'Boolean', description: 'Whether the match has no completions' }, + { name: 'decayed', type: 'Boolean', description: 'Whether the match has decayed' }, + { name: 'rank.season', type: 'Integer?', description: "Record rank of the match's season" }, + { name: 'rank.allTime', type: 'Integer?', description: 'Record rank of all-time' }, + { name: 'changes[].uuid', type: 'String', description: 'UUID of player' }, + { name: 'changes[].change', type: 'Integer?', description: 'Amount of changed Elo rate. It is null if the match is a placement.' }, + { name: 'changes[].eloRate', type: 'Integer?', description: 'Elo rate of the player. It is null if the match is a placement.' }, + { name: 'tag', type: 'String?', description: 'Special tag of this match. Used to get matches by tag.' }, + { name: 'beginner', type: 'Boolean', description: 'Whether beginner mode is enabled in the match.' }, + { name: 'vod[].uuid', type: 'String', description: 'UUID of VOD owner. Only players with public stream activated will be included.' }, + { name: 'vod[].url', type: 'String', description: 'VOD URL of this match' }, + { name: 'vod[].startsAt', type: 'Date', description: 'VOD start date. You can get a timestamp with {date} - {vod[].startsAt}' }, + { name: 'completions[].uuid', type: 'String', description: '(Advanced) Player uuid of completion' }, + { name: 'completions[].time', type: 'Time', description: '(Advanced) Match time of completion' }, + { name: 'timelines[].uuid', type: 'String', description: '(Advanced) Player uuid of timeline' }, + { name: 'timelines[].time', type: 'Time', description: '(Advanced) Match time of timeline' }, + { name: 'timelines[].type', type: 'String', description: '(Advanced) Identifier of timeline' }, + { name: 'replayExist', type: 'Boolean', description: '(Advanced) Whether the match replay exists in the server' }, + ] + }, + MatchSeed: { + kind: 'Class', + fields: [ + { name: 'id', type: 'String?', description: "Seed id if it's a ranked filtered seed. This is not the seed number. It is null if the seed is not filtered." }, + { name: 'overworld', type: 'String?', description: 'Overworld structure type of the seed. It is null if the seed is not filtered.' }, + { name: 'nether', type: 'String?', description: 'Bastion remnants type of the seed. It is null if the seed is not filtered.' }, + { name: 'endTowers', type: 'Integer[]', description: 'The zero related tower heights of in The End dimension. It is an empty array if the seed is not filtered.' }, + { name: 'variations', type: 'String[]', description: 'Noticeable variations of the seed. It is an empty array if the seed is not filtered.' }, + ] + }, + UserIdentifier: { + kind: 'String', + description: 'Identifier used when getting user information. You must use one of the formats below.', + variants: [ + { type: 'UUID', description: 'UUID of User. You can also use it with dashes (-).', example: 'bbc886da1b024739b4b80f1542e9f61d' }, + { type: 'Nickname', description: 'Nickname of User. It is not case-sensitive.', example: 'RED_LIME' }, + { type: 'Discord ID', description: 'Linked Discord ID (Snowflake) of User. Must be discord.[ID] format.', example: 'discord.338669823167037440' }, + ] + }, + MatchType: { + kind: 'Integer', + values: [ + { value: 1, description: 'Casual Match' }, + { value: 2, description: 'Ranked Match' }, + { value: 3, description: 'Private Room Match' }, + { value: 4, description: 'Event Mode Match' }, + ] + }, + Date: { + kind: 'Integer', + description: 'Displays a specific date as an epoch time (timestamp) in seconds. (NOT milliseconds!)', + }, + Time: { + kind: 'Integer', + description: 'Displays a specific duration in milliseconds.', + }, +}; + + +function buildObjectContainer(name, obj) { + const id = 'objects-' + name.toLowerCase(); + const labelClass = obj.kind === 'Class' ? 'label-success' : 'label-primary'; + + if (!obj.fields && !obj.variants && !obj.values) { + // Simple type (Date, Time) — just title + description + return /*html*/ `
+

${obj.kind}   ${name}

+

${obj.description || ''}

+
+
`; + } + + let bodyHtml = ''; + + if (obj.fields) { + // Class with fields table + const noteHtml = obj.note ? obj.note : ''; + const rows = obj.fields.map(f => + `${f.name}${f.type}${f.description || ''}` + ).join(''); + bodyHtml = ` + ${noteHtml} + + ${rows} +
ParameterTypeDescription
`; + } else if (obj.variants) { + // String type with variant formats (UserIdentifier) + const rows = obj.variants.map(v => + `${v.type}${v.description}${v.example}` + ).join(''); + bodyHtml = ` + + ${rows} +
TypeDescriptionExample
`; + } else if (obj.values) { + // Integer enum (MatchType) + const rows = obj.values.map(v => + `${v.value}${v.description}` + ).join(''); + bodyHtml = ` + + ${rows} +
ValueDescription
`; + } + + const descHtml = obj.description ? `

${obj.description}

` : ''; + + return /*html*/ `
+

${obj.kind}   ${name}

+ ${descHtml} +
+
+
+ ${bodyHtml} +
+
+
+
+
`; +} + +function buildObjectSidebar(name, obj) { + const id = 'objects-' + name.toLowerCase(); + const labelClass = obj.kind === 'Class' ? 'label-success' : 'label-primary'; + return `
  • ${obj.kind}   ${name}
  • `; +} diff --git a/index.html b/index.html index 5a1fe8b..ece123b 100644 --- a/index.html +++ b/index.html @@ -61,16 +61,7 @@
  • @@ -222,399 +213,8 @@

    Sample Response


    -
    -

    Class   UserProfile

    -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    ParameterTypeDescription
    uuidStringUser's UUID
    nicknameStringUser's nickname
    roleTypeIntegerUser's role type
    eloRateInteger?User's Elo rate. It is null if the user hasn't finished placement matches.
    eloRankInteger?User's Elo rank
    countryString?User's country code in lowercased ISO 3166-1 alpha-2 format.
    -
    -
    -
    -
    -
    -
    -

    Class   Achievement

    -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    ParameterTypeDescription
    idStringAchievement Identifier
    dateDateTimestamp of when the achievement was earned
    dataString[]Additional data array
    levelIntegerLevel of achievement
    valueInteger?Contains the current player's progression of the achievement. It is null if the achievement is not a leveling one.
    goalInteger?Next level goal of the achievement. It is null if the achievement is at max level or not a leveling one.
    -
    -
    -
    -
    -
    -
    -

    Class   MatchInfo

    -
    -
    -
    - - Advanced parameters are only available with /matches/{match_id} endpoint. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    ParameterTypeDescription
    idString
    typeMatchType
    seasonInteger
    categoryString?Match completions category. Default is ANY
    dateDate
    playersUserProfile[]
    spectatorsUserProfile[]
    seedMatchSeed?Seed ID if it's a ranked filtered seed. This is not the seed number. It is null if the seed is not filtered.
    result.uuidString?Winner's UUID. It is null if the match was a draw.
    result.timeTime
    forfeitedBooleanWhether the match has no completions
    decayedBooleanWhether the match has decayed
    rank.seasonInteger?Record rank of the match's season
    rank.allTimeInteger?Record rank of all-time
    changes[].uuidStringUUID of player
    changes[].changeInteger?Amount of changed Elo rate. It is null if the match is a placement.
    changes[].eloRateInteger?Elo rate of the player. It is null if the match is a placement.
    tagString?Special tag of this match. Used to get matches by tag.
    beginnerBooleanWhether beginner mode is enabled in the match.
    vod[].uuidStringUUID of VOD owner. Only players with public stream activated will be included.
    vod[].urlStringVOD URL of this match
    vod[].startsAtDateVOD start date. You can get a timestamp with {date} - {vod[].startsAt}
    completions[].uuidString(Advanced) Player uuid of completion
    completions[].timeTime(Advanced) Match time of completion
    timelines[].uuidString(Advanced) Player uuid of timeline
    timelines[].timeTime(Advanced) Match time of timeline
    timelines[].typeString(Advanced) Identifier of timeline
    replayExistBoolean(Advanced) Whether the match replay exists in the server
    -
    -
    -
    -
    -
    -
    -

    Class   MatchSeed

    -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    ParameterTypeDescription
    idString?Seed id if it's a ranked filtered seed. This is not the seed number. It is null if the seed is not filtered.
    overworldString?Overworld structure type of the seed. It is null if the seed is not filtered.
    netherString?Bastion remnants type of the seed. It is null if the seed is not filtered.
    endTowersInteger[]The zero related tower heights of in The End dimension. It is an empty array if the seed is not filtered.
    variationsString[]Noticeable variations of the seed. It is an empty array if the seed is not filtered.
    -
    -
    -
    -
    -
    -
    -

    String   UserIdentifier

    -

    Identifier used when getting user information. You must use one of the formats below.

    -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - -
    TypeDescriptionExample
    UUIDUUID of User. You can also use it with dashes (-).bbc886da1b024739b4b80f1542e9f61d
    NicknameNickname of User. It is not case-sensitive.RED_LIME
    Discord IDLinked Discord ID (Snowflake) of User. Must be discord.[ID] format.discord.338669823167037440
    -
    -
    -
    -
    -
    -
    -

    Integer   MatchType

    -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - -
    ValueDescription
    1Casual Match
    2Ranked Match
    3Private Room Match
    4Event Mode Match
    -
    -
    -
    -
    -
    -
    -

    Integer   Date

    -

    Displays a specific date as an epoch time (timestamp) in seconds. (NOT milliseconds!)

    -
    -
    -
    -

    Integer   Time

    -

    Displays a specific duration in milliseconds.

    -
    -
    + +
    @@ -632,6 +232,7 @@

    Displays a specific duration in milliseconds.

    +