├── .eslintignore ├── .eslintrc ├── .github └── workflows │ └── node.js.yml ├── .gitignore ├── .lintstagedrc ├── .npmignore ├── .prettierignore ├── LICENSE.md ├── README.md ├── package-lock.json ├── package.json ├── src ├── api │ └── index.ts ├── bw-connection.ts ├── errors.ts ├── index.ts └── response-types │ ├── v1 │ ├── classic-files-global-maps-1v1.ts │ ├── gateway.ts │ ├── leaderboard-entity.ts │ ├── leaderboard-name-search.ts │ ├── leaderboard-rank-by-toon.ts │ ├── leaderboard.ts │ ├── map-stats-by-toon.ts │ ├── matchmaker-gameinfo-by-toon.ts │ └── matchmaker-gameinfo-playerinfo.ts │ └── v2 │ ├── aurora-profile-by-toon-scr-mm-game-loading.ts │ ├── aurora-profile-by-toon-scr-mm-toon-info.ts │ ├── aurora-profile-by-toon-scr-profile.ts │ ├── aurora-profile-by-toon-scr-toon-info.ts │ └── aurora-profile-by-toon-superset.ts ├── test ├── api.test.ts └── data │ └── web-api │ ├── v1 │ ├── file-set │ │ └── classic.files.global.maps-1v1.json │ ├── gateway.json │ ├── leaderboard-name-search │ │ └── 1 │ │ │ └── bob.json │ ├── leaderboard-rank-by-toon │ │ └── 1 │ │ │ └── bob │ │ │ └── 10.json │ ├── leaderboard.json │ ├── leaderboard │ │ └── 1%3Foffset%3D0%26length%3D100.json │ ├── map-stats-by-toon │ │ └── bob │ │ │ └── 10.json │ ├── matchmaker-gameinfo-by-toon │ │ └── bob │ │ │ └── 10 │ │ │ └── 1 │ │ │ └── 1%3Foffset%3D0%26limit%3D15.json │ └── matchmaker-gameinfo-playerinfo │ │ └── mm-test.json │ └── v2 │ └── aurora-profile-by-toon │ └── bob │ ├── 10%3Frequest_flags%3Dscr_mmgameloading.json │ ├── 10%3Frequest_flags%3Dscr_mmtooninfo.json │ ├── 10%3Frequest_flags%3Dscr_profile.json │ └── 10%3Frequest_flags%3Dscr_tooninfo.json ├── tsconfig.json └── vite.config.ts /.eslintignore: -------------------------------------------------------------------------------- 1 | .history 2 | .husky 3 | .vscode 4 | coverage 5 | dist 6 | node_modules 7 | vite.config.ts 8 | jest.config.ts 9 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "plugins": ["@typescript-eslint", "prettier"], 5 | "extends": [ 6 | "eslint:recommended", 7 | "plugin:@typescript-eslint/eslint-recommended", 8 | "plugin:@typescript-eslint/recommended", 9 | "prettier" 10 | ], 11 | "env": { 12 | "browser": true, 13 | "node": true 14 | }, 15 | "rules": { 16 | "prettier/prettier": "error" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.github/workflows/node.js.yml: -------------------------------------------------------------------------------- 1 | name: Node.js CI 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | strategy: 14 | matrix: 15 | node-version: [18.x] 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | - name: Use Node.js ${{ matrix.node-version }} 20 | uses: actions/setup-node@v3 21 | with: 22 | node-version: ${{ matrix.node-version }} 23 | cache: "npm" 24 | - run: npm i 25 | - run: npm run check 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | coverage 15 | 16 | # Editor directories and files 17 | .vscode/* 18 | .history/* 19 | !.vscode/extensions.json 20 | .idea 21 | .DS_Store 22 | *.suo 23 | *.ntvs* 24 | *.njsproj 25 | *.sln 26 | *.sw? 27 | -------------------------------------------------------------------------------- /.lintstagedrc: -------------------------------------------------------------------------------- 1 | { 2 | "./**/*.{ts}": "npm run format:scripts" 3 | } 4 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .eslintignore 2 | .github 3 | .eslintrc 4 | .lintstagedrc 5 | .prettierignore 6 | .vscode/settings.json 7 | dts-bundle-generator.config.ts 8 | jest.config.ts 9 | *.tgz 10 | src/ 11 | test/ 12 | tsconfig.json 13 | vite.config.ts 14 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .history 2 | .husky 3 | .vscode 4 | coverage 5 | dist 6 | node_modules 7 | vite.config.ts 8 | jest.config.ts 9 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [2023] [Evan Rose] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BW Web API 2 | 3 | This package serves as both a typed API wrapper and documentation for the otherwise undocumented Brood War Remastered API. 4 | 5 | When logged in to Starcraft: Remastered, StarCraft.exe creates a local web server that exposes these endpoints. These endpoints are used when 6 | exploring the ladder, viewing profiles, etc. 7 | 8 | Below is a table of the known, supported endpoints and the corresponding methods exposed on the `SCApi` class. 9 | 10 | | Endpoint | `SCApi` method | Notes | 11 | | ----------------------------------------------------------------------------- | ----------------------------------------------------------- | -------------------------------------------- | 12 | | `/v1/file-set/classic.files.global.maps-1v1` | `classicFilesGlobalMaps1v1()` | List of ladder maps by season | 13 | | `/v1/gateway` | `gateway()` | Gateways, ids, online player counts | 14 | | `/v1/leaderboard/{ladder}?offset={offset}&length={length}` | `leaderboardEntity(ladder, offset, length)` | Paginated player rankings | 15 | | `/v1/leaderboard-name-search/{ladder}/{toon}` | `leaderboardNameSearch(toon)` | Name search of ranked players | 16 | | `/v1/leaderboard-rank-by-toon/{ladder}/{toon}/{gateway}` | `leaderboardRankByToon(ladder, toon, gateway)` | Ranked data for a given profile | 17 | | `/v1/leaderboard` | `leaderboard()` | List of all leaderboards | 18 | | `/v1/map-stats-by-toon/{toon}/{gateway}` | `mapStatsByToon(toon, gateway)` | Win rate by map and season | 19 | | `/v1/matchmaker-gameinfo-playerinfo/{matchId}` | `matchMakerGameInfoPlayerInfo(matchId)` | Ranked match info and link to replay | 20 | | `/v2/aurora-profile-by-toon/{toon}/{gateway}?request_flags=scr_mmgameloading` | `auroraProfileByToonv2(toon, gateway, 'scr_mmgameloading')` | Minimal acct info | 21 | | `/v2/aurora-profile-by-toon/{toon}/{gateway}?request_flags=scr_mmtooninfo` | `auroraProfileByToonv2(toon, gateway, 'scr_mmtooninfo')` | Minimal acct info + recent game played count | 22 | | `/v2/aurora-profile-by-toon/{toon}/{gateway}?request_flags=scr_profile` | `auroraProfileByToonv2(toon, gateway, 'scr_profile')` | Full acct info | 23 | | `/v2/aurora-profile-by-toon/{toon}/{gateway}?request_flags=scr_tooninfo` | `auroraProfileByToonv2(toon, gateway, 'scr_tooninfo')` | Full acct info minus game history | 24 | 25 | # Installation 26 | 27 | `npm i --save bw-web-api` 28 | 29 | # Usage 30 | 31 | ``` 32 | import { SCApi, BroodWarConnection } from 'bw-web-api'; 33 | 34 | const sc = new SCApi(new BroodWarConnection(`localhost:50250`)); 35 | 36 | const profile = sc.auroraProfileByToon('By.SnOw1', 30, "scr_mmgameloading"); 37 | ``` 38 | 39 | Note: for profile information, you have to provide a flag which corresponds to the in-game view. They likely implemented it this way because the "full view" (`scr_profile`) is very slow to load. 40 | 41 | # StarCraft Port 42 | 43 | You can determine the port StarCraft opens for the web API via: 44 | 45 | (as administrator) 46 | 47 | ``` 48 | (Get-NetTCPConnection -OwningProcess (Get-Process -Name StarCraft | Select-Object -ExpandProperty Id) | Where-Object {$_.State -eq "Listen"} | Sort-Object -Property LocalPort | Select-Object -First 1).LocalPort 49 | ``` 50 | 51 | # Notes 52 | 53 | ## Zod 54 | 55 | I've done my best to represent the various response types as [Zod](https://github.com/colinhacks/zod) typings, which means that if the response doesn't match the expected shape, 56 | the API will throw a `ZodError`. Conversely, if no error is thrown, you can be confident that the typings are correct. 57 | 58 | Be sure to catch `ZodError`s when invoking `SCApi` methods, log them, and, if possible, contribute the shape deviation back to this library. 59 | 60 | ## Providing an alternative fetch, passing headers, etc. 61 | 62 | The `BroodWarConnection` is just as pass-through to `fetch` (requires Node 18 or browser fetch, though you can probably inject `cross-fetch` pre-18). If you need to pass headers 63 | or use a different fetch, provide your own `IBroodWarConnection` imlementation to `SCApi`. 64 | 65 | # Testing 66 | 67 | `test/data` contains the expected shapes for various response types. Unfortunately, the response shape is volatile, so more test data is definitely needed for full coverage. For now, 68 | the tests just ensure that the Zod parsing is successful. 69 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bw-web-api", 3 | "version": "3.0.2", 4 | "main": "./dist/bw-web-api.umd.js", 5 | "module": "./dist/bw-web-api.mjs", 6 | "exports": { 7 | ".": { 8 | "import": "./dist/bw-web-api.mjs", 9 | "require": "./dist/bw-web-api.umd.js", 10 | "types": "./dist/index.d.ts" 11 | } 12 | }, 13 | "types": "./dist/index.d.ts", 14 | "scripts": { 15 | "check": "tsc && npm run test && npm run lint", 16 | "build": "vite build", 17 | "test": "vitest run", 18 | "lint": "eslint . --ext .ts", 19 | "format": "prettier . --write" 20 | }, 21 | "devDependencies": { 22 | "@types/node": "^18.15.6", 23 | "@typescript-eslint/eslint-plugin": "^5.56.0", 24 | "@typescript-eslint/parser": "^5.56.0", 25 | "eslint": "^8.36.0", 26 | "eslint-config-prettier": "^8.8.0", 27 | "eslint-plugin-prettier": "^4.2.1", 28 | "prettier": "^2.8.6", 29 | "ts-node": "^10.9.1", 30 | "typescript": "^5.0.2", 31 | "vite": "^4.2.1", 32 | "vite-plugin-dts": "^2.1.0", 33 | "vitest": "^0.29.7" 34 | }, 35 | "dependencies": { 36 | "zod": "^3.21.4" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/api/index.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | import { BroodWarApiPath, IBroodWarConnection } from "@/bw-connection"; 4 | import { 5 | ClassicFilesGlobalMaps1v1Response, 6 | ClassicFilesGlobalMaps1v1ResponseSchema, 7 | } from "@/response-types/v1/classic-files-global-maps-1v1"; 8 | import { 9 | GatewayResponse, 10 | GatewayResponseSchema, 11 | } from "@/response-types/v1/gateway"; 12 | import { 13 | LeaderboardResponse, 14 | LeaderboardResponseSchema, 15 | } from "@/response-types/v1/leaderboard"; 16 | import { 17 | LeaderboardEntityResponse, 18 | LeaderboardEntityResponseSchema, 19 | } from "@/response-types/v1/leaderboard-entity"; 20 | import { 21 | LeaderboardNameSearchResponse, 22 | LeaderboardNameSearchResponseSchema, 23 | } from "@/response-types/v1/leaderboard-name-search"; 24 | import { 25 | LeaderboardRankByToonResponse, 26 | LeaderboardRankByToonResponseSchema, 27 | } from "@/response-types/v1/leaderboard-rank-by-toon"; 28 | import { 29 | MapStatsByToonResponse, 30 | MapStatsByToonResponseSchema, 31 | } from "@/response-types/v1/map-stats-by-toon"; 32 | import { 33 | MatchMakerGameInfoByToonResponse, 34 | MatchMakerGameInfoByToonResponseSchema, 35 | } from "@/response-types/v1/matchmaker-gameinfo-by-toon"; 36 | import { 37 | MatchMakerGameInfoPlayerInfoResponse, 38 | MatchMakerGameInfoPlayerInfoResponseSchema, 39 | } from "@/response-types/v1/matchmaker-gameinfo-playerinfo"; 40 | import { 41 | AuroraProfileByToonScrMmGameLoadingResponse, 42 | AuroraProfileByToonScrMmGameLoadingResponseSchema, 43 | } from "@/response-types/v2/aurora-profile-by-toon-scr-mm-game-loading"; 44 | import { 45 | AuroraProfileByToonScrMmToonInfoResponse, 46 | AuroraProfileByToonScrMmToonInfoResponseSchema, 47 | } from "@/response-types/v2/aurora-profile-by-toon-scr-mm-toon-info"; 48 | import { 49 | AuroraProfileByToonScrProfileResponse, 50 | AuroraProfileByToonScrProfileResponseSchema, 51 | } from "@/response-types/v2/aurora-profile-by-toon-scr-profile"; 52 | import { 53 | AuroraProfileByToonScrToonInfoResponse, 54 | AuroraProfileByToonScrToonInfoResponseSchema, 55 | } from "@/response-types/v2/aurora-profile-by-toon-scr-toon-info"; 56 | import { InvalidInputError } from "../errors"; 57 | 58 | export type AuroraProfileByToonV2FieldMask = 59 | | "scr_mmgameloading" 60 | | "scr_mmtooninfo" 61 | | "scr_tooninfo" 62 | | "scr_profile"; 63 | 64 | export enum Region { 65 | USWest = 10, 66 | USEast = 11, 67 | Europe = 20, 68 | Korea = 30, 69 | Asia = 45, 70 | } 71 | 72 | export interface ISCApi { 73 | classicFilesGlobalMaps1v1: () => Promise; 74 | gateway: () => Promise; 75 | leaderboard: () => Promise; 76 | leaderboardEntity: ( 77 | leaderboardId: number, 78 | offset: number, 79 | length: number 80 | ) => Promise; 81 | leaderboardNameSearch: ( 82 | leaderboardId: number, 83 | toon: string 84 | ) => Promise; 85 | leaderboardRankByToon: ( 86 | ladder: number, 87 | toon: string, 88 | gateway: Region 89 | ) => Promise; 90 | mapStatsByToon: ( 91 | toon: string, 92 | gateway: Region 93 | ) => Promise; 94 | matchMakerGameInfoByToon: ( 95 | toon: string, 96 | gateway: Region, 97 | gameMode: number, 98 | season: number, 99 | offset: number, 100 | limit: number 101 | ) => Promise; 102 | matchMakerGameInfoPlayerInfo: ( 103 | matchId: string 104 | ) => Promise; 105 | auroraProfileByToon: ( 106 | toon: string, 107 | gateway: Region, 108 | mask: AuroraProfileByToonV2FieldMask 109 | ) => Promise< 110 | | AuroraProfileByToonScrMmGameLoadingResponse 111 | | AuroraProfileByToonScrMmToonInfoResponse 112 | | AuroraProfileByToonScrToonInfoResponse 113 | | AuroraProfileByToonScrProfileResponse 114 | >; 115 | } 116 | 117 | export class SCApi implements ISCApi { 118 | constructor(private bwConnection: IBroodWarConnection) {} 119 | 120 | schemaFetch = async ( 121 | schema: T, 122 | path: BroodWarApiPath 123 | ): Promise> => { 124 | const text = await this.bwConnection.fetch(path); 125 | 126 | try { 127 | return schema.parse(JSON.parse(text)); 128 | } catch (e) { 129 | console.error(`SCApi.schemaFetch error for path ${path}`); 130 | throw e; 131 | } 132 | }; 133 | 134 | classicFilesGlobalMaps1v1 = 135 | async (): Promise => 136 | await this.schemaFetch( 137 | ClassicFilesGlobalMaps1v1ResponseSchema, 138 | `web-api/v1/file-set/classic.files.global.maps-1v1` 139 | ); 140 | 141 | gateway = async (): Promise => 142 | await this.schemaFetch(GatewayResponseSchema, `web-api/v1/gateway`); 143 | 144 | leaderboardEntity = async ( 145 | leaderboardId: number, 146 | offset = 0, 147 | length = 100 148 | ): Promise => { 149 | if (offset < 0) throw new InvalidInputError("offset must be >= 0"); 150 | if (length > 100) throw new InvalidInputError("length must be <= 100"); 151 | 152 | return await this.schemaFetch( 153 | LeaderboardEntityResponseSchema, 154 | `web-api/v1/leaderboard/${leaderboardId}?offset=${offset}&length=${length}` 155 | ); 156 | }; 157 | 158 | leaderboardNameSearch = async ( 159 | leaderboardId: number, 160 | toon: string 161 | ): Promise => 162 | await this.schemaFetch( 163 | LeaderboardNameSearchResponseSchema, 164 | `web-api/v1/leaderboard-name-search/${leaderboardId}/${encodeURIComponent( 165 | toon 166 | )}` 167 | ); 168 | 169 | leaderboardRankByToon = async ( 170 | ladder: number, 171 | toon: string, 172 | gateway: Region 173 | ): Promise => 174 | await this.schemaFetch( 175 | LeaderboardRankByToonResponseSchema, 176 | `web-api/v1/leaderboard-rank-by-toon/${ladder}/${encodeURIComponent( 177 | toon 178 | )}/${gateway}` 179 | ); 180 | 181 | leaderboard = async (): Promise => 182 | await this.schemaFetch(LeaderboardResponseSchema, `web-api/v1/leaderboard`); 183 | 184 | mapStatsByToon = async ( 185 | toon: string, 186 | gateway: Region 187 | ): Promise => 188 | await this.schemaFetch( 189 | MapStatsByToonResponseSchema, 190 | `web-api/v1/map-stats-by-toon/${encodeURIComponent(toon)}/${gateway}` 191 | ); 192 | 193 | matchMakerGameInfoByToon = async ( 194 | toon: string, 195 | gateway: Region, 196 | gameMode: number, 197 | season: number, 198 | offset = 0, 199 | limit = 15 200 | ): Promise => 201 | await this.schemaFetch( 202 | MatchMakerGameInfoByToonResponseSchema, 203 | `web-api/v1/matchmaker-gameinfo-by-toon/${encodeURIComponent( 204 | toon 205 | )}/${gateway}/${gameMode}/${season}?offset=${offset}&limit=${limit}` 206 | ); 207 | 208 | matchMakerGameInfoPlayerInfo = async ( 209 | matchId: string 210 | ): Promise => 211 | await this.schemaFetch( 212 | MatchMakerGameInfoPlayerInfoResponseSchema, 213 | `web-api/v1/matchmaker-gameinfo-playerinfo/${matchId}` 214 | ); 215 | 216 | auroraProfileByToon = async ( 217 | toon: string, 218 | gateway: Region, 219 | mask: AuroraProfileByToonV2FieldMask 220 | ): Promise< 221 | | AuroraProfileByToonScrMmGameLoadingResponse 222 | | AuroraProfileByToonScrMmToonInfoResponse 223 | | AuroraProfileByToonScrProfileResponse 224 | | AuroraProfileByToonScrToonInfoResponse 225 | > => { 226 | switch (mask) { 227 | case "scr_mmgameloading": 228 | return await this.schemaFetch( 229 | AuroraProfileByToonScrMmGameLoadingResponseSchema, 230 | `web-api/v2/aurora-profile-by-toon/${encodeURIComponent( 231 | toon 232 | )}/${gateway}?request_flags=${mask}` 233 | ); 234 | case "scr_mmtooninfo": 235 | return await this.schemaFetch( 236 | AuroraProfileByToonScrMmToonInfoResponseSchema, 237 | `web-api/v2/aurora-profile-by-toon/${encodeURIComponent( 238 | toon 239 | )}/${gateway}?request_flags=${mask}` 240 | ); 241 | case "scr_profile": 242 | return await this.schemaFetch( 243 | AuroraProfileByToonScrProfileResponseSchema, 244 | `web-api/v2/aurora-profile-by-toon/${encodeURIComponent( 245 | toon 246 | )}/${gateway}?request_flags=${mask}` 247 | ); 248 | case "scr_tooninfo": 249 | return await this.schemaFetch( 250 | AuroraProfileByToonScrToonInfoResponseSchema, 251 | `web-api/v2/aurora-profile-by-toon/${encodeURIComponent( 252 | toon 253 | )}/${gateway}?request_flags=${mask}` 254 | ); 255 | } 256 | }; 257 | } 258 | -------------------------------------------------------------------------------- /src/bw-connection.ts: -------------------------------------------------------------------------------- 1 | export type BroodWarApiVersion = "1" | "2"; 2 | export type BroodWarApiPath = `web-api/v${BroodWarApiVersion}/${string}`; 3 | 4 | export interface IBroodWarConnection { 5 | fetch(url: BroodWarApiPath): Promise; 6 | } 7 | 8 | export class BroodWarConnection implements IBroodWarConnection { 9 | constructor(private server: string) {} 10 | 11 | public fetch = async (path: BroodWarApiPath): Promise => { 12 | const fetchResult = await fetch(`${this.server}/${path}`); 13 | return fetchResult.text(); 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /src/errors.ts: -------------------------------------------------------------------------------- 1 | export class BaseError extends Error { 2 | constructor(message?: string) { 3 | super(message); 4 | Object.setPrototypeOf(this, new.target.prototype); 5 | this.name = this.constructor.name; 6 | } 7 | } 8 | 9 | export class InvalidInputError extends BaseError {} 10 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "@/api"; 2 | export * from "@/bw-connection"; 3 | export * from "@/errors"; 4 | export * from "@/response-types/v1/classic-files-global-maps-1v1"; 5 | export * from "@/response-types/v1/gateway"; 6 | export * from "@/response-types/v1/leaderboard"; 7 | export * from "@/response-types/v1/leaderboard-entity"; 8 | export * from "@/response-types/v1/leaderboard-name-search"; 9 | export * from "@/response-types/v1/leaderboard-rank-by-toon"; 10 | export * from "@/response-types/v1/map-stats-by-toon"; 11 | export * from "@/response-types/v1/matchmaker-gameinfo-by-toon"; 12 | export * from "@/response-types/v1/matchmaker-gameinfo-playerinfo"; 13 | export * from "@/response-types/v2/aurora-profile-by-toon-scr-mm-game-loading"; 14 | export * from "@/response-types/v2/aurora-profile-by-toon-scr-mm-toon-info"; 15 | export * from "@/response-types/v2/aurora-profile-by-toon-scr-profile"; 16 | export * from "@/response-types/v2/aurora-profile-by-toon-scr-toon-info"; 17 | -------------------------------------------------------------------------------- /src/response-types/v1/classic-files-global-maps-1v1.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | export const ClassicFilesGlobalMaps1v1ResponseSchema = z.array( 4 | z.object({ 5 | attribute: z.object({ 6 | map_candidate: z.string(), 7 | map_description: z.string(), 8 | map_era: z.string(), 9 | map_height: z.string(), 10 | map_md5: z.string(), 11 | map_name: z.string(), 12 | map_path: z.string(), 13 | map_version: z.string(), 14 | map_width: z.string(), 15 | replay_humans: z.string(), 16 | replay_max_players: z.string(), 17 | replay_min_players: z.string(), 18 | replay_opponents: z.string(), 19 | season_id: z.string(), 20 | }), 21 | content_size: z.number(), 22 | content_type: z.string(), 23 | md5: z.string(), 24 | modified_epoch: z.number(), 25 | name: z.string(), 26 | url: z.string(), 27 | }) 28 | ); 29 | 30 | export type ClassicFilesGlobalMaps1v1Response = z.infer< 31 | typeof ClassicFilesGlobalMaps1v1ResponseSchema 32 | >; 33 | -------------------------------------------------------------------------------- /src/response-types/v1/gateway.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | export const GatewayResponseSchema = z.record( 4 | z.string().regex(/^\d+$/), 5 | z.object({ 6 | is_official: z.boolean(), 7 | name: z.string(), 8 | online_users: z.number(), 9 | region: z.string(), 10 | }) 11 | ); 12 | 13 | export type GatewayResponse = z.infer; 14 | -------------------------------------------------------------------------------- /src/response-types/v1/leaderboard-entity.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | export const LeaderboardEntityResponseSchema = z.object({ 4 | columns: z.tuple([ 5 | z.literal("rank"), 6 | z.literal("last_rank"), 7 | z.literal("gateway_id"), 8 | z.literal("points"), 9 | z.literal("wins"), 10 | z.literal("losses"), 11 | z.literal("disconnects"), 12 | z.literal("toon"), 13 | z.literal("battletag"), 14 | z.literal("avatar"), 15 | z.literal("feature_stat"), 16 | z.literal("rating"), 17 | z.literal("bucket"), 18 | ]), 19 | rows: z.array( 20 | z.tuple([ 21 | z.number().int(), 22 | z.number().int(), 23 | z.number().int(), 24 | z.number().int(), 25 | z.number().int(), 26 | z.number().int(), 27 | z.number().int(), 28 | z.string(), 29 | z.string(), 30 | z.string(), 31 | z.string(), 32 | z.number().int(), 33 | z.number().int(), 34 | ]) 35 | ), 36 | }); 37 | 38 | export type LeaderboardEntityResponse = z.infer< 39 | typeof LeaderboardEntityResponseSchema 40 | >; 41 | -------------------------------------------------------------------------------- /src/response-types/v1/leaderboard-name-search.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | export const LeaderboardNameSearchResponseSchema = z 4 | .object({ 5 | avatar: z.string(), 6 | battletag: z.string(), 7 | gateway_id: z.number(), 8 | last_rank: z.number(), 9 | name: z.string(), 10 | points: z.number(), 11 | rank: z.number(), 12 | }) 13 | .array(); 14 | 15 | export type LeaderboardNameSearchResponse = z.infer< 16 | typeof LeaderboardNameSearchResponseSchema 17 | >; 18 | -------------------------------------------------------------------------------- /src/response-types/v1/leaderboard-rank-by-toon.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | const ToonsSchema = z.array( 4 | z.object({ 5 | avatar: z.string(), 6 | battletag: z.string(), 7 | bucket: z.number(), 8 | disconnects: z.number(), 9 | feature_stat: z.string(), 10 | gateway_id: z.number(), 11 | last_rank: z.number(), 12 | losses: z.number(), 13 | name: z.string(), 14 | points: z.number(), 15 | rank: z.number(), 16 | wins: z.number(), 17 | }) 18 | ); 19 | 20 | const NoResultResponseSchema = z.object({ 21 | leaderboard_id: z.number(), 22 | matchmaked_current_season: z.number(), 23 | matchmaked_current_season_buckets: z.array(z.number()), 24 | toons: ToonsSchema.length(0), 25 | }); 26 | 27 | export const LeaderboardRankByToonResponseSchema = z.union([ 28 | z.object({ 29 | aurora_id: z.number().optional(), 30 | gateway_id: z.number().optional(), 31 | leaderboard_id: z.number(), 32 | matchmaked_current_season: z.number(), 33 | matchmaked_current_season_buckets: z.array(z.number()), 34 | mingames: z.number().optional(), 35 | total_rows: z.number().optional(), 36 | toons: ToonsSchema, 37 | }), 38 | NoResultResponseSchema, 39 | ]); 40 | 41 | export type LeaderboardRankByToonResponse = z.infer< 42 | typeof LeaderboardRankByToonResponseSchema 43 | >; 44 | -------------------------------------------------------------------------------- /src/response-types/v1/leaderboard.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | export const LeaderboardResponseSchema = z.object({ 4 | gamemodes: z.record( 5 | z.string().regex(/^\d+$/), 6 | z.object({ name: z.string() }) 7 | ), 8 | gateways: z.record( 9 | z.string().regex(/^\d+$/), 10 | z.object({ 11 | is_official: z.boolean(), 12 | name: z.string(), 13 | region: z.string(), 14 | }) 15 | ), 16 | leaderboards: z.record( 17 | z.string().regex(/^\d+$/), 18 | z.object({ 19 | benefactor_id: z.string(), 20 | gamemode_id: z.number(), 21 | gateway_id: z.number(), 22 | id: z.number(), 23 | last_update_time: z.string(), 24 | name: z.string(), 25 | next_update_time: z.string(), 26 | program_id: z.string(), 27 | season_id: z.number(), 28 | season_name: z.string(), 29 | }) 30 | ), 31 | matchmaked_current_season: z.number(), 32 | team_leaderboard_info: z.object({}), 33 | }); 34 | 35 | export type LeaderboardResponse = z.infer; 36 | -------------------------------------------------------------------------------- /src/response-types/v1/map-stats-by-toon.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | const NoResultResponseSchema = z.object({ 4 | current_season: z.number(), 5 | map_stat: z.object({}), 6 | }); 7 | 8 | export const MapStatsByToonResponseSchema = z.union([ 9 | z.object({ 10 | current_season: z.number(), 11 | map_stat: z.record( 12 | z.string().regex(/^\d+$/), // game mode 13 | z.record( 14 | z.string().regex(/^\d+$/), // season 15 | z.record( 16 | z.string(), // map md5 17 | z.object({ 18 | Protoss: z.object({ 19 | total_games: z.number(), 20 | total_global_games: z.number(), 21 | total_global_wins: z.number(), 22 | total_wins: z.number(), 23 | }), 24 | Random: z.object({ 25 | total_games: z.number(), 26 | total_global_games: z.number(), 27 | total_global_wins: z.number(), 28 | total_wins: z.number(), 29 | }), 30 | Terran: z.object({ 31 | total_games: z.number(), 32 | total_global_games: z.number(), 33 | total_global_wins: z.number(), 34 | total_wins: z.number(), 35 | }), 36 | Zerg: z.object({ 37 | total_games: z.number(), 38 | total_global_games: z.number(), 39 | total_global_wins: z.number(), 40 | total_wins: z.number(), 41 | }), 42 | }) 43 | ) 44 | ) 45 | ), 46 | }), 47 | NoResultResponseSchema, 48 | ]); 49 | 50 | export type MapStatsByToonResponse = z.infer< 51 | typeof MapStatsByToonResponseSchema 52 | >; 53 | -------------------------------------------------------------------------------- /src/response-types/v1/matchmaker-gameinfo-by-toon.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | export const MatchMakerGameInfoByToonResponseSchema = z.array( 4 | z.record( 5 | z.string(), 6 | z.object({ 7 | match_created: z.string(), 8 | players: z.array( 9 | z.record( 10 | z.object({ 11 | aurora_id: z.number(), 12 | avatar_url: z.string(), 13 | benefactor_id: z.string(), 14 | game_info: z 15 | .object({ 16 | attributes: z.object({ 17 | closed_slots: z.string(), 18 | flags: z.string(), 19 | game_speed: z.string(), 20 | host_name: z.string(), 21 | is_replay: z.string(), 22 | map_crc: z.string(), 23 | map_file_name: z.string(), 24 | map_file_size: z.string(), 25 | map_height: z.string(), 26 | map_md5: z.string(), 27 | map_name: z.string(), 28 | map_tile_set: z.string(), 29 | map_width: z.string(), 30 | net_turn_rate: z.string(), 31 | observers_current: z.string(), 32 | observers_max: z.string(), 33 | players_ai: z.string(), 34 | players_current: z.string(), 35 | players_max: z.string(), 36 | proxy: z.string().optional(), 37 | rank: z.string().optional(), 38 | save_game_id: z.string(), 39 | }), 40 | id: z.string(), 41 | name: z.string(), 42 | }) 43 | .optional(), 44 | game_result: z 45 | .record( 46 | z.string(), 47 | z 48 | .object({ 49 | attributes: z.object({ 50 | gPlayerData_idx: z.string(), 51 | left: z.string(), 52 | race: z.string().optional(), 53 | team: z.string().optional(), 54 | type: z.string(), 55 | }), 56 | is_computer: z.boolean().optional(), 57 | result: z.string(), 58 | }) 59 | .optional() 60 | ) 61 | .optional(), 62 | gateway_id: z.number(), 63 | info_attributes: z.object({ 64 | map: z.string(), 65 | map_selection: z.string().optional(), 66 | player_battle_tag: z.string().optional(), 67 | player_legacy_gateway_id: z.string().optional(), 68 | player_legacy_toon_name: z.string().optional(), 69 | player_region: z.string().optional(), 70 | player_routing_via_proxy_server: z.string().optional(), 71 | race: z.string().optional(), 72 | }), 73 | is_winner: z.string(), 74 | matching_attributes: z.object({ 75 | net_version: z.string().optional(), 76 | }), 77 | name: z.string(), 78 | score: z.object({ 79 | base: z.number(), 80 | bucket_new: z.number(), 81 | bucket_old: z.number(), 82 | delta: z.number(), 83 | win_streak: z.number(), 84 | }), 85 | }) 86 | ) 87 | ), 88 | }) 89 | ) 90 | ); 91 | 92 | export type MatchMakerGameInfoByToonResponse = z.infer< 93 | typeof MatchMakerGameInfoByToonResponseSchema 94 | >; 95 | -------------------------------------------------------------------------------- /src/response-types/v1/matchmaker-gameinfo-playerinfo.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | const ReplaysSchemas = z.array( 4 | z.union([ 5 | z.object({ 6 | attributes: z.object({ 7 | game_creator: z.string(), 8 | game_id: z.string(), 9 | game_name: z.string(), 10 | game_save_id: z.string(), 11 | game_speed: z.string(), 12 | game_sub_type: z.string(), 13 | game_type: z.string(), 14 | map_era: z.string(), 15 | map_height: z.string(), 16 | map_title: z.string(), 17 | map_width: z.string(), 18 | replay_description: z.string(), 19 | replay_humans: z.string(), 20 | replay_map_number: z.string(), 21 | replay_max_players: z.string(), 22 | replay_min_players: z.string(), 23 | replay_opponents: z.string(), 24 | replay_player_names: z.string().optional(), 25 | replay_player_races: z.string().optional(), 26 | replay_player_types: z.string().optional(), 27 | replay_result: z.string().optional(), 28 | }), 29 | create_time: z.number(), 30 | link: z.string(), 31 | md5: z.string(), 32 | url: z.string(), 33 | }), 34 | z.object({}), 35 | ]) 36 | ); 37 | 38 | const NoResultResponseSchema = z.object({ 39 | avatars: z.record(z.string(), z.string()), 40 | avatars_awards: z.record(z.string(), z.number()), 41 | avatars_locked: z.record( 42 | z.object({ 43 | level: z.number(), 44 | stat: z.string(), 45 | url: z.string(), 46 | }) 47 | ), 48 | avatars_stats: z.record(z.string(), z.record(z.string(), z.literal(0))), 49 | maps: z.array(z.unknown()).length(0), 50 | matchmaked_season_buckets: z.object({}), 51 | player_stats: z.array(z.unknown()).length(0), 52 | players: z.object({}), 53 | replays: ReplaysSchemas.length(0), 54 | }); 55 | 56 | export const MatchMakerGameInfoPlayerInfoResponseSchema = z.union([ 57 | NoResultResponseSchema, 58 | z.object({ 59 | avatars: z.record(z.string(), z.string()), 60 | avatars_awards: z.record(z.string(), z.number()), 61 | avatars_locked: z.record( 62 | z.object({ 63 | level: z.number(), 64 | stat: z.string(), 65 | url: z.string(), 66 | }) 67 | ), 68 | avatars_stats: z.record(z.string(), z.record(z.string(), z.number())), 69 | maps: z.array(z.unknown()), 70 | matchmaked_season_buckets: z.record(z.string(), z.array(z.number())), 71 | player_stats: z.array(z.unknown()), 72 | players: z.record( 73 | z.string(), 74 | z.object({ 75 | aurora_id: z.number(), 76 | benefactor_id: z.string(), 77 | game_info: z 78 | .object({ 79 | attributes: z.object({ 80 | closed_slots: z.string().optional(), 81 | flags: z.string().optional(), 82 | game_speed: z.string().optional(), 83 | host_name: z.string().optional(), 84 | is_replay: z.string().optional(), 85 | map_crc: z.string().optional(), 86 | map_file_name: z.string().optional(), 87 | map_file_size: z.string().optional(), 88 | map_height: z.string().optional(), 89 | map_md5: z.string().optional(), 90 | map_name: z.string().optional(), 91 | map_tile_set: z.string().optional(), 92 | map_width: z.string().optional(), 93 | net_turn_rate: z.string().optional(), 94 | observers_current: z.string().optional(), 95 | observers_max: z.string().optional(), 96 | players_ai: z.string().optional(), 97 | players_current: z.string().optional(), 98 | players_max: z.string().optional(), 99 | proxy: z.string().optional(), 100 | rank: z.string().optional(), 101 | save_game_id: z.string().optional(), 102 | }), 103 | id: z.string().optional(), 104 | name: z.string().optional(), 105 | }) 106 | .optional(), 107 | game_result: z 108 | .record( 109 | z.string(), 110 | z.object({ 111 | attributes: z.object({ 112 | gPlayerData_idx: z.string(), 113 | left: z.string(), 114 | race: z.string().optional(), 115 | team: z.string().optional(), 116 | type: z.string(), 117 | }), 118 | is_computer: z.boolean().optional(), 119 | result: z.string().optional(), 120 | }) 121 | ) 122 | .optional(), 123 | gateway_id: z.number(), 124 | info_attributes: z.object({ 125 | _default_region: z.string().optional(), 126 | connection_info: z.string().optional(), 127 | map: z.string().optional(), 128 | map_selection: z.string().optional(), 129 | player_battle_tag: z.string().optional(), 130 | player_legacy_gateway_id: z.string().optional(), 131 | player_legacy_toon_name: z.string().optional(), 132 | player_region: z.string().optional(), 133 | player_routing_via_proxy_server: z.string().optional(), 134 | race: z.string().optional(), 135 | }), 136 | matching_attributes: z.object({ net_version: z.string().optional() }), 137 | name: z.string(), 138 | score: z 139 | .object({ 140 | base: z.number().optional(), 141 | bucket_new: z.number().optional(), 142 | bucket_old: z.number().optional(), 143 | current_stat_bucket: z.number().optional(), 144 | current_stat_losses: z.number().optional(), 145 | current_stat_wins: z.number().optional(), 146 | delta: z.number().optional(), 147 | season_id: z.number().optional(), 148 | win_streak: z.number().optional(), 149 | }) 150 | .optional(), 151 | }) 152 | ), 153 | replays: ReplaysSchemas, 154 | }), 155 | ]); 156 | 157 | export type MatchMakerGameInfoPlayerInfoResponse = z.infer< 158 | typeof MatchMakerGameInfoPlayerInfoResponseSchema 159 | >; 160 | -------------------------------------------------------------------------------- /src/response-types/v2/aurora-profile-by-toon-scr-mm-game-loading.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AuroraProfileByToonSupersetNoResultResponseSchema, 3 | AuroraProfileByToonSupersetResponseSchema, 4 | } from "@/response-types/v2/aurora-profile-by-toon-superset"; 5 | import { z } from "zod"; 6 | 7 | const subset: Record = { 8 | account_flags: true, 9 | aurora_id: true, 10 | battle_tag: true, 11 | country_code: true, 12 | matchmaked_current_season: true, 13 | matchmaked_current_season_buckets: true, 14 | matchmaked_stats: true, 15 | program_id: true, 16 | toon_guid_by_gateway: true, 17 | }; 18 | 19 | export const AuroraProfileByToonScrMmGameLoadingResponsePlayerFoundSchema = 20 | AuroraProfileByToonSupersetResponseSchema.pick(subset); 21 | 22 | export const AuroraProfileByToonScrMmGameLoadingResponsePlayerNotFoundSchema = 23 | AuroraProfileByToonSupersetNoResultResponseSchema.pick(subset); 24 | 25 | export const AuroraProfileByToonScrMmGameLoadingResponseSchema = z.union([ 26 | AuroraProfileByToonScrMmGameLoadingResponsePlayerFoundSchema, 27 | AuroraProfileByToonScrMmGameLoadingResponsePlayerNotFoundSchema, 28 | ]); 29 | 30 | export type AuroraProfileByToonScrMmGameLoadingResponsePlayerFound = z.infer< 31 | typeof AuroraProfileByToonScrMmGameLoadingResponsePlayerFoundSchema 32 | >; 33 | 34 | export type AuroraProfileByToonScrMmGameLoadingResponsePlayerNotFound = z.infer< 35 | typeof AuroraProfileByToonScrMmGameLoadingResponsePlayerNotFoundSchema 36 | >; 37 | 38 | export type AuroraProfileByToonScrMmGameLoadingResponse = z.infer< 39 | typeof AuroraProfileByToonScrMmGameLoadingResponseSchema 40 | >; 41 | -------------------------------------------------------------------------------- /src/response-types/v2/aurora-profile-by-toon-scr-mm-toon-info.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AuroraProfileByToonSupersetNoResultResponseSchema, 3 | AuroraProfileByToonSupersetResponseSchema, 4 | } from "@/response-types/v2/aurora-profile-by-toon-superset"; 5 | import { z } from "zod"; 6 | 7 | const subset: Record = { 8 | account_flags: true, 9 | aurora_id: true, 10 | battle_tag: true, 11 | country_code: true, 12 | matchmaked_current_season: true, 13 | matchmaked_current_season_buckets: true, 14 | matchmaked_stats: true, 15 | program_id: true, 16 | toon_guid_by_gateway: true, 17 | toons: true, 18 | }; 19 | 20 | export const AuroraProfileByToonScrMmToonInfoResponsePlayerFoundSchema = 21 | AuroraProfileByToonSupersetResponseSchema.pick(subset); 22 | 23 | export const AuroraProfileByToonScrMmToonInfoResponsePlayerNotFoundSchema = 24 | AuroraProfileByToonSupersetNoResultResponseSchema.pick(subset); 25 | 26 | export const AuroraProfileByToonScrMmToonInfoResponseSchema = z.union([ 27 | AuroraProfileByToonScrMmToonInfoResponsePlayerFoundSchema, 28 | AuroraProfileByToonScrMmToonInfoResponsePlayerNotFoundSchema, 29 | ]); 30 | 31 | export type AuroraProfileByToonScrMmToonInfoResponsePlayerFound = z.infer< 32 | typeof AuroraProfileByToonScrMmToonInfoResponsePlayerFoundSchema 33 | >; 34 | 35 | export type AuroraProfileByToonScrMmToonInfoResponsePlayerNotFound = z.infer< 36 | typeof AuroraProfileByToonScrMmToonInfoResponsePlayerNotFoundSchema 37 | >; 38 | 39 | export type AuroraProfileByToonScrMmToonInfoResponse = z.infer< 40 | typeof AuroraProfileByToonScrMmToonInfoResponseSchema 41 | >; 42 | -------------------------------------------------------------------------------- /src/response-types/v2/aurora-profile-by-toon-scr-profile.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AuroraProfileByToonSupersetNoResultResponseSchema, 3 | AuroraProfileByToonSupersetResponseSchema, 4 | } from "@/response-types/v2/aurora-profile-by-toon-superset"; 5 | import { z } from "zod"; 6 | 7 | const subset: Record = { 8 | account_flags: true, 9 | aurora_id: true, 10 | avatars: true, 11 | avatars_framed: true, 12 | avatars_unlocked: true, 13 | battle_tag: true, 14 | country_code: true, 15 | game_results: true, 16 | matchmaked_current_season: true, 17 | matchmaked_current_season_buckets: true, 18 | matchmaked_stats: true, 19 | profiles: true, 20 | program_id: true, 21 | replays: true, 22 | stats: true, 23 | toon_guid_by_gateway: true, 24 | toons: true, 25 | }; 26 | 27 | export const AuroraProfileByToonScrProfileResponsePlayerFoundSchema = 28 | AuroraProfileByToonSupersetResponseSchema.pick(subset); 29 | 30 | export const AuroraProfileByToonScrProfileResponsePlayerNotFoundSchema = 31 | AuroraProfileByToonSupersetNoResultResponseSchema.pick(subset); 32 | 33 | export const AuroraProfileByToonScrProfileResponseSchema = z.union([ 34 | AuroraProfileByToonScrProfileResponsePlayerFoundSchema, 35 | AuroraProfileByToonScrProfileResponsePlayerNotFoundSchema, 36 | ]); 37 | 38 | export type AuroraProfileByToonScrProfileResponsePlayerFound = z.infer< 39 | typeof AuroraProfileByToonScrProfileResponsePlayerFoundSchema 40 | >; 41 | 42 | export type AuroraProfileByToonScrProfileResponsePlayerNotFound = z.infer< 43 | typeof AuroraProfileByToonScrProfileResponsePlayerNotFoundSchema 44 | >; 45 | 46 | export type AuroraProfileByToonScrProfileResponse = z.infer< 47 | typeof AuroraProfileByToonScrProfileResponseSchema 48 | >; 49 | -------------------------------------------------------------------------------- /src/response-types/v2/aurora-profile-by-toon-scr-toon-info.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AuroraProfileByToonSupersetNoResultResponseSchema, 3 | AuroraProfileByToonSupersetResponseSchema, 4 | } from "@/response-types/v2/aurora-profile-by-toon-superset"; 5 | import { z } from "zod"; 6 | 7 | const subset: Record = { 8 | account_flags: true, 9 | aurora_id: true, 10 | avatars: true, 11 | avatars_framed: true, 12 | avatars_unlocked: true, 13 | battle_tag: true, 14 | country_code: true, 15 | matchmaked_current_season: true, 16 | matchmaked_current_season_buckets: true, 17 | matchmaked_stats: true, 18 | profiles: true, 19 | program_id: true, 20 | stats: true, 21 | toon_guid_by_gateway: true, 22 | toons: true, 23 | }; 24 | 25 | export const AuroraProfileByToonScrToonInfoResponsePlayerFoundSchema = 26 | AuroraProfileByToonSupersetResponseSchema.pick(subset); 27 | 28 | export const AuroraProfileByToonScrToonInfoResponsePlayerNotFoundSchema = 29 | AuroraProfileByToonSupersetNoResultResponseSchema.pick(subset); 30 | 31 | export const AuroraProfileByToonScrToonInfoResponseSchema = z.union([ 32 | AuroraProfileByToonScrToonInfoResponsePlayerFoundSchema, 33 | AuroraProfileByToonScrToonInfoResponsePlayerNotFoundSchema, 34 | ]); 35 | 36 | export type AuroraProfileByToonScrToonInfoResponsePlayerFound = z.infer< 37 | typeof AuroraProfileByToonScrToonInfoResponsePlayerFoundSchema 38 | >; 39 | 40 | export type AuroraProfileByToonScrToonInfoResponsePlayerNotFound = z.infer< 41 | typeof AuroraProfileByToonScrToonInfoResponsePlayerNotFoundSchema 42 | >; 43 | 44 | export type AuroraProfileByToonScrToonInfoResponse = z.infer< 45 | typeof AuroraProfileByToonScrToonInfoResponseSchema 46 | >; 47 | -------------------------------------------------------------------------------- /src/response-types/v2/aurora-profile-by-toon-superset.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | const ToonsSchema = z.array( 4 | z.object({ 5 | games_last_week: z.number(), 6 | gateway_id: z.number(), 7 | guid: z.number(), 8 | toon: z.string(), 9 | }) 10 | ); 11 | 12 | const StatsSchema = z.array( 13 | z.object({ 14 | benefactor_id: z.string(), 15 | gateway_id: z.number(), 16 | raw: z.object({ 17 | legacy_disconnects: z.number(), 18 | legacy_losses: z.number(), 19 | legacy_toon_creation_time: z.number(), 20 | legacy_wins: z.number(), 21 | protoss_apm_max: z.number(), 22 | protoss_apm_min: z.number(), 23 | protoss_apm_sum: z.number(), 24 | protoss_disconnects_max: z.number(), 25 | protoss_disconnects_min: z.number(), 26 | protoss_disconnects_sum: z.number(), 27 | protoss_draws_max: z.number(), 28 | protoss_draws_min: z.number(), 29 | protoss_draws_sum: z.number(), 30 | protoss_losses_max: z.number(), 31 | protoss_losses_min: z.number(), 32 | protoss_losses_sum: z.number(), 33 | protoss_play_time_max: z.number(), 34 | protoss_play_time_min: z.number(), 35 | protoss_play_time_sum: z.number(), 36 | protoss_resources_gas_max: z.number(), 37 | protoss_resources_gas_min: z.number(), 38 | protoss_resources_gas_sum: z.number(), 39 | protoss_resources_minerals_max: z.number(), 40 | protoss_resources_minerals_min: z.number(), 41 | protoss_resources_minerals_sum: z.number(), 42 | protoss_resources_score_max: z.number(), 43 | protoss_resources_score_min: z.number(), 44 | protoss_resources_score_sum: z.number(), 45 | protoss_resources_spent_max: z.number(), 46 | protoss_resources_spent_min: z.number(), 47 | protoss_resources_spent_sum: z.number(), 48 | protoss_structures_constructed_max: z.number(), 49 | protoss_structures_constructed_min: z.number(), 50 | protoss_structures_constructed_sum: z.number(), 51 | protoss_structures_lost_max: z.number(), 52 | protoss_structures_lost_min: z.number(), 53 | protoss_structures_lost_sum: z.number(), 54 | protoss_structures_razed_max: z.number(), 55 | protoss_structures_razed_min: z.number(), 56 | protoss_structures_razed_sum: z.number(), 57 | protoss_structures_score_max: z.number(), 58 | protoss_structures_score_min: z.number(), 59 | protoss_structures_score_sum: z.number(), 60 | protoss_units_killed_max: z.number(), 61 | protoss_units_killed_min: z.number(), 62 | protoss_units_killed_sum: z.number(), 63 | protoss_units_lost_max: z.number(), 64 | protoss_units_lost_min: z.number(), 65 | protoss_units_lost_sum: z.number(), 66 | protoss_units_produced_max: z.number(), 67 | protoss_units_produced_min: z.number(), 68 | protoss_units_produced_sum: z.number(), 69 | protoss_units_score_max: z.number(), 70 | protoss_units_score_min: z.number(), 71 | protoss_units_score_sum: z.number(), 72 | protoss_wins_max: z.number(), 73 | protoss_wins_min: z.number(), 74 | protoss_wins_sum: z.number(), 75 | terran_apm_max: z.number(), 76 | terran_apm_min: z.number(), 77 | terran_apm_sum: z.number(), 78 | terran_disconnects_max: z.number(), 79 | terran_disconnects_min: z.number(), 80 | terran_disconnects_sum: z.number(), 81 | terran_draws_max: z.number(), 82 | terran_draws_min: z.number(), 83 | terran_draws_sum: z.number(), 84 | terran_losses_max: z.number(), 85 | terran_losses_min: z.number(), 86 | terran_losses_sum: z.number(), 87 | terran_play_time_max: z.number(), 88 | terran_play_time_min: z.number(), 89 | terran_play_time_sum: z.number(), 90 | terran_resources_gas_max: z.number(), 91 | terran_resources_gas_min: z.number(), 92 | terran_resources_gas_sum: z.number(), 93 | terran_resources_minerals_max: z.number(), 94 | terran_resources_minerals_min: z.number(), 95 | terran_resources_minerals_sum: z.number(), 96 | terran_resources_score_max: z.number(), 97 | terran_resources_score_min: z.number(), 98 | terran_resources_score_sum: z.number(), 99 | terran_resources_spent_max: z.number(), 100 | terran_resources_spent_min: z.number(), 101 | terran_resources_spent_sum: z.number(), 102 | terran_structures_constructed_max: z.number(), 103 | terran_structures_constructed_min: z.number(), 104 | terran_structures_constructed_sum: z.number(), 105 | terran_structures_lost_max: z.number(), 106 | terran_structures_lost_min: z.number(), 107 | terran_structures_lost_sum: z.number(), 108 | terran_structures_razed_max: z.number(), 109 | terran_structures_razed_min: z.number(), 110 | terran_structures_razed_sum: z.number(), 111 | terran_structures_score_max: z.number(), 112 | terran_structures_score_min: z.number(), 113 | terran_structures_score_sum: z.number(), 114 | terran_units_killed_max: z.number(), 115 | terran_units_killed_min: z.number(), 116 | terran_units_killed_sum: z.number(), 117 | terran_units_lost_max: z.number(), 118 | terran_units_lost_min: z.number(), 119 | terran_units_lost_sum: z.number(), 120 | terran_units_produced_max: z.number(), 121 | terran_units_produced_min: z.number(), 122 | terran_units_produced_sum: z.number(), 123 | terran_units_score_max: z.number(), 124 | terran_units_score_min: z.number(), 125 | terran_units_score_sum: z.number(), 126 | terran_wins_max: z.number(), 127 | terran_wins_min: z.number(), 128 | terran_wins_sum: z.number(), 129 | zerg_apm_max: z.number(), 130 | zerg_apm_min: z.number(), 131 | zerg_apm_sum: z.number(), 132 | zerg_disconnects_max: z.number(), 133 | zerg_disconnects_min: z.number(), 134 | zerg_disconnects_sum: z.number(), 135 | zerg_draws_max: z.number(), 136 | zerg_draws_min: z.number(), 137 | zerg_draws_sum: z.number(), 138 | zerg_losses_max: z.number(), 139 | zerg_losses_min: z.number(), 140 | zerg_losses_sum: z.number(), 141 | zerg_play_time_max: z.number(), 142 | zerg_play_time_min: z.number(), 143 | zerg_play_time_sum: z.number(), 144 | zerg_resources_gas_max: z.number(), 145 | zerg_resources_gas_min: z.number(), 146 | zerg_resources_gas_sum: z.number(), 147 | zerg_resources_minerals_max: z.number(), 148 | zerg_resources_minerals_min: z.number(), 149 | zerg_resources_minerals_sum: z.number(), 150 | zerg_resources_score_max: z.number(), 151 | zerg_resources_score_min: z.number(), 152 | zerg_resources_score_sum: z.number(), 153 | zerg_resources_spent_max: z.number(), 154 | zerg_resources_spent_min: z.number(), 155 | zerg_resources_spent_sum: z.number(), 156 | zerg_structures_constructed_max: z.number(), 157 | zerg_structures_constructed_min: z.number(), 158 | zerg_structures_constructed_sum: z.number(), 159 | zerg_structures_lost_max: z.number(), 160 | zerg_structures_lost_min: z.number(), 161 | zerg_structures_lost_sum: z.number(), 162 | zerg_structures_razed_max: z.number(), 163 | zerg_structures_razed_min: z.number(), 164 | zerg_structures_razed_sum: z.number(), 165 | zerg_structures_score_max: z.number(), 166 | zerg_structures_score_min: z.number(), 167 | zerg_structures_score_sum: z.number(), 168 | zerg_units_killed_max: z.number(), 169 | zerg_units_killed_min: z.number(), 170 | zerg_units_killed_sum: z.number(), 171 | zerg_units_lost_max: z.number(), 172 | zerg_units_lost_min: z.number(), 173 | zerg_units_lost_sum: z.number(), 174 | zerg_units_produced_max: z.number(), 175 | zerg_units_produced_min: z.number(), 176 | zerg_units_produced_sum: z.number(), 177 | zerg_units_score_max: z.number(), 178 | zerg_units_score_min: z.number(), 179 | zerg_units_score_sum: z.number(), 180 | zerg_wins_max: z.number(), 181 | zerg_wins_min: z.number(), 182 | zerg_wins_sum: z.number(), 183 | }), 184 | season_id: z.number(), 185 | toon: z.string(), 186 | }) 187 | ); 188 | 189 | const ReplaysSchema = z.array( 190 | z.object({ 191 | attributes: z.object({ 192 | game_creator: z.string(), 193 | game_id: z.string(), 194 | game_name: z.string(), 195 | game_save_id: z.string(), 196 | game_speed: z.string(), 197 | game_sub_type: z.string(), 198 | game_type: z.string(), 199 | map_era: z.string(), 200 | map_height: z.string(), 201 | map_title: z.string(), 202 | map_width: z.string(), 203 | replay_description: z.string(), 204 | replay_humans: z.string(), 205 | replay_map_number: z.string(), 206 | replay_max_players: z.string(), 207 | replay_min_players: z.string(), 208 | replay_opponents: z.string(), 209 | replay_player_names: z.string(), 210 | replay_player_races: z.string(), 211 | replay_player_types: z.string(), 212 | replay_result: z.string(), 213 | }), 214 | create_time: z.number(), 215 | link: z.string(), 216 | }) 217 | ); 218 | 219 | const MatchMakedStatsSchema = z.array( 220 | z.object({ 221 | benefactor_id: z.string(), 222 | bucket: z.number(), 223 | disconnects: z.number(), 224 | game_mode_id: z.number(), 225 | highest_points: z.number(), 226 | highest_rating: z.number(), 227 | loss_streak: z.number(), 228 | losses: z.number(), 229 | points: z.number(), 230 | rating: z.number(), 231 | season_id: z.number(), 232 | toon: z.string(), 233 | toon_guid: z.number(), 234 | win_streak: z.number(), 235 | wins: z.number(), 236 | }) 237 | ); 238 | 239 | const GameResultsSchema = z.array( 240 | z.object({ 241 | attributes: z.object({ 242 | client_version: z.string(), 243 | mapName: z.string(), 244 | tileset: z.string(), 245 | }), 246 | benefactor_id: z.string(), 247 | create_time: z.string(), 248 | game_id: z.string(), 249 | gateway_id: z.number(), 250 | match_guid: z.string(), 251 | players: z.array( 252 | z.union([ 253 | z.object({ 254 | attributes: z.object({ 255 | gPlayerData_idx: z.string(), 256 | left: z.string(), 257 | race: z.string(), 258 | team: z.string(), 259 | type: z.string(), 260 | }), 261 | result: z.string(), 262 | stats: z.union([ 263 | z.strictObject({}), 264 | z.intersection( 265 | z.object({ 266 | zerg_apm: z.string(), 267 | zerg_games_played: z.string(), 268 | zerg_play_time: z.string(), 269 | zerg_resources_gas: z.string(), 270 | zerg_resources_minerals: z.string(), 271 | zerg_resources_score: z.string(), 272 | zerg_resources_spent: z.string(), 273 | zerg_score_overall: z.string(), 274 | zerg_structures_constructed: z.string(), 275 | zerg_structures_lost: z.string(), 276 | zerg_structures_razed: z.string(), 277 | zerg_structures_score: z.string(), 278 | zerg_units_killed: z.string(), 279 | zerg_units_lost: z.string(), 280 | zerg_units_produced: z.string(), 281 | zerg_units_score: z.string(), 282 | }), 283 | z.union([ 284 | z.object({ 285 | zerg_draws: z.string(), 286 | }), 287 | z.object({ 288 | zerg_losses: z.string(), 289 | }), 290 | z.object({ 291 | zerg_wins: z.string(), 292 | }), 293 | ]) 294 | ), 295 | z.intersection( 296 | z.object({ 297 | terran_apm: z.string(), 298 | terran_games_played: z.string(), 299 | terran_play_time: z.string(), 300 | terran_resources_gas: z.string(), 301 | terran_resources_minerals: z.string(), 302 | terran_resources_score: z.string(), 303 | terran_resources_spent: z.string(), 304 | terran_score_overall: z.string(), 305 | terran_structures_constructed: z.string(), 306 | terran_structures_lost: z.string(), 307 | terran_structures_razed: z.string(), 308 | terran_structures_score: z.string(), 309 | terran_units_killed: z.string(), 310 | terran_units_lost: z.string(), 311 | terran_units_produced: z.string(), 312 | terran_units_score: z.string(), 313 | }), 314 | z.union([ 315 | z.object({ 316 | terran_draws: z.string(), 317 | }), 318 | z.object({ 319 | terran_losses: z.string(), 320 | }), 321 | z.object({ 322 | terran_wins: z.string(), 323 | }), 324 | ]) 325 | ), 326 | z.intersection( 327 | z.object({ 328 | protoss_apm: z.string(), 329 | protoss_games_played: z.string(), 330 | protoss_play_time: z.string(), 331 | protoss_resources_gas: z.string(), 332 | protoss_resources_minerals: z.string(), 333 | protoss_resources_score: z.string(), 334 | protoss_resources_spent: z.string(), 335 | protoss_score_overall: z.string(), 336 | protoss_structures_constructed: z.string(), 337 | protoss_structures_lost: z.string(), 338 | protoss_structures_razed: z.string(), 339 | protoss_structures_score: z.string(), 340 | protoss_units_killed: z.string(), 341 | protoss_units_lost: z.string(), 342 | protoss_units_produced: z.string(), 343 | protoss_units_score: z.string(), 344 | }), 345 | z.union([ 346 | z.object({ 347 | protoss_draws: z.string(), 348 | }), 349 | z.object({ 350 | protoss_losses: z.string(), 351 | }), 352 | z.object({ 353 | protoss_wins: z.string(), 354 | }), 355 | ]) 356 | ), 357 | ]), 358 | toon: z.string(), 359 | }), 360 | z.object({ 361 | attributes: z.object({ 362 | gPlayerData_idx: z.string(), 363 | left: z.string(), 364 | type: z.string(), 365 | }), 366 | result: z.string(), 367 | stats: z.object({}), 368 | toon: z.string(), 369 | }), 370 | z.object({ 371 | attributes: z.object({ 372 | gPlayerData_idx: z.string(), 373 | left: z.string(), 374 | race: z.string(), 375 | team: z.string(), 376 | type: z.string(), 377 | }), 378 | result: z.string(), 379 | stats: z.object({}), 380 | toon: z.string(), 381 | }), 382 | ]) 383 | ), 384 | }) 385 | ); 386 | 387 | export const AuroraProfileByToonSupersetNoResultResponseSchema = z.object({ 388 | aurora_id: z.literal(0), 389 | avatars: z.record(z.string(), z.string()), 390 | avatars_framed: z.record( 391 | z.string(), 392 | z.object({ 393 | level: z.literal(0), 394 | stat: z.literal(""), 395 | url: z.string(), 396 | }) 397 | ), 398 | avatars_unlocked: z.record( 399 | z.string(), 400 | z.object({ 401 | level: z.number(), 402 | stat: z.string(), 403 | url: z.string(), 404 | }) 405 | ), 406 | game_results: GameResultsSchema.length(0), 407 | matchmaked_current_season: z.number(), 408 | matchmaked_current_season_buckets: z.array(z.number()), 409 | matchmaked_stats: MatchMakedStatsSchema.length(0), 410 | profiles: z.null(), 411 | program_id: z.string(), 412 | replays: ReplaysSchema.length(0), 413 | stats: StatsSchema.length(0), 414 | toon_guid_by_gateway: z.object({}), 415 | toons: ToonsSchema.length(0), 416 | }); 417 | 418 | export const AuroraProfileByToonSupersetResponseSchema = z.object({ 419 | account_flags: z.string().optional(), 420 | aurora_id: z.number().nonnegative().int(), 421 | avatars: z.record(z.string(), z.string()), 422 | avatars_framed: z.record( 423 | z.string(), 424 | z.object({ 425 | level: z.number(), 426 | stat: z.string(), 427 | url: z.string(), 428 | }) 429 | ), 430 | avatars_unlocked: z.record( 431 | z.string(), 432 | z.object({ 433 | level: z.number(), 434 | stat: z.string(), 435 | url: z.string(), 436 | }) 437 | ), 438 | battle_tag: z.string(), 439 | country_code: z.string(), 440 | game_results: GameResultsSchema, 441 | matchmaked_current_season: z.number(), 442 | matchmaked_current_season_buckets: z.array(z.number()), 443 | matchmaked_stats: MatchMakedStatsSchema, 444 | profiles: z 445 | .array( 446 | z.object({ 447 | avatar_id: z.string(), 448 | description: z.string(), 449 | private: z.boolean(), 450 | show_avatar_frame: z.boolean(), 451 | title: z.string(), 452 | toon: z.string(), 453 | toon_guid: z.number(), 454 | }) 455 | ) 456 | .nullable(), 457 | program_id: z.string(), 458 | replays: ReplaysSchema, 459 | stats: StatsSchema, 460 | toon_guid_by_gateway: z.record( 461 | z.string().regex(/^\d+$/), // gateway 462 | z.record(z.string(), z.number()) // toon -> guid 463 | ), 464 | toons: ToonsSchema, 465 | }); 466 | 467 | export type AuroraProfileByToonSupersetResponse = z.infer< 468 | typeof AuroraProfileByToonSupersetResponseSchema 469 | >; 470 | -------------------------------------------------------------------------------- /test/api.test.ts: -------------------------------------------------------------------------------- 1 | import { Region, SCApi } from "@/api"; 2 | import { BroodWarConnection } from "@/bw-connection"; 3 | import { readFile } from "fs/promises"; 4 | import { assert, describe, it, vi } from "vitest"; 5 | 6 | const encodeURIByParts = (parts: string) => 7 | parts.split("/").map(encodeURIComponent).join("/"); 8 | 9 | vi.stubGlobal("fetch", async (path: string) => ({ 10 | text: async () => { 11 | const response = await readFile( 12 | `./test/data/${encodeURIByParts(path)}.json`, 13 | "utf8" 14 | ); 15 | 16 | return response; 17 | }, 18 | })); 19 | 20 | describe("SCApi", () => { 21 | const api = new SCApi(new BroodWarConnection("")); 22 | 23 | it("can fetch and parse the classic files global maps 1v1 API response", async () => { 24 | await api.classicFilesGlobalMaps1v1(); 25 | }); 26 | 27 | it("can fetch and parse the gateway API response", async () => { 28 | await api.gateway(); 29 | }); 30 | 31 | it("can fetch and parse the leaderboard entity API response", async () => { 32 | await api.leaderboardEntity(1); 33 | }); 34 | 35 | it("can fetch and parse the leaderboard name search API response", async () => { 36 | await api.leaderboardNameSearch(1, "bob"); 37 | }); 38 | 39 | it("can fetch and parse the leaderboard rank by toon API response", async () => { 40 | await api.leaderboardRankByToon(1, "bob", Region.USWest); 41 | }); 42 | 43 | it("can fetch and parse the leaderboard API response", async () => { 44 | await api.leaderboard(); 45 | }); 46 | 47 | it("can fetch and parse the map stats by toon API response", async () => { 48 | const stats = await api.mapStatsByToon("bob", Region.USWest); 49 | assert(stats.map_stat); 50 | }); 51 | 52 | it("can fetch and parse the match maker game info by toon API response", async () => { 53 | await api.matchMakerGameInfoByToon("bob", Region.USWest, 1, 1); 54 | }); 55 | 56 | it("can fetch and parse the match maker player info API response", async () => { 57 | await api.matchMakerGameInfoPlayerInfo("mm-test"); 58 | }); 59 | 60 | it("can fetch and parse the aurora profile by toon with scr_mmgameloading mask API response", async () => { 61 | await api.auroraProfileByToon("bob", Region.USWest, "scr_mmgameloading"); 62 | }); 63 | 64 | it("can fetch and parse the aurora profile by toon with scr_mmtooninfo mask API response", async () => { 65 | await api.auroraProfileByToon("bob", Region.USWest, "scr_mmtooninfo"); 66 | }); 67 | 68 | it("can fetch and parse the aurora profile by toon with scr_profile mask API response", async () => { 69 | await api.auroraProfileByToon("bob", Region.USWest, "scr_profile"); 70 | }); 71 | 72 | it("can fetch and parse the aurora profile by toon with scr_tooninfo mask API response", async () => { 73 | await api.auroraProfileByToon("bob", Region.USWest, "scr_tooninfo"); 74 | }); 75 | }); 76 | -------------------------------------------------------------------------------- /test/data/web-api/v1/gateway.json: -------------------------------------------------------------------------------- 1 | { 2 | "10": { 3 | "is_official": true, 4 | "name": "U.S. West", 5 | "online_users": 1077, 6 | "region": "usw" 7 | }, 8 | "11": { 9 | "is_official": true, 10 | "name": "U.S. East", 11 | "online_users": 113, 12 | "region": "use" 13 | }, 14 | "20": { 15 | "is_official": true, 16 | "name": "Europe", 17 | "online_users": 420, 18 | "region": "eu" 19 | }, 20 | "30": { 21 | "is_official": true, 22 | "name": "Korea", 23 | "online_users": 6037, 24 | "region": "kr" 25 | }, 26 | "45": { 27 | "is_official": true, 28 | "name": "Asia", 29 | "online_users": 164, 30 | "region": "asia" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /test/data/web-api/v1/leaderboard-name-search/1/bob.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "avatar": "", 4 | "battletag": "Bob", 5 | "gateway_id": 10, 6 | "last_rank": 3070, 7 | "name": "bob", 8 | "points": 2104, 9 | "rank": 3070 10 | }, 11 | { 12 | "avatar": "", 13 | "battletag": "Bobbbyy", 14 | "gateway_id": 11, 15 | "last_rank": 2589, 16 | "name": "asdf", 17 | "points": 2123, 18 | "rank": 2589 19 | } 20 | ] 21 | -------------------------------------------------------------------------------- /test/data/web-api/v1/leaderboard-rank-by-toon/1/bob/10.json: -------------------------------------------------------------------------------- 1 | { 2 | "aurora_id": 18578165, 3 | "gateway_id": 0, 4 | "leaderboard_id": 12948, 5 | "matchmaked_current_season": 13, 6 | "matchmaked_current_season_buckets": [ 7 | 0, 1163, 1397, 1561, 1742, 2028, 2244, 9999 8 | ], 9 | "mingames": 5, 10 | "toons": [ 11 | { 12 | "avatar": "", 13 | "battletag": "조기석", 14 | "bucket": 7, 15 | "disconnects": 0, 16 | "feature_stat": "terran", 17 | "gateway_id": 30, 18 | "last_rank": 100, 19 | "losses": 26, 20 | "name": "sdsdsadasdsdsda", 21 | "points": 2452, 22 | "rank": 101, 23 | "wins": 60 24 | }, 25 | { 26 | "avatar": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/bacfd18d7eaa155bdd694ee607cad8fd.png", 27 | "battletag": "조기석", 28 | "bucket": 7, 29 | "disconnects": 0, 30 | "feature_stat": "terran", 31 | "gateway_id": 11, 32 | "last_rank": 120, 33 | "losses": 17, 34 | "name": "iiiiilililli", 35 | "points": 2433, 36 | "rank": 121, 37 | "wins": 48 38 | }, 39 | { 40 | "avatar": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/305f777452daf1196ba0ea8a6b59184f.png", 41 | "battletag": "조기석", 42 | "bucket": 7, 43 | "disconnects": 0, 44 | "feature_stat": "terran", 45 | "gateway_id": 45, 46 | "last_rank": 138, 47 | "losses": 1, 48 | "name": "iiilililiilllii", 49 | "points": 2420, 50 | "rank": 139, 51 | "wins": 16 52 | }, 53 | { 54 | "avatar": "", 55 | "battletag": "조기석", 56 | "bucket": 6, 57 | "disconnects": 0, 58 | "feature_stat": "terran", 59 | "gateway_id": 45, 60 | "last_rank": 1260, 61 | "losses": 21, 62 | "name": "iiiiiillililiii", 63 | "points": 2199, 64 | "rank": 1261, 65 | "wins": 52 66 | }, 67 | { 68 | "avatar": "", 69 | "battletag": "조기석", 70 | "bucket": 6, 71 | "disconnects": 0, 72 | "feature_stat": "terran", 73 | "gateway_id": 30, 74 | "last_rank": 3595, 75 | "losses": 2, 76 | "name": "Sharp1", 77 | "points": 2074, 78 | "rank": 3597, 79 | "wins": 10 80 | }, 81 | { 82 | "avatar": "", 83 | "battletag": "조기석", 84 | "bucket": 4, 85 | "disconnects": 0, 86 | "feature_stat": "terran", 87 | "gateway_id": 10, 88 | "last_rank": 24160, 89 | "losses": 5, 90 | "name": "iiilililililill", 91 | "points": 1647, 92 | "rank": 24160, 93 | "wins": 0 94 | } 95 | ], 96 | "total_rows": 59127 97 | } 98 | -------------------------------------------------------------------------------- /test/data/web-api/v1/leaderboard.json: -------------------------------------------------------------------------------- 1 | { 2 | "gamemodes": { "1": { "name": "1v1" } }, 3 | "gateways": { 4 | "10": { "is_official": true, "name": "U.S. West", "region": "usw" }, 5 | "11": { "is_official": true, "name": "U.S. East", "region": "use" }, 6 | "20": { "is_official": true, "name": "Europe", "region": "eu" }, 7 | "30": { "is_official": true, "name": "Korea", "region": "kr" }, 8 | "45": { "is_official": true, "name": "Asia", "region": "asia" } 9 | }, 10 | "leaderboards": { 11 | "1": { 12 | "benefactor_id": "0", 13 | "gamemode_id": 1, 14 | "gateway_id": 0, 15 | "id": 1, 16 | "last_update_time": "1679585287", 17 | "name": "Global", 18 | "next_update_time": "1679585587", 19 | "program_id": "S1", 20 | "season_id": 1, 21 | "season_name": "" 22 | }, 23 | "10": { 24 | "benefactor_id": "0", 25 | "gamemode_id": 1, 26 | "gateway_id": 20, 27 | "id": 10, 28 | "last_update_time": "1679585397", 29 | "name": "Europe", 30 | "next_update_time": "1679585697", 31 | "program_id": "S1", 32 | "season_id": 2, 33 | "season_name": "2018 %s 1" 34 | }, 35 | "10414": { 36 | "benefactor_id": "0", 37 | "gamemode_id": 1, 38 | "gateway_id": 0, 39 | "id": 10414, 40 | "last_update_time": "1679585497", 41 | "name": "Global", 42 | "next_update_time": "1679585797", 43 | "program_id": "S1", 44 | "season_id": 8, 45 | "season_name": "%s 7" 46 | }, 47 | "10415": { 48 | "benefactor_id": "0", 49 | "gamemode_id": 1, 50 | "gateway_id": 10, 51 | "id": 10415, 52 | "last_update_time": "1679585499", 53 | "name": "U.S. West", 54 | "next_update_time": "1679585799", 55 | "program_id": "S1", 56 | "season_id": 8, 57 | "season_name": "%s 7" 58 | }, 59 | "10416": { 60 | "benefactor_id": "0", 61 | "gamemode_id": 1, 62 | "gateway_id": 11, 63 | "id": 10416, 64 | "last_update_time": "1679585501", 65 | "name": "U.S. East", 66 | "next_update_time": "1679585801", 67 | "program_id": "S1", 68 | "season_id": 8, 69 | "season_name": "%s 7" 70 | }, 71 | "10417": { 72 | "benefactor_id": "0", 73 | "gamemode_id": 1, 74 | "gateway_id": 20, 75 | "id": 10417, 76 | "last_update_time": "1679585502", 77 | "name": "Europe", 78 | "next_update_time": "1679585802", 79 | "program_id": "S1", 80 | "season_id": 8, 81 | "season_name": "%s 7" 82 | }, 83 | "10418": { 84 | "benefactor_id": "0", 85 | "gamemode_id": 1, 86 | "gateway_id": 30, 87 | "id": 10418, 88 | "last_update_time": "1679585506", 89 | "name": "Korea", 90 | "next_update_time": "1679585806", 91 | "program_id": "S1", 92 | "season_id": 8, 93 | "season_name": "%s 7" 94 | }, 95 | "10419": { 96 | "benefactor_id": "0", 97 | "gamemode_id": 1, 98 | "gateway_id": 45, 99 | "id": 10419, 100 | "last_update_time": "1679585508", 101 | "name": "Asia", 102 | "next_update_time": "1679585808", 103 | "program_id": "S1", 104 | "season_id": 8, 105 | "season_name": "%s 7" 106 | }, 107 | "11": { 108 | "benefactor_id": "0", 109 | "gamemode_id": 1, 110 | "gateway_id": 45, 111 | "id": 11, 112 | "last_update_time": "1679585399", 113 | "name": "Asia", 114 | "next_update_time": "1679585699", 115 | "program_id": "S1", 116 | "season_id": 2, 117 | "season_name": "2018 %s 1" 118 | }, 119 | "11685": { 120 | "benefactor_id": "0", 121 | "gamemode_id": 1, 122 | "gateway_id": 0, 123 | "id": 11685, 124 | "last_update_time": "1679585513", 125 | "name": "Global", 126 | "next_update_time": "1679585813", 127 | "program_id": "S1", 128 | "season_id": 9, 129 | "season_name": "%s 8" 130 | }, 131 | "11686": { 132 | "benefactor_id": "0", 133 | "gamemode_id": 1, 134 | "gateway_id": 10, 135 | "id": 11686, 136 | "last_update_time": "1679585514", 137 | "name": "U.S. West", 138 | "next_update_time": "1679585814", 139 | "program_id": "S1", 140 | "season_id": 9, 141 | "season_name": "%s 8" 142 | }, 143 | "11687": { 144 | "benefactor_id": "0", 145 | "gamemode_id": 1, 146 | "gateway_id": 11, 147 | "id": 11687, 148 | "last_update_time": "1679585516", 149 | "name": "U.S. East", 150 | "next_update_time": "1679585816", 151 | "program_id": "S1", 152 | "season_id": 9, 153 | "season_name": "%s 8" 154 | }, 155 | "11688": { 156 | "benefactor_id": "0", 157 | "gamemode_id": 1, 158 | "gateway_id": 20, 159 | "id": 11688, 160 | "last_update_time": "1679585518", 161 | "name": "Europe", 162 | "next_update_time": "1679585818", 163 | "program_id": "S1", 164 | "season_id": 9, 165 | "season_name": "%s 8" 166 | }, 167 | "11689": { 168 | "benefactor_id": "0", 169 | "gamemode_id": 1, 170 | "gateway_id": 30, 171 | "id": 11689, 172 | "last_update_time": "1679585522", 173 | "name": "Korea", 174 | "next_update_time": "1679585822", 175 | "program_id": "S1", 176 | "season_id": 9, 177 | "season_name": "%s 8" 178 | }, 179 | "11690": { 180 | "benefactor_id": "0", 181 | "gamemode_id": 1, 182 | "gateway_id": 45, 183 | "id": 11690, 184 | "last_update_time": "1679585524", 185 | "name": "Asia", 186 | "next_update_time": "1679585824", 187 | "program_id": "S1", 188 | "season_id": 9, 189 | "season_name": "%s 8" 190 | }, 191 | "12": { 192 | "benefactor_id": "0", 193 | "gamemode_id": 1, 194 | "gateway_id": 30, 195 | "id": 12, 196 | "last_update_time": "1679585403", 197 | "name": "Korea", 198 | "next_update_time": "1679585703", 199 | "program_id": "S1", 200 | "season_id": 2, 201 | "season_name": "2018 %s 1" 202 | }, 203 | "12716": { 204 | "benefactor_id": "0", 205 | "gamemode_id": 1, 206 | "gateway_id": 0, 207 | "id": 12716, 208 | "last_update_time": "1679585535", 209 | "name": "Global", 210 | "next_update_time": "1679585835", 211 | "program_id": "S1", 212 | "season_id": 10, 213 | "season_name": "%s 9" 214 | }, 215 | "12717": { 216 | "benefactor_id": "0", 217 | "gamemode_id": 1, 218 | "gateway_id": 10, 219 | "id": 12717, 220 | "last_update_time": "1679585539", 221 | "name": "U.S. West", 222 | "next_update_time": "1679585839", 223 | "program_id": "S1", 224 | "season_id": 10, 225 | "season_name": "%s 9" 226 | }, 227 | "12718": { 228 | "benefactor_id": "0", 229 | "gamemode_id": 1, 230 | "gateway_id": 11, 231 | "id": 12718, 232 | "last_update_time": "1679585242", 233 | "name": "U.S. East", 234 | "next_update_time": "1679585542", 235 | "program_id": "S1", 236 | "season_id": 10, 237 | "season_name": "%s 9" 238 | }, 239 | "12719": { 240 | "benefactor_id": "0", 241 | "gamemode_id": 1, 242 | "gateway_id": 20, 243 | "id": 12719, 244 | "last_update_time": "1679585246", 245 | "name": "Europe", 246 | "next_update_time": "1679585546", 247 | "program_id": "S1", 248 | "season_id": 10, 249 | "season_name": "%s 9" 250 | }, 251 | "12720": { 252 | "benefactor_id": "0", 253 | "gamemode_id": 1, 254 | "gateway_id": 30, 255 | "id": 12720, 256 | "last_update_time": "1679585256", 257 | "name": "Korea", 258 | "next_update_time": "1679585556", 259 | "program_id": "S1", 260 | "season_id": 10, 261 | "season_name": "%s 9" 262 | }, 263 | "12721": { 264 | "benefactor_id": "0", 265 | "gamemode_id": 1, 266 | "gateway_id": 45, 267 | "id": 12721, 268 | "last_update_time": "1679585259", 269 | "name": "Asia", 270 | "next_update_time": "1679585559", 271 | "program_id": "S1", 272 | "season_id": 10, 273 | "season_name": "%s 9" 274 | }, 275 | "12931": { 276 | "benefactor_id": "0", 277 | "gamemode_id": 1, 278 | "gateway_id": 0, 279 | "id": 12931, 280 | "last_update_time": "1679585275", 281 | "name": "Global", 282 | "next_update_time": "1679585575", 283 | "program_id": "S1", 284 | "season_id": 11, 285 | "season_name": "%s 10" 286 | }, 287 | "12932": { 288 | "benefactor_id": "0", 289 | "gamemode_id": 1, 290 | "gateway_id": 10, 291 | "id": 12932, 292 | "last_update_time": "1679585280", 293 | "name": "U.S. West", 294 | "next_update_time": "1679585580", 295 | "program_id": "S1", 296 | "season_id": 11, 297 | "season_name": "%s 10" 298 | }, 299 | "12933": { 300 | "benefactor_id": "0", 301 | "gamemode_id": 1, 302 | "gateway_id": 11, 303 | "id": 12933, 304 | "last_update_time": "1679585284", 305 | "name": "U.S. East", 306 | "next_update_time": "1679585584", 307 | "program_id": "S1", 308 | "season_id": 11, 309 | "season_name": "%s 10" 310 | }, 311 | "12934": { 312 | "benefactor_id": "0", 313 | "gamemode_id": 1, 314 | "gateway_id": 20, 315 | "id": 12934, 316 | "last_update_time": "1679585289", 317 | "name": "Europe", 318 | "next_update_time": "1679585589", 319 | "program_id": "S1", 320 | "season_id": 11, 321 | "season_name": "%s 10" 322 | }, 323 | "12935": { 324 | "benefactor_id": "0", 325 | "gamemode_id": 1, 326 | "gateway_id": 30, 327 | "id": 12935, 328 | "last_update_time": "1679585303", 329 | "name": "Korea", 330 | "next_update_time": "1679585603", 331 | "program_id": "S1", 332 | "season_id": 11, 333 | "season_name": "%s 10" 334 | }, 335 | "12936": { 336 | "benefactor_id": "0", 337 | "gamemode_id": 1, 338 | "gateway_id": 45, 339 | "id": 12936, 340 | "last_update_time": "1679585308", 341 | "name": "Asia", 342 | "next_update_time": "1679585608", 343 | "program_id": "S1", 344 | "season_id": 11, 345 | "season_name": "%s 10" 346 | }, 347 | "12941": { 348 | "benefactor_id": "0", 349 | "gamemode_id": 1, 350 | "gateway_id": 0, 351 | "id": 12941, 352 | "last_update_time": "1679585315", 353 | "name": "Global", 354 | "next_update_time": "1679585615", 355 | "program_id": "S1", 356 | "season_id": 12, 357 | "season_name": "%s 11" 358 | }, 359 | "12942": { 360 | "benefactor_id": "0", 361 | "gamemode_id": 1, 362 | "gateway_id": 10, 363 | "id": 12942, 364 | "last_update_time": "1679585318", 365 | "name": "U.S. West", 366 | "next_update_time": "1679585618", 367 | "program_id": "S1", 368 | "season_id": 12, 369 | "season_name": "%s 11" 370 | }, 371 | "12943": { 372 | "benefactor_id": "0", 373 | "gamemode_id": 1, 374 | "gateway_id": 11, 375 | "id": 12943, 376 | "last_update_time": "1679585320", 377 | "name": "U.S. East", 378 | "next_update_time": "1679585620", 379 | "program_id": "S1", 380 | "season_id": 12, 381 | "season_name": "%s 11" 382 | }, 383 | "12944": { 384 | "benefactor_id": "0", 385 | "gamemode_id": 1, 386 | "gateway_id": 20, 387 | "id": 12944, 388 | "last_update_time": "1679585323", 389 | "name": "Europe", 390 | "next_update_time": "1679585623", 391 | "program_id": "S1", 392 | "season_id": 12, 393 | "season_name": "%s 11" 394 | }, 395 | "12945": { 396 | "benefactor_id": "0", 397 | "gamemode_id": 1, 398 | "gateway_id": 30, 399 | "id": 12945, 400 | "last_update_time": "1679585330", 401 | "name": "Korea", 402 | "next_update_time": "1679585630", 403 | "program_id": "S1", 404 | "season_id": 12, 405 | "season_name": "%s 11" 406 | }, 407 | "12946": { 408 | "benefactor_id": "0", 409 | "gamemode_id": 1, 410 | "gateway_id": 45, 411 | "id": 12946, 412 | "last_update_time": "1679585332", 413 | "name": "Asia", 414 | "next_update_time": "1679585632", 415 | "program_id": "S1", 416 | "season_id": 12, 417 | "season_name": "%s 11" 418 | }, 419 | "12948": { 420 | "benefactor_id": "0", 421 | "gamemode_id": 1, 422 | "gateway_id": 0, 423 | "id": 12948, 424 | "last_update_time": "1679585337", 425 | "name": "Global", 426 | "next_update_time": "1679585637", 427 | "program_id": "S1", 428 | "season_id": 13, 429 | "season_name": "2023 %s 1" 430 | }, 431 | "12949": { 432 | "benefactor_id": "0", 433 | "gamemode_id": 1, 434 | "gateway_id": 10, 435 | "id": 12949, 436 | "last_update_time": "1679585339", 437 | "name": "U.S. West", 438 | "next_update_time": "1679585639", 439 | "program_id": "S1", 440 | "season_id": 13, 441 | "season_name": "2023 %s 1" 442 | }, 443 | "12950": { 444 | "benefactor_id": "0", 445 | "gamemode_id": 1, 446 | "gateway_id": 11, 447 | "id": 12950, 448 | "last_update_time": "1679585341", 449 | "name": "U.S. East", 450 | "next_update_time": "1679585641", 451 | "program_id": "S1", 452 | "season_id": 13, 453 | "season_name": "2023 %s 1" 454 | }, 455 | "12951": { 456 | "benefactor_id": "0", 457 | "gamemode_id": 1, 458 | "gateway_id": 20, 459 | "id": 12951, 460 | "last_update_time": "1679585343", 461 | "name": "Europe", 462 | "next_update_time": "1679585643", 463 | "program_id": "S1", 464 | "season_id": 13, 465 | "season_name": "2023 %s 1" 466 | }, 467 | "12952": { 468 | "benefactor_id": "0", 469 | "gamemode_id": 1, 470 | "gateway_id": 30, 471 | "id": 12952, 472 | "last_update_time": "1679585347", 473 | "name": "Korea", 474 | "next_update_time": "1679585647", 475 | "program_id": "S1", 476 | "season_id": 13, 477 | "season_name": "2023 %s 1" 478 | }, 479 | "12953": { 480 | "benefactor_id": "0", 481 | "gamemode_id": 1, 482 | "gateway_id": 45, 483 | "id": 12953, 484 | "last_update_time": "1679585349", 485 | "name": "Asia", 486 | "next_update_time": "1679585649", 487 | "program_id": "S1", 488 | "season_id": 13, 489 | "season_name": "2023 %s 1" 490 | }, 491 | "13": { 492 | "benefactor_id": "0", 493 | "gamemode_id": 1, 494 | "gateway_id": 0, 495 | "id": 13, 496 | "last_update_time": "1679585411", 497 | "name": "Global", 498 | "next_update_time": "1679585711", 499 | "program_id": "S1", 500 | "season_id": 3, 501 | "season_name": "2018 %s 2" 502 | }, 503 | "14": { 504 | "benefactor_id": "0", 505 | "gamemode_id": 1, 506 | "gateway_id": 10, 507 | "id": 14, 508 | "last_update_time": "1679585413", 509 | "name": "U.S. West", 510 | "next_update_time": "1679585713", 511 | "program_id": "S1", 512 | "season_id": 3, 513 | "season_name": "2018 %s 2" 514 | }, 515 | "15": { 516 | "benefactor_id": "0", 517 | "gamemode_id": 1, 518 | "gateway_id": 11, 519 | "id": 15, 520 | "last_update_time": "1679585415", 521 | "name": "U.S. East", 522 | "next_update_time": "1679585715", 523 | "program_id": "S1", 524 | "season_id": 3, 525 | "season_name": "2018 %s 2" 526 | }, 527 | "16": { 528 | "benefactor_id": "0", 529 | "gamemode_id": 1, 530 | "gateway_id": 20, 531 | "id": 16, 532 | "last_update_time": "1679585417", 533 | "name": "Europe", 534 | "next_update_time": "1679585717", 535 | "program_id": "S1", 536 | "season_id": 3, 537 | "season_name": "2018 %s 2" 538 | }, 539 | "17": { 540 | "benefactor_id": "0", 541 | "gamemode_id": 1, 542 | "gateway_id": 45, 543 | "id": 17, 544 | "last_update_time": "1679585419", 545 | "name": "Asia", 546 | "next_update_time": "1679585719", 547 | "program_id": "S1", 548 | "season_id": 3, 549 | "season_name": "2018 %s 2" 550 | }, 551 | "18": { 552 | "benefactor_id": "0", 553 | "gamemode_id": 1, 554 | "gateway_id": 30, 555 | "id": 18, 556 | "last_update_time": "1679585425", 557 | "name": "Korea", 558 | "next_update_time": "1679585725", 559 | "program_id": "S1", 560 | "season_id": 3, 561 | "season_name": "2018 %s 2" 562 | }, 563 | "19": { 564 | "benefactor_id": "0", 565 | "gamemode_id": 1, 566 | "gateway_id": 0, 567 | "id": 19, 568 | "last_update_time": "1679585431", 569 | "name": "Global", 570 | "next_update_time": "1679585731", 571 | "program_id": "S1", 572 | "season_id": 5, 573 | "season_name": "2019 %s 2" 574 | }, 575 | "2": { 576 | "benefactor_id": "0", 577 | "gamemode_id": 1, 578 | "gateway_id": 10, 579 | "id": 2, 580 | "last_update_time": "1679585302", 581 | "name": "U.S. West", 582 | "next_update_time": "1679585602", 583 | "program_id": "S1", 584 | "season_id": 1, 585 | "season_name": "" 586 | }, 587 | "20": { 588 | "benefactor_id": "0", 589 | "gamemode_id": 1, 590 | "gateway_id": 10, 591 | "id": 20, 592 | "last_update_time": "1679585433", 593 | "name": "U.S. West", 594 | "next_update_time": "1679585733", 595 | "program_id": "S1", 596 | "season_id": 5, 597 | "season_name": "2019 %s 2" 598 | }, 599 | "21": { 600 | "benefactor_id": "0", 601 | "gamemode_id": 1, 602 | "gateway_id": 11, 603 | "id": 21, 604 | "last_update_time": "1679585434", 605 | "name": "U.S. East", 606 | "next_update_time": "1679585734", 607 | "program_id": "S1", 608 | "season_id": 5, 609 | "season_name": "2019 %s 2" 610 | }, 611 | "22": { 612 | "benefactor_id": "0", 613 | "gamemode_id": 1, 614 | "gateway_id": 20, 615 | "id": 22, 616 | "last_update_time": "1679585436", 617 | "name": "Europe", 618 | "next_update_time": "1679585736", 619 | "program_id": "S1", 620 | "season_id": 5, 621 | "season_name": "2019 %s 2" 622 | }, 623 | "23": { 624 | "benefactor_id": "0", 625 | "gamemode_id": 1, 626 | "gateway_id": 30, 627 | "id": 23, 628 | "last_update_time": "1679585441", 629 | "name": "Korea", 630 | "next_update_time": "1679585741", 631 | "program_id": "S1", 632 | "season_id": 5, 633 | "season_name": "2019 %s 2" 634 | }, 635 | "24": { 636 | "benefactor_id": "0", 637 | "gamemode_id": 1, 638 | "gateway_id": 45, 639 | "id": 24, 640 | "last_update_time": "1679585443", 641 | "name": "Asia", 642 | "next_update_time": "1679585743", 643 | "program_id": "S1", 644 | "season_id": 5, 645 | "season_name": "2019 %s 2" 646 | }, 647 | "25": { 648 | "benefactor_id": "0", 649 | "gamemode_id": 1, 650 | "gateway_id": 0, 651 | "id": 25, 652 | "last_update_time": "1679585447", 653 | "name": "Global", 654 | "next_update_time": "1679585747", 655 | "program_id": "S1", 656 | "season_id": 6, 657 | "season_name": "%s 5" 658 | }, 659 | "26": { 660 | "benefactor_id": "0", 661 | "gamemode_id": 1, 662 | "gateway_id": 10, 663 | "id": 26, 664 | "last_update_time": "1679585449", 665 | "name": "U.S. West", 666 | "next_update_time": "1679585749", 667 | "program_id": "S1", 668 | "season_id": 6, 669 | "season_name": "%s 5" 670 | }, 671 | "27": { 672 | "benefactor_id": "0", 673 | "gamemode_id": 1, 674 | "gateway_id": 11, 675 | "id": 27, 676 | "last_update_time": "1679585450", 677 | "name": "U.S. East", 678 | "next_update_time": "1679585750", 679 | "program_id": "S1", 680 | "season_id": 6, 681 | "season_name": "%s 5" 682 | }, 683 | "28": { 684 | "benefactor_id": "0", 685 | "gamemode_id": 1, 686 | "gateway_id": 20, 687 | "id": 28, 688 | "last_update_time": "1679585451", 689 | "name": "Europe", 690 | "next_update_time": "1679585751", 691 | "program_id": "S1", 692 | "season_id": 6, 693 | "season_name": "%s 5" 694 | }, 695 | "29": { 696 | "benefactor_id": "0", 697 | "gamemode_id": 1, 698 | "gateway_id": 30, 699 | "id": 29, 700 | "last_update_time": "1679585454", 701 | "name": "Korea", 702 | "next_update_time": "1679585754", 703 | "program_id": "S1", 704 | "season_id": 6, 705 | "season_name": "%s 5" 706 | }, 707 | "3": { 708 | "benefactor_id": "0", 709 | "gamemode_id": 1, 710 | "gateway_id": 11, 711 | "id": 3, 712 | "last_update_time": "1679585317", 713 | "name": "U.S. East", 714 | "next_update_time": "1679585617", 715 | "program_id": "S1", 716 | "season_id": 1, 717 | "season_name": "" 718 | }, 719 | "30": { 720 | "benefactor_id": "0", 721 | "gamemode_id": 1, 722 | "gateway_id": 45, 723 | "id": 30, 724 | "last_update_time": "1679585456", 725 | "name": "Asia", 726 | "next_update_time": "1679585756", 727 | "program_id": "S1", 728 | "season_id": 6, 729 | "season_name": "%s 5" 730 | }, 731 | "31": { 732 | "benefactor_id": "0", 733 | "gamemode_id": 1, 734 | "gateway_id": 0, 735 | "id": 31, 736 | "last_update_time": "1679585461", 737 | "name": "Global", 738 | "next_update_time": "1679585761", 739 | "program_id": "S1", 740 | "season_id": 7, 741 | "season_name": "%s 6" 742 | }, 743 | "32": { 744 | "benefactor_id": "0", 745 | "gamemode_id": 1, 746 | "gateway_id": 10, 747 | "id": 32, 748 | "last_update_time": "1679585463", 749 | "name": "U.S. West", 750 | "next_update_time": "1679585763", 751 | "program_id": "S1", 752 | "season_id": 7, 753 | "season_name": "%s 6" 754 | }, 755 | "33": { 756 | "benefactor_id": "0", 757 | "gamemode_id": 1, 758 | "gateway_id": 11, 759 | "id": 33, 760 | "last_update_time": "1679585464", 761 | "name": "U.S. East", 762 | "next_update_time": "1679585764", 763 | "program_id": "S1", 764 | "season_id": 7, 765 | "season_name": "%s 6" 766 | }, 767 | "34": { 768 | "benefactor_id": "0", 769 | "gamemode_id": 1, 770 | "gateway_id": 20, 771 | "id": 34, 772 | "last_update_time": "1679585466", 773 | "name": "Europe", 774 | "next_update_time": "1679585766", 775 | "program_id": "S1", 776 | "season_id": 7, 777 | "season_name": "%s 6" 778 | }, 779 | "35": { 780 | "benefactor_id": "0", 781 | "gamemode_id": 1, 782 | "gateway_id": 30, 783 | "id": 35, 784 | "last_update_time": "1679585469", 785 | "name": "Korea", 786 | "next_update_time": "1679585769", 787 | "program_id": "S1", 788 | "season_id": 7, 789 | "season_name": "%s 6" 790 | }, 791 | "36": { 792 | "benefactor_id": "0", 793 | "gamemode_id": 1, 794 | "gateway_id": 45, 795 | "id": 36, 796 | "last_update_time": "1679585471", 797 | "name": "Asia", 798 | "next_update_time": "1679585771", 799 | "program_id": "S1", 800 | "season_id": 7, 801 | "season_name": "%s 6" 802 | }, 803 | "4": { 804 | "benefactor_id": "0", 805 | "gamemode_id": 1, 806 | "gateway_id": 20, 807 | "id": 4, 808 | "last_update_time": "1679585333", 809 | "name": "Europe", 810 | "next_update_time": "1679585633", 811 | "program_id": "S1", 812 | "season_id": 1, 813 | "season_name": "" 814 | }, 815 | "5": { 816 | "benefactor_id": "0", 817 | "gamemode_id": 1, 818 | "gateway_id": 30, 819 | "id": 5, 820 | "last_update_time": "1679585369", 821 | "name": "Korea", 822 | "next_update_time": "1679585669", 823 | "program_id": "S1", 824 | "season_id": 1, 825 | "season_name": "" 826 | }, 827 | "6": { 828 | "benefactor_id": "0", 829 | "gamemode_id": 1, 830 | "gateway_id": 45, 831 | "id": 6, 832 | "last_update_time": "1679585386", 833 | "name": "Asia", 834 | "next_update_time": "1679585686", 835 | "program_id": "S1", 836 | "season_id": 1, 837 | "season_name": "" 838 | }, 839 | "7": { 840 | "benefactor_id": "0", 841 | "gamemode_id": 1, 842 | "gateway_id": 0, 843 | "id": 7, 844 | "last_update_time": "1679585391", 845 | "name": "Global", 846 | "next_update_time": "1679585691", 847 | "program_id": "S1", 848 | "season_id": 2, 849 | "season_name": "2018 %s 1" 850 | }, 851 | "8": { 852 | "benefactor_id": "0", 853 | "gamemode_id": 1, 854 | "gateway_id": 10, 855 | "id": 8, 856 | "last_update_time": "1679585393", 857 | "name": "U.S. West", 858 | "next_update_time": "1679585693", 859 | "program_id": "S1", 860 | "season_id": 2, 861 | "season_name": "2018 %s 1" 862 | }, 863 | "817": { 864 | "benefactor_id": "0", 865 | "gamemode_id": 1, 866 | "gateway_id": 0, 867 | "id": 817, 868 | "last_update_time": "1679585478", 869 | "name": "Global", 870 | "next_update_time": "1679585778", 871 | "program_id": "S1", 872 | "season_id": 4, 873 | "season_name": "2019 %s 1" 874 | }, 875 | "818": { 876 | "benefactor_id": "0", 877 | "gamemode_id": 1, 878 | "gateway_id": 10, 879 | "id": 818, 880 | "last_update_time": "1679585480", 881 | "name": "U.S. West", 882 | "next_update_time": "1679585780", 883 | "program_id": "S1", 884 | "season_id": 4, 885 | "season_name": "2019 %s 1" 886 | }, 887 | "819": { 888 | "benefactor_id": "0", 889 | "gamemode_id": 1, 890 | "gateway_id": 11, 891 | "id": 819, 892 | "last_update_time": "1679585483", 893 | "name": "U.S. East", 894 | "next_update_time": "1679585783", 895 | "program_id": "S1", 896 | "season_id": 4, 897 | "season_name": "2019 %s 1" 898 | }, 899 | "820": { 900 | "benefactor_id": "0", 901 | "gamemode_id": 1, 902 | "gateway_id": 20, 903 | "id": 820, 904 | "last_update_time": "1679585485", 905 | "name": "Europe", 906 | "next_update_time": "1679585785", 907 | "program_id": "S1", 908 | "season_id": 4, 909 | "season_name": "2019 %s 1" 910 | }, 911 | "821": { 912 | "benefactor_id": "0", 913 | "gamemode_id": 1, 914 | "gateway_id": 30, 915 | "id": 821, 916 | "last_update_time": "1679585491", 917 | "name": "Korea", 918 | "next_update_time": "1679585791", 919 | "program_id": "S1", 920 | "season_id": 4, 921 | "season_name": "2019 %s 1" 922 | }, 923 | "822": { 924 | "benefactor_id": "0", 925 | "gamemode_id": 1, 926 | "gateway_id": 45, 927 | "id": 822, 928 | "last_update_time": "1679585493", 929 | "name": "Asia", 930 | "next_update_time": "1679585793", 931 | "program_id": "S1", 932 | "season_id": 4, 933 | "season_name": "2019 %s 1" 934 | }, 935 | "9": { 936 | "benefactor_id": "0", 937 | "gamemode_id": 1, 938 | "gateway_id": 11, 939 | "id": 9, 940 | "last_update_time": "1679585395", 941 | "name": "U.S. East", 942 | "next_update_time": "1679585695", 943 | "program_id": "S1", 944 | "season_id": 2, 945 | "season_name": "2018 %s 1" 946 | } 947 | }, 948 | "matchmaked_current_season": 13, 949 | "team_leaderboard_info": {} 950 | } 951 | -------------------------------------------------------------------------------- /test/data/web-api/v1/leaderboard/1%3Foffset%3D0%26length%3D100.json: -------------------------------------------------------------------------------- 1 | { 2 | "columns": [ 3 | "rank", 4 | "last_rank", 5 | "gateway_id", 6 | "points", 7 | "wins", 8 | "losses", 9 | "disconnects", 10 | "toon", 11 | "battletag", 12 | "avatar", 13 | "feature_stat", 14 | "rating", 15 | "bucket" 16 | ], 17 | "rows": [ 18 | [ 19 | 1, 20 | 1, 21 | 30, 22 | 3471, 23 | 157, 24 | 53, 25 | 0, 26 | "IIlIIllIIllIIII", 27 | "September", 28 | "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/d2edd0800865e3a5e0c0c86898010f90.png", 29 | "terran", 30 | 3471, 31 | 7 32 | ], 33 | [ 34 | 2, 35 | 2, 36 | 30, 37 | 3394, 38 | 105, 39 | 25, 40 | 0, 41 | "IIllIIlIlIlI", 42 | "IIllIIlIlIlI", 43 | "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/ed92f4237ece35a572c84f98ec3b0b1a.png", 44 | "terran", 45 | 3394, 46 | 7 47 | ], 48 | [ 49 | 3, 50 | 3, 51 | 30, 52 | 3297, 53 | 147, 54 | 61, 55 | 0, 56 | "ggaemoda", 57 | "사랑애", 58 | "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/d045500bdc0a723e4fd52422d3692ba9.webp", 59 | "zerg", 60 | 3297, 61 | 7 62 | ], 63 | [ 64 | 4, 65 | 4, 66 | 30, 67 | 3230, 68 | 409, 69 | 289, 70 | 26, 71 | "Nowayout", 72 | "군주", 73 | "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/8c49f2317cebf70ce5f61550f26501b4.png", 74 | "terran", 75 | 3230, 76 | 7 77 | ], 78 | [ 79 | 5, 80 | 5, 81 | 30, 82 | 3222, 83 | 240, 84 | 149, 85 | 3, 86 | "Best[WHITE]", 87 | "HoeJJa", 88 | "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/65d8e88a91ac99aa4de4d7cb17c38dc8.png", 89 | "protoss", 90 | 3222, 91 | 7 92 | ], 93 | [ 94 | 6, 95 | 6, 96 | 45, 97 | 3222, 98 | 79, 99 | 14, 100 | 0, 101 | "Indus)jh8476", 102 | "베지밀정현", 103 | "", 104 | "terran", 105 | 3222, 106 | 7 107 | ], 108 | [7, 7, 10, 3206, 123, 45, 2, "lllllilli", "RSI", "", "terran", 3206, 7], 109 | [ 110 | 8, 111 | 8, 112 | 30, 113 | 3199, 114 | 1142, 115 | 929, 116 | 38, 117 | "IIIlllIIIllll", 118 | "MoDeL", 119 | "", 120 | "zerg", 121 | 3199, 122 | 7 123 | ], 124 | [ 125 | 9, 126 | 9, 127 | 30, 128 | 3198, 129 | 185, 130 | 108, 131 | 0, 132 | "yseongmin", 133 | "리쌍", 134 | "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/1517e40a796ffb9bb61927e44d469891.webp", 135 | "protoss", 136 | 3198, 137 | 7 138 | ], 139 | [ 140 | 10, 141 | 10, 142 | 30, 143 | 3197, 144 | 170, 145 | 89, 146 | 0, 147 | "TwotheG", 148 | "포기하면편해", 149 | "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/d2eef4b5396a5a1808429f48f9f07280.png", 150 | "zerg", 151 | 3197, 152 | 7 153 | ], 154 | [ 155 | 11, 156 | 11, 157 | 30, 158 | 3197, 159 | 111, 160 | 40, 161 | 0, 162 | "Yerim2[WHITE]", 163 | "비아이", 164 | "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/b8edc96001b905d234d144912244dcd2.webp", 165 | "terran", 166 | 3197, 167 | 7 168 | ], 169 | [ 170 | 12, 171 | 12, 172 | 30, 173 | 3195, 174 | 271, 175 | 159, 176 | 0, 177 | "AB(AB)", 178 | "September", 179 | "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/d2edd0800865e3a5e0c0c86898010f90.png", 180 | "terran", 181 | 3195, 182 | 7 183 | ], 184 | [ 185 | 13, 186 | 13, 187 | 30, 188 | 3188, 189 | 111, 190 | 25, 191 | 0, 192 | "IlIIlllIlIlIII", 193 | "그랑마니에르", 194 | "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/8c49f2317cebf70ce5f61550f26501b4.png", 195 | "terran", 196 | 3188, 197 | 7 198 | ], 199 | [ 200 | 14, 201 | 14, 202 | 10, 203 | 3179, 204 | 81, 205 | 18, 206 | 0, 207 | "lIlIlIlIlllIIlI", 208 | "홍채인식", 209 | "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/07fc3e5397f62dd5488026c077c67409.png", 210 | "terran", 211 | 3179, 212 | 7 213 | ], 214 | [ 215 | 15, 216 | 15, 217 | 30, 218 | 3178, 219 | 116, 220 | 47, 221 | 0, 222 | "IlllIlllIllIllI", 223 | "희수", 224 | "", 225 | "zerg", 226 | 3178, 227 | 7 228 | ], 229 | [ 230 | 16, 231 | 16, 232 | 30, 233 | 3163, 234 | 233, 235 | 136, 236 | 0, 237 | "COCACOLA3", 238 | "최유진", 239 | "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/ed92f4237ece35a572c84f98ec3b0b1a.png", 240 | "protoss", 241 | 3163, 242 | 7 243 | ], 244 | [ 245 | 17, 246 | 17, 247 | 30, 248 | 3154, 249 | 214, 250 | 124, 251 | 0, 252 | "policeonetop", 253 | "봉동이", 254 | "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/8c49f2317cebf70ce5f61550f26501b4.png", 255 | "terran", 256 | 3154, 257 | 7 258 | ], 259 | [ 260 | 18, 261 | 18, 262 | 20, 263 | 3139, 264 | 98, 265 | 31, 266 | 0, 267 | "ChangChen", 268 | "스타만20년째", 269 | "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/56a97b6a462bf89d71831642d0f72f20.png", 270 | "terran", 271 | 3139, 272 | 7 273 | ], 274 | [ 275 | 19, 276 | 19, 277 | 30, 278 | 3124, 279 | 188, 280 | 111, 281 | 2, 282 | "Scan[KaL]", 283 | "CoveredMask", 284 | "", 285 | "terran", 286 | 3124, 287 | 7 288 | ], 289 | [ 290 | 20, 291 | 20, 292 | 10, 293 | 3114, 294 | 156, 295 | 71, 296 | 0, 297 | "SouL)T(eSaGiTo", 298 | "유승곤", 299 | "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/b60e2c0517b1349e096f925aeb1ad590.png", 300 | "terran", 301 | 3114, 302 | 7 303 | ], 304 | [ 305 | 21, 306 | 21, 307 | 30, 308 | 3110, 309 | 234, 310 | 145, 311 | 6, 312 | "LoveMechanic", 313 | "thekara", 314 | "", 315 | "terran", 316 | 3110, 317 | 7 318 | ], 319 | [ 320 | 22, 321 | 22, 322 | 30, 323 | 3104, 324 | 175, 325 | 61, 326 | 2, 327 | "GOMSUJANG", 328 | "조일장", 329 | "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/93f4430c907e7e2c90af548dcca2c9a3.png", 330 | "zerg", 331 | 3104, 332 | 7 333 | ], 334 | [ 335 | 23, 336 | 23, 337 | 10, 338 | 3104, 339 | 86, 340 | 16, 341 | 0, 342 | "Scan", 343 | "유승곤", 344 | "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/bacfd18d7eaa155bdd694ee607cad8fd.png", 345 | "terran", 346 | 3104, 347 | 7 348 | ], 349 | [ 350 | 24, 351 | 24, 352 | 30, 353 | 3097, 354 | 197, 355 | 75, 356 | 22, 357 | "qweqewqqe", 358 | "lIllllllllll", 359 | "", 360 | "terran", 361 | 3097, 362 | 7 363 | ], 364 | [25, 25, 45, 3094, 141, 73, 0, "Last.", "malibu", "", "terran", 3094, 7], 365 | [ 366 | 26, 367 | 26, 368 | 30, 369 | 3094, 370 | 69, 371 | 16, 372 | 0, 373 | "IIllIIlllllIIII", 374 | "압도", 375 | "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/840039d33bb1ff1bbb00af0c2129e4d5.webp", 376 | "protoss", 377 | 3094, 378 | 7 379 | ], 380 | [ 381 | 27, 382 | 27, 383 | 30, 384 | 3094, 385 | 101, 386 | 39, 387 | 0, 388 | "[sSa]Zerg", 389 | "샌드박스", 390 | "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/1be12a4cfee97809578322dd982d02cf.png", 391 | "terran", 392 | 3094, 393 | 7 394 | ], 395 | [ 396 | 28, 397 | 28, 398 | 10, 399 | 3091, 400 | 78, 401 | 20, 402 | 0, 403 | "iiilililililill", 404 | "조기석", 405 | "", 406 | "terran", 407 | 3091, 408 | 7 409 | ], 410 | [ 411 | 29, 412 | 29, 413 | 30, 414 | 3083, 415 | 109, 416 | 53, 417 | 3, 418 | "llllIIlIIIlIllI", 419 | "매새끼", 420 | "", 421 | "terran", 422 | 3083, 423 | 7 424 | ], 425 | [ 426 | 30, 427 | 30, 428 | 30, 429 | 3082, 430 | 126, 431 | 62, 432 | 0, 433 | "lIIllIIllIIIIll", 434 | "Draco", 435 | "", 436 | "terran", 437 | 3082, 438 | 7 439 | ], 440 | [31, 31, 30, 3070, 114, 52, 0, "jjabMae", "후룰루루", "", "zerg", 3070, 7], 441 | [32, 32, 30, 3069, 121, 59, 0, "KNYLove", "KNY", "", "zerg", 3069, 7], 442 | [ 443 | 33, 444 | 33, 445 | 30, 446 | 3067, 447 | 64, 448 | 8, 449 | 0, 450 | "terran11111", 451 | "조기선", 452 | "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/8c49f2317cebf70ce5f61550f26501b4.png", 453 | "terran", 454 | 3067, 455 | 7 456 | ], 457 | [ 458 | 34, 459 | 34, 460 | 30, 461 | 3067, 462 | 155, 463 | 88, 464 | 0, 465 | "ns.99", 466 | "댕기머리", 467 | "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/6c3739760daace07e4ea50f01906f3e0.webp", 468 | "zerg", 469 | 3067, 470 | 7 471 | ], 472 | [ 473 | 35, 474 | 35, 475 | 30, 476 | 3058, 477 | 200, 478 | 133, 479 | 3, 480 | "hidel", 481 | "Noel", 482 | "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/7f80e6f1dc933fe6c9aa8ad8648ccaa3.webp", 483 | "terran", 484 | 3058, 485 | 7 486 | ], 487 | [ 488 | 36, 489 | 36, 490 | 30, 491 | 3051, 492 | 123, 493 | 69, 494 | 0, 495 | "IlIlIIIlllIIlII", 496 | "쿼이", 497 | "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/e4209753a27beb9ef27e350450781304.png", 498 | "zerg", 499 | 3051, 500 | 7 501 | ], 502 | [ 503 | 37, 504 | 37, 505 | 30, 506 | 3050, 507 | 196, 508 | 111, 509 | 3, 510 | "llIIIlllIIlllll", 511 | "고독", 512 | "", 513 | "zerg", 514 | 3050, 515 | 7 516 | ], 517 | [38, 38, 30, 3042, 883, 731, 0, "PISTACHIO.", "Check", "", "zerg", 3042, 7], 518 | [39, 39, 30, 3041, 165, 95, 0, "ksudif", "어부동산", "", "zerg", 3041, 7], 519 | [ 520 | 40, 521 | 40, 522 | 30, 523 | 3039, 524 | 89, 525 | 22, 526 | 0, 527 | "Mongsense", 528 | "sjdlfjslkdf", 529 | "", 530 | "terran", 531 | 3039, 532 | 7 533 | ], 534 | [ 535 | 41, 536 | 41, 537 | 30, 538 | 3039, 539 | 79, 540 | 20, 541 | 0, 542 | "lllllIIllIlIlII", 543 | "유승곤", 544 | "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/bacfd18d7eaa155bdd694ee607cad8fd.png", 545 | "terran", 546 | 3039, 547 | 7 548 | ], 549 | [42, 42, 30, 3032, 458, 358, 0, "GDraGon!", "뉴틱", "", "zerg", 3032, 7], 550 | [ 551 | 43, 552 | 43, 553 | 30, 554 | 3030, 555 | 339, 556 | 204, 557 | 0, 558 | "By.SnOw1", 559 | "장윤철", 560 | "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/ca849b3e45c18c8f9640290aff5e2fad.png", 561 | "protoss", 562 | 3030, 563 | 7 564 | ], 565 | [ 566 | 44, 567 | 44, 568 | 10, 569 | 3030, 570 | 88, 571 | 21, 572 | 0, 573 | "iliilululyliuli", 574 | "조기석", 575 | "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/bacfd18d7eaa155bdd694ee607cad8fd.png", 576 | "terran", 577 | 3030, 578 | 7 579 | ], 580 | [ 581 | 45, 582 | 45, 583 | 30, 584 | 3030, 585 | 257, 586 | 195, 587 | 1, 588 | "IIllIIllIIllIl", 589 | "Tyson", 590 | "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/f6790fdd4a92e038cea10197ebaa8c7d.png", 591 | "zerg", 592 | 3030, 593 | 7 594 | ], 595 | [ 596 | 46, 597 | 46, 598 | 30, 599 | 3029, 600 | 224, 601 | 161, 602 | 2, 603 | "I.JOa", 604 | "정성", 605 | "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/31b81ea790b71db84b1e4bab49a57720.png", 606 | "terran", 607 | 3029, 608 | 7 609 | ], 610 | [ 611 | 47, 612 | 47, 613 | 10, 614 | 3025, 615 | 275, 616 | 193, 617 | 0, 618 | "SouL)T(Dandy", 619 | "Dandy", 620 | "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/77796a5c835b3b5e0e239cc9f3c4eaf7.webp", 621 | "terran", 622 | 3025, 623 | 7 624 | ], 625 | [ 626 | 48, 627 | 48, 628 | 30, 629 | 3020, 630 | 63, 631 | 8, 632 | 0, 633 | "ErOs_Rascal", 634 | "뇌없냐상현아", 635 | "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/ed92f4237ece35a572c84f98ec3b0b1a.png", 636 | "terran", 637 | 3020, 638 | 7 639 | ], 640 | [ 641 | 49, 642 | 49, 643 | 30, 644 | 3019, 645 | 57, 646 | 4, 647 | 0, 648 | "Gaemul", 649 | "무식한곰탱이", 650 | "", 651 | "terran", 652 | 3019, 653 | 7 654 | ], 655 | [ 656 | 50, 657 | 50, 658 | 30, 659 | 3017, 660 | 236, 661 | 171, 662 | 0, 663 | "yuinaema", 664 | "Invincible", 665 | "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/d2edd0800865e3a5e0c0c86898010f90.png", 666 | "zerg", 667 | 3017, 668 | 7 669 | ] 670 | ] 671 | } 672 | -------------------------------------------------------------------------------- /test/data/web-api/v1/map-stats-by-toon/bob/10.json: -------------------------------------------------------------------------------- 1 | { 2 | "current_season": 13, 3 | "map_stat": { 4 | "1": { 5 | "11": { 6 | "1519C49FF7BA9CED4F80BB95744B3913": { 7 | "Protoss": { 8 | "total_games": 0, 9 | "total_global_games": 817290, 10 | "total_global_wins": 422775, 11 | "total_wins": 0 12 | }, 13 | "Random": { 14 | "total_games": 0, 15 | "total_global_games": 100220, 16 | "total_global_wins": 50954, 17 | "total_wins": 0 18 | }, 19 | "Terran": { 20 | "total_games": 0, 21 | "total_global_games": 365534, 22 | "total_global_wins": 168614, 23 | "total_wins": 0 24 | }, 25 | "Zerg": { 26 | "total_games": 1, 27 | "total_global_games": 445909, 28 | "total_global_wins": 221963, 29 | "total_wins": 0 30 | } 31 | } 32 | }, 33 | "12": { 34 | "3C7671368F9267E1EA07E56B7517E13A": { 35 | "Protoss": { 36 | "total_games": 0, 37 | "total_global_games": 1607968, 38 | "total_global_wins": 802930, 39 | "total_wins": 0 40 | }, 41 | "Random": { 42 | "total_games": 0, 43 | "total_global_games": 177294, 44 | "total_global_wins": 91979, 45 | "total_wins": 0 46 | }, 47 | "Terran": { 48 | "total_games": 0, 49 | "total_global_games": 1058900, 50 | "total_global_wins": 522688, 51 | "total_wins": 0 52 | }, 53 | "Zerg": { 54 | "total_games": 22, 55 | "total_global_games": 1068264, 56 | "total_global_wins": 538616, 57 | "total_wins": 11 58 | } 59 | }, 60 | "5168494D085086DDE9ED3D0132A06D59": { 61 | "Protoss": { 62 | "total_games": 0, 63 | "total_global_games": 431736, 64 | "total_global_wins": 221742, 65 | "total_wins": 0 66 | }, 67 | "Random": { 68 | "total_games": 0, 69 | "total_global_games": 42952, 70 | "total_global_wins": 21703, 71 | "total_wins": 0 72 | }, 73 | "Terran": { 74 | "total_games": 0, 75 | "total_global_games": 203536, 76 | "total_global_wins": 95546, 77 | "total_wins": 0 78 | }, 79 | "Zerg": { 80 | "total_games": 15, 81 | "total_global_games": 208944, 82 | "total_global_wins": 104593, 83 | "total_wins": 6 84 | } 85 | }, 86 | "6CD4728A32ECD7485C3B1592A84C8077": { 87 | "Protoss": { 88 | "total_games": 0, 89 | "total_global_games": 144329, 90 | "total_global_wins": 73651, 91 | "total_wins": 0 92 | }, 93 | "Random": { 94 | "total_games": 0, 95 | "total_global_games": 22229, 96 | "total_global_wins": 11476, 97 | "total_wins": 0 98 | }, 99 | "Terran": { 100 | "total_games": 0, 101 | "total_global_games": 94884, 102 | "total_global_wins": 44802, 103 | "total_wins": 0 104 | }, 105 | "Zerg": { 106 | "total_games": 2, 107 | "total_global_games": 93002, 108 | "total_global_wins": 47293, 109 | "total_wins": 0 110 | } 111 | }, 112 | "7776542CC2CF2038417CD9919F5C35F0": { 113 | "Protoss": { 114 | "total_games": 0, 115 | "total_global_games": 957031, 116 | "total_global_wins": 489857, 117 | "total_wins": 0 118 | }, 119 | "Random": { 120 | "total_games": 0, 121 | "total_global_games": 96142, 122 | "total_global_wins": 47480, 123 | "total_wins": 0 124 | }, 125 | "Terran": { 126 | "total_games": 0, 127 | "total_global_games": 449773, 128 | "total_global_wins": 215493, 129 | "total_wins": 0 130 | }, 131 | "Zerg": { 132 | "total_games": 11, 133 | "total_global_games": 500562, 134 | "total_global_wins": 248924, 135 | "total_wins": 1 136 | } 137 | }, 138 | "8C28E5C07D2AE6C7318BDB44980AFA36": { 139 | "Protoss": { 140 | "total_games": 0, 141 | "total_global_games": 659236, 142 | "total_global_wins": 328808, 143 | "total_wins": 0 144 | }, 145 | "Random": { 146 | "total_games": 0, 147 | "total_global_games": 83774, 148 | "total_global_wins": 43338, 149 | "total_wins": 0 150 | }, 151 | "Terran": { 152 | "total_games": 0, 153 | "total_global_games": 455998, 154 | "total_global_wins": 220048, 155 | "total_wins": 0 156 | }, 157 | "Zerg": { 158 | "total_games": 3, 159 | "total_global_games": 492330, 160 | "total_global_wins": 253475, 161 | "total_wins": 0 162 | } 163 | }, 164 | "A45C0223C31CCAD0B18A8380432776D8": { 165 | "Protoss": { 166 | "total_games": 0, 167 | "total_global_games": 866562, 168 | "total_global_wins": 429542, 169 | "total_wins": 0 170 | }, 171 | "Random": { 172 | "total_games": 0, 173 | "total_global_games": 105766, 174 | "total_global_wins": 54697, 175 | "total_wins": 0 176 | }, 177 | "Terran": { 178 | "total_games": 0, 179 | "total_global_games": 676365, 180 | "total_global_wins": 337209, 181 | "total_wins": 0 182 | }, 183 | "Zerg": { 184 | "total_games": 14, 185 | "total_global_games": 671643, 186 | "total_global_wins": 338720, 187 | "total_wins": 5 188 | } 189 | }, 190 | "E666DB327C0261E6667DB1B79F677654": { 191 | "Protoss": { 192 | "total_games": 0, 193 | "total_global_games": 1404288, 194 | "total_global_wins": 703528, 195 | "total_wins": 0 196 | }, 197 | "Random": { 198 | "total_games": 0, 199 | "total_global_games": 161589, 200 | "total_global_wins": 83264, 201 | "total_wins": 0 202 | }, 203 | "Terran": { 204 | "total_games": 0, 205 | "total_global_games": 941124, 206 | "total_global_wins": 467545, 207 | "total_wins": 0 208 | }, 209 | "Zerg": { 210 | "total_games": 23, 211 | "total_global_games": 900383, 212 | "total_global_wins": 449355, 213 | "total_wins": 12 214 | } 215 | } 216 | }, 217 | "13": { 218 | "3C7671368F9267E1EA07E56B7517E13A": { 219 | "Protoss": { 220 | "total_games": 0, 221 | "total_global_games": 559226, 222 | "total_global_wins": 279961, 223 | "total_wins": 0 224 | }, 225 | "Random": { 226 | "total_games": 0, 227 | "total_global_games": 62228, 228 | "total_global_wins": 32287, 229 | "total_wins": 0 230 | }, 231 | "Terran": { 232 | "total_games": 0, 233 | "total_global_games": 376706, 234 | "total_global_wins": 184760, 235 | "total_wins": 0 236 | }, 237 | "Zerg": { 238 | "total_games": 195, 239 | "total_global_games": 362552, 240 | "total_global_wins": 183348, 241 | "total_wins": 93 242 | } 243 | }, 244 | "5168494D085086DDE9ED3D0132A06D59": { 245 | "Protoss": { 246 | "total_games": 0, 247 | "total_global_games": 140801, 248 | "total_global_wins": 72322, 249 | "total_wins": 0 250 | }, 251 | "Random": { 252 | "total_games": 0, 253 | "total_global_games": 14071, 254 | "total_global_wins": 6837, 255 | "total_wins": 0 256 | }, 257 | "Terran": { 258 | "total_games": 0, 259 | "total_global_games": 66383, 260 | "total_global_wins": 31182, 261 | "total_wins": 0 262 | }, 263 | "Zerg": { 264 | "total_games": 73, 265 | "total_global_games": 65497, 266 | "total_global_wins": 33035, 267 | "total_wins": 35 268 | } 269 | }, 270 | "7776542CC2CF2038417CD9919F5C35F0": { 271 | "Protoss": { 272 | "total_games": 0, 273 | "total_global_games": 321896, 274 | "total_global_wins": 164801, 275 | "total_wins": 0 276 | }, 277 | "Random": { 278 | "total_games": 0, 279 | "total_global_games": 31048, 280 | "total_global_wins": 15323, 281 | "total_wins": 0 282 | }, 283 | "Terran": { 284 | "total_games": 0, 285 | "total_global_games": 160680, 286 | "total_global_wins": 76959, 287 | "total_wins": 0 288 | }, 289 | "Zerg": { 290 | "total_games": 105, 291 | "total_global_games": 166446, 292 | "total_global_wins": 82952, 293 | "total_wins": 58 294 | } 295 | }, 296 | "8C28E5C07D2AE6C7318BDB44980AFA36": { 297 | "Protoss": { 298 | "total_games": 0, 299 | "total_global_games": 249176, 300 | "total_global_wins": 124306, 301 | "total_wins": 0 302 | }, 303 | "Random": { 304 | "total_games": 0, 305 | "total_global_games": 30551, 306 | "total_global_wins": 15779, 307 | "total_wins": 0 308 | }, 309 | "Terran": { 310 | "total_games": 0, 311 | "total_global_games": 178795, 312 | "total_global_wins": 86526, 313 | "total_wins": 0 314 | }, 315 | "Zerg": { 316 | "total_games": 20, 317 | "total_global_games": 185744, 318 | "total_global_wins": 95522, 319 | "total_wins": 7 320 | } 321 | }, 322 | "A45C0223C31CCAD0B18A8380432776D8": { 323 | "Protoss": { 324 | "total_games": 0, 325 | "total_global_games": 346511, 326 | "total_global_wins": 171290, 327 | "total_wins": 0 328 | }, 329 | "Random": { 330 | "total_games": 0, 331 | "total_global_games": 41390, 332 | "total_global_wins": 21365, 333 | "total_wins": 0 334 | }, 335 | "Terran": { 336 | "total_games": 0, 337 | "total_global_games": 277525, 338 | "total_global_wins": 138497, 339 | "total_wins": 0 340 | }, 341 | "Zerg": { 342 | "total_games": 38, 343 | "total_global_games": 259932, 344 | "total_global_wins": 131527, 345 | "total_wins": 18 346 | } 347 | }, 348 | "E666DB327C0261E6667DB1B79F677654": { 349 | "Protoss": { 350 | "total_games": 0, 351 | "total_global_games": 484765, 352 | "total_global_wins": 243228, 353 | "total_wins": 0 354 | }, 355 | "Random": { 356 | "total_games": 0, 357 | "total_global_games": 55970, 358 | "total_global_wins": 28547, 359 | "total_wins": 0 360 | }, 361 | "Terran": { 362 | "total_games": 0, 363 | "total_global_games": 331568, 364 | "total_global_wins": 163850, 365 | "total_wins": 0 366 | }, 367 | "Zerg": { 368 | "total_games": 170, 369 | "total_global_games": 301481, 370 | "total_global_wins": 151267, 371 | "total_wins": 83 372 | } 373 | } 374 | } 375 | } 376 | } 377 | } 378 | -------------------------------------------------------------------------------- /test/data/web-api/v1/matchmaker-gameinfo-playerinfo/mm-test.json: -------------------------------------------------------------------------------- 1 | { 2 | "avatars": { 3 | "avatar_default_scrlogo.jpg": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/d2edd0800865e3a5e0c0c86898010f90.png", 4 | "avatar_default_scrlogo.jpg?f=1": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/35650878522dce72d2ea156a34eb8d2c.png", 5 | "avatar_neutral_contest_kerrigan.jpg": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/ed92f4237ece35a572c84f98ec3b0b1a.png", 6 | "avatar_neutral_contest_kerrigan.jpg?f=1": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/d6457bf7d4d0a15390cbbe39e31bd399.png", 7 | "avatar_neutral_protoss.jpg": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/ba15b43108a74f6e9249265db1e1d5ec.png", 8 | "avatar_neutral_protoss.jpg?f=1": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/b7fffe673e27da9e43cf2c07cd0c4b88.png", 9 | "avatar_neutral_terran.jpg": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/cbe98f2e1d28ee9c66a827f8cf8b5afa.png", 10 | "avatar_neutral_terran.jpg?f=1": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/1876b578f3438d098792226105430c4b.png", 11 | "avatar_neutral_zerg.jpg": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/f6790fdd4a92e038cea10197ebaa8c7d.png", 12 | "avatar_neutral_zerg.jpg?f=1": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/2607e624dba1e6370f116f7b5dd63bd4.png", 13 | "avatar_protoss_advisor.jpg": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/3dabdfc201effbe32ce54e29ebfff551.png", 14 | "avatar_protoss_advisor.jpg?f=1": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/150f58e67a1aeca3e4a0d7657d7b1032.png", 15 | "avatar_protoss_probe.jpg": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/ca849b3e45c18c8f9640290aff5e2fad.png", 16 | "avatar_protoss_probe.jpg?f=1": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/c966c375c2383a5138b80beb4414e3c8.png", 17 | "avatar_terran_advisor.jpg": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/b924d7cebc9fcdd9832636804bbb2c0c.png", 18 | "avatar_terran_advisor.jpg?f=1": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/c140cd97426bfb050bcedd79f5c61c2d.png", 19 | "avatar_terran_scv.jpg": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/3c8531bc888c3565aff04a5a1d0902ef.png", 20 | "avatar_terran_scv.jpg?f=1": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/fa836426e7746a595762daeb8c91f565.png", 21 | "avatar_zerg_advisor.jpg": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/d2eef4b5396a5a1808429f48f9f07280.png", 22 | "avatar_zerg_advisor.jpg?f=1": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/2a08afcf992b2abb3044a241db008251.png", 23 | "avatar_zerg_drone.jpg": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/e4209753a27beb9ef27e350450781304.png", 24 | "avatar_zerg_drone.jpg?f=1": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/6a7dcbb0a6de43d48e6c82c14bae3689.png" 25 | }, 26 | "avatars_awards": { "win_igr": 12.0, "win_normal": 10 }, 27 | "avatars_locked": { 28 | "avatar_protoss_arbiter.jpg": { 29 | "level": 5000, 30 | "stat": "mm_protoss_wins", 31 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/8535588141e1ec4aa5e6e89eb3ee3740.png" 32 | }, 33 | "avatar_protoss_arbiter.jpg?f=1": { 34 | "level": 5000, 35 | "stat": "mm_protoss_wins", 36 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/a87b9466df5c7f2d00dc4417e20d9c62.png" 37 | }, 38 | "avatar_protoss_carrier.jpg": { 39 | "level": 15000, 40 | "stat": "mm_protoss_wins", 41 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/7f19e7af8f63fbda946bf75857505e4e.png" 42 | }, 43 | "avatar_protoss_carrier.jpg?f=1": { 44 | "level": 15000, 45 | "stat": "mm_protoss_wins", 46 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/4514a1087f2b513f2e6a29853a18c6b8.png" 47 | }, 48 | "avatar_protoss_darkarchon.jpg": { 49 | "level": 50000, 50 | "stat": "mm_protoss_wins", 51 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/53f70f33d24be0782307ad0ccdf3b728.png" 52 | }, 53 | "avatar_protoss_darkarchon.jpg?f=1": { 54 | "level": 50000, 55 | "stat": "mm_protoss_wins", 56 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/474a9362751ae67aa22472efcffc0076.png" 57 | }, 58 | "avatar_protoss_darktemplar.jpg": { 59 | "level": 10000, 60 | "stat": "mm_protoss_wins", 61 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/584d9c9dba614a34e626f5f81d36d87f.png" 62 | }, 63 | "avatar_protoss_darktemplar.jpg?f=1": { 64 | "level": 10000, 65 | "stat": "mm_protoss_wins", 66 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/bb1ba4e32899617810ca1249c9b83993.png" 67 | }, 68 | "avatar_protoss_dragoon.jpg": { 69 | "level": 2500, 70 | "stat": "mm_protoss_wins", 71 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/f931798e26f1d5a5fec9821fd70745e6.png" 72 | }, 73 | "avatar_protoss_dragoon.jpg?f=1": { 74 | "level": 2500, 75 | "stat": "mm_protoss_wins", 76 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/62471117ed82e7cbc0174ce74d210ccf.png" 77 | }, 78 | "avatar_protoss_interceptor.jpg": { 79 | "level": 25000, 80 | "stat": "mm_protoss_wins", 81 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/a57704fd42417b2a0ab088dd15ff7051.png" 82 | }, 83 | "avatar_protoss_interceptor.jpg?f=1": { 84 | "level": 25000, 85 | "stat": "mm_protoss_wins", 86 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/79febca8412c90e6def869f5b6644dcb.png" 87 | }, 88 | "avatar_protoss_observer.jpg": { 89 | "level": 250, 90 | "stat": "mm_protoss_wins", 91 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/da0c15010a74bf93ab35fdcf9ef74e0c.png" 92 | }, 93 | "avatar_protoss_observer.jpg?f=1": { 94 | "level": 250, 95 | "stat": "mm_protoss_wins", 96 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/69a4d4aed189ba644b4614a1b39b95ce.png" 97 | }, 98 | "avatar_protoss_templar.jpg": { 99 | "level": 1000, 100 | "stat": "mm_protoss_wins", 101 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/a04de118d291f12385a868ba950f0f2e.png" 102 | }, 103 | "avatar_protoss_templar.jpg?f=1": { 104 | "level": 1000, 105 | "stat": "mm_protoss_wins", 106 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/094e26aa49f368b28873ddee987862ad.png" 107 | }, 108 | "avatar_protoss_zealot.jpg": { 109 | "level": 500, 110 | "stat": "mm_protoss_wins", 111 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/65d8e88a91ac99aa4de4d7cb17c38dc8.png" 112 | }, 113 | "avatar_protoss_zealot.jpg?f=1": { 114 | "level": 500, 115 | "stat": "mm_protoss_wins", 116 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/85fba4327ffe9b6773957f2f4b7cdbd5.png" 117 | }, 118 | "avatar_terran_battlecruiser.jpg": { 119 | "level": 50000, 120 | "stat": "mm_terran_wins", 121 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/91c1e2b160bad7ffcac3a2a2b3eaef30.png" 122 | }, 123 | "avatar_terran_battlecruiser.jpg?f=1": { 124 | "level": 50000, 125 | "stat": "mm_terran_wins", 126 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/ba59cac45a5fd3c09bd1c2426af33843.png" 127 | }, 128 | "avatar_terran_bomber.jpg": { 129 | "level": 15000, 130 | "stat": "mm_terran_wins", 131 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/56a97b6a462bf89d71831642d0f72f20.png" 132 | }, 133 | "avatar_terran_bomber.jpg?f=1": { 134 | "level": 15000, 135 | "stat": "mm_terran_wins", 136 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/1bb2c670014a71827ca4581e460d4055.png" 137 | }, 138 | "avatar_terran_dropship.jpg": { 139 | "level": 2500, 140 | "stat": "mm_terran_wins", 141 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/07fc3e5397f62dd5488026c077c67409.png" 142 | }, 143 | "avatar_terran_dropship.jpg?f=1": { 144 | "level": 2500, 145 | "stat": "mm_terran_wins", 146 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/8e3d437aea525ad8b6c214663286d40f.png" 147 | }, 148 | "avatar_terran_ghost.jpg": { 149 | "level": 5000, 150 | "stat": "mm_terran_wins", 151 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/fc5a31374fd384ed7e6b2296067efcc5.png" 152 | }, 153 | "avatar_terran_ghost.jpg?f=1": { 154 | "level": 5000, 155 | "stat": "mm_terran_wins", 156 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/649602a298f245cd7081c933bbfd06ab.png" 157 | }, 158 | "avatar_terran_goliath.jpg": { 159 | "level": 25000, 160 | "stat": "mm_terran_wins", 161 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/b60e2c0517b1349e096f925aeb1ad590.png" 162 | }, 163 | "avatar_terran_goliath.jpg?f=1": { 164 | "level": 25000, 165 | "stat": "mm_terran_wins", 166 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/e99f93500b0bf7255083ae3d7dd75c6a.png" 167 | }, 168 | "avatar_terran_marine.jpg": { 169 | "level": 500, 170 | "stat": "mm_terran_wins", 171 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/8c49f2317cebf70ce5f61550f26501b4.png" 172 | }, 173 | "avatar_terran_marine.jpg?f=1": { 174 | "level": 500, 175 | "stat": "mm_terran_wins", 176 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/3f910f07d245e6ebfc4ca21384986e6d.png" 177 | }, 178 | "avatar_terran_medic.jpg": { 179 | "level": 10000, 180 | "stat": "mm_terran_wins", 181 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/9915f7f503e0116733f348dcca90f61d.png" 182 | }, 183 | "avatar_terran_medic.jpg?f=1": { 184 | "level": 10000, 185 | "stat": "mm_terran_wins", 186 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/7cacf56511b13dbf608147c035fcce19.png" 187 | }, 188 | "avatar_terran_spidermine.jpg": { 189 | "level": 250, 190 | "stat": "mm_terran_wins", 191 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/7e42adeb13d2e9df5193bcfcbd3195cc.png" 192 | }, 193 | "avatar_terran_spidermine.jpg?f=1": { 194 | "level": 250, 195 | "stat": "mm_terran_wins", 196 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/dd50373319a85fea011983767674cb75.png" 197 | }, 198 | "avatar_terran_vulture.jpg": { 199 | "level": 1000, 200 | "stat": "mm_terran_wins", 201 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/31b81ea790b71db84b1e4bab49a57720.png" 202 | }, 203 | "avatar_terran_vulture.jpg?f=1": { 204 | "level": 1000, 205 | "stat": "mm_terran_wins", 206 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/efb9ffcb472f7ee25c53730ef3281d1c.png" 207 | }, 208 | "avatar_zerg_devourer.jpg": { 209 | "level": 5000, 210 | "stat": "mm_zerg_wins", 211 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/f358977c6cb7489dc41b1de4addf5cd1.png" 212 | }, 213 | "avatar_zerg_devourer.jpg?f=1": { 214 | "level": 5000, 215 | "stat": "mm_zerg_wins", 216 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/5be3c4513b6a3b25aca6d9f5dfb9b2c4.png" 217 | }, 218 | "avatar_zerg_guardian.jpg": { 219 | "level": 10000, 220 | "stat": "mm_zerg_wins", 221 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/3c88d48d97694527a53df1c70a2480aa.png" 222 | }, 223 | "avatar_zerg_guardian.jpg?f=1": { 224 | "level": 10000, 225 | "stat": "mm_zerg_wins", 226 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/c6a49c908fe3b7928cf111103f63a05f.png" 227 | }, 228 | "avatar_zerg_hydralisk.jpg": { 229 | "level": 1000, 230 | "stat": "mm_zerg_wins", 231 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/3a85084b4c09b8381704941ea7ca3ea3.png" 232 | }, 233 | "avatar_zerg_hydralisk.jpg?f=1": { 234 | "level": 1000, 235 | "stat": "mm_zerg_wins", 236 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/7a94bedd980be37dfbf13404ceff03bc.png" 237 | }, 238 | "avatar_zerg_lurker.jpg": { 239 | "level": 15000, 240 | "stat": "mm_zerg_wins", 241 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/a4ead4677341b0e0b7d4d7714466b07e.png" 242 | }, 243 | "avatar_zerg_lurker.jpg?f=1": { 244 | "level": 15000, 245 | "stat": "mm_zerg_wins", 246 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/7543096596cee23eed6159dd1b308463.png" 247 | }, 248 | "avatar_zerg_mutalisk.jpg": { 249 | "level": 2500, 250 | "stat": "mm_zerg_wins", 251 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/93f4430c907e7e2c90af548dcca2c9a3.png" 252 | }, 253 | "avatar_zerg_mutalisk.jpg?f=1": { 254 | "level": 2500, 255 | "stat": "mm_zerg_wins", 256 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/19dadf69e02d71f1d2a07f2d7f4dde39.png" 257 | }, 258 | "avatar_zerg_overlord.jpg": { 259 | "level": 250, 260 | "stat": "mm_zerg_wins", 261 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/ea2a8f38cb465e237126947632d76b5c.png" 262 | }, 263 | "avatar_zerg_overlord.jpg?f=1": { 264 | "level": 250, 265 | "stat": "mm_zerg_wins", 266 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/139b48f9b628b0585f34153a07647189.png" 267 | }, 268 | "avatar_zerg_queen.jpg": { 269 | "level": 25000, 270 | "stat": "mm_zerg_wins", 271 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/08d99d3f010087e86f374c7eb69f62b9.png" 272 | }, 273 | "avatar_zerg_queen.jpg?f=1": { 274 | "level": 25000, 275 | "stat": "mm_zerg_wins", 276 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/65a80cecfdc3d9b07fe28087d69ecbe6.png" 277 | }, 278 | "avatar_zerg_ultralisk.jpg": { 279 | "level": 50000, 280 | "stat": "mm_zerg_wins", 281 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/34b083d5b2d61299abf343d643b1ecca.png" 282 | }, 283 | "avatar_zerg_ultralisk.jpg?f=1": { 284 | "level": 50000, 285 | "stat": "mm_zerg_wins", 286 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/3fa83c7f32fc3e6962481401e20a641b.png" 287 | }, 288 | "avatar_zerg_zergling.jpg": { 289 | "level": 500, 290 | "stat": "mm_zerg_wins", 291 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/580e4f797aacffcf5cda5e3ec0bfbaee.png" 292 | }, 293 | "avatar_zerg_zergling.jpg?f=1": { 294 | "level": 500, 295 | "stat": "mm_zerg_wins", 296 | "url": "https://d8un0y0mnd29o.cloudfront.net/avatar-icons/S1/cdd9f2316af2e5dc091a29e9275b47ac.png" 297 | } 298 | }, 299 | "avatars_stats": { 300 | "mm_protoss_wins": { "bonus": 0, "normal": 0, "total": 0 }, 301 | "mm_terran_wins": { "bonus": 0, "normal": 0, "total": 0 }, 302 | "mm_zerg_wins": { "bonus": 0, "normal": 0, "total": 0 } 303 | }, 304 | "maps": [], 305 | "matchmaked_season_buckets": { 306 | "12": [0, 1163, 1397, 1561, 1742, 2028, 2244, 9999] 307 | }, 308 | "player_stats": [], 309 | "players": { 310 | "106009855": { 311 | "aurora_id": 1794270, 312 | "benefactor_id": "0", 313 | "game_info": { 314 | "attributes": { 315 | "closed_slots": "0", 316 | "flags": "34", 317 | "game_speed": "6", 318 | "host_name": "bob9", 319 | "is_replay": "false", 320 | "map_crc": "1427268323", 321 | "map_file_name": "(4)Polypoid 1.65.scx", 322 | "map_file_size": "109564", 323 | "map_height": "128", 324 | "map_md5": "3C7671368F9267E1EA07E56B7517E13A", 325 | "map_name": "\u0007Polyp\u0006oid \u00061\u0003.65", 326 | "map_tile_set": "4", 327 | "map_width": "128", 328 | "net_turn_rate": "16", 329 | "observers_current": "0", 330 | "observers_max": "0", 331 | "players_ai": "0", 332 | "players_current": "2", 333 | "players_max": "2", 334 | "proxy": "false", 335 | "rank": "3", 336 | "save_game_id": "0" 337 | }, 338 | "id": "1045576024", 339 | "name": "CHYMpmCQX^HI" 340 | }, 341 | "game_result": { 342 | "": { 343 | "attributes": { "gPlayerData_idx": "7", "left": "0", "type": "none" }, 344 | "is_computer": false, 345 | "result": "Undecided" 346 | }, 347 | "FRObob": { 348 | "attributes": { 349 | "gPlayerData_idx": "3", 350 | "left": "1", 351 | "race": "terran", 352 | "team": "2", 353 | "type": "player" 354 | }, 355 | "is_computer": false, 356 | "result": "Loss" 357 | }, 358 | "bob9": { 359 | "attributes": { 360 | "gPlayerData_idx": "0", 361 | "left": "0", 362 | "race": "zerg", 363 | "team": "1", 364 | "type": "player" 365 | }, 366 | "is_computer": false, 367 | "result": "Win" 368 | } 369 | }, 370 | "gateway_id": 10, 371 | "info_attributes": { 372 | "_default_region": "ORD", 373 | "_email": "bob@GMAIL.COM", 374 | "connection_info": "CHYMpmCQX^HI", 375 | "map": "3c7671368f9267e1ea07e56b7517e13a", 376 | "map_selection": "8c28e5c07d2ae6c7318bdb44980afa36", 377 | "player_battle_tag": "bob#1840", 378 | "player_legacy_gateway_id": "10", 379 | "player_legacy_toon_name": "bob9", 380 | "player_region": "US", 381 | "player_routing_via_proxy_server": "false", 382 | "race": "Zerg" 383 | }, 384 | "matching_attributes": { "net_version": "233" }, 385 | "name": "bob9", 386 | "score": { 387 | "base": 1284, 388 | "bucket_new": 2, 389 | "bucket_old": 2, 390 | "current_stat_bucket": 3, 391 | "current_stat_losses": 308, 392 | "current_stat_wins": 296, 393 | "delta": 19, 394 | "season_id": 12, 395 | "win_streak": 0 396 | } 397 | }, 398 | "51337919": { 399 | "aurora_id": 378001376, 400 | "benefactor_id": "0", 401 | "game_info": { 402 | "attributes": { 403 | "closed_slots": "0", 404 | "flags": "34", 405 | "game_speed": "6", 406 | "host_name": "bob9", 407 | "is_replay": "false", 408 | "map_crc": "1427268323", 409 | "map_file_name": "(4)Polypoid 1.65.scx", 410 | "map_file_size": "109564", 411 | "map_height": "128", 412 | "map_md5": "3C7671368F9267E1EA07E56B7517E13A", 413 | "map_name": "\u0007Polyp\u0006oid \u00061\u0003.65", 414 | "map_tile_set": "4", 415 | "map_width": "128", 416 | "net_turn_rate": "16", 417 | "observers_current": "0", 418 | "observers_max": "0", 419 | "players_ai": "0", 420 | "players_current": "1", 421 | "players_max": "2", 422 | "proxy": "false", 423 | "rank": "3", 424 | "save_game_id": "0" 425 | }, 426 | "id": "1045576024", 427 | "name": "CHYMpmCQX^HI" 428 | }, 429 | "game_result": { 430 | "": { 431 | "attributes": { "gPlayerData_idx": "7", "left": "0", "type": "none" }, 432 | "is_computer": false, 433 | "result": "Undecided" 434 | }, 435 | "FRObob": { 436 | "attributes": { 437 | "gPlayerData_idx": "3", 438 | "left": "0", 439 | "race": "terran", 440 | "team": "2", 441 | "type": "player" 442 | }, 443 | "is_computer": false, 444 | "result": "Loss" 445 | }, 446 | "bob9": { 447 | "attributes": { 448 | "gPlayerData_idx": "0", 449 | "left": "0", 450 | "race": "zerg", 451 | "team": "1", 452 | "type": "player" 453 | }, 454 | "is_computer": false, 455 | "result": "Win" 456 | } 457 | }, 458 | "gateway_id": 10, 459 | "info_attributes": { 460 | "_default_region": "ORD", 461 | "_email": "BRANDON-102030@HOTMAIL.COM", 462 | "connection_info": "l^wFdbGfArCK", 463 | "map": "3c7671368f9267e1ea07e56b7517e13a", 464 | "player_battle_tag": "FRObob#11676", 465 | "player_legacy_gateway_id": "10", 466 | "player_legacy_toon_name": "FRObob", 467 | "player_region": "US", 468 | "player_routing_via_proxy_server": "false", 469 | "race": "Terran" 470 | }, 471 | "matching_attributes": { "net_version": "233" }, 472 | "name": "FRObob", 473 | "score": { 474 | "base": 1379, 475 | "bucket_new": 2, 476 | "bucket_old": 2, 477 | "current_stat_bucket": 2, 478 | "current_stat_losses": 80, 479 | "current_stat_wins": 73, 480 | "delta": -26, 481 | "season_id": 12, 482 | "win_streak": 0 483 | } 484 | } 485 | }, 486 | "replays": [ 487 | { 488 | "attributes": { 489 | "game_creator": "bob9", 490 | "game_id": "0", 491 | "game_name": "CHYMpmCQX^HI", 492 | "game_save_id": "0", 493 | "game_speed": "6", 494 | "game_sub_type": "1", 495 | "game_type": "15", 496 | "map_era": "4", 497 | "map_height": "128", 498 | "map_title": "\u0007Polyp\u0006oid \u00061\u0003.65", 499 | "map_width": "128", 500 | "replay_description": "", 501 | "replay_humans": "2", 502 | "replay_map_number": "0", 503 | "replay_max_players": "8", 504 | "replay_min_players": "1", 505 | "replay_opponents": "0", 506 | "replay_player_names": "bob9,FRObob", 507 | "replay_player_races": "Z,T", 508 | "replay_player_types": "1,1", 509 | "replay_result": "1" 510 | }, 511 | "create_time": 1675174886, 512 | "link": "", 513 | "md5": "a99791753017beb2cb66b298e1f94cfe", 514 | "url": "https://s3-us-west-1.amazonaws.com/user-uploads-prod.classic.blizzard.com/S1-replays/1794270/106009855/a99791753017beb2cb66b298e1f94cfe.replay" 515 | }, 516 | { 517 | "attributes": { 518 | "game_creator": "bob9", 519 | "game_id": "1", 520 | "game_name": "CHYMpmCQX^HI", 521 | "game_save_id": "0", 522 | "game_speed": "6", 523 | "game_sub_type": "1", 524 | "game_type": "15", 525 | "map_era": "4", 526 | "map_height": "128", 527 | "map_title": "\u0007Polyp\u0006oid \u00061\u0003.65", 528 | "map_width": "128", 529 | "replay_description": "", 530 | "replay_humans": "2", 531 | "replay_map_number": "0", 532 | "replay_max_players": "8", 533 | "replay_min_players": "1", 534 | "replay_opponents": "0", 535 | "replay_player_names": "bob9,FRObob", 536 | "replay_player_races": "Z,T", 537 | "replay_player_types": "1,1", 538 | "replay_result": "2" 539 | }, 540 | "create_time": 1675174861, 541 | "link": "", 542 | "md5": "120398123098123908", 543 | "url": "https://s3-us-west-1.amazonaws.com/user-uploads-prod.classic.blizzard.com/S1-replays/378001376/51337919/120398123098123908.replay" 544 | } 545 | ] 546 | } 547 | -------------------------------------------------------------------------------- /test/data/web-api/v2/aurora-profile-by-toon/bob/10%3Frequest_flags%3Dscr_mmgameloading.json: -------------------------------------------------------------------------------- 1 | { 2 | "account_flags": "sc-carbot,hd,scr-s8-rank-u,sc-presale,scr-s10-rank-u,sc-goty-2018", 3 | "aurora_id": 123123, 4 | "battle_tag": "bob", 5 | "country_code": "USA", 6 | "matchmaked_current_season": 13, 7 | "matchmaked_current_season_buckets": [ 8 | 0, 1163, 1397, 1561, 1742, 2028, 2244, 9999 9 | ], 10 | "matchmaked_stats": [ 11 | { 12 | "benefactor_id": "0", 13 | "bucket": 3, 14 | "disconnects": 3, 15 | "game_mode_id": 1, 16 | "highest_points": 13600, 17 | "highest_rating": 1653, 18 | "loss_streak": 1, 19 | "losses": 308, 20 | "points": 12000, 21 | "rating": 1471, 22 | "season_id": 13, 23 | "toon": "bob9", 24 | "toon_guid": 3, 25 | "win_streak": 0, 26 | "wins": 296 27 | }, 28 | { 29 | "benefactor_id": "0", 30 | "bucket": 3, 31 | "disconnects": 1, 32 | "game_mode_id": 1, 33 | "highest_points": 3200, 34 | "highest_rating": 1527, 35 | "loss_streak": 3, 36 | "losses": 8, 37 | "points": 2600, 38 | "rating": 1478, 39 | "season_id": 13, 40 | "toon": "whateverman", 41 | "toon_guid": 7, 42 | "win_streak": 0, 43 | "wins": 10 44 | }, 45 | { 46 | "benefactor_id": "0", 47 | "bucket": 0, 48 | "disconnects": 0, 49 | "game_mode_id": 1, 50 | "highest_points": 200, 51 | "highest_rating": 1479, 52 | "loss_streak": 1, 53 | "losses": 2, 54 | "points": 200, 55 | "rating": 0, 56 | "season_id": 13, 57 | "toon": "lololollol", 58 | "toon_guid": 6, 59 | "win_streak": 0, 60 | "wins": 1 61 | }, 62 | { 63 | "benefactor_id": "0", 64 | "bucket": 4, 65 | "disconnects": 0, 66 | "game_mode_id": 1, 67 | "highest_points": 13600, 68 | "highest_rating": 1691, 69 | "loss_streak": 0, 70 | "losses": 66, 71 | "points": 13600, 72 | "rating": 1685, 73 | "season_id": 13, 74 | "toon": "bob", 75 | "toon_guid": 2, 76 | "win_streak": 1, 77 | "wins": 79 78 | }, 79 | { 80 | "benefactor_id": "0", 81 | "bucket": 3, 82 | "disconnects": 0, 83 | "game_mode_id": 1, 84 | "highest_points": 400, 85 | "highest_rating": 1464, 86 | "loss_streak": 2, 87 | "losses": 5, 88 | "points": 400, 89 | "rating": 1435, 90 | "season_id": 13, 91 | "toon": "bobzy", 92 | "toon_guid": 4, 93 | "win_streak": 0, 94 | "wins": 2 95 | }, 96 | { 97 | "benefactor_id": "0", 98 | "bucket": 2, 99 | "disconnects": 0, 100 | "game_mode_id": 1, 101 | "highest_points": 0, 102 | "highest_rating": 1490, 103 | "loss_streak": 5, 104 | "losses": 5, 105 | "points": 0, 106 | "rating": 1190, 107 | "season_id": 13, 108 | "toon": "hehehhehehe", 109 | "toon_guid": 5, 110 | "win_streak": 0, 111 | "wins": 0 112 | }, 113 | { 114 | "benefactor_id": "0", 115 | "bucket": 2, 116 | "disconnects": 0, 117 | "game_mode_id": 1, 118 | "highest_points": 6800, 119 | "highest_rating": 1729, 120 | "loss_streak": 4, 121 | "losses": 68, 122 | "points": 5000, 123 | "rating": 1273, 124 | "season_id": 12, 125 | "toon": "bob9", 126 | "toon_guid": 3, 127 | "win_streak": 0, 128 | "wins": 46 129 | }, 130 | { 131 | "benefactor_id": "0", 132 | "bucket": 3, 133 | "disconnects": 0, 134 | "game_mode_id": 1, 135 | "highest_points": 1400, 136 | "highest_rating": 1500, 137 | "loss_streak": 0, 138 | "losses": 3, 139 | "points": 1400, 140 | "rating": 1486, 141 | "season_id": 12, 142 | "toon": "hehehhehehe", 143 | "toon_guid": 5, 144 | "win_streak": 3, 145 | "wins": 5 146 | }, 147 | { 148 | "benefactor_id": "0", 149 | "bucket": 0, 150 | "disconnects": 0, 151 | "game_mode_id": 1, 152 | "highest_points": 0, 153 | "highest_rating": 1468, 154 | "loss_streak": 1, 155 | "losses": 1, 156 | "points": 0, 157 | "rating": 0, 158 | "season_id": 12, 159 | "toon": "bobzy", 160 | "toon_guid": 4, 161 | "win_streak": 0, 162 | "wins": 0 163 | }, 164 | { 165 | "benefactor_id": "0", 166 | "bucket": 0, 167 | "disconnects": 0, 168 | "game_mode_id": 1, 169 | "highest_points": 0, 170 | "highest_rating": 1472, 171 | "loss_streak": 1, 172 | "losses": 1, 173 | "points": 0, 174 | "rating": 0, 175 | "season_id": 12, 176 | "toon": "kekekekek", 177 | "toon_guid": 1, 178 | "win_streak": 0, 179 | "wins": 0 180 | }, 181 | { 182 | "benefactor_id": "0", 183 | "bucket": 0, 184 | "disconnects": 0, 185 | "game_mode_id": 1, 186 | "highest_points": 200, 187 | "highest_rating": 1546, 188 | "loss_streak": 2, 189 | "losses": 2, 190 | "points": 200, 191 | "rating": 0, 192 | "season_id": 11, 193 | "toon": "bob", 194 | "toon_guid": 2, 195 | "win_streak": 0, 196 | "wins": 1 197 | }, 198 | { 199 | "benefactor_id": "0", 200 | "bucket": 0, 201 | "disconnects": 0, 202 | "game_mode_id": 1, 203 | "highest_points": 0, 204 | "highest_rating": 1530, 205 | "loss_streak": 1, 206 | "losses": 1, 207 | "points": 0, 208 | "rating": 0, 209 | "season_id": 11, 210 | "toon": "bob9", 211 | "toon_guid": 3, 212 | "win_streak": 0, 213 | "wins": 0 214 | }, 215 | { 216 | "benefactor_id": "0", 217 | "bucket": 4, 218 | "disconnects": 1, 219 | "game_mode_id": 1, 220 | "highest_points": 14200, 221 | "highest_rating": 1620, 222 | "loss_streak": 0, 223 | "losses": 126, 224 | "points": 14200, 225 | "rating": 1620, 226 | "season_id": 9, 227 | "toon": "bob", 228 | "toon_guid": 2, 229 | "win_streak": 7, 230 | "wins": 132 231 | }, 232 | { 233 | "benefactor_id": "0", 234 | "bucket": 0, 235 | "disconnects": 0, 236 | "game_mode_id": 1, 237 | "highest_points": 0, 238 | "highest_rating": 1466, 239 | "loss_streak": 1, 240 | "losses": 1, 241 | "points": 0, 242 | "rating": 0, 243 | "season_id": 1, 244 | "toon": "bob", 245 | "toon_guid": 2, 246 | "win_streak": 0, 247 | "wins": 0 248 | } 249 | ], 250 | "program_id": "S1", 251 | "toon_guid_by_gateway": { 252 | "10": { 253 | "kekekekek": 1, 254 | "bob9": 3, 255 | "lololollol": 6 256 | }, 257 | "11": { 258 | "bob": 2 259 | }, 260 | "20": { 261 | "bobzy": 4 262 | }, 263 | "30": { 264 | "hehehhehehe": 5, 265 | "whateverman": 7 266 | } 267 | } 268 | } 269 | -------------------------------------------------------------------------------- /test/data/web-api/v2/aurora-profile-by-toon/bob/10%3Frequest_flags%3Dscr_mmtooninfo.json: -------------------------------------------------------------------------------- 1 | { 2 | "account_flags": "sc-carbot,hd,scr-s8-rank-u,sc-presale,scr-s10-rank-u,sc-goty-2018", 3 | "aurora_id": 123123, 4 | "battle_tag": "bob", 5 | "country_code": "USA", 6 | "matchmaked_current_season": 13, 7 | "matchmaked_current_season_buckets": [ 8 | 0, 1163, 1397, 1561, 1742, 2028, 2244, 9999 9 | ], 10 | "matchmaked_stats": [ 11 | { 12 | "benefactor_id": "0", 13 | "bucket": 3, 14 | "disconnects": 3, 15 | "game_mode_id": 1, 16 | "highest_points": 13600, 17 | "highest_rating": 1653, 18 | "loss_streak": 1, 19 | "losses": 308, 20 | "points": 12000, 21 | "rating": 1471, 22 | "season_id": 13, 23 | "toon": "bob9", 24 | "toon_guid": 3, 25 | "win_streak": 0, 26 | "wins": 296 27 | }, 28 | { 29 | "benefactor_id": "0", 30 | "bucket": 3, 31 | "disconnects": 1, 32 | "game_mode_id": 1, 33 | "highest_points": 3200, 34 | "highest_rating": 1527, 35 | "loss_streak": 3, 36 | "losses": 8, 37 | "points": 2600, 38 | "rating": 1478, 39 | "season_id": 13, 40 | "toon": "kekekekekee", 41 | "toon_guid": 7, 42 | "win_streak": 0, 43 | "wins": 10 44 | }, 45 | { 46 | "benefactor_id": "0", 47 | "bucket": 0, 48 | "disconnects": 0, 49 | "game_mode_id": 1, 50 | "highest_points": 200, 51 | "highest_rating": 1479, 52 | "loss_streak": 1, 53 | "losses": 2, 54 | "points": 200, 55 | "rating": 0, 56 | "season_id": 13, 57 | "toon": "heheheheheeh", 58 | "toon_guid": 6, 59 | "win_streak": 0, 60 | "wins": 1 61 | }, 62 | { 63 | "benefactor_id": "0", 64 | "bucket": 4, 65 | "disconnects": 0, 66 | "game_mode_id": 1, 67 | "highest_points": 13600, 68 | "highest_rating": 1691, 69 | "loss_streak": 0, 70 | "losses": 66, 71 | "points": 13600, 72 | "rating": 1685, 73 | "season_id": 13, 74 | "toon": "bob", 75 | "toon_guid": 2, 76 | "win_streak": 1, 77 | "wins": 79 78 | }, 79 | { 80 | "benefactor_id": "0", 81 | "bucket": 3, 82 | "disconnects": 0, 83 | "game_mode_id": 1, 84 | "highest_points": 400, 85 | "highest_rating": 1464, 86 | "loss_streak": 2, 87 | "losses": 5, 88 | "points": 400, 89 | "rating": 1435, 90 | "season_id": 13, 91 | "toon": "bobzy", 92 | "toon_guid": 4, 93 | "win_streak": 0, 94 | "wins": 2 95 | }, 96 | { 97 | "benefactor_id": "0", 98 | "bucket": 2, 99 | "disconnects": 0, 100 | "game_mode_id": 1, 101 | "highest_points": 0, 102 | "highest_rating": 1490, 103 | "loss_streak": 5, 104 | "losses": 5, 105 | "points": 0, 106 | "rating": 1190, 107 | "season_id": 13, 108 | "toon": "weeeeeeeeeeeeeeeeeeeee", 109 | "toon_guid": 5, 110 | "win_streak": 0, 111 | "wins": 0 112 | }, 113 | { 114 | "benefactor_id": "0", 115 | "bucket": 2, 116 | "disconnects": 0, 117 | "game_mode_id": 1, 118 | "highest_points": 6800, 119 | "highest_rating": 1729, 120 | "loss_streak": 4, 121 | "losses": 68, 122 | "points": 5000, 123 | "rating": 1273, 124 | "season_id": 12, 125 | "toon": "bob9", 126 | "toon_guid": 3, 127 | "win_streak": 0, 128 | "wins": 46 129 | }, 130 | { 131 | "benefactor_id": "0", 132 | "bucket": 3, 133 | "disconnects": 0, 134 | "game_mode_id": 1, 135 | "highest_points": 1400, 136 | "highest_rating": 1500, 137 | "loss_streak": 0, 138 | "losses": 3, 139 | "points": 1400, 140 | "rating": 1486, 141 | "season_id": 12, 142 | "toon": "weeeeeeeeeeeeeeeeeeeee", 143 | "toon_guid": 5, 144 | "win_streak": 3, 145 | "wins": 5 146 | }, 147 | { 148 | "benefactor_id": "0", 149 | "bucket": 0, 150 | "disconnects": 0, 151 | "game_mode_id": 1, 152 | "highest_points": 0, 153 | "highest_rating": 1468, 154 | "loss_streak": 1, 155 | "losses": 1, 156 | "points": 0, 157 | "rating": 0, 158 | "season_id": 12, 159 | "toon": "bobzy", 160 | "toon_guid": 4, 161 | "win_streak": 0, 162 | "wins": 0 163 | }, 164 | { 165 | "benefactor_id": "0", 166 | "bucket": 0, 167 | "disconnects": 0, 168 | "game_mode_id": 1, 169 | "highest_points": 0, 170 | "highest_rating": 1472, 171 | "loss_streak": 1, 172 | "losses": 1, 173 | "points": 0, 174 | "rating": 0, 175 | "season_id": 12, 176 | "toon": "deqsi", 177 | "toon_guid": 1, 178 | "win_streak": 0, 179 | "wins": 0 180 | }, 181 | { 182 | "benefactor_id": "0", 183 | "bucket": 0, 184 | "disconnects": 0, 185 | "game_mode_id": 1, 186 | "highest_points": 200, 187 | "highest_rating": 1546, 188 | "loss_streak": 2, 189 | "losses": 2, 190 | "points": 200, 191 | "rating": 0, 192 | "season_id": 11, 193 | "toon": "bob", 194 | "toon_guid": 2, 195 | "win_streak": 0, 196 | "wins": 1 197 | }, 198 | { 199 | "benefactor_id": "0", 200 | "bucket": 0, 201 | "disconnects": 0, 202 | "game_mode_id": 1, 203 | "highest_points": 0, 204 | "highest_rating": 1530, 205 | "loss_streak": 1, 206 | "losses": 1, 207 | "points": 0, 208 | "rating": 0, 209 | "season_id": 11, 210 | "toon": "bob9", 211 | "toon_guid": 3, 212 | "win_streak": 0, 213 | "wins": 0 214 | }, 215 | { 216 | "benefactor_id": "0", 217 | "bucket": 4, 218 | "disconnects": 1, 219 | "game_mode_id": 1, 220 | "highest_points": 14200, 221 | "highest_rating": 1620, 222 | "loss_streak": 0, 223 | "losses": 126, 224 | "points": 14200, 225 | "rating": 1620, 226 | "season_id": 9, 227 | "toon": "bob", 228 | "toon_guid": 2, 229 | "win_streak": 7, 230 | "wins": 132 231 | }, 232 | { 233 | "benefactor_id": "0", 234 | "bucket": 0, 235 | "disconnects": 0, 236 | "game_mode_id": 1, 237 | "highest_points": 0, 238 | "highest_rating": 1466, 239 | "loss_streak": 1, 240 | "losses": 1, 241 | "points": 0, 242 | "rating": 0, 243 | "season_id": 1, 244 | "toon": "bob", 245 | "toon_guid": 2, 246 | "win_streak": 0, 247 | "wins": 0 248 | } 249 | ], 250 | "program_id": "S1", 251 | "toon_guid_by_gateway": { 252 | "10": { 253 | "deqsi": 1, 254 | "bob9": 3, 255 | "heheheheheeh": 6 256 | }, 257 | "11": { 258 | "bob": 2 259 | }, 260 | "20": { 261 | "bobzy": 4 262 | }, 263 | "30": { 264 | "weeeeeeeeeeeeeeeeeeeee": 5, 265 | "kekekekekee": 7 266 | } 267 | }, 268 | "toons": [ 269 | { 270 | "games_last_week": 0, 271 | "gateway_id": 10, 272 | "guid": 1, 273 | "toon": "deqsi" 274 | }, 275 | { 276 | "games_last_week": 0, 277 | "gateway_id": 11, 278 | "guid": 2, 279 | "toon": "bob" 280 | }, 281 | { 282 | "games_last_week": 89, 283 | "gateway_id": 10, 284 | "guid": 3, 285 | "toon": "bob9" 286 | }, 287 | { 288 | "games_last_week": 0, 289 | "gateway_id": 20, 290 | "guid": 4, 291 | "toon": "bobzy" 292 | }, 293 | { 294 | "games_last_week": 0, 295 | "gateway_id": 30, 296 | "guid": 5, 297 | "toon": "weeeeeeeeeeeeeeeeeeeee" 298 | }, 299 | { 300 | "games_last_week": 0, 301 | "gateway_id": 10, 302 | "guid": 6, 303 | "toon": "heheheheheeh" 304 | }, 305 | { 306 | "games_last_week": 4, 307 | "gateway_id": 30, 308 | "guid": 7, 309 | "toon": "kekekekekee" 310 | } 311 | ] 312 | } 313 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "rootDir": "./", 4 | "baseUrl": ".", 5 | "paths": { 6 | "@/*": ["./src/*"] 7 | }, 8 | "target": "ESNext", 9 | "useDefineForClassFields": true, 10 | "module": "ESNext", 11 | "lib": ["ESNext", "DOM"], 12 | "moduleResolution": "Node", 13 | "strict": true, 14 | "sourceMap": true, 15 | "resolveJsonModule": true, 16 | "esModuleInterop": true, 17 | "noEmit": true, 18 | "noUnusedLocals": true, 19 | "noUnusedParameters": true, 20 | "noImplicitReturns": true, 21 | "forceConsistentCasingInFileNames": true, 22 | "types": ["node"], 23 | "inlineSources": true 24 | }, 25 | "include": ["src", "test"], 26 | "exclude": ["node_modules", ".history/**"] 27 | } 28 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import dts from 'vite-plugin-dts'; 3 | import { defineConfig } from "vitest/config"; 4 | 5 | module.exports = defineConfig({ 6 | base: "./", 7 | plugins: [dts()], 8 | resolve: { 9 | alias: { 10 | "@": path.resolve(__dirname, "src"), 11 | } 12 | }, 13 | build: { 14 | lib: { 15 | entry: path.resolve(__dirname, "src/index.ts"), 16 | name: 'BwWebApi', 17 | fileName: 'bw-web-api', 18 | }, 19 | sourcemap: true, 20 | }, 21 | test: {} 22 | }); 23 | --------------------------------------------------------------------------------