@timmsy/riftjs 2.1.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +217 -130
- package/dist/endpoints/datadragon.d.ts +4 -0
- package/dist/endpoints/datadragon.js +40 -0
- package/dist/endpoints/riot.d.ts +2 -0
- package/dist/endpoints/riot.js +169 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +106 -0
- package/dist/test-endpoints.d.ts +1 -0
- package/{test-endpoints.js → dist/test-endpoints.js} +29 -39
- package/dist/types.d.ts +60 -0
- package/dist/types.js +2 -0
- package/package.json +23 -3
- package/.github/workflows/publish.yml +0 -52
- package/endpoints/datadragon.js +0 -40
- package/endpoints/riot.js +0 -217
- package/index.js +0 -88
package/dist/index.js
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.DataDragon = exports.RiotAPI = void 0;
|
|
7
|
+
require("dotenv/config");
|
|
8
|
+
const axios_1 = __importDefault(require("axios"));
|
|
9
|
+
const datadragon_1 = __importDefault(require("./endpoints/datadragon"));
|
|
10
|
+
const riot_1 = __importDefault(require("./endpoints/riot"));
|
|
11
|
+
const regionMap = {
|
|
12
|
+
BR1: { platform: 'br1.api.riotgames.com', shard: 'americas.api.riotgames.com' },
|
|
13
|
+
EUN1: { platform: 'eun1.api.riotgames.com', shard: 'europe.api.riotgames.com' },
|
|
14
|
+
EUW1: { platform: 'euw1.api.riotgames.com', shard: 'europe.api.riotgames.com' },
|
|
15
|
+
JP1: { platform: 'jp1.api.riotgames.com', shard: 'asia.api.riotgames.com' },
|
|
16
|
+
KR: { platform: 'kr.api.riotgames.com', shard: 'asia.api.riotgames.com' },
|
|
17
|
+
LA1: { platform: 'la1.api.riotgames.com', shard: 'americas.api.riotgames.com' },
|
|
18
|
+
LA2: { platform: 'la2.api.riotgames.com', shard: 'americas.api.riotgames.com' },
|
|
19
|
+
NA1: { platform: 'na1.api.riotgames.com', shard: 'americas.api.riotgames.com' },
|
|
20
|
+
OC1: { platform: 'oc1.api.riotgames.com', shard: 'sea.api.riotgames.com' },
|
|
21
|
+
TR1: { platform: 'tr1.api.riotgames.com', shard: 'europe.api.riotgames.com' },
|
|
22
|
+
RU: { platform: 'ru.api.riotgames.com', shard: 'europe.api.riotgames.com' },
|
|
23
|
+
PH2: { platform: 'ph2.api.riotgames.com', shard: 'sea.api.riotgames.com' },
|
|
24
|
+
SG2: { platform: 'sg2.api.riotgames.com', shard: 'sea.api.riotgames.com' },
|
|
25
|
+
TH2: { platform: 'th2.api.riotgames.com', shard: 'sea.api.riotgames.com' },
|
|
26
|
+
TW2: { platform: 'tw2.api.riotgames.com', shard: 'sea.api.riotgames.com' },
|
|
27
|
+
VN2: { platform: 'vn2.api.riotgames.com', shard: 'sea.api.riotgames.com' },
|
|
28
|
+
};
|
|
29
|
+
const parseRegion = (region) => {
|
|
30
|
+
// Maintainer note (Timmsy): fail fast on bad region input so routing bugs are obvious immediately.
|
|
31
|
+
const upper = region.toUpperCase();
|
|
32
|
+
if (!regionMap[upper])
|
|
33
|
+
throw new Error(`Invalid region: ${region}`);
|
|
34
|
+
return upper;
|
|
35
|
+
};
|
|
36
|
+
class RiotAPI {
|
|
37
|
+
constructor() {
|
|
38
|
+
this._handleError = (error) => {
|
|
39
|
+
if (axios_1.default.isAxiosError(error)) {
|
|
40
|
+
if (error.response) {
|
|
41
|
+
const status = error.response.status;
|
|
42
|
+
const data = error.response.data;
|
|
43
|
+
return new Error(`API error ${status}: ${data?.status?.message || 'Unknown error'}`);
|
|
44
|
+
}
|
|
45
|
+
if (error.request) {
|
|
46
|
+
return new Error('No response received from the server');
|
|
47
|
+
}
|
|
48
|
+
return new Error(`Request error: ${error.message}`);
|
|
49
|
+
}
|
|
50
|
+
if (error instanceof Error) {
|
|
51
|
+
return new Error(`Request error: ${error.message}`);
|
|
52
|
+
}
|
|
53
|
+
return new Error('Request error: Unknown error');
|
|
54
|
+
};
|
|
55
|
+
this.apiKey = process.env.RIOT_API_KEY || '';
|
|
56
|
+
if (!this.apiKey)
|
|
57
|
+
throw new Error('RIOT_API_KEY is required in .env');
|
|
58
|
+
this.region = parseRegion(process.env.REGION || 'EUW1');
|
|
59
|
+
this.client = axios_1.default.create({
|
|
60
|
+
headers: { 'X-Riot-Token': this.apiKey },
|
|
61
|
+
});
|
|
62
|
+
// Maintainer note (Timmsy): keep endpoint methods attached here so the class API stays flat for consumers.
|
|
63
|
+
Object.assign(this, (0, riot_1.default)({
|
|
64
|
+
client: this.client,
|
|
65
|
+
defaultRegion: this.region,
|
|
66
|
+
regionMap,
|
|
67
|
+
handleError: this._handleError,
|
|
68
|
+
}));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
exports.RiotAPI = RiotAPI;
|
|
72
|
+
class DataDragon {
|
|
73
|
+
constructor(version = null, locale = 'en_US') {
|
|
74
|
+
this.version = version;
|
|
75
|
+
this.locale = locale;
|
|
76
|
+
this.baseURL = null;
|
|
77
|
+
this.baseURLPromise = null;
|
|
78
|
+
Object.assign(this, (0, datadragon_1.default)(() => this.resolveBaseURL()));
|
|
79
|
+
}
|
|
80
|
+
async resolveBaseURL() {
|
|
81
|
+
if (this.baseURL)
|
|
82
|
+
return this.baseURL;
|
|
83
|
+
if (this.baseURLPromise)
|
|
84
|
+
return this.baseURLPromise;
|
|
85
|
+
// Maintainer note (Timmsy): share one in-flight resolver to avoid duplicate version requests under concurrency.
|
|
86
|
+
this.baseURLPromise = (async () => {
|
|
87
|
+
if (!this.version) {
|
|
88
|
+
const response = await axios_1.default.get('https://ddragon.leagueoflegends.com/api/versions.json');
|
|
89
|
+
const latestVersion = Array.isArray(response.data) ? response.data[0] : null;
|
|
90
|
+
if (!latestVersion) {
|
|
91
|
+
throw new Error('Could not resolve latest Data Dragon version');
|
|
92
|
+
}
|
|
93
|
+
this.version = latestVersion;
|
|
94
|
+
}
|
|
95
|
+
this.baseURL = `https://ddragon.leagueoflegends.com/cdn/${this.version}/data/${this.locale}`;
|
|
96
|
+
return this.baseURL;
|
|
97
|
+
})();
|
|
98
|
+
try {
|
|
99
|
+
return await this.baseURLPromise;
|
|
100
|
+
}
|
|
101
|
+
finally {
|
|
102
|
+
this.baseURLPromise = null;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
exports.DataDragon = DataDragon;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import 'dotenv/config';
|
|
@@ -1,71 +1,61 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
require("dotenv/config");
|
|
4
|
+
const index_1 = require("./index");
|
|
4
5
|
async function run() {
|
|
5
6
|
const riotId = process.env.TEST_RIOT_ID;
|
|
6
7
|
const tagLine = process.env.TEST_TAG_LINE;
|
|
7
|
-
const dd = new DataDragon();
|
|
8
|
-
|
|
8
|
+
const dd = new index_1.DataDragon();
|
|
9
9
|
if (process.env.RIOT_API_KEY && riotId) {
|
|
10
|
-
const riot = new RiotAPI();
|
|
10
|
+
const riot = new index_1.RiotAPI();
|
|
11
11
|
const account = await riot.getAccountByRiotId(riotId, tagLine);
|
|
12
12
|
console.log('[PASS] getAccountByRiotId:', account.puuid);
|
|
13
|
-
|
|
14
|
-
const summoner = await riot.getSummonerByPuuid(
|
|
13
|
+
const puuid = String(account.puuid || '');
|
|
14
|
+
const summoner = await riot.getSummonerByPuuid(puuid);
|
|
15
15
|
console.log('[PASS] getSummonerByPuuid:', {
|
|
16
16
|
puuid: summoner.puuid,
|
|
17
17
|
summonerLevel: summoner.summonerLevel,
|
|
18
18
|
});
|
|
19
|
-
|
|
20
|
-
const rank = await riot.getRankByPuuid(account.puuid);
|
|
19
|
+
const rank = await riot.getRankByPuuid(puuid);
|
|
21
20
|
console.log('[PASS] getRankByPuuid:', {
|
|
22
|
-
solo: rank.solo
|
|
23
|
-
|
|
21
|
+
solo: rank.solo
|
|
22
|
+
? `${rank.solo.tier} ${rank.solo.rank} | ${rank.solo.leaguePoints} LP | ${rank.solo.wins}W-${rank.solo.losses}L | ${rank.solo.winRate}% WR`
|
|
23
|
+
: null,
|
|
24
|
+
flex: rank.flex
|
|
25
|
+
? `${rank.flex.tier} ${rank.flex.rank} | ${rank.flex.leaguePoints} LP | ${rank.flex.wins}W-${rank.flex.losses}L | ${rank.flex.winRate}% WR`
|
|
26
|
+
: null,
|
|
24
27
|
});
|
|
25
|
-
|
|
26
|
-
const matchIds = await riot.getMatchlistByPuuid(account.puuid, { start: 0, count: 3 });
|
|
28
|
+
const matchIds = await riot.getMatchlistByPuuid(puuid, { start: 0, count: 3 });
|
|
27
29
|
console.log('[PASS] getMatchlistByPuuid:', matchIds.length, 'match ids');
|
|
28
|
-
|
|
29
30
|
if (matchIds.length > 0) {
|
|
30
31
|
const match = await riot.getMatchById(matchIds[0]);
|
|
31
|
-
console.log('[PASS] getMatchById:', match.metadata
|
|
32
|
-
|
|
32
|
+
console.log('[PASS] getMatchById:', match.metadata?.matchId);
|
|
33
33
|
const timeline = await riot.getMatchTimelineById(matchIds[0]);
|
|
34
|
-
console.log('[PASS] getMatchTimelineById:', timeline.metadata
|
|
35
|
-
|
|
36
|
-
const allMatchIds = await riot.getMatchlistByPuuidAll(
|
|
37
|
-
account.puuid,
|
|
38
|
-
{ start: 0 },
|
|
39
|
-
undefined,
|
|
40
|
-
{ maxMatches: 2, delayMs: 0 }
|
|
41
|
-
);
|
|
34
|
+
console.log('[PASS] getMatchTimelineById:', timeline.metadata?.matchId);
|
|
35
|
+
const allMatchIds = await riot.getMatchlistByPuuidAll(puuid, { start: 0 }, undefined, { maxMatches: 2, delayMs: 0 });
|
|
42
36
|
console.log('[PASS] getMatchlistByPuuidAll:', allMatchIds.length, 'match ids');
|
|
43
|
-
|
|
44
|
-
const withDetails = await riot.getMatchesWithDetailsByPuuid(
|
|
45
|
-
account.puuid,
|
|
46
|
-
{ start: 0 },
|
|
47
|
-
undefined,
|
|
48
|
-
{ maxMatches: 2, pageDelayMs: 0, detailDelayMs: 0 }
|
|
49
|
-
);
|
|
37
|
+
const withDetails = await riot.getMatchesWithDetailsByPuuid(puuid, { start: 0 }, undefined, { maxMatches: 2, pageDelayMs: 0, detailDelayMs: 0 });
|
|
50
38
|
console.log('[PASS] getMatchesWithDetailsByPuuid:', withDetails.matches.length, 'matches');
|
|
51
|
-
}
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
// Maintainer note (Timmsy): no-match accounts are valid, so keep this as a skip rather than a failure.
|
|
52
42
|
console.log('[SKIP] Match-by-id/timeline/all/details checks: no matches returned');
|
|
53
43
|
}
|
|
54
|
-
}
|
|
44
|
+
}
|
|
45
|
+
else if (process.env.RIOT_API_KEY) {
|
|
55
46
|
console.log('[SKIP] Riot endpoints: set TEST_RIOT_ID (and TEST_TAG_LINE if needed)');
|
|
56
|
-
}
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
57
49
|
console.log('[SKIP] Riot endpoints: set RIOT_API_KEY and TEST_RIOT_ID');
|
|
58
50
|
}
|
|
59
|
-
|
|
60
51
|
const champions = await dd.getChampions();
|
|
61
52
|
console.log('[PASS] getChampions:', Object.keys(champions.data || {}).length, 'champions');
|
|
62
53
|
console.log('[INFO] DataDragon version:', dd.version);
|
|
63
|
-
|
|
64
54
|
const items = await dd.getItems();
|
|
65
55
|
console.log('[PASS] getItems:', Object.keys(items.data || {}).length, 'items');
|
|
66
56
|
}
|
|
67
|
-
|
|
68
57
|
run().catch((error) => {
|
|
69
|
-
|
|
58
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
59
|
+
console.error('[FAIL]', message);
|
|
70
60
|
process.exitCode = 1;
|
|
71
61
|
});
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { AxiosInstance } from 'axios';
|
|
2
|
+
export type RegionCode = 'BR1' | 'EUN1' | 'EUW1' | 'JP1' | 'KR' | 'LA1' | 'LA2' | 'NA1' | 'OC1' | 'TR1' | 'RU' | 'PH2' | 'SG2' | 'TH2' | 'TW2' | 'VN2';
|
|
3
|
+
export interface RegionHosts {
|
|
4
|
+
platform: string;
|
|
5
|
+
shard: string;
|
|
6
|
+
}
|
|
7
|
+
export type RegionMap = Record<RegionCode, RegionHosts>;
|
|
8
|
+
export interface MatchlistOptions {
|
|
9
|
+
startTime?: number;
|
|
10
|
+
endTime?: number;
|
|
11
|
+
queue?: number;
|
|
12
|
+
type?: string;
|
|
13
|
+
start?: number;
|
|
14
|
+
count?: number;
|
|
15
|
+
}
|
|
16
|
+
export interface MatchlistAllPacing {
|
|
17
|
+
delayMs?: number;
|
|
18
|
+
maxMatches?: number | null;
|
|
19
|
+
}
|
|
20
|
+
export interface MatchDetailsPacing {
|
|
21
|
+
pageDelayMs?: number;
|
|
22
|
+
detailDelayMs?: number;
|
|
23
|
+
maxMatches?: number | null;
|
|
24
|
+
}
|
|
25
|
+
export interface RankEntry extends Record<string, unknown> {
|
|
26
|
+
queueType?: string;
|
|
27
|
+
wins?: number;
|
|
28
|
+
losses?: number;
|
|
29
|
+
}
|
|
30
|
+
export interface RankEntryWithMetrics extends RankEntry {
|
|
31
|
+
winRate: number;
|
|
32
|
+
}
|
|
33
|
+
export interface RiotEndpointMethods {
|
|
34
|
+
getAccountByRiotId(riotId: string, tagLine?: string | null, region?: RegionCode): Promise<Record<string, unknown>>;
|
|
35
|
+
getSummonerByPuuid(puuid: string, region?: RegionCode): Promise<Record<string, unknown>>;
|
|
36
|
+
getRankEntriesByPuuid(puuid: string, region?: RegionCode): Promise<RankEntry[]>;
|
|
37
|
+
getRankByPuuid(puuid: string, region?: RegionCode): Promise<{
|
|
38
|
+
solo: RankEntryWithMetrics | null;
|
|
39
|
+
flex: RankEntryWithMetrics | null;
|
|
40
|
+
entries: RankEntry[];
|
|
41
|
+
}>;
|
|
42
|
+
getMatchlistByPuuid(puuid: string, options?: MatchlistOptions, region?: RegionCode): Promise<string[]>;
|
|
43
|
+
getMatchById(matchId: string, region?: RegionCode): Promise<Record<string, unknown>>;
|
|
44
|
+
getMatchTimelineById(matchId: string, region?: RegionCode): Promise<Record<string, unknown>>;
|
|
45
|
+
getMatchlistByPuuidAll(puuid: string, options?: MatchlistOptions, region?: RegionCode, pacing?: MatchlistAllPacing): Promise<string[]>;
|
|
46
|
+
getMatchesWithDetailsByPuuid(puuid: string, options?: MatchlistOptions, region?: RegionCode, pacing?: MatchDetailsPacing): Promise<{
|
|
47
|
+
matchIds: string[];
|
|
48
|
+
matches: Record<string, unknown>[];
|
|
49
|
+
}>;
|
|
50
|
+
}
|
|
51
|
+
export interface RiotEndpointsFactoryArgs {
|
|
52
|
+
client: AxiosInstance;
|
|
53
|
+
defaultRegion: RegionCode;
|
|
54
|
+
regionMap: RegionMap;
|
|
55
|
+
handleError: (error: unknown) => Error;
|
|
56
|
+
}
|
|
57
|
+
export interface DataDragonEndpointMethods {
|
|
58
|
+
getChampions(): Promise<Record<string, unknown>>;
|
|
59
|
+
getItems(): Promise<Record<string, unknown>>;
|
|
60
|
+
}
|
package/dist/types.js
ADDED
package/package.json
CHANGED
|
@@ -1,15 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@timmsy/riftjs",
|
|
3
|
-
"version": "
|
|
4
|
-
"main": "index.js",
|
|
3
|
+
"version": "3.1.0",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"types": "dist/index.d.ts",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"require": "./dist/index.js",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"README.md",
|
|
16
|
+
"LICENSE"
|
|
17
|
+
],
|
|
5
18
|
"scripts": {
|
|
19
|
+
"build": "tsc -p tsconfig.json",
|
|
6
20
|
"test": "npm run test:endpoints",
|
|
7
|
-
"test:endpoints": "node test-endpoints.js"
|
|
21
|
+
"test:endpoints": "npm run build && node dist/test-endpoints.js",
|
|
22
|
+
"prepack": "npm run build"
|
|
8
23
|
},
|
|
9
24
|
"dependencies": {
|
|
10
25
|
"axios": "^1.7.7",
|
|
11
26
|
"dotenv": "^16.4.5"
|
|
12
27
|
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/node": "^22.13.10",
|
|
30
|
+
"typescript": "^5.8.2"
|
|
31
|
+
},
|
|
13
32
|
"keywords": [
|
|
14
33
|
"riot-api",
|
|
15
34
|
"league-of-legends",
|
|
@@ -20,6 +39,7 @@
|
|
|
20
39
|
"game-data",
|
|
21
40
|
"node-js",
|
|
22
41
|
"javascript",
|
|
42
|
+
"typescript",
|
|
23
43
|
"api-wrapper"
|
|
24
44
|
],
|
|
25
45
|
"author": "James Timms",
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
name: Publish package
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
tags:
|
|
6
|
-
- "v*"
|
|
7
|
-
|
|
8
|
-
jobs:
|
|
9
|
-
publish:
|
|
10
|
-
runs-on: ubuntu-latest
|
|
11
|
-
permissions:
|
|
12
|
-
contents: read
|
|
13
|
-
packages: write
|
|
14
|
-
|
|
15
|
-
steps:
|
|
16
|
-
- name: Checkout
|
|
17
|
-
uses: actions/checkout@v4
|
|
18
|
-
|
|
19
|
-
- name: Setup Node
|
|
20
|
-
uses: actions/setup-node@v4
|
|
21
|
-
with:
|
|
22
|
-
node-version: 20
|
|
23
|
-
registry-url: https://registry.npmjs.org
|
|
24
|
-
|
|
25
|
-
- name: Install dependencies
|
|
26
|
-
run: npm ci
|
|
27
|
-
|
|
28
|
-
- name: Run tests
|
|
29
|
-
run: npm test
|
|
30
|
-
|
|
31
|
-
- name: Validate tag matches package version
|
|
32
|
-
run: |
|
|
33
|
-
TAG_VERSION="${GITHUB_REF_NAME#v}"
|
|
34
|
-
PKG_VERSION="$(node -p "require('./package.json').version")"
|
|
35
|
-
if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then
|
|
36
|
-
echo "Tag version v$TAG_VERSION does not match package.json version $PKG_VERSION"
|
|
37
|
-
exit 1
|
|
38
|
-
fi
|
|
39
|
-
|
|
40
|
-
- name: Publish to npm
|
|
41
|
-
run: npm publish --access public
|
|
42
|
-
env:
|
|
43
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
44
|
-
|
|
45
|
-
- name: Publish to GitHub Packages
|
|
46
|
-
run: |
|
|
47
|
-
echo "@timmsy:registry=https://npm.pkg.github.com" >> "$NPM_CONFIG_USERCONFIG"
|
|
48
|
-
echo "//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}" >> "$NPM_CONFIG_USERCONFIG"
|
|
49
|
-
npm pkg set name="@timmsy1998/riftjs"
|
|
50
|
-
npm publish --registry=https://npm.pkg.github.com
|
|
51
|
-
env:
|
|
52
|
-
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
package/endpoints/datadragon.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
const axios = require('axios');
|
|
2
|
-
|
|
3
|
-
module.exports = (baseURLOrResolver) => {
|
|
4
|
-
const resolveBaseURL = async () => {
|
|
5
|
-
if (typeof baseURLOrResolver === 'function') {
|
|
6
|
-
return baseURLOrResolver();
|
|
7
|
-
}
|
|
8
|
-
return baseURLOrResolver;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
return {
|
|
12
|
-
/**
|
|
13
|
-
* Fetch champion metadata for the configured Data Dragon version/locale.
|
|
14
|
-
* @returns {Promise<object>} Champion data.
|
|
15
|
-
*/
|
|
16
|
-
async getChampions() {
|
|
17
|
-
try {
|
|
18
|
-
const baseURL = await resolveBaseURL();
|
|
19
|
-
const response = await axios.get(`${baseURL}/champion.json`);
|
|
20
|
-
return response.data;
|
|
21
|
-
} catch (error) {
|
|
22
|
-
throw new Error(`DataDragon error: ${error.message}`);
|
|
23
|
-
}
|
|
24
|
-
},
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Fetch item metadata for the configured Data Dragon version/locale.
|
|
28
|
-
* @returns {Promise<object>} Item data.
|
|
29
|
-
*/
|
|
30
|
-
async getItems() {
|
|
31
|
-
try {
|
|
32
|
-
const baseURL = await resolveBaseURL();
|
|
33
|
-
const response = await axios.get(`${baseURL}/item.json`);
|
|
34
|
-
return response.data;
|
|
35
|
-
} catch (error) {
|
|
36
|
-
throw new Error(`DataDragon error: ${error.message}`);
|
|
37
|
-
}
|
|
38
|
-
},
|
|
39
|
-
};
|
|
40
|
-
};
|
package/endpoints/riot.js
DELETED
|
@@ -1,217 +0,0 @@
|
|
|
1
|
-
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
2
|
-
const SOLO_QUEUE = 'RANKED_SOLO_5x5';
|
|
3
|
-
const FLEX_QUEUE = 'RANKED_FLEX_SR';
|
|
4
|
-
const withRankMetrics = (entry) => {
|
|
5
|
-
if (!entry) return null;
|
|
6
|
-
const wins = Number(entry.wins) || 0;
|
|
7
|
-
const losses = Number(entry.losses) || 0;
|
|
8
|
-
const gamesPlayed = wins + losses;
|
|
9
|
-
const winRate = gamesPlayed > 0 ? Number(((wins / gamesPlayed) * 100).toFixed(2)) : 0;
|
|
10
|
-
return { ...entry, winRate };
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
module.exports = (client, defaultRegion, regionMap) => ({
|
|
14
|
-
/**
|
|
15
|
-
* Fetch account data by Riot ID.
|
|
16
|
-
* @param {string} riotId - Riot ID (e.g., "Timmsy#BRUV" or "Timmsy", "BRUV").
|
|
17
|
-
* @param {string} [tagLine] - Optional tagLine if not included in riotId.
|
|
18
|
-
* @param {string} [region] - Region code used to resolve shard routing.
|
|
19
|
-
* @returns {Promise<object>} Account payload including `puuid`.
|
|
20
|
-
*/
|
|
21
|
-
async getAccountByRiotId(riotId, tagLine = null, region = defaultRegion) {
|
|
22
|
-
let gameName, tag;
|
|
23
|
-
if (riotId.includes('#')) {
|
|
24
|
-
[gameName, tag] = riotId.split('#');
|
|
25
|
-
} else {
|
|
26
|
-
gameName = riotId;
|
|
27
|
-
tag = tagLine || '';
|
|
28
|
-
}
|
|
29
|
-
if (!tag) throw new Error('TagLine is required for getAccountByRiotId');
|
|
30
|
-
const shard = regionMap[region].shard;
|
|
31
|
-
try {
|
|
32
|
-
const response = await client.get(`/riot/account/v1/accounts/by-riot-id/${encodeURIComponent(gameName)}/${encodeURIComponent(tag)}`, {
|
|
33
|
-
baseURL: `https://${shard}`,
|
|
34
|
-
});
|
|
35
|
-
return response.data;
|
|
36
|
-
} catch (error) {
|
|
37
|
-
throw this._handleError(error);
|
|
38
|
-
}
|
|
39
|
-
},
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Fetch Summoner-V4 data for a player's PUUID.
|
|
43
|
-
* @param {string} puuid - Encrypted PUUID.
|
|
44
|
-
* @param {string} [region] - Region code used to resolve platform routing.
|
|
45
|
-
* @returns {Promise<object>} Summoner payload.
|
|
46
|
-
*/
|
|
47
|
-
async getSummonerByPuuid(puuid, region = defaultRegion) {
|
|
48
|
-
const platform = regionMap[region].platform;
|
|
49
|
-
try {
|
|
50
|
-
const response = await client.get(`/lol/summoner/v4/summoners/by-puuid/${encodeURIComponent(puuid)}`, {
|
|
51
|
-
baseURL: `https://${platform}`,
|
|
52
|
-
});
|
|
53
|
-
return response.data;
|
|
54
|
-
} catch (error) {
|
|
55
|
-
throw this._handleError(error);
|
|
56
|
-
}
|
|
57
|
-
},
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Fetch all ranked entries for a player PUUID.
|
|
61
|
-
* @param {string} puuid - Player PUUID.
|
|
62
|
-
* @param {string} [region] - Region code used to resolve platform routing.
|
|
63
|
-
* @returns {Promise<object[]>} Ranked entries from League-V4.
|
|
64
|
-
*/
|
|
65
|
-
async getRankEntriesByPuuid(puuid, region = defaultRegion) {
|
|
66
|
-
const platform = regionMap[region].platform;
|
|
67
|
-
try {
|
|
68
|
-
const response = await client.get(`/lol/league/v4/entries/by-puuid/${encodeURIComponent(puuid)}`, {
|
|
69
|
-
baseURL: `https://${platform}`,
|
|
70
|
-
});
|
|
71
|
-
return response.data;
|
|
72
|
-
} catch (error) {
|
|
73
|
-
throw this._handleError(error);
|
|
74
|
-
}
|
|
75
|
-
},
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Fetch ranked info split into Solo and Flex queues.
|
|
79
|
-
* @param {string} puuid - Player PUUID.
|
|
80
|
-
* @param {string} [region] - Region code used to resolve platform routing.
|
|
81
|
-
* @returns {Promise<{solo: object|null, flex: object|null, entries: object[]}>} Queue-split rank payload.
|
|
82
|
-
*/
|
|
83
|
-
async getRankByPuuid(puuid, region = defaultRegion) {
|
|
84
|
-
const entries = await this.getRankEntriesByPuuid(puuid, region);
|
|
85
|
-
const solo = withRankMetrics(entries.find((entry) => entry.queueType === SOLO_QUEUE) || null);
|
|
86
|
-
const flex = withRankMetrics(entries.find((entry) => entry.queueType === FLEX_QUEUE) || null);
|
|
87
|
-
return { solo, flex, entries };
|
|
88
|
-
},
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Fetch match IDs for a PUUID from Match-V5.
|
|
92
|
-
* @param {string} puuid - Player PUUID.
|
|
93
|
-
* @param {object} [options] - Query params such as `start` and `count`.
|
|
94
|
-
* @param {string} [region] - Region code used to resolve shard routing.
|
|
95
|
-
* @returns {Promise<string[]>} Array of match IDs.
|
|
96
|
-
*/
|
|
97
|
-
async getMatchlistByPuuid(puuid, options = {}, region = defaultRegion) {
|
|
98
|
-
const shard = regionMap[region].shard;
|
|
99
|
-
try {
|
|
100
|
-
const response = await client.get(`/lol/match/v5/matches/by-puuid/${encodeURIComponent(puuid)}/ids`, {
|
|
101
|
-
baseURL: `https://${shard}`,
|
|
102
|
-
params: options,
|
|
103
|
-
});
|
|
104
|
-
return response.data;
|
|
105
|
-
} catch (error) {
|
|
106
|
-
throw this._handleError(error);
|
|
107
|
-
}
|
|
108
|
-
},
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Fetch full match details by match ID.
|
|
112
|
-
* @param {string} matchId - Match ID (e.g., "EUW1_1234567890").
|
|
113
|
-
* @param {string} [region] - Region code used to resolve shard routing.
|
|
114
|
-
* @returns {Promise<object>} Match payload.
|
|
115
|
-
*/
|
|
116
|
-
async getMatchById(matchId, region = defaultRegion) {
|
|
117
|
-
const shard = regionMap[region].shard;
|
|
118
|
-
try {
|
|
119
|
-
const response = await client.get(`/lol/match/v5/matches/${matchId}`, {
|
|
120
|
-
baseURL: `https://${shard}`,
|
|
121
|
-
});
|
|
122
|
-
return response.data;
|
|
123
|
-
} catch (error) {
|
|
124
|
-
throw this._handleError(error);
|
|
125
|
-
}
|
|
126
|
-
},
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Fetch match timeline data by match ID.
|
|
130
|
-
* @param {string} matchId - Match ID (e.g., "EUW1_1234567890").
|
|
131
|
-
* @param {string} [region] - Region code used to resolve shard routing.
|
|
132
|
-
* @returns {Promise<object>} Match timeline payload.
|
|
133
|
-
*/
|
|
134
|
-
async getMatchTimelineById(matchId, region = defaultRegion) {
|
|
135
|
-
const shard = regionMap[region].shard;
|
|
136
|
-
try {
|
|
137
|
-
const response = await client.get(`/lol/match/v5/matches/${matchId}/timeline`, {
|
|
138
|
-
baseURL: `https://${shard}`,
|
|
139
|
-
});
|
|
140
|
-
return response.data;
|
|
141
|
-
} catch (error) {
|
|
142
|
-
throw this._handleError(error);
|
|
143
|
-
}
|
|
144
|
-
},
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Fetch all match IDs for a PUUID using Riot's max page size (100).
|
|
148
|
-
* @param {string} puuid - Player PUUID.
|
|
149
|
-
* @param {object} [options] - Riot filters: startTime, endTime, queue, type, start.
|
|
150
|
-
* @param {string} [region] - Region code used to resolve shard routing.
|
|
151
|
-
* @param {object} [pacing] - Pacing controls.
|
|
152
|
-
* @param {number} [pacing.delayMs=1250] - Delay between page requests.
|
|
153
|
-
* @param {number|null} [pacing.maxMatches=null] - Optional cap on total IDs returned.
|
|
154
|
-
* @returns {Promise<string[]>} All matched IDs.
|
|
155
|
-
*/
|
|
156
|
-
async getMatchlistByPuuidAll(puuid, options = {}, region = defaultRegion, pacing = {}) {
|
|
157
|
-
const baseStart = Number.isInteger(options.start) ? options.start : 0;
|
|
158
|
-
const pageDelayMs = Number.isInteger(pacing.delayMs) ? pacing.delayMs : 1250;
|
|
159
|
-
const maxMatches = Number.isInteger(pacing.maxMatches) && pacing.maxMatches >= 0 ? pacing.maxMatches : null;
|
|
160
|
-
const filters = {
|
|
161
|
-
startTime: options.startTime,
|
|
162
|
-
endTime: options.endTime,
|
|
163
|
-
queue: options.queue,
|
|
164
|
-
type: options.type,
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
let start = baseStart;
|
|
168
|
-
const allMatchIds = [];
|
|
169
|
-
|
|
170
|
-
while (true) {
|
|
171
|
-
const remaining = maxMatches === null ? 100 : Math.min(100, maxMatches - allMatchIds.length);
|
|
172
|
-
if (remaining <= 0) break;
|
|
173
|
-
|
|
174
|
-
const page = await this.getMatchlistByPuuid(puuid, { ...filters, start, count: remaining }, region);
|
|
175
|
-
allMatchIds.push(...page);
|
|
176
|
-
|
|
177
|
-
if (page.length < remaining) break;
|
|
178
|
-
start += page.length;
|
|
179
|
-
if (pageDelayMs > 0) await sleep(pageDelayMs);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
return allMatchIds;
|
|
183
|
-
},
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Fetch match IDs and full match payloads for each ID.
|
|
187
|
-
* @param {string} puuid - Player PUUID.
|
|
188
|
-
* @param {object} [options] - Riot filters: startTime, endTime, queue, type, start.
|
|
189
|
-
* @param {string} [region] - Region code used to resolve shard routing.
|
|
190
|
-
* @param {object} [pacing] - Pacing controls.
|
|
191
|
-
* @param {number} [pacing.pageDelayMs=1250] - Delay between matchlist page requests.
|
|
192
|
-
* @param {number} [pacing.detailDelayMs=1250] - Delay between match detail requests.
|
|
193
|
-
* @param {number|null} [pacing.maxMatches=null] - Optional cap on total matches fetched.
|
|
194
|
-
* @returns {Promise<{matchIds: string[], matches: object[]}>} IDs and full match payloads.
|
|
195
|
-
*/
|
|
196
|
-
async getMatchesWithDetailsByPuuid(puuid, options = {}, region = defaultRegion, pacing = {}) {
|
|
197
|
-
const pageDelayMs = Number.isInteger(pacing.pageDelayMs) ? pacing.pageDelayMs : 1250;
|
|
198
|
-
const detailDelayMs = Number.isInteger(pacing.detailDelayMs) ? pacing.detailDelayMs : 1250;
|
|
199
|
-
const maxMatches = Number.isInteger(pacing.maxMatches) && pacing.maxMatches >= 0 ? pacing.maxMatches : null;
|
|
200
|
-
const matchIds = await this.getMatchlistByPuuidAll(
|
|
201
|
-
puuid,
|
|
202
|
-
options,
|
|
203
|
-
region,
|
|
204
|
-
{ delayMs: pageDelayMs, maxMatches }
|
|
205
|
-
);
|
|
206
|
-
const matches = [];
|
|
207
|
-
|
|
208
|
-
for (let i = 0; i < matchIds.length; i += 1) {
|
|
209
|
-
matches.push(await this.getMatchById(matchIds[i], region));
|
|
210
|
-
if (detailDelayMs > 0 && i < matchIds.length - 1) {
|
|
211
|
-
await sleep(detailDelayMs);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
return { matchIds, matches };
|
|
216
|
-
},
|
|
217
|
-
});
|