Compare commits

...

27 Commits

Author SHA1 Message Date
maxswa
6adcb02545 Add Colosseum Glory, Lunar Chests, Sol Heredit 2024-03-20 19:18:35 -04:00
maxswa
3b502cb7cf v2.17.0 2024-01-24 11:25:48 -05:00
Max Swartwout
b3f81e66eb Merge pull request #88 from maxswa/scurrius
Add Scurrius
2024-01-24 11:24:34 -05:00
Max Swartwout
01150b6234 Merge pull request #93 from maxswa/update-readme-json-api
Add reference to official JSON API in README
2024-01-19 18:43:47 -05:00
maxswa
ca4d75f2c7 Add reference to official JSON API in README. 2024-01-19 18:37:14 -05:00
Max Swartwout
03b2ef42d2 Merge pull request #91 from maxswa/dependabot/npm_and_yarn/follow-redirects-1.15.4
Bump follow-redirects from 1.15.3 to 1.15.4
2024-01-19 18:18:24 -05:00
dependabot[bot]
7e2603b235 Bump follow-redirects from 1.15.3 to 1.15.4
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.3 to 1.15.4.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.3...v1.15.4)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-11 04:36:21 +00:00
maxswa
92452e240c Add Scurrius 2023-12-30 23:25:32 -05:00
maxswa
d01b36422e v2.16.3 2023-12-17 20:17:17 -05:00
Max Swartwout
3bc1352838 Merge pull request #90 from maxswa/deadman-points
Add Deadman Points
2023-12-17 20:16:28 -05:00
maxswa
91066b5366 Add deadmanPoints 2023-12-17 20:13:06 -05:00
maxswa
4872d04301 v2.16.2 2023-11-26 19:53:20 -05:00
Max Swartwout
55312ba0fd Merge pull request #85 from seditionist/main
Add Custom Errors
2023-11-26 19:52:07 -05:00
maxswa
331a448503 Disabled eslint rule. 2023-11-26 19:43:35 -05:00
maxswa
84c704a846 Add test for excluded gamemodes. 2023-11-26 19:42:46 -05:00
seditionist
561495632c Fix gamemode checks 2023-11-26 18:55:26 -05:00
seditionist
bdfdf1eb14 Merge branch 'maxswa-main' 2023-11-26 18:23:31 -05:00
seditionist
e349776060 Merge branch 'main' of github.com:maxswa/osrs-json-hiscores into maxswa-main
# Conflicts:
#	src/hiscores.ts
2023-11-26 18:20:03 -05:00
seditionist
546bc5acf7 Remove unnecessary type cast 2023-11-26 17:43:38 -05:00
seditionist
66528cd9d9 Restore error message constants 2023-11-26 17:42:55 -05:00
maxswa
99ea3fb722 v2.16.1 2023-11-25 22:07:55 -05:00
Max Swartwout
7f16d26e3c Merge pull request #89 from maxswa/bump-axios
Bump `axios`
2023-11-25 22:06:07 -05:00
seditionist
5483e54d78 cleanup 2023-08-17 00:58:37 -04:00
seditionist
97532b0c03 fix tests 2023-08-17 00:35:22 -04:00
seditionist
f9a56e2b3a update hiscores to throw new custom errors 2023-08-17 00:32:23 -04:00
seditionist
9f43f0c39f update validRSN to use InvalidRSNError 2023-08-17 00:12:27 -04:00
seditionist
d67ffa3e20 created custom errors 2023-08-17 00:11:18 -04:00
15 changed files with 3966 additions and 4646 deletions

View File

