@timmsy/riftjs 1.5.0 → 2.0.2
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/.github/workflows/publish.yml +51 -0
- package/LICENSE +1 -1
- package/README.md +48 -8
- package/endpoints/datadragon.js +36 -25
- package/endpoints/riot.js +106 -14
- package/index.js +35 -18
- package/package.json +4 -3
- package/test-endpoints.js +65 -0
|
@@ -0,0 +1,51 @@
|
|
|
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 publish --registry=https://npm.pkg.github.com
|
|
50
|
+
env:
|
|
51
|
+
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ RiftJS simplifies interaction with the Riot Games API and DataDragon static data
|
|
|
20
20
|
|
|
21
21
|
Install RiftJS via npm:
|
|
22
22
|
|
|
23
|
-
```
|
|
23
|
+
```bash
|
|
24
24
|
npm install @timmsy/riftjs
|
|
25
25
|
```
|
|
26
26
|
|
|
@@ -33,18 +33,23 @@ You’ll also need a Riot Games API key from [developer.riotgames.com](https://d
|
|
|
33
33
|
|
|
34
34
|
2. **Configure Environment**:
|
|
35
35
|
Create a `.env` file in your project root with your API key and region:
|
|
36
|
-
|
|
36
|
+
|
|
37
|
+
```env
|
|
37
38
|
RIOT_API_KEY=RGAPI-your-api-key-here
|
|
38
39
|
REGION=EUW1
|
|
40
|
+
TEST_RIOT_ID=YourRiotName
|
|
41
|
+
TEST_TAG_LINE=EUW
|
|
39
42
|
```
|
|
43
|
+
|
|
40
44
|
- Replace `RGAPI-your-api-key-here` with your API key.
|
|
41
45
|
- Use a short region code (e.g., `EUW1`, `NA1`). See [Region Mapping](#region-mapping) for details.
|
|
46
|
+
- `TEST_RIOT_ID` and `TEST_TAG_LINE` are used by the endpoint test script.
|
|
42
47
|
|
|
43
48
|
## Usage
|
|
44
49
|
|
|
45
50
|
Here’s a basic example to get started:
|
|
46
51
|
|
|
47
|
-
```
|
|
52
|
+
```js
|
|
48
53
|
const { RiotAPI, DataDragon } = require('@timmsy/riftjs');
|
|
49
54
|
|
|
50
55
|
// Initialize RiotAPI
|
|
@@ -92,22 +97,45 @@ fetchStaticData();
|
|
|
92
97
|
## API Reference
|
|
93
98
|
|
|
94
99
|
### RiotAPI
|
|
100
|
+
|
|
95
101
|
- `getAccountByRiotId(riotId, [tagLine], [region])`: Fetch account by Riot ID (e.g., `Timmsy#BRUV`).
|
|
96
102
|
- `getSummonerByPuuid(puuid, [region])`: Get summoner data by PUUID.
|
|
97
103
|
- `getMatchlistByPuuid(puuid, [options], [region])`: Get match history (options: `{ start, count }`).
|
|
98
|
-
- `getMatchById(matchId, [region])`: Get match
|
|
104
|
+
- `getMatchById(matchId, [region])`: Get full match payload (`metadata` + `info`) by match ID.
|
|
105
|
+
- `getMatchTimelineById(matchId, [region])`: Get timeline payload by match ID.
|
|
106
|
+
- `getMatchlistByPuuidAll(puuid, [options], [region], [pacing])`: Fetch all match IDs in pages of 100.
|
|
107
|
+
- `getMatchesWithDetailsByPuuid(puuid, [options], [region], [pacing])`: Fetch all match IDs and their match payloads.
|
|
108
|
+
|
|
109
|
+
`options` supports Riot Match-V5 query params:
|
|
110
|
+
- `startTime` (epoch seconds)
|
|
111
|
+
- `endTime` (epoch seconds)
|
|
112
|
+
- `queue` (int)
|
|
113
|
+
- `type` (string)
|
|
114
|
+
- `start` (int, default `0`)
|
|
115
|
+
- `count` (int, `0-100`, single-page method only)
|
|
116
|
+
|
|
117
|
+
`pacing` helps respect rate limits on multi-request methods:
|
|
118
|
+
- `getMatchlistByPuuidAll`: `{ delayMs, maxMatches }`
|
|
119
|
+
- `getMatchesWithDetailsByPuuid`: `{ pageDelayMs, detailDelayMs, maxMatches }`
|
|
99
120
|
|
|
100
121
|
### DataDragon
|
|
122
|
+
|
|
101
123
|
- `getChampions()`: Fetch all champion data.
|
|
102
124
|
- `getItems()`: Fetch all item data.
|
|
125
|
+
- `new DataDragon()` resolves the latest Data Dragon patch automatically.
|
|
126
|
+
- `new DataDragon('x.y.z')` pins requests to an explicit patch version.
|
|
103
127
|
|
|
104
128
|
## Region Mapping
|
|
105
129
|
|
|
106
130
|
RiftJS uses a region map to route requests correctly:
|
|
131
|
+
|
|
107
132
|
- **Platform Routing** (e.g., Summoner V4):
|
|
133
|
+
|
|
108
134
|
- `EUW1` → `euw1.api.riotgames.com`
|
|
109
135
|
- `NA1` → `na1.api.riotgames.com`
|
|
136
|
+
|
|
110
137
|
- **Shard Routing** (e.g., Account V1, Match V5):
|
|
138
|
+
|
|
111
139
|
- `EUW1` → `europe.api.riotgames.com`
|
|
112
140
|
- `NA1` → `americas.api.riotgames.com`
|
|
113
141
|
|
|
@@ -129,17 +157,29 @@ Supported regions: `BR1`, `EUN1`, `EUW1`, `JP1`, `KR`, `LA1`, `LA2`, `NA1`, `OC1
|
|
|
129
157
|
## Development
|
|
130
158
|
|
|
131
159
|
To contribute or run locally:
|
|
160
|
+
|
|
132
161
|
1. Clone the repo:
|
|
133
|
-
|
|
162
|
+
|
|
163
|
+
```bash
|
|
134
164
|
git clone https://github.com/timmsy1998/RiftJS.git
|
|
135
165
|
cd RiftJS
|
|
136
166
|
```
|
|
167
|
+
|
|
137
168
|
2. Install dependencies:
|
|
138
|
-
|
|
169
|
+
|
|
170
|
+
```bash
|
|
139
171
|
npm install
|
|
140
172
|
```
|
|
173
|
+
|
|
141
174
|
3. Create a `.env` file (see [Setup](#setup)).
|
|
142
|
-
4.
|
|
175
|
+
4. Run endpoint checks:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
npm test
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
- Riot API calls run when `TEST_RIOT_ID` is set.
|
|
182
|
+
- Data Dragon calls always run.
|
|
143
183
|
|
|
144
184
|
## License
|
|
145
185
|
|
|
@@ -149,4 +189,4 @@ MIT License © 2025 James Timms. See [LICENSE](LICENSE) for details.
|
|
|
149
189
|
|
|
150
190
|
- **npm Registry**: [https://www.npmjs.com/package/@timmsy/riftjs](https://www.npmjs.com/package/@timmsy/riftjs)
|
|
151
191
|
- **GitHub Repository**: [https://github.com/timmsy1998/RiftJS](https://github.com/timmsy1998/RiftJS)
|
|
152
|
-
- **Riot Developer Portal**: [https://developer.riotgames.com/](https://developer.riotgames.com/)
|
|
192
|
+
- **Riot Developer Portal**: [https://developer.riotgames.com/](https://developer.riotgames.com/)
|
package/endpoints/datadragon.js
CHANGED
|
@@ -1,29 +1,40 @@
|
|
|
1
1
|
const axios = require('axios');
|
|
2
2
|
|
|
3
|
-
module.exports = (
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
*/
|
|
8
|
-
async getChampions() {
|
|
9
|
-
try {
|
|
10
|
-
const response = await axios.get(`${baseURL}/champion.json`);
|
|
11
|
-
return response.data;
|
|
12
|
-
} catch (error) {
|
|
13
|
-
throw new Error(`DataDragon error: ${error.message}`);
|
|
3
|
+
module.exports = (baseURLOrResolver) => {
|
|
4
|
+
const resolveBaseURL = async () => {
|
|
5
|
+
if (typeof baseURLOrResolver === 'function') {
|
|
6
|
+
return baseURLOrResolver();
|
|
14
7
|
}
|
|
15
|
-
|
|
8
|
+
return baseURLOrResolver;
|
|
9
|
+
};
|
|
16
10
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
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
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
2
|
+
|
|
1
3
|
module.exports = (client, defaultRegion, regionMap) => ({
|
|
2
4
|
/**
|
|
3
|
-
*
|
|
5
|
+
* Fetch account data by Riot ID.
|
|
4
6
|
* @param {string} riotId - Riot ID (e.g., "Timmsy#BRUV" or "Timmsy", "BRUV").
|
|
5
7
|
* @param {string} [tagLine] - Optional tagLine if not included in riotId.
|
|
6
|
-
* @param {string} [region] -
|
|
7
|
-
* @returns {Promise<object>} Account
|
|
8
|
+
* @param {string} [region] - Region code used to resolve shard routing.
|
|
9
|
+
* @returns {Promise<object>} Account payload including `puuid`.
|
|
8
10
|
*/
|
|
9
11
|
async getAccountByRiotId(riotId, tagLine = null, region = defaultRegion) {
|
|
10
12
|
let gameName, tag;
|
|
@@ -27,10 +29,10 @@ module.exports = (client, defaultRegion, regionMap) => ({
|
|
|
27
29
|
},
|
|
28
30
|
|
|
29
31
|
/**
|
|
30
|
-
*
|
|
32
|
+
* Fetch Summoner-V4 data for a player's PUUID.
|
|
31
33
|
* @param {string} puuid - Encrypted PUUID.
|
|
32
|
-
* @param {string} [region] -
|
|
33
|
-
* @returns {Promise<object>} Summoner
|
|
34
|
+
* @param {string} [region] - Region code used to resolve platform routing.
|
|
35
|
+
* @returns {Promise<object>} Summoner payload.
|
|
34
36
|
*/
|
|
35
37
|
async getSummonerByPuuid(puuid, region = defaultRegion) {
|
|
36
38
|
const platform = regionMap[region].platform;
|
|
@@ -45,10 +47,10 @@ module.exports = (client, defaultRegion, regionMap) => ({
|
|
|
45
47
|
},
|
|
46
48
|
|
|
47
49
|
/**
|
|
48
|
-
*
|
|
49
|
-
* @param {string} puuid -
|
|
50
|
-
* @param {object} [options] - Query
|
|
51
|
-
* @param {string} [region] -
|
|
50
|
+
* Fetch match IDs for a PUUID from Match-V5.
|
|
51
|
+
* @param {string} puuid - Player PUUID.
|
|
52
|
+
* @param {object} [options] - Query params such as `start` and `count`.
|
|
53
|
+
* @param {string} [region] - Region code used to resolve shard routing.
|
|
52
54
|
* @returns {Promise<string[]>} Array of match IDs.
|
|
53
55
|
*/
|
|
54
56
|
async getMatchlistByPuuid(puuid, options = {}, region = defaultRegion) {
|
|
@@ -65,10 +67,10 @@ module.exports = (client, defaultRegion, regionMap) => ({
|
|
|
65
67
|
},
|
|
66
68
|
|
|
67
69
|
/**
|
|
68
|
-
*
|
|
70
|
+
* Fetch full match details by match ID.
|
|
69
71
|
* @param {string} matchId - Match ID (e.g., "EUW1_1234567890").
|
|
70
|
-
* @param {string} [region] -
|
|
71
|
-
* @returns {Promise<object>} Match
|
|
72
|
+
* @param {string} [region] - Region code used to resolve shard routing.
|
|
73
|
+
* @returns {Promise<object>} Match payload.
|
|
72
74
|
*/
|
|
73
75
|
async getMatchById(matchId, region = defaultRegion) {
|
|
74
76
|
const shard = regionMap[region].shard;
|
|
@@ -81,4 +83,94 @@ module.exports = (client, defaultRegion, regionMap) => ({
|
|
|
81
83
|
throw this._handleError(error);
|
|
82
84
|
}
|
|
83
85
|
},
|
|
84
|
-
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Fetch match timeline data by match ID.
|
|
89
|
+
* @param {string} matchId - Match ID (e.g., "EUW1_1234567890").
|
|
90
|
+
* @param {string} [region] - Region code used to resolve shard routing.
|
|
91
|
+
* @returns {Promise<object>} Match timeline payload.
|
|
92
|
+
*/
|
|
93
|
+
async getMatchTimelineById(matchId, region = defaultRegion) {
|
|
94
|
+
const shard = regionMap[region].shard;
|
|
95
|
+
try {
|
|
96
|
+
const response = await client.get(`/lol/match/v5/matches/${matchId}/timeline`, {
|
|
97
|
+
baseURL: `https://${shard}`,
|
|
98
|
+
});
|
|
99
|
+
return response.data;
|
|
100
|
+
} catch (error) {
|
|
101
|
+
throw this._handleError(error);
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Fetch all match IDs for a PUUID using Riot's max page size (100).
|
|
107
|
+
* @param {string} puuid - Player PUUID.
|
|
108
|
+
* @param {object} [options] - Riot filters: startTime, endTime, queue, type, start.
|
|
109
|
+
* @param {string} [region] - Region code used to resolve shard routing.
|
|
110
|
+
* @param {object} [pacing] - Pacing controls.
|
|
111
|
+
* @param {number} [pacing.delayMs=1250] - Delay between page requests.
|
|
112
|
+
* @param {number|null} [pacing.maxMatches=null] - Optional cap on total IDs returned.
|
|
113
|
+
* @returns {Promise<string[]>} All matched IDs.
|
|
114
|
+
*/
|
|
115
|
+
async getMatchlistByPuuidAll(puuid, options = {}, region = defaultRegion, pacing = {}) {
|
|
116
|
+
const baseStart = Number.isInteger(options.start) ? options.start : 0;
|
|
117
|
+
const pageDelayMs = Number.isInteger(pacing.delayMs) ? pacing.delayMs : 1250;
|
|
118
|
+
const maxMatches = Number.isInteger(pacing.maxMatches) && pacing.maxMatches >= 0 ? pacing.maxMatches : null;
|
|
119
|
+
const filters = {
|
|
120
|
+
startTime: options.startTime,
|
|
121
|
+
endTime: options.endTime,
|
|
122
|
+
queue: options.queue,
|
|
123
|
+
type: options.type,
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
let start = baseStart;
|
|
127
|
+
const allMatchIds = [];
|
|
128
|
+
|
|
129
|
+
while (true) {
|
|
130
|
+
const remaining = maxMatches === null ? 100 : Math.min(100, maxMatches - allMatchIds.length);
|
|
131
|
+
if (remaining <= 0) break;
|
|
132
|
+
|
|
133
|
+
const page = await this.getMatchlistByPuuid(puuid, { ...filters, start, count: remaining }, region);
|
|
134
|
+
allMatchIds.push(...page);
|
|
135
|
+
|
|
136
|
+
if (page.length < remaining) break;
|
|
137
|
+
start += page.length;
|
|
138
|
+
if (pageDelayMs > 0) await sleep(pageDelayMs);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return allMatchIds;
|
|
142
|
+
},
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Fetch match IDs and full match payloads for each ID.
|
|
146
|
+
* @param {string} puuid - Player PUUID.
|
|
147
|
+
* @param {object} [options] - Riot filters: startTime, endTime, queue, type, start.
|
|
148
|
+
* @param {string} [region] - Region code used to resolve shard routing.
|
|
149
|
+
* @param {object} [pacing] - Pacing controls.
|
|
150
|
+
* @param {number} [pacing.pageDelayMs=1250] - Delay between matchlist page requests.
|
|
151
|
+
* @param {number} [pacing.detailDelayMs=1250] - Delay between match detail requests.
|
|
152
|
+
* @param {number|null} [pacing.maxMatches=null] - Optional cap on total matches fetched.
|
|
153
|
+
* @returns {Promise<{matchIds: string[], matches: object[]}>} IDs and full match payloads.
|
|
154
|
+
*/
|
|
155
|
+
async getMatchesWithDetailsByPuuid(puuid, options = {}, region = defaultRegion, pacing = {}) {
|
|
156
|
+
const pageDelayMs = Number.isInteger(pacing.pageDelayMs) ? pacing.pageDelayMs : 1250;
|
|
157
|
+
const detailDelayMs = Number.isInteger(pacing.detailDelayMs) ? pacing.detailDelayMs : 1250;
|
|
158
|
+
const maxMatches = Number.isInteger(pacing.maxMatches) && pacing.maxMatches >= 0 ? pacing.maxMatches : null;
|
|
159
|
+
const matchIds = await this.getMatchlistByPuuidAll(
|
|
160
|
+
puuid,
|
|
161
|
+
options,
|
|
162
|
+
region,
|
|
163
|
+
{ delayMs: pageDelayMs, maxMatches }
|
|
164
|
+
);
|
|
165
|
+
const matches = [];
|
|
166
|
+
|
|
167
|
+
for (let i = 0; i < matchIds.length; i += 1) {
|
|
168
|
+
matches.push(await this.getMatchById(matchIds[i], region));
|
|
169
|
+
if (detailDelayMs > 0 && i < matchIds.length - 1) {
|
|
170
|
+
await sleep(detailDelayMs);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return { matchIds, matches };
|
|
175
|
+
},
|
|
176
|
+
});
|
package/index.js
CHANGED
|
@@ -3,9 +3,8 @@ const axios = require('axios');
|
|
|
3
3
|
const riotEndpoints = require('./endpoints/riot');
|
|
4
4
|
const dataDragonEndpoints = require('./endpoints/datadragon');
|
|
5
5
|
|
|
6
|
-
//
|
|
6
|
+
// Maps region codes to the platform and routing shard hosts required by Riot APIs.
|
|
7
7
|
const regionMap = {
|
|
8
|
-
// Platform Routing (short regions)
|
|
9
8
|
BR1: { platform: 'br1.api.riotgames.com', shard: 'americas.api.riotgames.com' },
|
|
10
9
|
EUN1: { platform: 'eun1.api.riotgames.com', shard: 'europe.api.riotgames.com' },
|
|
11
10
|
EUW1: { platform: 'euw1.api.riotgames.com', shard: 'europe.api.riotgames.com' },
|
|
@@ -24,9 +23,6 @@ const regionMap = {
|
|
|
24
23
|
VN2: { platform: 'vn2.api.riotgames.com', shard: 'sea.api.riotgames.com' },
|
|
25
24
|
};
|
|
26
25
|
|
|
27
|
-
/**
|
|
28
|
-
* RiotAPI class for interacting with Riot Games API endpoints.
|
|
29
|
-
*/
|
|
30
26
|
class RiotAPI {
|
|
31
27
|
constructor() {
|
|
32
28
|
this.apiKey = process.env.RIOT_API_KEY;
|
|
@@ -36,14 +32,11 @@ class RiotAPI {
|
|
|
36
32
|
this.client = axios.create({
|
|
37
33
|
headers: { 'X-Riot-Token': this.apiKey },
|
|
38
34
|
});
|
|
39
|
-
// Attach
|
|
35
|
+
// Attach endpoint methods with a shared axios client and region configuration.
|
|
40
36
|
Object.assign(this, riotEndpoints(this.client, this.region, regionMap));
|
|
41
37
|
}
|
|
42
38
|
|
|
43
|
-
|
|
44
|
-
* Handle axios errors and provide meaningful messages.
|
|
45
|
-
* @private
|
|
46
|
-
*/
|
|
39
|
+
// Normalize axios errors to stable Error messages for consumers.
|
|
47
40
|
_handleError(error) {
|
|
48
41
|
if (error.response) {
|
|
49
42
|
const { status, data } = error.response;
|
|
@@ -55,17 +48,41 @@ class RiotAPI {
|
|
|
55
48
|
}
|
|
56
49
|
}
|
|
57
50
|
|
|
58
|
-
/**
|
|
59
|
-
* DataDragon class for accessing static game data.
|
|
60
|
-
*/
|
|
61
51
|
class DataDragon {
|
|
62
|
-
constructor(version =
|
|
52
|
+
constructor(version = null, locale = 'en_US') {
|
|
63
53
|
this.version = version;
|
|
64
54
|
this.locale = locale;
|
|
65
|
-
this.baseURL =
|
|
66
|
-
|
|
67
|
-
|
|
55
|
+
this.baseURL = null;
|
|
56
|
+
this._baseURLPromise = null;
|
|
57
|
+
|
|
58
|
+
// Attach static-data endpoint methods that resolve the latest version when needed.
|
|
59
|
+
Object.assign(this, dataDragonEndpoints(() => this._resolveBaseURL()));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async _resolveBaseURL() {
|
|
63
|
+
if (this.baseURL) return this.baseURL;
|
|
64
|
+
if (this._baseURLPromise) return this._baseURLPromise;
|
|
65
|
+
|
|
66
|
+
this._baseURLPromise = (async () => {
|
|
67
|
+
if (!this.version) {
|
|
68
|
+
const response = await axios.get('https://ddragon.leagueoflegends.com/api/versions.json');
|
|
69
|
+
const latestVersion = Array.isArray(response.data) ? response.data[0] : null;
|
|
70
|
+
if (!latestVersion) {
|
|
71
|
+
throw new Error('Could not resolve latest Data Dragon version');
|
|
72
|
+
}
|
|
73
|
+
this.version = latestVersion;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
this.baseURL = `https://ddragon.leagueoflegends.com/cdn/${this.version}/data/${this.locale}`;
|
|
77
|
+
return this.baseURL;
|
|
78
|
+
})();
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
return await this._baseURLPromise;
|
|
82
|
+
} finally {
|
|
83
|
+
this._baseURLPromise = null;
|
|
84
|
+
}
|
|
68
85
|
}
|
|
69
86
|
}
|
|
70
87
|
|
|
71
|
-
module.exports = { RiotAPI, DataDragon };
|
|
88
|
+
module.exports = { RiotAPI, DataDragon };
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@timmsy/riftjs",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"scripts": {
|
|
6
|
-
"test": "
|
|
6
|
+
"test": "npm run test:endpoints",
|
|
7
|
+
"test:endpoints": "node test-endpoints.js"
|
|
7
8
|
},
|
|
8
9
|
"dependencies": {
|
|
9
10
|
"axios": "^1.7.7",
|
|
@@ -28,4 +29,4 @@
|
|
|
28
29
|
"type": "git",
|
|
29
30
|
"url": "git+https://github.com/timmsy1998/RiftJS.git"
|
|
30
31
|
}
|
|
31
|
-
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
require('dotenv').config();
|
|
2
|
+
const { RiotAPI, DataDragon } = require('./index');
|
|
3
|
+
|
|
4
|
+
async function run() {
|
|
5
|
+
const riotId = process.env.TEST_RIOT_ID;
|
|
6
|
+
const tagLine = process.env.TEST_TAG_LINE;
|
|
7
|
+
const dd = new DataDragon();
|
|
8
|
+
|
|
9
|
+
if (process.env.RIOT_API_KEY && riotId) {
|
|
10
|
+
const riot = new RiotAPI();
|
|
11
|
+
const account = await riot.getAccountByRiotId(riotId, tagLine);
|
|
12
|
+
console.log('[PASS] getAccountByRiotId:', account.puuid);
|
|
13
|
+
|
|
14
|
+
const summoner = await riot.getSummonerByPuuid(account.puuid);
|
|
15
|
+
console.log('[PASS] getSummonerByPuuid:', {
|
|
16
|
+
puuid: summoner.puuid,
|
|
17
|
+
summonerLevel: summoner.summonerLevel,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const matchIds = await riot.getMatchlistByPuuid(account.puuid, { start: 0, count: 3 });
|
|
21
|
+
console.log('[PASS] getMatchlistByPuuid:', matchIds.length, 'match ids');
|
|
22
|
+
|
|
23
|
+
if (matchIds.length > 0) {
|
|
24
|
+
const match = await riot.getMatchById(matchIds[0]);
|
|
25
|
+
console.log('[PASS] getMatchById:', match.metadata.matchId);
|
|
26
|
+
|
|
27
|
+
const timeline = await riot.getMatchTimelineById(matchIds[0]);
|
|
28
|
+
console.log('[PASS] getMatchTimelineById:', timeline.metadata.matchId);
|
|
29
|
+
|
|
30
|
+
const allMatchIds = await riot.getMatchlistByPuuidAll(
|
|
31
|
+
account.puuid,
|
|
32
|
+
{ start: 0 },
|
|
33
|
+
undefined,
|
|
34
|
+
{ maxMatches: 2, delayMs: 0 }
|
|
35
|
+
);
|
|
36
|
+
console.log('[PASS] getMatchlistByPuuidAll:', allMatchIds.length, 'match ids');
|
|
37
|
+
|
|
38
|
+
const withDetails = await riot.getMatchesWithDetailsByPuuid(
|
|
39
|
+
account.puuid,
|
|
40
|
+
{ start: 0 },
|
|
41
|
+
undefined,
|
|
42
|
+
{ maxMatches: 2, pageDelayMs: 0, detailDelayMs: 0 }
|
|
43
|
+
);
|
|
44
|
+
console.log('[PASS] getMatchesWithDetailsByPuuid:', withDetails.matches.length, 'matches');
|
|
45
|
+
} else {
|
|
46
|
+
console.log('[SKIP] Match-by-id/timeline/all/details checks: no matches returned');
|
|
47
|
+
}
|
|
48
|
+
} else if (process.env.RIOT_API_KEY) {
|
|
49
|
+
console.log('[SKIP] Riot endpoints: set TEST_RIOT_ID (and TEST_TAG_LINE if needed)');
|
|
50
|
+
} else {
|
|
51
|
+
console.log('[SKIP] Riot endpoints: set RIOT_API_KEY and TEST_RIOT_ID');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const champions = await dd.getChampions();
|
|
55
|
+
console.log('[PASS] getChampions:', Object.keys(champions.data || {}).length, 'champions');
|
|
56
|
+
console.log('[INFO] DataDragon version:', dd.version);
|
|
57
|
+
|
|
58
|
+
const items = await dd.getItems();
|
|
59
|
+
console.log('[PASS] getItems:', Object.keys(items.data || {}).length, 'items');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
run().catch((error) => {
|
|
63
|
+
console.error('[FAIL]', error.message);
|
|
64
|
+
process.exitCode = 1;
|
|
65
|
+
});
|