@@ -5,22 +5,24 @@
[![types](https://img.shields.io/npm/types/osrs-json-hiscores.svg?style=flat-square)](https://github.com/maxswa/osrs-json-hiscores/blob/master/src/types.ts)
[![build](https://img.shields.io/github/actions/workflow/status/maxswa/osrs-json-hiscores/main.yml?style=flat-square&branch=main)](https://github.com/maxswa/osrs-json-hiscores/actions/workflows/main.yml?query=branch%3Amain)
**The Old School Runescape API wrapper that does more!**
**The Old School RuneScape API wrapper that does more!**
## What it does
The official hiscores API for Old School Runescape (OSRS) returns CSV.
This wrapper converts it to json and provides extra information about the given player. By comparing player info it infers the player's game mode, as well as any previous modes (de-ultimated, de-ironed and/or died as a hardcore ironman).
The official hiscores API for Old School RuneScape (OSRS) can return CSV or a simple JSON array.
This wrapper converts the hiscores data into a more usable JSON object and provides extra information about the given player. By comparing player info it infers the player's game mode, as well as any previous modes (de-ultimated, de-ironed and/or died as a hardcore ironman).
Additional functions are provided that screen-scrape the OSRS leaderboards and return a list of players as json.
Additional functions are provided that screen-scrape the OSRS leaderboards and return a list of players as json. Also simple utility functions are provided to fetch the raw responses from Jagex's APIs, if desired.
`osrs-json-hiscores` has TypeScript support, with full definitions for all functions and custom data types.
---
### Disclaimer
### Disclaimer
Jagex does not provide `Access-Control-Allow-Origin` headers in their responses. This means that [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) will block all browser requests to their hiscores API. In order to get around this, osrs-json-hiscores should be installed on the server side and exposed to the front end via a simple API. Here is an example of this in use: [codesandbox.io/s/osrs-json-hiscores-demo](https://codesandbox.io/s/osrs-json-hiscores-demo-qz656)
Jagex does not provide `Access-Control-Allow-Origin` headers in their responses. This means that [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) will block all browser requests to their hiscores API. In order to get around this, osrs-json-hiscores needs to be installed on the server side and exposed to the front end via a simple API. Here is an example of this in use: [codesandbox.io/s/osrs-json-hiscores-demo](https://codesandbox.io/s/osrs-json-hiscores-demo-qz656)
TLDR: You cannot use this library directly in your client side app e.g. React or Vue, you must set up a server which uses this lib internally and have your client fetch data from your server.
---
@@ -42,27 +44,14 @@ $ yarn add osrs-json-hiscores
Install the package and then import it into your project:
```javascript
const hiscores = require('osrs-json-hiscores');
```typescript
import { getStatsByGamemode, getSkillPage } from 'osrs-json-hiscores';
```
Once you import it you can call the functions asynchronously:
```javascript
hiscores
.getStats('Lynx Titan')
.then((res) => console.log(res))
.catch((err) => console.error(err));
```
If you are using TypeScript or transpiling your JS you can use ES6 syntax:
```javascript
import hiscores, { getSkillPage } from 'osrs-json-hiscores';
// ...
const stats = await hiscores.getStats('Lynx Titan');
```typescript
const stats = await getStatsByGamemode('Lynx Titan');
const topPage = await getSkillPage('overall');
```
@@ -81,9 +70,8 @@ const topPage = await getSkillPage('overall');
`getSkillPage` and `getActivityPage` require a skill / activity and optionally a gamemode and page:
```javascript
hiscores
.getSkillPage('attack', 'main', 1)
```typescript
getSkillPage('attack', 'main', 1)
.then((res) => console.log(res))
.catch((err) => console.error(err));
```
@@ -114,12 +102,14 @@ Activities consist of all levels of clue scrolls as well as minigames and bosses
| PvP Arena - Rank | `pvpArena` |
| Soul Wars Zeal | `soulWarsZeal` |
| Rifts closed | `riftsClosed` |
| Colosseum Glory | `colosseumGlory` |
### Leagues
### Points
| Activity | Param |
| ------------- | :------------: |
| League Points | `leaguePoints` |
| Activity | Param |
| -------------- | :-------------: |
| League Points | `leaguePoints` |
| Deadman Points | `deadmanPoints` |
### Bosses
@@ -154,6 +144,7 @@ Activities consist of all levels of clue scrolls as well as minigames and bosses
| Kraken | `kraken` |
| Kreearra | `kreeArra` |
| K'ril Tsutsaroth | `krilTsutsaroth` |
| Lunar Chests | `lunarChests` |
| Mimic | `mimic` |
| Nex | `nex` |
| Nightmare | `nightmare` |
@@ -162,7 +153,9 @@ Activities consist of all levels of clue scrolls as well as minigames and bosses
| Phantom Muspah | `phantomMuspah` |
| Sarachnis | `sarachnis` |
| Scorpia | `scorpia` |
| Scurrius | `scurrius` |
| Skotizo | `skotizo` |
| Sol Heredit | `solHeredit` |
| Spindel | `spindel` |
| Tempoross | `tempoross` |
| The Gauntlet | `gauntlet` |
@@ -188,7 +181,7 @@ Activities consist of all levels of clue scrolls as well as minigames and bosses
`getStats` returns a player object that looks like this:
```javascript
```typescript
{
name: 'Lynx Titan',
mode: 'main',
@@ -216,7 +209,7 @@ Activities consist of all levels of clue scrolls as well as minigames and bosses
`getSkillPage` returns and array of 25 players (This represents a page on the hiscores):
```javascript
```typescript
[
{ rank: 1, name: 'Lynx Titan', level: 2277, xp: 4600000000, dead: false },
{},
@@ -229,7 +222,7 @@ Activities consist of all levels of clue scrolls as well as minigames and bosses
Get the properly formatted name of any skill, boss, clue or other activity:
```javascript
```typescript
// kril === "K'ril Tsutsaroth"
const kril = FORMATTED_BOSS_NAMES['krilTsutsaroth'];
```

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,98 +1,103 @@
3923,2277,792976020
23024,99,29963318
12244,99,28197154
2261,99,134139762
4074,99,112054504
7166,99,101083246
3747,99,15110682
4516,99,50824811
126288,99,13353110
24800,99,16366466
49293,99,13453226
20784,99,16654289
16376,99,19114676
42069,99,14055874
9305,99,16527135
25135,99,14657869
35831,99,13233130
6197,99,15739327
48215,99,13963265
4786,99,33830972
3402,99,62531484
4314,99,22733194
14826,99,17399368
1009,99,17989158
2910,2277,943515557
24996,99,30606377
4759,99,40283500
1523,99,171953134
2244,99,147696928
5929,99,118171038
4560,99,15170201
2503,99,71406360
141823,99,13354119
22348,99,18680181
56125,99,13456850
23026,99,16655688
18672,99,19123987
48108,99,14072560
10956,99,16552060
27980,99,14967150
40661,99,13252766
7114,99,15760818
53839,99,14058762
5352,99,34669574
2456,99,84892847
4849,99,22734071
16368,99,17968711
1147,99,18027875
-1,-1
22270,10
10481,3
149217,8
103672,7
253,9508
713,825
71,6000
1943,1600
42364,287
467,436
1634,360
12937,2521
-1,-1
5222,14780
3007,1060
2578,2192
84703,594
19500,143
3335,1830
191697,5
27457,293
43607,58
17384,1905
171607,33
2074,501
78908,50
135830,26
48781,287
2112,2000
138748,41
31297,707
40908,698
31273,714
76034,25
2391,688
17409,1228
60841,474
1895,2140
19948,159
1855,2046
46423,579
107879,1908
9791,920
2050,1444
848,33
24797,620
4157,744
4154,500
880,217
15860,251
60424,119
100429,26
358191,9
1131,1569
33908,273
165651,7
64278,201
1533,583
748,700
21700,250
13200,7
6622,3066
87093,35
2449,502
14541,2
28384,10
14076,3
148183,8
102684,7
338,9641
1002,825
114,6000
2246,1606
44261,298
603,460
1238,452
15827,2521
-1,-1
1048,1432
138,7096
58203,51
13949,2780
827440,62
153191,25
216690,274
7898,14780
5421,1060
7,24522
2902,2192
94883,594
34000,143
3834,1830
218428,5
36717,293
74959,58
19421,1905
186551,34
2571,515
85921,50
154580,26
54677,287
2586,2000
153371,41
33154,707
43433,698
33088,714
81968,25
12249,731
20424,1228
70188,474
2248,2140
11128,226
2117,2046
50095,580
120438,1908
10997,920
2326,1444
-1,-1
700,40
31471,626
4119,749
4349,500
1078,217
20126,301
70523,119
114632,26
2945,1245
385801,9
-1,-1
2412,1569
43814,273
207949,7
86335,201
7905,601
732,1783
21039,310
4949,192
7584,3066
109360,36
160,1500
6733,7
131888,8
3128,2113
209,7096
75591,51
15167,2780
911570,62
173436,25
233645,275
Can't render this file because it has a wrong number of fields in line 25.

View File

@@ -3,192 +3,203 @@
{
"id": 0,
"name": "Overall",
"rank": 3923,
"rank": 2910,
"level": 2277,
"xp": 792976020
"xp": 943515557
},
{ "id": 1, "name": "Attack", "rank": 23024, "level": 99, "xp": 29963318 },
{ "id": 2, "name": "Defence", "rank": 12244, "level": 99, "xp": 28197154 },
{ "id": 3, "name": "Strength", "rank": 2261, "level": 99, "xp": 134139762 },
{ "id": 1, "name": "Attack", "rank": 24996, "level": 99, "xp": 30606377 },
{ "id": 2, "name": "Defence", "rank": 4759, "level": 99, "xp": 40283500 },
{ "id": 3, "name": "Strength", "rank": 1523, "level": 99, "xp": 171953134 },
{
"id": 4,
"name": "Hitpoints",
"rank": 4074,
"rank": 2244,
"level": 99,
"xp": 112054504
"xp": 147696928
},
{ "id": 5, "name": "Ranged", "rank": 7166, "level": 99, "xp": 101083246 },
{ "id": 6, "name": "Prayer", "rank": 3747, "level": 99, "xp": 15110682 },
{ "id": 7, "name": "Magic", "rank": 4516, "level": 99, "xp": 50824811 },
{ "id": 8, "name": "Cooking", "rank": 126288, "level": 99, "xp": 13353110 },
{ "id": 5, "name": "Ranged", "rank": 5929, "level": 99, "xp": 118171038 },
{ "id": 6, "name": "Prayer", "rank": 4560, "level": 99, "xp": 15170201 },
{ "id": 7, "name": "Magic", "rank": 2503, "level": 99, "xp": 71406360 },
{ "id": 8, "name": "Cooking", "rank": 141823, "level": 99, "xp": 13354119 },
{
"id": 9,
"name": "Woodcutting",
"rank": 24800,
"rank": 22348,
"level": 99,
"xp": 16366466
"xp": 18680181
},
{
"id": 10,
"name": "Fletching",
"rank": 49293,
"rank": 56125,
"level": 99,
"xp": 13453226
"xp": 13456850
},
{ "id": 11, "name": "Fishing", "rank": 20784, "level": 99, "xp": 16654289 },
{ "id": 11, "name": "Fishing", "rank": 23026, "level": 99, "xp": 16655688 },
{
"id": 12,
"name": "Firemaking",
"rank": 16376,
"rank": 18672,
"level": 99,
"xp": 19114676
"xp": 19123987
},
{
"id": 13,
"name": "Crafting",
"rank": 42069,
"rank": 48108,
"level": 99,
"xp": 14055874
"xp": 14072560
},
{ "id": 14, "name": "Smithing", "rank": 9305, "level": 99, "xp": 16527135 },
{ "id": 15, "name": "Mining", "rank": 25135, "level": 99, "xp": 14657869 },
{
"id": 14,
"name": "Smithing",
"rank": 10956,
"level": 99,
"xp": 16552060
},
{ "id": 15, "name": "Mining", "rank": 27980, "level": 99, "xp": 14967150 },
{
"id": 16,
"name": "Herblore",
"rank": 35831,
"rank": 40661,
"level": 99,
"xp": 13233130
"xp": 13252766
},
{ "id": 17, "name": "Agility", "rank": 6197, "level": 99, "xp": 15739327 },
{ "id": 17, "name": "Agility", "rank": 7114, "level": 99, "xp": 15760818 },
{
"id": 18,
"name": "Thieving",
"rank": 48215,
"rank": 53839,
"level": 99,
"xp": 13963265
"xp": 14058762
},
{ "id": 19, "name": "Slayer", "rank": 4786, "level": 99, "xp": 33830972 },
{ "id": 20, "name": "Farming", "rank": 3402, "level": 99, "xp": 62531484 },
{ "id": 19, "name": "Slayer", "rank": 5352, "level": 99, "xp": 34669574 },
{ "id": 20, "name": "Farming", "rank": 2456, "level": 99, "xp": 84892847 },
{
"id": 21,
"name": "Runecraft",
"rank": 4314,
"rank": 4849,
"level": 99,
"xp": 22733194
"xp": 22734071
},
{ "id": 22, "name": "Hunter", "rank": 14826, "level": 99, "xp": 17399368 },
{ "id": 22, "name": "Hunter", "rank": 16368, "level": 99, "xp": 17968711 },
{
"id": 23,
"name": "Construction",
"rank": 1009,
"rank": 1147,
"level": 99,
"xp": 17989158
"xp": 18027875
}
],
"activities": [
{ "id": 0, "name": "League Points", "rank": -1, "score": -1 },
{ "id": 1, "name": "Bounty Hunter - Hunter", "rank": 22270, "score": 10 },
{ "id": 2, "name": "Bounty Hunter - Rogue", "rank": 10481, "score": 3 },
{ "id": 1, "name": "Deadman Points", "rank": -1, "score": -1 },
{ "id": 2, "name": "Bounty Hunter - Hunter", "rank": 28384, "score": 10 },
{ "id": 3, "name": "Bounty Hunter - Rogue", "rank": 14076, "score": 3 },
{
"id": 3,
"id": 4,
"name": "Bounty Hunter (Legacy) - Hunter",
"rank": 149217,
"rank": 148183,
"score": 8
},
{
"id": 4,
"id": 5,
"name": "Bounty Hunter (Legacy) - Rogue",
"rank": 103672,
"rank": 102684,
"score": 7
},
{ "id": 5, "name": "Clue Scrolls (all)", "rank": 253, "score": 9508 },
{ "id": 6, "name": "Clue Scrolls (beginner)", "rank": 713, "score": 825 },
{ "id": 7, "name": "Clue Scrolls (easy)", "rank": 71, "score": 6000 },
{ "id": 8, "name": "Clue Scrolls (medium)", "rank": 1943, "score": 1600 },
{ "id": 9, "name": "Clue Scrolls (hard)", "rank": 42364, "score": 287 },
{ "id": 10, "name": "Clue Scrolls (elite)", "rank": 467, "score": 436 },
{ "id": 11, "name": "Clue Scrolls (master)", "rank": 1634, "score": 360 },
{ "id": 12, "name": "LMS - Rank", "rank": 12937, "score": 2521 },
{ "id": 13, "name": "PvP Arena - Rank", "rank": -1, "score": -1 },
{ "id": 14, "name": "Soul Wars Zeal", "rank": 5222, "score": 14780 },
{ "id": 15, "name": "Rifts closed", "rank": 3007, "score": 1060 },
{ "id": 16, "name": "Abyssal Sire", "rank": 2578, "score": 2192 },
{ "id": 17, "name": "Alchemical Hydra", "rank": 84703, "score": 594 },
{ "id": 18, "name": "Artio", "rank": 19500, "score": 143 },
{ "id": 19, "name": "Barrows Chests", "rank": 3335, "score": 1830 },
{ "id": 20, "name": "Bryophyta", "rank": 191697, "score": 5 },
{ "id": 21, "name": "Callisto", "rank": 27457, "score": 293 },
{ "id": 22, "name": "Calvar'ion", "rank": 43607, "score": 58 },
{ "id": 23, "name": "Cerberus", "rank": 17384, "score": 1905 },
{ "id": 24, "name": "Chambers of Xeric", "rank": 171607, "score": 33 },
{ "id": 6, "name": "Clue Scrolls (all)", "rank": 338, "score": 9641 },
{ "id": 7, "name": "Clue Scrolls (beginner)", "rank": 1002, "score": 825 },
{ "id": 8, "name": "Clue Scrolls (easy)", "rank": 114, "score": 6000 },
{ "id": 9, "name": "Clue Scrolls (medium)", "rank": 2246, "score": 1606 },
{ "id": 10, "name": "Clue Scrolls (hard)", "rank": 44261, "score": 298 },
{ "id": 11, "name": "Clue Scrolls (elite)", "rank": 603, "score": 460 },
{ "id": 12, "name": "Clue Scrolls (master)", "rank": 1238, "score": 452 },
{ "id": 13, "name": "LMS - Rank", "rank": 15827, "score": 2521 },
{ "id": 14, "name": "PvP Arena - Rank", "rank": -1, "score": -1 },
{ "id": 15, "name": "Soul Wars Zeal", "rank": 7898, "score": 14780 },
{ "id": 16, "name": "Rifts closed", "rank": 5421, "score": 1060 },
{ "id": 17, "name": "Colosseum Glory", "rank": 7, "score": 24522 },
{ "id": 18, "name": "Abyssal Sire", "rank": 2902, "score": 2192 },
{ "id": 19, "name": "Alchemical Hydra", "rank": 94883, "score": 594 },
{ "id": 20, "name": "Artio", "rank": 34000, "score": 143 },
{ "id": 21, "name": "Barrows Chests", "rank": 3834, "score": 1830 },
{ "id": 22, "name": "Bryophyta", "rank": 218428, "score": 5 },
{ "id": 23, "name": "Callisto", "rank": 36717, "score": 293 },
{ "id": 24, "name": "Calvar'ion", "rank": 74959, "score": 58 },
{ "id": 25, "name": "Cerberus", "rank": 19421, "score": 1905 },
{ "id": 26, "name": "Chambers of Xeric", "rank": 186551, "score": 34 },
{
"id": 25,
"id": 27,
"name": "Chambers of Xeric: Challenge Mode",
"rank": 2074,
"score": 501
"rank": 2571,
"score": 515
},
{ "id": 26, "name": "Chaos Elemental", "rank": 78908, "score": 50 },
{ "id": 27, "name": "Chaos Fanatic", "rank": 135830, "score": 26 },
{ "id": 28, "name": "Commander Zilyana", "rank": 48781, "score": 287 },
{ "id": 29, "name": "Corporeal Beast", "rank": 2112, "score": 2000 },
{ "id": 30, "name": "Crazy Archaeologist", "rank": 138748, "score": 41 },
{ "id": 31, "name": "Dagannoth Prime", "rank": 31297, "score": 707 },
{ "id": 32, "name": "Dagannoth Rex", "rank": 40908, "score": 698 },
{ "id": 33, "name": "Dagannoth Supreme", "rank": 31273, "score": 714 },
{ "id": 34, "name": "Deranged Archaeologist", "rank": 76034, "score": 25 },
{ "id": 35, "name": "Duke Sucellus", "rank": 2391, "score": 688 },
{ "id": 36, "name": "General Graardor", "rank": 17409, "score": 1228 },
{ "id": 37, "name": "Giant Mole", "rank": 60841, "score": 474 },
{ "id": 38, "name": "Grotesque Guardians", "rank": 1895, "score": 2140 },
{ "id": 39, "name": "Hespori", "rank": 19948, "score": 159 },
{ "id": 40, "name": "Kalphite Queen", "rank": 1855, "score": 2046 },
{ "id": 41, "name": "King Black Dragon", "rank": 46423, "score": 579 },
{ "id": 42, "name": "Kraken", "rank": 107879, "score": 1908 },
{ "id": 43, "name": "Kree'Arra", "rank": 9791, "score": 920 },
{ "id": 44, "name": "K'ril Tsutsaroth", "rank": 2050, "score": 1444 },
{ "id": 45, "name": "Mimic", "rank": 848, "score": 33 },
{ "id": 46, "name": "Nex", "rank": 24797, "score": 620 },
{ "id": 47, "name": "Nightmare", "rank": 4157, "score": 744 },
{ "id": 48, "name": "Phosani's Nightmare", "rank": 4154, "score": 500 },
{ "id": 49, "name": "Obor", "rank": 880, "score": 217 },
{ "id": 50, "name": "Phantom Muspah", "rank": 15860, "score": 251 },
{ "id": 51, "name": "Sarachnis", "rank": 60424, "score": 119 },
{ "id": 52, "name": "Scorpia", "rank": 100429, "score": 26 },
{ "id": 53, "name": "Skotizo", "rank": 358191, "score": 9 },
{ "id": 54, "name": "Spindel", "rank": 1131, "score": 1569 },
{ "id": 55, "name": "Tempoross", "rank": 33908, "score": 273 },
{ "id": 56, "name": "The Gauntlet", "rank": 165651, "score": 7 },
{ "id": 57, "name": "The Corrupted Gauntlet", "rank": 64278, "score": 201 },
{ "id": 58, "name": "The Leviathan", "rank": 1533, "score": 583 },
{ "id": 59, "name": "The Whisperer", "rank": 748, "score": 700 },
{ "id": 60, "name": "Theatre of Blood", "rank": 21700, "score": 250 },
{ "id": 28, "name": "Chaos Elemental", "rank": 85921, "score": 50 },
{ "id": 29, "name": "Chaos Fanatic", "rank": 154580, "score": 26 },
{ "id": 30, "name": "Commander Zilyana", "rank": 54677, "score": 287 },
{ "id": 31, "name": "Corporeal Beast", "rank": 2586, "score": 2000 },
{ "id": 32, "name": "Crazy Archaeologist", "rank": 153371, "score": 41 },
{ "id": 33, "name": "Dagannoth Prime", "rank": 33154, "score": 707 },
{ "id": 34, "name": "Dagannoth Rex", "rank": 43433, "score": 698 },
{ "id": 35, "name": "Dagannoth Supreme", "rank": 33088, "score": 714 },
{ "id": 36, "name": "Deranged Archaeologist", "rank": 81968, "score": 25 },
{ "id": 37, "name": "Duke Sucellus", "rank": 12249, "score": 731 },
{ "id": 38, "name": "General Graardor", "rank": 20424, "score": 1228 },
{ "id": 39, "name": "Giant Mole", "rank": 70188, "score": 474 },
{ "id": 40, "name": "Grotesque Guardians", "rank": 2248, "score": 2140 },
{ "id": 41, "name": "Hespori", "rank": 11128, "score": 226 },
{ "id": 42, "name": "Kalphite Queen", "rank": 2117, "score": 2046 },
{ "id": 43, "name": "King Black Dragon", "rank": 50095, "score": 580 },
{ "id": 44, "name": "Kraken", "rank": 120438, "score": 1908 },
{ "id": 45, "name": "Kree'Arra", "rank": 10997, "score": 920 },
{ "id": 46, "name": "K'ril Tsutsaroth", "rank": 2326, "score": 1444 },
{ "id": 47, "name": "Lunar Chests", "rank": -1, "score": -1 },
{ "id": 48, "name": "Mimic", "rank": 700, "score": 40 },
{ "id": 49, "name": "Nex", "rank": 31471, "score": 626 },
{ "id": 50, "name": "Nightmare", "rank": 4119, "score": 749 },
{ "id": 51, "name": "Phosani's Nightmare", "rank": 4349, "score": 500 },
{ "id": 52, "name": "Obor", "rank": 1078, "score": 217 },
{ "id": 53, "name": "Phantom Muspah", "rank": 20126, "score": 301 },
{ "id": 54, "name": "Sarachnis", "rank": 70523, "score": 119 },
{ "id": 55, "name": "Scorpia", "rank": 114632, "score": 26 },
{ "id": 56, "name": "Scurrius", "rank": 2945, "score": 1245 },
{ "id": 57, "name": "Skotizo", "rank": 385801, "score": 9 },
{ "id": 58, "name": "Sol Heredit", "rank": -1, "score": -1 },
{ "id": 59, "name": "Spindel", "rank": 2412, "score": 1569 },
{ "id": 60, "name": "Tempoross", "rank": 43814, "score": 273 },
{ "id": 61, "name": "The Gauntlet", "rank": 207949, "score": 7 },
{ "id": 62, "name": "The Corrupted Gauntlet", "rank": 86335, "score": 201 },
{ "id": 63, "name": "The Leviathan", "rank": 7905, "score": 601 },
{ "id": 64, "name": "The Whisperer", "rank": 732, "score": 1783 },
{ "id": 65, "name": "Theatre of Blood", "rank": 21039, "score": 310 },
{
"id": 61,
"id": 66,
"name": "Theatre of Blood: Hard Mode",
"rank": 13200,
"score": 7
"rank": 4949,
"score": 192
},
{
"id": 62,
"id": 67,
"name": "Thermonuclear Smoke Devil",
"rank": 6622,
"rank": 7584,
"score": 3066
},
{ "id": 63, "name": "Tombs of Amascut", "rank": 87093, "score": 35 },
{ "id": 68, "name": "Tombs of Amascut", "rank": 109360, "score": 36 },
{
"id": 64,
"id": 69,
"name": "Tombs of Amascut: Expert Mode",
"rank": 2449,
"score": 502
"rank": 160,
"score": 1500
},
{ "id": 65, "name": "TzKal-Zuk", "rank": 14541, "score": 2 },
{ "id": 66, "name": "TzTok-Jad", "rank": -1, "score": -1 },
{ "id": 67, "name": "Vardorvis", "rank": 1048, "score": 1432 },
{ "id": 68, "name": "Venenatis", "rank": 138, "score": 7096 },
{ "id": 69, "name": "Vet'ion", "rank": 58203, "score": 51 },
{ "id": 70, "name": "Vorkath", "rank": 13949, "score": 2780 },
{ "id": 71, "name": "Wintertodt", "rank": 827440, "score": 62 },
{ "id": 72, "name": "Zalcano", "rank": 153191, "score": 25 },
{ "id": 73, "name": "Zulrah", "rank": 216690, "score": 274 }
{ "id": 70, "name": "TzKal-Zuk", "rank": 6733, "score": 7 },
{ "id": 71, "name": "TzTok-Jad", "rank": 131888, "score": 8 },
{ "id": 72, "name": "Vardorvis", "rank": 3128, "score": 2113 },
{ "id": 73, "name": "Venenatis", "rank": 209, "score": 7096 },
{ "id": 74, "name": "Vet'ion", "rank": 75591, "score": 51 },
{ "id": 75, "name": "Vorkath", "rank": 15167, "score": 2780 },
{ "id": 76, "name": "Wintertodt", "rank": 911570, "score": 62 },
{ "id": 77, "name": "Zalcano", "rank": 173436, "score": 25 },
{ "id": 78, "name": "Zulrah", "rank": 233645, "score": 275 }
]
}

View File

@@ -12,7 +12,7 @@ import {
getSkillPageURL,
getStatsURL,
BOSSES,
INVALID_FORMAT_ERROR,
InvalidFormatError,
BH_MODES,
parseJsonStats,
HiscoresResponse
@@ -86,6 +86,7 @@ test('Parse CSV to json', () => {
810,99,37688883
92,99,32005622
23423,478
89554,301
89914,35
99834,25
99831,23
@@ -101,6 +102,7 @@ test('Parse CSV to json', () => {
13,4057
37,225
25,1110
7827,43249
382,2780
944,3000
704,892
@@ -130,6 +132,7 @@ test('Parse CSV to json', () => {
41643,1477
625,2391
120,2981
54,2958
1,109
99,39002
3,22666
@@ -138,7 +141,9 @@ test('Parse CSV to json', () => {
44,6233
201,1101
82,3404
555,7079
5085,61
8731,1423
678,903
18823,23
63,375
@@ -188,6 +193,7 @@ test('Parse CSV to json', () => {
construction: { rank: 92, level: 99, xp: 32005622 }
},
leaguePoints: { rank: 23423, score: 478 },
deadmanPoints: { rank: 89554, score: 301 },
bountyHunter: {
hunterV2: { rank: 89914, score: 35 },
rogueV2: { rank: 99834, score: 25 },
@@ -198,6 +204,7 @@ test('Parse CSV to json', () => {
pvpArena: { rank: 13, score: 4057 },
soulWarsZeal: { rank: 37, score: 225 },
riftsClosed: { rank: 25, score: 1110 },
colosseumGlory: { rank: 7827, score: 43249 },
clues: {
all: { rank: 32, score: 12148 },
beginner: { rank: 3105, score: 76 },
@@ -237,6 +244,7 @@ test('Parse CSV to json', () => {
kraken: { rank: 41643, score: 1477 },
kreeArra: { rank: 625, score: 2391 },
krilTsutsaroth: { rank: 120, score: 2981 },
lunarChests: { rank: 54, score: 2958 },
mimic: { rank: 1, score: 109 },
nex: { rank: 99, score: 39002 },
nightmare: { rank: 3, score: 22666 },
@@ -245,7 +253,9 @@ test('Parse CSV to json', () => {
phantomMuspah: { rank: 44, score: 6233 },
sarachnis: { rank: 201, score: 1101 },
scorpia: { rank: 82, score: 3404 },
scurrius: { rank: 555, score: 7079 },
skotizo: { rank: 5085, score: 61 },
solHeredit: { rank: 8731, score: 1423 },
spindel: { rank: 678, score: 903 },
tempoross: { rank: 18823, score: 23 },
gauntlet: { rank: 63, score: 375 },
@@ -276,12 +286,12 @@ test('Parse CSV with unknown activity', () => {
const statsWithUnknownActivity = `${lynxTitanStats}
-1,-1`;
expect(() => parseStats(statsWithUnknownActivity)).toThrow(
INVALID_FORMAT_ERROR
InvalidFormatError
);
});
test('Parse invalid CSV', () => {
expect(() => parseStats('invalid')).toThrow(INVALID_FORMAT_ERROR);
expect(() => parseStats('invalid')).toThrow(InvalidFormatError);
});
describe('Get name format', () => {
@@ -580,6 +590,12 @@ describe('Get stats options', () => {
)
).toBeFalsy();
});
it('omits excluded gamemodes', async () => {
const response = await getStats(rsn, {
otherGamemodes: ['ironman', 'ultimate']
});
expect(response.hardcore).toBeUndefined();
});
});
test('CSV and JSON parsing outputs identical object', async () => {

File diff suppressed because it is too large Load Diff

View File

@@ -7,8 +7,8 @@
{ "id": 4, "name": "Hitpoints", "rank": 7, "level": 99, "xp": 200000000 },
{ "id": 5, "name": "Ranged", "rank": 8, "level": 99, "xp": 200000000 },
{ "id": 6, "name": "Prayer", "rank": 11, "level": 99, "xp": 200000000 },
{ "id": 7, "name": "Magic", "rank": 32, "level": 99, "xp": 200000000 },
{ "id": 8, "name": "Cooking", "rank": 157, "level": 99, "xp": 200000000 },
{ "id": 7, "name": "Magic", "rank": 30, "level": 99, "xp": 200000000 },
{ "id": 8, "name": "Cooking", "rank": 154, "level": 99, "xp": 200000000 },
{
"id": 9,
"name": "Woodcutting",
@@ -27,13 +27,13 @@
},
{ "id": 13, "name": "Crafting", "rank": 4, "level": 99, "xp": 200000000 },
{ "id": 14, "name": "Smithing", "rank": 3, "level": 99, "xp": 200000000 },
{ "id": 15, "name": "Mining", "rank": 25, "level": 99, "xp": 200000000 },
{ "id": 15, "name": "Mining", "rank": 24, "level": 99, "xp": 200000000 },
{ "id": 16, "name": "Herblore", "rank": 5, "level": 99, "xp": 200000000 },
{ "id": 17, "name": "Agility", "rank": 24, "level": 99, "xp": 200000000 },
{ "id": 18, "name": "Thieving", "rank": 12, "level": 99, "xp": 200000000 },
{ "id": 19, "name": "Slayer", "rank": 2, "level": 99, "xp": 200000000 },
{ "id": 20, "name": "Farming", "rank": 19, "level": 99, "xp": 200000000 },
{ "id": 21, "name": "Runecraft", "rank": 7, "level": 99, "xp": 200000000 },
{ "id": 21, "name": "Runecraft", "rank": 6, "level": 99, "xp": 200000000 },
{ "id": 22, "name": "Hunter", "rank": 4, "level": 99, "xp": 200000000 },
{
"id": 23,
@@ -45,103 +45,108 @@
],
"activities": [
{ "id": 0, "name": "League Points", "rank": -1, "score": -1 },
{ "id": 1, "name": "Bounty Hunter - Hunter", "rank": -1, "score": -1 },
{ "id": 2, "name": "Bounty Hunter - Rogue", "rank": -1, "score": -1 },
{ "id": 1, "name": "Deadman Points", "rank": -1, "score": -1 },
{ "id": 2, "name": "Bounty Hunter - Hunter", "rank": -1, "score": -1 },
{ "id": 3, "name": "Bounty Hunter - Rogue", "rank": -1, "score": -1 },
{
"id": 3,
"id": 4,
"name": "Bounty Hunter (Legacy) - Hunter",
"rank": -1,
"score": -1
},
{
"id": 4,
"id": 5,
"name": "Bounty Hunter (Legacy) - Rogue",
"rank": -1,
"score": -1
},
{ "id": 5, "name": "Clue Scrolls (all)", "rank": 769527, "score": 22 },
{ "id": 6, "name": "Clue Scrolls (beginner)", "rank": -1, "score": -1 },
{ "id": 7, "name": "Clue Scrolls (easy)", "rank": -1, "score": -1 },
{ "id": 8, "name": "Clue Scrolls (medium)", "rank": -1, "score": -1 },
{ "id": 9, "name": "Clue Scrolls (hard)", "rank": 483333, "score": 22 },
{ "id": 10, "name": "Clue Scrolls (elite)", "rank": -1, "score": -1 },
{ "id": 11, "name": "Clue Scrolls (master)", "rank": -1, "score": -1 },
{ "id": 12, "name": "LMS - Rank", "rank": -1, "score": -1 },
{ "id": 13, "name": "PvP Arena - Rank", "rank": -1, "score": -1 },
{ "id": 14, "name": "Soul Wars Zeal", "rank": -1, "score": -1 },
{ "id": 15, "name": "Rifts closed", "rank": -1, "score": -1 },
{ "id": 16, "name": "Abyssal Sire", "rank": -1, "score": -1 },
{ "id": 17, "name": "Alchemical Hydra", "rank": -1, "score": -1 },
{ "id": 18, "name": "Artio", "rank": -1, "score": -1 },
{ "id": 19, "name": "Barrows Chests", "rank": -1, "score": -1 },
{ "id": 20, "name": "Bryophyta", "rank": -1, "score": -1 },
{ "id": 21, "name": "Callisto", "rank": -1, "score": -1 },
{ "id": 22, "name": "Calvar'ion", "rank": -1, "score": -1 },
{ "id": 23, "name": "Cerberus", "rank": -1, "score": -1 },
{ "id": 24, "name": "Chambers of Xeric", "rank": -1, "score": -1 },
{ "id": 6, "name": "Clue Scrolls (all)", "rank": 832420, "score": 22 },
{ "id": 7, "name": "Clue Scrolls (beginner)", "rank": -1, "score": -1 },
{ "id": 8, "name": "Clue Scrolls (easy)", "rank": -1, "score": -1 },
{ "id": 9, "name": "Clue Scrolls (medium)", "rank": -1, "score": -1 },
{ "id": 10, "name": "Clue Scrolls (hard)", "rank": 517091, "score": 22 },
{ "id": 11, "name": "Clue Scrolls (elite)", "rank": -1, "score": -1 },
{ "id": 12, "name": "Clue Scrolls (master)", "rank": -1, "score": -1 },
{ "id": 13, "name": "LMS - Rank", "rank": -1, "score": -1 },
{ "id": 14, "name": "PvP Arena - Rank", "rank": -1, "score": -1 },
{ "id": 15, "name": "Soul Wars Zeal", "rank": -1, "score": -1 },
{ "id": 16, "name": "Rifts closed", "rank": -1, "score": -1 },
{ "id": 17, "name": "Colosseum Glory", "rank": -1, "score": -1 },
{ "id": 18, "name": "Abyssal Sire", "rank": -1, "score": -1 },
{ "id": 19, "name": "Alchemical Hydra", "rank": -1, "score": -1 },
{ "id": 20, "name": "Artio", "rank": -1, "score": -1 },
{ "id": 21, "name": "Barrows Chests", "rank": -1, "score": -1 },
{ "id": 22, "name": "Bryophyta", "rank": -1, "score": -1 },
{ "id": 23, "name": "Callisto", "rank": -1, "score": -1 },
{ "id": 24, "name": "Calvar'ion", "rank": -1, "score": -1 },
{ "id": 25, "name": "Cerberus", "rank": -1, "score": -1 },
{ "id": 26, "name": "Chambers of Xeric", "rank": -1, "score": -1 },
{
"id": 25,
"id": 27,
"name": "Chambers of Xeric: Challenge Mode",
"rank": -1,
"score": -1
},
{ "id": 26, "name": "Chaos Elemental", "rank": -1, "score": -1 },
{ "id": 27, "name": "Chaos Fanatic", "rank": -1, "score": -1 },
{ "id": 28, "name": "Commander Zilyana", "rank": -1, "score": -1 },
{ "id": 29, "name": "Corporeal Beast", "rank": -1, "score": -1 },
{ "id": 30, "name": "Crazy Archaeologist", "rank": -1, "score": -1 },
{ "id": 31, "name": "Dagannoth Prime", "rank": -1, "score": -1 },
{ "id": 32, "name": "Dagannoth Rex", "rank": -1, "score": -1 },
{ "id": 33, "name": "Dagannoth Supreme", "rank": -1, "score": -1 },
{ "id": 34, "name": "Deranged Archaeologist", "rank": -1, "score": -1 },
{ "id": 35, "name": "Duke Sucellus", "rank": -1, "score": -1 },
{ "id": 36, "name": "General Graardor", "rank": -1, "score": -1 },
{ "id": 37, "name": "Giant Mole", "rank": -1, "score": -1 },
{ "id": 38, "name": "Grotesque Guardians", "rank": -1, "score": -1 },
{ "id": 39, "name": "Hespori", "rank": -1, "score": -1 },
{ "id": 40, "name": "Kalphite Queen", "rank": -1, "score": -1 },
{ "id": 41, "name": "King Black Dragon", "rank": -1, "score": -1 },
{ "id": 42, "name": "Kraken", "rank": -1, "score": -1 },
{ "id": 43, "name": "Kree'Arra", "rank": -1, "score": -1 },
{ "id": 44, "name": "K'ril Tsutsaroth", "rank": -1, "score": -1 },
{ "id": 45, "name": "Mimic", "rank": -1, "score": -1 },
{ "id": 46, "name": "Nex", "rank": -1, "score": -1 },
{ "id": 47, "name": "Nightmare", "rank": -1, "score": -1 },
{ "id": 48, "name": "Phosani's Nightmare", "rank": -1, "score": -1 },
{ "id": 49, "name": "Obor", "rank": -1, "score": -1 },
{ "id": 50, "name": "Phantom Muspah", "rank": -1, "score": -1 },
{ "id": 51, "name": "Sarachnis", "rank": -1, "score": -1 },
{ "id": 52, "name": "Scorpia", "rank": -1, "score": -1 },
{ "id": 53, "name": "Skotizo", "rank": -1, "score": -1 },
{ "id": 54, "name": "Spindel", "rank": -1, "score": -1 },
{ "id": 55, "name": "Tempoross", "rank": -1, "score": -1 },
{ "id": 56, "name": "The Gauntlet", "rank": -1, "score": -1 },
{ "id": 57, "name": "The Corrupted Gauntlet", "rank": -1, "score": -1 },
{ "id": 58, "name": "The Leviathan", "rank": -1, "score": -1 },
{ "id": 59, "name": "The Whisperer", "rank": -1, "score": -1 },
{ "id": 60, "name": "Theatre of Blood", "rank": -1, "score": -1 },
{ "id": 28, "name": "Chaos Elemental", "rank": -1, "score": -1 },
{ "id": 29, "name": "Chaos Fanatic", "rank": -1, "score": -1 },
{ "id": 30, "name": "Commander Zilyana", "rank": -1, "score": -1 },
{ "id": 31, "name": "Corporeal Beast", "rank": -1, "score": -1 },
{ "id": 32, "name": "Crazy Archaeologist", "rank": -1, "score": -1 },
{ "id": 33, "name": "Dagannoth Prime", "rank": -1, "score": -1 },
{ "id": 34, "name": "Dagannoth Rex", "rank": -1, "score": -1 },
{ "id": 35, "name": "Dagannoth Supreme", "rank": -1, "score": -1 },
{ "id": 36, "name": "Deranged Archaeologist", "rank": -1, "score": -1 },
{ "id": 37, "name": "Duke Sucellus", "rank": -1, "score": -1 },
{ "id": 38, "name": "General Graardor", "rank": -1, "score": -1 },
{ "id": 39, "name": "Giant Mole", "rank": -1, "score": -1 },
{ "id": 40, "name": "Grotesque Guardians", "rank": -1, "score": -1 },
{ "id": 41, "name": "Hespori", "rank": -1, "score": -1 },
{ "id": 42, "name": "Kalphite Queen", "rank": -1, "score": -1 },
{ "id": 43, "name": "King Black Dragon", "rank": -1, "score": -1 },
{ "id": 44, "name": "Kraken", "rank": -1, "score": -1 },
{ "id": 45, "name": "Kree'Arra", "rank": -1, "score": -1 },
{ "id": 46, "name": "K'ril Tsutsaroth", "rank": -1, "score": -1 },
{ "id": 47, "name": "Lunar Chests", "rank": -1, "score": -1 },
{ "id": 48, "name": "Mimic", "rank": -1, "score": -1 },
{ "id": 49, "name": "Nex", "rank": -1, "score": -1 },
{ "id": 50, "name": "Nightmare", "rank": -1, "score": -1 },
{ "id": 51, "name": "Phosani's Nightmare", "rank": -1, "score": -1 },
{ "id": 52, "name": "Obor", "rank": -1, "score": -1 },
{ "id": 53, "name": "Phantom Muspah", "rank": -1, "score": -1 },
{ "id": 54, "name": "Sarachnis", "rank": -1, "score": -1 },
{ "id": 55, "name": "Scorpia", "rank": -1, "score": -1 },
{ "id": 56, "name": "Scurrius", "rank": -1, "score": -1 },
{ "id": 57, "name": "Skotizo", "rank": -1, "score": -1 },
{ "id": 58, "name": "Sol Heredit", "rank": -1, "score": -1 },
{ "id": 59, "name": "Spindel", "rank": -1, "score": -1 },
{ "id": 60, "name": "Tempoross", "rank": -1, "score": -1 },
{ "id": 61, "name": "The Gauntlet", "rank": -1, "score": -1 },
{ "id": 62, "name": "The Corrupted Gauntlet", "rank": -1, "score": -1 },
{ "id": 63, "name": "The Leviathan", "rank": -1, "score": -1 },
{ "id": 64, "name": "The Whisperer", "rank": -1, "score": -1 },
{ "id": 65, "name": "Theatre of Blood", "rank": -1, "score": -1 },
{
"id": 61,
"id": 66,
"name": "Theatre of Blood: Hard Mode",
"rank": -1,
"score": -1
},
{ "id": 62, "name": "Thermonuclear Smoke Devil", "rank": -1, "score": -1 },
{ "id": 63, "name": "Tombs of Amascut", "rank": -1, "score": -1 },
{ "id": 67, "name": "Thermonuclear Smoke Devil", "rank": -1, "score": -1 },
{ "id": 68, "name": "Tombs of Amascut", "rank": -1, "score": -1 },
{
"id": 64,
"id": 69,
"name": "Tombs of Amascut: Expert Mode",
"rank": -1,
"score": -1
},
{ "id": 65, "name": "TzKal-Zuk", "rank": -1, "score": -1 },
{ "id": 66, "name": "TzTok-Jad", "rank": 198, "score": 186 },
{ "id": 67, "name": "Vardorvis", "rank": -1, "score": -1 },
{ "id": 68, "name": "Venenatis", "rank": -1, "score": -1 },
{ "id": 69, "name": "Vet'ion", "rank": -1, "score": -1 },
{ "id": 70, "name": "Vorkath", "rank": -1, "score": -1 },
{ "id": 71, "name": "Wintertodt", "rank": -1, "score": -1 },
{ "id": 72, "name": "Zalcano", "rank": -1, "score": -1 },
{ "id": 73, "name": "Zulrah", "rank": -1, "score": -1 }
{ "id": 70, "name": "TzKal-Zuk", "rank": -1, "score": -1 },
{ "id": 71, "name": "TzTok-Jad", "rank": 251, "score": 186 },
{ "id": 72, "name": "Vardorvis", "rank": -1, "score": -1 },
{ "id": 73, "name": "Venenatis", "rank": -1, "score": -1 },
{ "id": 74, "name": "Vet'ion", "rank": -1, "score": -1 },
{ "id": 75, "name": "Vorkath", "rank": -1, "score": -1 },
{ "id": 76, "name": "Wintertodt", "rank": -1, "score": -1 },
{ "id": 77, "name": "Zalcano", "rank": -1, "score": -1 },
{ "id": 78, "name": "Zulrah", "rank": -1, "score": -1 }
]
}

View File

@@ -1,6 +1,6 @@
{
"name": "osrs-json-hiscores",
"version": "2.16.0",
"version": "2.17.0",
"description": "The Old School Runescape API wrapper that does more!",
"main": "lib/index.js",
"types": "lib/index.d.ts",
@@ -67,7 +67,10 @@
],
"ignorePatterns": [
"**/@types/*"
]
],
"rules": {
"max-classes-per-file": "off"
}
},
"prettier": {
"trailingComma": "none",

View File

@@ -1,8 +1,4 @@
import {
AxiosRequestConfig,
AxiosResponse,
InternalAxiosRequestConfig
} from 'axios';
import axios, { AxiosRequestConfig } from 'axios';
import { BinaryData, JSDOM } from 'jsdom';
import {
Player,
@@ -35,9 +31,10 @@ import {
getActivityPageURL,
httpGet,
BOSSES,
INVALID_FORMAT_ERROR,
InvalidFormatError,
PlayerNotFoundError,
HiScoresError,
validateRSN,
PLAYER_NOT_FOUND_ERROR,
FORMATTED_SKILL_NAMES,
FORMATTED_BH_NAMES,
FORMATTED_CLUE_NAMES,
@@ -46,7 +43,9 @@ import {
FORMATTED_LMS,
FORMATTED_PVP_ARENA,
FORMATTED_SOUL_WARS,
FORMATTED_RIFTS_CLOSED
FORMATTED_RIFTS_CLOSED,
FORMATTED_DEADMAN_POINTS,
FORMATTED_COLOSSEUM_GLORY
} from './utils';
/**
@@ -68,8 +67,12 @@ export async function getOfficialStats(
try {
const response = await httpGet<HiscoresResponse>(url, config);
return response.data;
} catch {
throw Error(PLAYER_NOT_FOUND_ERROR);
} catch (err) {
if (!axios.isAxiosError(err)) throw err;
if (err.response?.status === 404) throw new PlayerNotFoundError();
throw new HiScoresError();
}
}
@@ -99,9 +102,9 @@ export async function getRSNFormat(
if (anchor) {
return rsnFromElement(anchor);
}
throw Error(PLAYER_NOT_FOUND_ERROR);
throw new PlayerNotFoundError();
} catch {
throw Error(PLAYER_NOT_FOUND_ERROR);
throw new HiScoresError();
}
}
@@ -155,19 +158,23 @@ export function parseJsonStats(json: HiscoresResponse): Stats {
const bosses = reduceActivity(BOSSES, FORMATTED_BOSS_NAMES);
const leaguePoints = getActivity(FORMATTED_LEAGUE_POINTS);
const deadmanPoints = getActivity(FORMATTED_DEADMAN_POINTS);
const lastManStanding = getActivity(FORMATTED_LMS);
const pvpArena = getActivity(FORMATTED_PVP_ARENA);
const soulWarsZeal = getActivity(FORMATTED_SOUL_WARS);
const riftsClosed = getActivity(FORMATTED_RIFTS_CLOSED);
const colosseumGlory = getActivity(FORMATTED_COLOSSEUM_GLORY);
const stats: Stats = {
skills,
leaguePoints,
deadmanPoints,
bountyHunter,
lastManStanding,
pvpArena,
soulWarsZeal,
riftsClosed,
colosseumGlory,
clues,
bosses
};
@@ -187,11 +194,8 @@ export function parseStats(csv: string): Stats {
.filter((entry) => !!entry)
.map((stat) => stat.split(','));
if (
splitCSV.length !==
SKILLS.length + BH_MODES.length + CLUES.length + BOSSES.length + 5
) {
throw Error(INVALID_FORMAT_ERROR);
if (splitCSV.length !== SKILLS.length + ACTIVITIES.length) {
throw new InvalidFormatError();
}
const skillObjects: Skill[] = splitCSV
@@ -217,11 +221,11 @@ export function parseStats(csv: string): Stats {
return activity;
});
const [leaguePoints] = activityObjects.splice(0, 1);
const [leaguePoints, deadmanPoints] = activityObjects.splice(0, 2);
const bhObjects = activityObjects.splice(0, BH_MODES.length);
const clueObjects = activityObjects.splice(0, CLUES.length);
const [lastManStanding, pvpArena, soulWarsZeal, riftsClosed] =
activityObjects.splice(0, 4);
const [lastManStanding, pvpArena, soulWarsZeal, riftsClosed, colosseumGlory] =
activityObjects.splice(0, 5);
const bossObjects = activityObjects.splice(0, BOSSES.length);
const skills: Skills = skillObjects.reduce<Skills>((prev, curr, index) => {
@@ -251,11 +255,13 @@ export function parseStats(csv: string): Stats {
const stats: Stats = {
skills,
leaguePoints,
deadmanPoints,
bountyHunter,
lastManStanding,
pvpArena,
soulWarsZeal,
riftsClosed,
colosseumGlory,
clues,
bosses
};
@@ -284,91 +290,70 @@ export async function getStats(
];
const shouldGetFormattedRsn = options?.shouldGetFormattedRsn ?? true;
const mainRes = await httpGet<HiscoresResponse>(
getStatsURL('main', rsn, true),
options?.axiosConfigs?.main
);
if (mainRes.status === 200) {
const emptyResponse: AxiosResponse<HiscoresResponse> = {
status: 404,
data: { skills: [], activities: [] },
statusText: '',
headers: {},
config: {} as InternalAxiosRequestConfig
};
const getModeStats = async (
mode: Extract<Gamemode, 'ironman' | 'hardcore' | 'ultimate'>
): Promise<AxiosResponse<HiscoresResponse>> =>
otherGamemodes.includes(mode)
? httpGet<HiscoresResponse>(
getStatsURL(mode, rsn, true),
options?.axiosConfigs?.[mode]
).catch((err) => err)
: emptyResponse;
const formattedName = shouldGetFormattedRsn
? await getRSNFormat(rsn, options?.axiosConfigs?.rsn).catch(
const main = await getOfficialStats(rsn, 'main', options?.axiosConfigs?.main);
const getModeStats = async (
mode: Extract<Gamemode, 'ironman' | 'hardcore' | 'ultimate'>
): Promise<HiscoresResponse | undefined> =>
otherGamemodes.includes(mode)
? getOfficialStats(rsn, mode, options?.axiosConfigs?.[mode]).catch(
() => undefined
)
: undefined;
const formattedName = shouldGetFormattedRsn
? await getRSNFormat(rsn, options?.axiosConfigs?.rsn).catch(() => undefined)
: undefined;
const player: Player = {
name: formattedName ?? rsn,
mode: 'main',
dead: false,
deulted: false,
deironed: false
};
player.main = parseJsonStats(mainRes.data);
const player: Player = {
name: formattedName ?? rsn,
mode: 'main',
dead: false,
deulted: false,
deironed: false
};
player.main = parseJsonStats(main);
const ironRes = await getModeStats('ironman');
if (ironRes.status === 200) {
player.ironman = parseJsonStats(ironRes.data);
const hcRes = await getModeStats('hardcore');
const ultRes = await getModeStats('ultimate');
if (hcRes.status === 200) {
player.mode = 'hardcore';
player.hardcore = parseJsonStats(hcRes.data);
if (
player.ironman.skills.overall.xp !== player.hardcore.skills.overall.xp
) {
player.dead = true;
player.mode = 'ironman';
}
if (
player.main.skills.overall.xp !== player.ironman.skills.overall.xp
) {
player.deironed = true;
player.mode = 'main';
}
} else if (ultRes.status === 200) {
player.mode = 'ultimate';
player.ultimate = parseJsonStats(ultRes.data);
if (
player.ironman.skills.overall.xp !== player.ultimate.skills.overall.xp
) {
player.deulted = true;
player.mode = 'ironman';
}
if (
player.main.skills.overall.xp !== player.ironman.skills.overall.xp
) {
player.deironed = true;
player.mode = 'main';
}
} else {
const iron = await getModeStats('ironman');
if (iron) {
player.ironman = parseJsonStats(iron);
const hc = await getModeStats('hardcore');
const ult = await getModeStats('ultimate');
if (hc) {
player.mode = 'hardcore';
player.hardcore = parseJsonStats(hc);
if (
player.ironman.skills.overall.xp !== player.hardcore.skills.overall.xp
) {
player.dead = true;
player.mode = 'ironman';
if (
player.main.skills.overall.xp !== player.ironman.skills.overall.xp
) {
player.deironed = true;
player.mode = 'main';
}
}
if (player.main.skills.overall.xp !== player.ironman.skills.overall.xp) {
player.deironed = true;
player.mode = 'main';
}
} else if (ult) {
player.mode = 'ultimate';
player.ultimate = parseJsonStats(ult);
if (
player.ironman.skills.overall.xp !== player.ultimate.skills.overall.xp
) {
player.deulted = true;
player.mode = 'ironman';
}
if (player.main.skills.overall.xp !== player.ironman.skills.overall.xp) {
player.deironed = true;
player.mode = 'main';
}
} else {
player.mode = 'ironman';
if (player.main.skills.overall.xp !== player.ironman.skills.overall.xp) {
player.deironed = true;
player.mode = 'main';
}
}
return player;
}
throw Error(PLAYER_NOT_FOUND_ERROR);
return player;
}
/**

View File

@@ -96,6 +96,7 @@ export type Boss =
| 'kraken'
| 'kreeArra'
| 'krilTsutsaroth'
| 'lunarChests'
| 'mimic'
| 'nex'
| 'nightmare'
@@ -104,7 +105,9 @@ export type Boss =
| 'phantomMuspah'
| 'sarachnis'
| 'scorpia'
| 'scurrius'
| 'skotizo'
| 'solHeredit'
| 'spindel'
| 'tempoross'
| 'gauntlet'
@@ -130,6 +133,7 @@ export type Bosses = { [Type in Boss]: Activity };
export type ActivityName =
| 'leaguePoints'
| 'deadmanPoints'
| 'hunterBHV2'
| 'rogueBHV2'
| 'hunterBH'
@@ -145,17 +149,26 @@ export type ActivityName =
| 'hardClues'
| 'eliteClues'
| 'masterClues'
| 'colosseumGlory'
| Boss;
export interface Stats {
skills: Skills;
clues: Clues;
/**
* Will only contain rank and score data for the `seasonal` gamemode.
*/
leaguePoints: Activity;
/**
* Will only contain rank and score data for the `tournament` gamemode.
*/
deadmanPoints: Activity;
bountyHunter: BH;
lastManStanding: Activity;
pvpArena: Activity;
soulWarsZeal: Activity;
riftsClosed: Activity;
colosseumGlory: Activity;
bosses: Bosses;
}
export type Modes = { [M in Gamemode]?: Stats };

View File

@@ -103,6 +103,7 @@ export const BOSSES: Boss[] = [
'kraken',
'kreeArra',
'krilTsutsaroth',
'lunarChests',
'mimic',
'nex',
'nightmare',
@@ -111,7 +112,9 @@ export const BOSSES: Boss[] = [
'phantomMuspah',
'sarachnis',
'scorpia',
'scurrius',
'skotizo',
'solHeredit',
'spindel',
'tempoross',
'gauntlet',
@@ -135,6 +138,7 @@ export const BOSSES: Boss[] = [
];
export const ACTIVITIES: ActivityName[] = [
'leaguePoints',
'deadmanPoints',
'hunterBHV2',
'rogueBHV2',
'hunterBH',
@@ -150,6 +154,7 @@ export const ACTIVITIES: ActivityName[] = [
'pvpArena',
'soulWarsZeal',
'riftsClosed',
'colosseumGlory',
...BOSSES
];
@@ -187,6 +192,7 @@ export const FORMATTED_BOSS_NAMES: FormattedBossNames = {
kraken: 'Kraken',
kreeArra: "Kree'Arra",
krilTsutsaroth: "K'ril Tsutsaroth",
lunarChests: 'Lunar Chests',
mimic: 'Mimic',
nex: 'Nex',
nightmare: 'Nightmare',
@@ -195,7 +201,9 @@ export const FORMATTED_BOSS_NAMES: FormattedBossNames = {
phantomMuspah: 'Phantom Muspah',
sarachnis: 'Sarachnis',
scorpia: 'Scorpia',
scurrius: 'Scurrius',
skotizo: 'Skotizo',
solHeredit: 'Sol Heredit',
spindel: 'Spindel',
tempoross: 'Tempoross',
gauntlet: 'The Gauntlet',
@@ -278,7 +286,46 @@ export const FORMATTED_LMS = 'LMS - Rank';
export const FORMATTED_PVP_ARENA = 'PvP Arena - Rank';
export const FORMATTED_SOUL_WARS = 'Soul Wars Zeal';
export const FORMATTED_LEAGUE_POINTS = 'League Points';
export const FORMATTED_DEADMAN_POINTS = 'Deadman Points';
export const FORMATTED_RIFTS_CLOSED = 'Rifts closed';
export const FORMATTED_COLOSSEUM_GLORY = 'Colosseum Glory';
export const INVALID_FORMAT_ERROR = 'Invalid hiscores format';
export const PLAYER_NOT_FOUND_ERROR = 'Player not found';
export const HISCORES_ERROR = 'HiScores not responding';
export class InvalidFormatError extends Error {
__proto__ = Error;
constructor() {
super(INVALID_FORMAT_ERROR);
Object.setPrototypeOf(this, InvalidFormatError.prototype);
}
}
export class InvalidRSNError extends Error {
__proto__ = Error;
constructor(message: string) {
super(message);
Object.setPrototypeOf(this, InvalidRSNError.prototype);
}
}
export class PlayerNotFoundError extends Error {
__proto__ = Error;
constructor() {
super(PLAYER_NOT_FOUND_ERROR);
Object.setPrototypeOf(this, PlayerNotFoundError.prototype);
}
}
export class HiScoresError extends Error {
__proto__ = Error;
constructor() {
super(HISCORES_ERROR);
Object.setPrototypeOf(this, HiScoresError.prototype);
}
}

View File

@@ -7,7 +7,8 @@ import {
SCORES_URL,
SKILLS,
ACTIVITIES,
JSON_STATS_URL
JSON_STATS_URL,
InvalidRSNError
} from './constants';
/**
@@ -119,10 +120,10 @@ export const httpGet = <Response>(
*/
export const validateRSN = (rsn: string) => {
if (typeof rsn !== 'string') {
throw Error('RSN must be a string');
throw new InvalidRSNError('RSN must be a string');
} else if (!/^[a-zA-Z0-9 _-]+$/.test(rsn)) {
throw Error('RSN contains invalid character');
throw new InvalidRSNError('RSN contains invalid character');
} else if (rsn.length > 12 || rsn.length < 1) {
throw Error('RSN must be between 1 and 12 characters');
throw new InvalidRSNError('RSN must be between 1 and 12 characters');
}
};

View File

@@ -6,10 +6,7 @@
"outDir": "./lib",
"strict": true,
"lib": ["ES2015", "DOM", "DOM.Iterable"],
"typeRoots": [
"./node_modules/@types",
"./src/@types"
]
"typeRoots": ["./node_modules/@types", "./src/@types"]
},
"include": ["src"],
"exclude": ["node_modules", "**/__tests__/*"]

View File

@@ -2429,9 +2429,9 @@ flatted@^3.1.0:
integrity sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==
follow-redirects@^1.15.0:
version "1.15.3"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.3.tgz#fe2f3ef2690afce7e82ed0b44db08165b207123a"
integrity sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==
version "1.15.4"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.4.tgz#cdc7d308bf6493126b17ea2191ea0ccf3e535adf"
integrity sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==
for-each@^0.3.3:
version "0.3.3"