mirror of
https://github.com/maxswa/osrs-json-hiscores.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
27 Commits
v2.15.0
...
deadman-po
Author | SHA1 | Date | |
---|---|---|---|
![]() |
91066b5366 | ||
![]() |
4872d04301 | ||
![]() |
55312ba0fd | ||
![]() |
331a448503 | ||
![]() |
84c704a846 | ||
![]() |
561495632c | ||
![]() |
bdfdf1eb14 | ||
![]() |
e349776060 | ||
![]() |
546bc5acf7 | ||
![]() |
66528cd9d9 | ||
![]() |
99ea3fb722 | ||
![]() |
7f16d26e3c | ||
![]() |
ed9fcf47b3 | ||
![]() |
bb935bb6c9 | ||
![]() |
d046fffa9e | ||
![]() |
5483e54d78 | ||
![]() |
97532b0c03 | ||
![]() |
f9a56e2b3a | ||
![]() |
9f43f0c39f | ||
![]() |
d67ffa3e20 | ||
![]() |
7bdde9f5d1 | ||
![]() |
b4a50e69c8 | ||
![]() |
7935c5a523 | ||
![]() |
f1e2155428 | ||
![]() |
dd90fe1260 | ||
![]() |
12c4e530a2 | ||
![]() |
5a2b0d9ad8 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
|||||||
.idea/
|
.idea/
|
||||||
node_modules
|
node_modules
|
||||||
/lib
|
/lib
|
||||||
|
.vscode
|
17
README.md
17
README.md
@@ -110,16 +110,17 @@ Activities consist of all levels of clue scrolls as well as minigames and bosses
|
|||||||
| Bounty Hunter (Legacy - Hunter) | `hunterBH` |
|
| Bounty Hunter (Legacy - Hunter) | `hunterBH` |
|
||||||
| Bounty Hunter (Rogue) | `rogueBHV2` |
|
| Bounty Hunter (Rogue) | `rogueBHV2` |
|
||||||
| Bounty Hunter (Hunter) | `hunterBHV2` |
|
| Bounty Hunter (Hunter) | `hunterBHV2` |
|
||||||
| Last Man Standing | `lastManStanding` |
|
| LMS - Rank | `lastManStanding` |
|
||||||
| PvP Arena | `pvpArena` |
|
| PvP Arena - Rank | `pvpArena` |
|
||||||
| Soul Wars Zeal | `soulWarsZeal` |
|
| Soul Wars Zeal | `soulWarsZeal` |
|
||||||
| Rifts Closed | `riftsClosed` |
|
| Rifts closed | `riftsClosed` |
|
||||||
|
|
||||||
### Leagues
|
### Points
|
||||||
|
|
||||||
| Activity | Param |
|
| Activity | Param |
|
||||||
| ------------- | :------------: |
|
| -------------- | :-------------: |
|
||||||
| League Points | `leaguePoints` |
|
| League Points | `leaguePoints` |
|
||||||
|
| Deadman Points | `deadmanPoints` |
|
||||||
|
|
||||||
### Bosses
|
### Bosses
|
||||||
|
|
||||||
@@ -156,7 +157,7 @@ Activities consist of all levels of clue scrolls as well as minigames and bosses
|
|||||||
| K'ril Tsutsaroth | `krilTsutsaroth` |
|
| K'ril Tsutsaroth | `krilTsutsaroth` |
|
||||||
| Mimic | `mimic` |
|
| Mimic | `mimic` |
|
||||||
| Nex | `nex` |
|
| Nex | `nex` |
|
||||||
| The Nightmare of Ashihama | `nightmare` |
|
| Nightmare | `nightmare` |
|
||||||
| Phosani's Nightmare | `phosanisNightmare` |
|
| Phosani's Nightmare | `phosanisNightmare` |
|
||||||
| Obor | `obor` |
|
| Obor | `obor` |
|
||||||
| Phantom Muspah | `phantomMuspah` |
|
| Phantom Muspah | `phantomMuspah` |
|
||||||
|
2515
__tests__/attackTopPage.html
vendored
2515
__tests__/attackTopPage.html
vendored
File diff suppressed because it is too large
Load Diff
2578
__tests__/b0atyNamePage.html
vendored
2578
__tests__/b0atyNamePage.html
vendored
File diff suppressed because it is too large
Load Diff
99
__tests__/b0atyStats.csv
Normal file
99
__tests__/b0atyStats.csv
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
3745,2277,840426611
|
||||||
|
24080,99,30276246
|
||||||
|
9559,99,31228199
|
||||||
|
2212,99,143599407
|
||||||
|
3550,99,123248914
|
||||||
|
6564,99,109953707
|
||||||
|
4244,99,15144846
|
||||||
|
4107,99,57072224
|
||||||
|
135556,99,13353511
|
||||||
|
25855,99,16903268
|
||||||
|
53472,99,13456850
|
||||||
|
22453,99,16654917
|
||||||
|
17690,99,19118307
|
||||||
|
45816,99,14059776
|
||||||
|
10409,99,16530015
|
||||||
|
27702,99,14765145
|
||||||
|
39430,99,13235063
|
||||||
|
6722,99,15754877
|
||||||
|
51813,99,14023027
|
||||||
|
5324,99,33835543
|
||||||
|
3154,99,69527777
|
||||||
|
4719,99,22733384
|
||||||
|
15135,99,17952893
|
||||||
|
1089,99,17998715
|
||||||
|
-1,-1
|
||||||
|
-1,-1
|
||||||
|
26164,10
|
||||||
|
12886,3
|
||||||
|
148658,8
|
||||||
|
103161,7
|
||||||
|
377,9556
|
||||||
|
862,825
|
||||||
|
148,6000
|
||||||
|
2153,1606
|
||||||
|
42107,298
|
||||||
|
504,459
|
||||||
|
1816,368
|
||||||
|
14701,2521
|
||||||
|
-1,-1
|
||||||
|
6776,14780
|
||||||
|
4773,1060
|
||||||
|
2741,2192
|
||||||
|
90203,594
|
||||||
|
29573,143
|
||||||
|
3668,1830
|
||||||
|
206778,5
|
||||||
|
32897,293
|
||||||
|
64112,58
|
||||||
|
18492,1905
|
||||||
|
178941,34
|
||||||
|
2379,501
|
||||||
|
82902,50
|
||||||
|
147358,26
|
||||||
|
51973,287
|
||||||
|
2377,2000
|
||||||
|
147406,41
|
||||||
|
32225,707
|
||||||
|
42229,698
|
||||||
|
32212,714
|
||||||
|
79605,25
|
||||||
|
9517,688
|
||||||
|
19125,1228
|
||||||
|
65849,474
|
||||||
|
2080,2140
|
||||||
|
16433,182
|
||||||
|
2006,2046
|
||||||
|
48575,580
|
||||||
|
115056,1908
|
||||||
|
10406,920
|
||||||
|
2196,1444
|
||||||
|
1005,33
|
||||||
|
28413,620
|
||||||
|
4157,744
|
||||||
|
4261,500
|
||||||
|
993,217
|
||||||
|
21848,251
|
||||||
|
66260,119
|
||||||
|
108898,26
|
||||||
|
373975,9
|
||||||
|
2005,1569
|
||||||
|
40001,273
|
||||||
|
192608,7
|
||||||
|
78367,201
|
||||||
|
5679,583
|
||||||
|
478,1760
|
||||||
|
22932,250
|
||||||
|
15059,7
|
||||||
|
7161,3066
|
||||||
|
101555,35
|
||||||
|
610,933
|
||||||
|
15733,2
|
||||||
|
-1,-1
|
||||||
|
2051,2078
|
||||||
|
194,7096
|
||||||
|
69260,51
|
||||||
|
14039,2780
|
||||||
|
876367,62
|
||||||
|
165341,25
|
||||||
|
226318,275
|
Can't render this file because it has a wrong number of fields in line 25.
|
201
__tests__/b0atyStats.json
Normal file
201
__tests__/b0atyStats.json
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
{
|
||||||
|
"skills": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "Overall",
|
||||||
|
"rank": 3745,
|
||||||
|
"level": 2277,
|
||||||
|
"xp": 840426611
|
||||||
|
},
|
||||||
|
{ "id": 1, "name": "Attack", "rank": 24080, "level": 99, "xp": 30276246 },
|
||||||
|
{ "id": 2, "name": "Defence", "rank": 9559, "level": 99, "xp": 31228199 },
|
||||||
|
{ "id": 3, "name": "Strength", "rank": 2212, "level": 99, "xp": 143599407 },
|
||||||
|
{
|
||||||
|
"id": 4,
|
||||||
|
"name": "Hitpoints",
|
||||||
|
"rank": 3550,
|
||||||
|
"level": 99,
|
||||||
|
"xp": 123248914
|
||||||
|
},
|
||||||
|
{ "id": 5, "name": "Ranged", "rank": 6564, "level": 99, "xp": 109953707 },
|
||||||
|
{ "id": 6, "name": "Prayer", "rank": 4244, "level": 99, "xp": 15144846 },
|
||||||
|
{ "id": 7, "name": "Magic", "rank": 4107, "level": 99, "xp": 57072224 },
|
||||||
|
{ "id": 8, "name": "Cooking", "rank": 135556, "level": 99, "xp": 13353511 },
|
||||||
|
{
|
||||||
|
"id": 9,
|
||||||
|
"name": "Woodcutting",
|
||||||
|
"rank": 25855,
|
||||||
|
"level": 99,
|
||||||
|
"xp": 16903268
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 10,
|
||||||
|
"name": "Fletching",
|
||||||
|
"rank": 53472,
|
||||||
|
"level": 99,
|
||||||
|
"xp": 13456850
|
||||||
|
},
|
||||||
|
{ "id": 11, "name": "Fishing", "rank": 22453, "level": 99, "xp": 16654917 },
|
||||||
|
{
|
||||||
|
"id": 12,
|
||||||
|
"name": "Firemaking",
|
||||||
|
"rank": 17690,
|
||||||
|
"level": 99,
|
||||||
|
"xp": 19118307
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 13,
|
||||||
|
"name": "Crafting",
|
||||||
|
"rank": 45816,
|
||||||
|
"level": 99,
|
||||||
|
"xp": 14059776
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 14,
|
||||||
|
"name": "Smithing",
|
||||||
|
"rank": 10409,
|
||||||
|
"level": 99,
|
||||||
|
"xp": 16530015
|
||||||
|
},
|
||||||
|
{ "id": 15, "name": "Mining", "rank": 27702, "level": 99, "xp": 14765145 },
|
||||||
|
{
|
||||||
|
"id": 16,
|
||||||
|
"name": "Herblore",
|
||||||
|
"rank": 39430,
|
||||||
|
"level": 99,
|
||||||
|
"xp": 13235063
|
||||||
|
},
|
||||||
|
{ "id": 17, "name": "Agility", "rank": 6722, "level": 99, "xp": 15754877 },
|
||||||
|
{
|
||||||
|
"id": 18,
|
||||||
|
"name": "Thieving",
|
||||||
|
"rank": 51813,
|
||||||
|
"level": 99,
|
||||||
|
"xp": 14023027
|
||||||
|
},
|
||||||
|
{ "id": 19, "name": "Slayer", "rank": 5324, "level": 99, "xp": 33835543 },
|
||||||
|
{ "id": 20, "name": "Farming", "rank": 3154, "level": 99, "xp": 69527777 },
|
||||||
|
{
|
||||||
|
"id": 21,
|
||||||
|
"name": "Runecraft",
|
||||||
|
"rank": 4719,
|
||||||
|
"level": 99,
|
||||||
|
"xp": 22733384
|
||||||
|
},
|
||||||
|
{ "id": 22, "name": "Hunter", "rank": 15135, "level": 99, "xp": 17952893 },
|
||||||
|
{
|
||||||
|
"id": 23,
|
||||||
|
"name": "Construction",
|
||||||
|
"rank": 1089,
|
||||||
|
"level": 99,
|
||||||
|
"xp": 17998715
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"activities": [
|
||||||
|
{ "id": 0, "name": "League Points", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 1, "name": "Deadman Points", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 2, "name": "Bounty Hunter - Hunter", "rank": 26164, "score": 10 },
|
||||||
|
{ "id": 3, "name": "Bounty Hunter - Rogue", "rank": 12886, "score": 3 },
|
||||||
|
{
|
||||||
|
"id": 4,
|
||||||
|
"name": "Bounty Hunter (Legacy) - Hunter",
|
||||||
|
"rank": 148658,
|
||||||
|
"score": 8
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5,
|
||||||
|
"name": "Bounty Hunter (Legacy) - Rogue",
|
||||||
|
"rank": 103161,
|
||||||
|
"score": 7
|
||||||
|
},
|
||||||
|
{ "id": 6, "name": "Clue Scrolls (all)", "rank": 377, "score": 9556 },
|
||||||
|
{ "id": 7, "name": "Clue Scrolls (beginner)", "rank": 862, "score": 825 },
|
||||||
|
{ "id": 8, "name": "Clue Scrolls (easy)", "rank": 148, "score": 6000 },
|
||||||
|
{ "id": 9, "name": "Clue Scrolls (medium)", "rank": 2153, "score": 1606 },
|
||||||
|
{ "id": 10, "name": "Clue Scrolls (hard)", "rank": 42107, "score": 298 },
|
||||||
|
{ "id": 11, "name": "Clue Scrolls (elite)", "rank": 504, "score": 459 },
|
||||||
|
{ "id": 12, "name": "Clue Scrolls (master)", "rank": 1816, "score": 368 },
|
||||||
|
{ "id": 13, "name": "LMS - Rank", "rank": 14701, "score": 2521 },
|
||||||
|
{ "id": 14, "name": "PvP Arena - Rank", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 15, "name": "Soul Wars Zeal", "rank": 6776, "score": 14780 },
|
||||||
|
{ "id": 16, "name": "Rifts closed", "rank": 4773, "score": 1060 },
|
||||||
|
{ "id": 17, "name": "Abyssal Sire", "rank": 2741, "score": 2192 },
|
||||||
|
{ "id": 18, "name": "Alchemical Hydra", "rank": 90203, "score": 594 },
|
||||||
|
{ "id": 19, "name": "Artio", "rank": 29573, "score": 143 },
|
||||||
|
{ "id": 20, "name": "Barrows Chests", "rank": 3668, "score": 1830 },
|
||||||
|
{ "id": 21, "name": "Bryophyta", "rank": 206778, "score": 5 },
|
||||||
|
{ "id": 22, "name": "Callisto", "rank": 32897, "score": 293 },
|
||||||
|
{ "id": 23, "name": "Calvar'ion", "rank": 64112, "score": 58 },
|
||||||
|
{ "id": 24, "name": "Cerberus", "rank": 18492, "score": 1905 },
|
||||||
|
{ "id": 25, "name": "Chambers of Xeric", "rank": 178941, "score": 34 },
|
||||||
|
{
|
||||||
|
"id": 26,
|
||||||
|
"name": "Chambers of Xeric: Challenge Mode",
|
||||||
|
"rank": 2379,
|
||||||
|
"score": 501
|
||||||
|
},
|
||||||
|
{ "id": 27, "name": "Chaos Elemental", "rank": 82902, "score": 50 },
|
||||||
|
{ "id": 28, "name": "Chaos Fanatic", "rank": 147358, "score": 26 },
|
||||||
|
{ "id": 29, "name": "Commander Zilyana", "rank": 51973, "score": 287 },
|
||||||
|
{ "id": 30, "name": "Corporeal Beast", "rank": 2377, "score": 2000 },
|
||||||
|
{ "id": 31, "name": "Crazy Archaeologist", "rank": 147406, "score": 41 },
|
||||||
|
{ "id": 32, "name": "Dagannoth Prime", "rank": 32225, "score": 707 },
|
||||||
|
{ "id": 33, "name": "Dagannoth Rex", "rank": 42229, "score": 698 },
|
||||||
|
{ "id": 34, "name": "Dagannoth Supreme", "rank": 32212, "score": 714 },
|
||||||
|
{ "id": 35, "name": "Deranged Archaeologist", "rank": 79605, "score": 25 },
|
||||||
|
{ "id": 36, "name": "Duke Sucellus", "rank": 9517, "score": 688 },
|
||||||
|
{ "id": 37, "name": "General Graardor", "rank": 19125, "score": 1228 },
|
||||||
|
{ "id": 38, "name": "Giant Mole", "rank": 65849, "score": 474 },
|
||||||
|
{ "id": 39, "name": "Grotesque Guardians", "rank": 2080, "score": 2140 },
|
||||||
|
{ "id": 40, "name": "Hespori", "rank": 16433, "score": 182 },
|
||||||
|
{ "id": 41, "name": "Kalphite Queen", "rank": 2006, "score": 2046 },
|
||||||
|
{ "id": 42, "name": "King Black Dragon", "rank": 48575, "score": 580 },
|
||||||
|
{ "id": 43, "name": "Kraken", "rank": 115056, "score": 1908 },
|
||||||
|
{ "id": 44, "name": "Kree'Arra", "rank": 10406, "score": 920 },
|
||||||
|
{ "id": 45, "name": "K'ril Tsutsaroth", "rank": 2196, "score": 1444 },
|
||||||
|
{ "id": 46, "name": "Mimic", "rank": 1005, "score": 33 },
|
||||||
|
{ "id": 47, "name": "Nex", "rank": 28413, "score": 620 },
|
||||||
|
{ "id": 48, "name": "Nightmare", "rank": 4157, "score": 744 },
|
||||||
|
{ "id": 49, "name": "Phosani's Nightmare", "rank": 4261, "score": 500 },
|
||||||
|
{ "id": 50, "name": "Obor", "rank": 993, "score": 217 },
|
||||||
|
{ "id": 51, "name": "Phantom Muspah", "rank": 21848, "score": 251 },
|
||||||
|
{ "id": 52, "name": "Sarachnis", "rank": 66260, "score": 119 },
|
||||||
|
{ "id": 53, "name": "Scorpia", "rank": 108898, "score": 26 },
|
||||||
|
{ "id": 54, "name": "Skotizo", "rank": 373975, "score": 9 },
|
||||||
|
{ "id": 55, "name": "Spindel", "rank": 2005, "score": 1569 },
|
||||||
|
{ "id": 56, "name": "Tempoross", "rank": 40001, "score": 273 },
|
||||||
|
{ "id": 57, "name": "The Gauntlet", "rank": 192608, "score": 7 },
|
||||||
|
{ "id": 58, "name": "The Corrupted Gauntlet", "rank": 78367, "score": 201 },
|
||||||
|
{ "id": 59, "name": "The Leviathan", "rank": 5679, "score": 583 },
|
||||||
|
{ "id": 60, "name": "The Whisperer", "rank": 478, "score": 1760 },
|
||||||
|
{ "id": 61, "name": "Theatre of Blood", "rank": 22932, "score": 250 },
|
||||||
|
{
|
||||||
|
"id": 62,
|
||||||
|
"name": "Theatre of Blood: Hard Mode",
|
||||||
|
"rank": 15059,
|
||||||
|
"score": 7
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 63,
|
||||||
|
"name": "Thermonuclear Smoke Devil",
|
||||||
|
"rank": 7161,
|
||||||
|
"score": 3066
|
||||||
|
},
|
||||||
|
{ "id": 64, "name": "Tombs of Amascut", "rank": 101555, "score": 35 },
|
||||||
|
{
|
||||||
|
"id": 65,
|
||||||
|
"name": "Tombs of Amascut: Expert Mode",
|
||||||
|
"rank": 610,
|
||||||
|
"score": 933
|
||||||
|
},
|
||||||
|
{ "id": 66, "name": "TzKal-Zuk", "rank": 15733, "score": 2 },
|
||||||
|
{ "id": 67, "name": "TzTok-Jad", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 68, "name": "Vardorvis", "rank": 2051, "score": 2078 },
|
||||||
|
{ "id": 69, "name": "Venenatis", "rank": 194, "score": 7096 },
|
||||||
|
{ "id": 70, "name": "Vet'ion", "rank": 69260, "score": 51 },
|
||||||
|
{ "id": 71, "name": "Vorkath", "rank": 14039, "score": 2780 },
|
||||||
|
{ "id": 72, "name": "Wintertodt", "rank": 876367, "score": 62 },
|
||||||
|
{ "id": 73, "name": "Zalcano", "rank": 165341, "score": 25 },
|
||||||
|
{ "id": 74, "name": "Zulrah", "rank": 226318, "score": 275 }
|
||||||
|
]
|
||||||
|
}
|
@@ -12,8 +12,10 @@ import {
|
|||||||
getSkillPageURL,
|
getSkillPageURL,
|
||||||
getStatsURL,
|
getStatsURL,
|
||||||
BOSSES,
|
BOSSES,
|
||||||
INVALID_FORMAT_ERROR,
|
InvalidFormatError,
|
||||||
BH_MODES
|
BH_MODES,
|
||||||
|
parseJsonStats,
|
||||||
|
HiscoresResponse
|
||||||
} from '../src/index';
|
} from '../src/index';
|
||||||
|
|
||||||
const B0ATY_NAME = 'B0ATY';
|
const B0ATY_NAME = 'B0ATY';
|
||||||
@@ -25,7 +27,13 @@ const LYNX_TITAN_FORMATTED_NAME = 'Lynx Titan';
|
|||||||
|
|
||||||
const attackTopPage = readFileSync(`${__dirname}/attackTopPage.html`, 'utf8');
|
const attackTopPage = readFileSync(`${__dirname}/attackTopPage.html`, 'utf8');
|
||||||
const b0atyNamePage = readFileSync(`${__dirname}/b0atyNamePage.html`, 'utf8');
|
const b0atyNamePage = readFileSync(`${__dirname}/b0atyNamePage.html`, 'utf8');
|
||||||
const lynxTitanStats = readFileSync(`${__dirname}/lynxTitanStats.csv`, 'utf8');
|
const b0atyStatsCsv = readFileSync(`${__dirname}/b0atyStats.csv`, 'utf8');
|
||||||
|
const b0atyStatsJson: HiscoresResponse = JSON.parse(
|
||||||
|
readFileSync(`${__dirname}/b0atyStats.json`, 'utf8')
|
||||||
|
);
|
||||||
|
const lynxTitanStats = JSON.parse(
|
||||||
|
readFileSync(`${__dirname}/lynxTitanStats.json`, 'utf8')
|
||||||
|
);
|
||||||
const lynxTitanNamePage = readFileSync(
|
const lynxTitanNamePage = readFileSync(
|
||||||
`${__dirname}/lynxTitanNamePage.html`,
|
`${__dirname}/lynxTitanNamePage.html`,
|
||||||
'utf8'
|
'utf8'
|
||||||
@@ -46,7 +54,7 @@ jest.spyOn(axios, 'get').mockImplementation((url) => {
|
|||||||
if (getSkillPageURL('main', 'attack', 1) === url) {
|
if (getSkillPageURL('main', 'attack', 1) === url) {
|
||||||
return Promise.resolve({ data: attackTopPage });
|
return Promise.resolve({ data: attackTopPage });
|
||||||
}
|
}
|
||||||
if (getStatsURL('main', LYNX_TITAN_FORMATTED_NAME) === url) {
|
if (getStatsURL('main', LYNX_TITAN_FORMATTED_NAME, true) === url) {
|
||||||
return Promise.resolve({ status: 200, data: lynxTitanStats });
|
return Promise.resolve({ status: 200, data: lynxTitanStats });
|
||||||
}
|
}
|
||||||
throw new Error(`No mock response for URL: ${url}`);
|
throw new Error(`No mock response for URL: ${url}`);
|
||||||
@@ -78,6 +86,7 @@ test('Parse CSV to json', () => {
|
|||||||
810,99,37688883
|
810,99,37688883
|
||||||
92,99,32005622
|
92,99,32005622
|
||||||
23423,478
|
23423,478
|
||||||
|
89554,301
|
||||||
89914,35
|
89914,35
|
||||||
99834,25
|
99834,25
|
||||||
99831,23
|
99831,23
|
||||||
@@ -180,11 +189,12 @@ test('Parse CSV to json', () => {
|
|||||||
construction: { rank: 92, level: 99, xp: 32005622 }
|
construction: { rank: 92, level: 99, xp: 32005622 }
|
||||||
},
|
},
|
||||||
leaguePoints: { rank: 23423, score: 478 },
|
leaguePoints: { rank: 23423, score: 478 },
|
||||||
|
deadmanPoints: { rank: 89554, score: 301 },
|
||||||
bountyHunter: {
|
bountyHunter: {
|
||||||
hunterV2: { rank: 89914, score: 35 },
|
hunterV2: { rank: 89914, score: 35 },
|
||||||
rogueV2: { rank: 99834, score: 25 },
|
rogueV2: { rank: 99834, score: 25 },
|
||||||
hunter: { rank: 99831, score: 23 },
|
hunter: { rank: 99831, score: 23 },
|
||||||
rogue: { rank: 89912, score: 37 },
|
rogue: { rank: 89912, score: 37 }
|
||||||
},
|
},
|
||||||
lastManStanding: { rank: 4814, score: 898 },
|
lastManStanding: { rank: 4814, score: 898 },
|
||||||
pvpArena: { rank: 13, score: 4057 },
|
pvpArena: { rank: 13, score: 4057 },
|
||||||
@@ -268,12 +278,12 @@ test('Parse CSV with unknown activity', () => {
|
|||||||
const statsWithUnknownActivity = `${lynxTitanStats}
|
const statsWithUnknownActivity = `${lynxTitanStats}
|
||||||
-1,-1`;
|
-1,-1`;
|
||||||
expect(() => parseStats(statsWithUnknownActivity)).toThrow(
|
expect(() => parseStats(statsWithUnknownActivity)).toThrow(
|
||||||
INVALID_FORMAT_ERROR
|
InvalidFormatError
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Parse invalid CSV', () => {
|
test('Parse invalid CSV', () => {
|
||||||
expect(() => parseStats('invalid')).toThrow(INVALID_FORMAT_ERROR);
|
expect(() => parseStats('invalid')).toThrow(InvalidFormatError);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Get name format', () => {
|
describe('Get name format', () => {
|
||||||
@@ -533,13 +543,13 @@ describe('Get stats options', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
axios.get = jest.fn(
|
axios.get = jest.fn(
|
||||||
(url) =>
|
(url) =>
|
||||||
new Promise<any>((resolve) =>
|
new Promise<any>((resolve) => {
|
||||||
resolve(
|
resolve(
|
||||||
url === getPlayerTableURL('main', rsn)
|
url === getPlayerTableURL('main', rsn)
|
||||||
? { data: lynxTitanNamePage }
|
? { data: lynxTitanNamePage }
|
||||||
: { status: 200, data: lynxTitanStats }
|
: { status: 200, data: lynxTitanStats }
|
||||||
)
|
);
|
||||||
)
|
})
|
||||||
);
|
);
|
||||||
axiosMock = axios.get as any;
|
axiosMock = axios.get as any;
|
||||||
axiosMock.mockClear();
|
axiosMock.mockClear();
|
||||||
@@ -547,11 +557,11 @@ describe('Get stats options', () => {
|
|||||||
it('fetches all gamemodes and formatted RSN when no options provided', async () => {
|
it('fetches all gamemodes and formatted RSN when no options provided', async () => {
|
||||||
await getStats(rsn);
|
await getStats(rsn);
|
||||||
expect(axiosMock.mock.calls.map((val) => val[0])).toEqual([
|
expect(axiosMock.mock.calls.map((val) => val[0])).toEqual([
|
||||||
getStatsURL('main', rsn),
|
getStatsURL('main', rsn, true),
|
||||||
getPlayerTableURL('main', rsn),
|
getPlayerTableURL('main', rsn),
|
||||||
getStatsURL('ironman', rsn),
|
getStatsURL('ironman', rsn, true),
|
||||||
getStatsURL('hardcore', rsn),
|
getStatsURL('hardcore', rsn, true),
|
||||||
getStatsURL('ultimate', rsn)
|
getStatsURL('ultimate', rsn, true)
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
it('skips fetching formatted RSN when option is provided', async () => {
|
it('skips fetching formatted RSN when option is provided', async () => {
|
||||||
@@ -572,4 +582,16 @@ describe('Get stats options', () => {
|
|||||||
)
|
)
|
||||||
).toBeFalsy();
|
).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 () => {
|
||||||
|
const csvOutput = parseStats(b0atyStatsCsv);
|
||||||
|
const jsonOutput = parseJsonStats(b0atyStatsJson);
|
||||||
|
expect(csvOutput).toEqual(jsonOutput);
|
||||||
});
|
});
|
||||||
|
2571
__tests__/lynxTitanNamePage.html
vendored
2571
__tests__/lynxTitanNamePage.html
vendored
File diff suppressed because it is too large
Load Diff
@@ -1,98 +0,0 @@
|
|||||||
1,2277,4600000000
|
|
||||||
15,99,200000000
|
|
||||||
28,99,200000000
|
|
||||||
18,99,200000000
|
|
||||||
7,99,200000000
|
|
||||||
8,99,200000000
|
|
||||||
11,99,200000000
|
|
||||||
32,99,200000000
|
|
||||||
157,99,200000000
|
|
||||||
15,99,200000000
|
|
||||||
12,99,200000000
|
|
||||||
9,99,200000000
|
|
||||||
48,99,200000000
|
|
||||||
4,99,200000000
|
|
||||||
3,99,200000000
|
|
||||||
25,99,200000000
|
|
||||||
5,99,200000000
|
|
||||||
24,99,200000000
|
|
||||||
12,99,200000000
|
|
||||||
2,99,200000000
|
|
||||||
19,99,200000000
|
|
||||||
7,99,200000000
|
|
||||||
4,99,200000000
|
|
||||||
4,99,200000000
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
764013,22
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
480246,22
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
196,186
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
||||||
-1,-1
|
|
Can't render this file because it has a wrong number of fields in line 25.
|
148
__tests__/lynxTitanStats.json
Normal file
148
__tests__/lynxTitanStats.json
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
{
|
||||||
|
"skills": [
|
||||||
|
{ "id": 0, "name": "Overall", "rank": 1, "level": 2277, "xp": 4600000000 },
|
||||||
|
{ "id": 1, "name": "Attack", "rank": 15, "level": 99, "xp": 200000000 },
|
||||||
|
{ "id": 2, "name": "Defence", "rank": 28, "level": 99, "xp": 200000000 },
|
||||||
|
{ "id": 3, "name": "Strength", "rank": 18, "level": 99, "xp": 200000000 },
|
||||||
|
{ "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": 31, "level": 99, "xp": 200000000 },
|
||||||
|
{ "id": 8, "name": "Cooking", "rank": 155, "level": 99, "xp": 200000000 },
|
||||||
|
{
|
||||||
|
"id": 9,
|
||||||
|
"name": "Woodcutting",
|
||||||
|
"rank": 15,
|
||||||
|
"level": 99,
|
||||||
|
"xp": 200000000
|
||||||
|
},
|
||||||
|
{ "id": 10, "name": "Fletching", "rank": 12, "level": 99, "xp": 200000000 },
|
||||||
|
{ "id": 11, "name": "Fishing", "rank": 9, "level": 99, "xp": 200000000 },
|
||||||
|
{
|
||||||
|
"id": 12,
|
||||||
|
"name": "Firemaking",
|
||||||
|
"rank": 48,
|
||||||
|
"level": 99,
|
||||||
|
"xp": 200000000
|
||||||
|
},
|
||||||
|
{ "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": 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": 6, "level": 99, "xp": 200000000 },
|
||||||
|
{ "id": 22, "name": "Hunter", "rank": 4, "level": 99, "xp": 200000000 },
|
||||||
|
{
|
||||||
|
"id": 23,
|
||||||
|
"name": "Construction",
|
||||||
|
"rank": 4,
|
||||||
|
"level": 99,
|
||||||
|
"xp": 200000000
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"activities": [
|
||||||
|
{ "id": 0, "name": "League Points", "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": 4,
|
||||||
|
"name": "Bounty Hunter (Legacy) - Hunter",
|
||||||
|
"rank": -1,
|
||||||
|
"score": -1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5,
|
||||||
|
"name": "Bounty Hunter (Legacy) - Rogue",
|
||||||
|
"rank": -1,
|
||||||
|
"score": -1
|
||||||
|
},
|
||||||
|
{ "id": 6, "name": "Clue Scrolls (all)", "rank": 805212, "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": 502504, "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": "Abyssal Sire", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 18, "name": "Alchemical Hydra", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 19, "name": "Artio", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 20, "name": "Barrows Chests", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 21, "name": "Bryophyta", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 22, "name": "Callisto", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 23, "name": "Calvar'ion", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 24, "name": "Cerberus", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 25, "name": "Chambers of Xeric", "rank": -1, "score": -1 },
|
||||||
|
{
|
||||||
|
"id": 26,
|
||||||
|
"name": "Chambers of Xeric: Challenge Mode",
|
||||||
|
"rank": -1,
|
||||||
|
"score": -1
|
||||||
|
},
|
||||||
|
{ "id": 27, "name": "Chaos Elemental", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 28, "name": "Chaos Fanatic", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 29, "name": "Commander Zilyana", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 30, "name": "Corporeal Beast", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 31, "name": "Crazy Archaeologist", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 32, "name": "Dagannoth Prime", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 33, "name": "Dagannoth Rex", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 34, "name": "Dagannoth Supreme", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 35, "name": "Deranged Archaeologist", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 36, "name": "Duke Sucellus", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 37, "name": "General Graardor", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 38, "name": "Giant Mole", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 39, "name": "Grotesque Guardians", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 40, "name": "Hespori", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 41, "name": "Kalphite Queen", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 42, "name": "King Black Dragon", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 43, "name": "Kraken", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 44, "name": "Kree'Arra", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 45, "name": "K'ril Tsutsaroth", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 46, "name": "Mimic", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 47, "name": "Nex", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 48, "name": "Nightmare", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 49, "name": "Phosani's Nightmare", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 50, "name": "Obor", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 51, "name": "Phantom Muspah", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 52, "name": "Sarachnis", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 53, "name": "Scorpia", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 54, "name": "Skotizo", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 55, "name": "Spindel", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 56, "name": "Tempoross", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 57, "name": "The Gauntlet", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 58, "name": "The Corrupted Gauntlet", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 59, "name": "The Leviathan", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 60, "name": "The Whisperer", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 61, "name": "Theatre of Blood", "rank": -1, "score": -1 },
|
||||||
|
{
|
||||||
|
"id": 62,
|
||||||
|
"name": "Theatre of Blood: Hard Mode",
|
||||||
|
"rank": -1,
|
||||||
|
"score": -1
|
||||||
|
},
|
||||||
|
{ "id": 63, "name": "Thermonuclear Smoke Devil", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 64, "name": "Tombs of Amascut", "rank": -1, "score": -1 },
|
||||||
|
{
|
||||||
|
"id": 65,
|
||||||
|
"name": "Tombs of Amascut: Expert Mode",
|
||||||
|
"rank": -1,
|
||||||
|
"score": -1
|
||||||
|
},
|
||||||
|
{ "id": 66, "name": "TzKal-Zuk", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 67, "name": "TzTok-Jad", "rank": 225, "score": 186 },
|
||||||
|
{ "id": 68, "name": "Vardorvis", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 69, "name": "Venenatis", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 70, "name": "Vet'ion", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 71, "name": "Vorkath", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 72, "name": "Wintertodt", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 73, "name": "Zalcano", "rank": -1, "score": -1 },
|
||||||
|
{ "id": 74, "name": "Zulrah", "rank": -1, "score": -1 }
|
||||||
|
]
|
||||||
|
}
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "osrs-json-hiscores",
|
"name": "osrs-json-hiscores",
|
||||||
"version": "2.15.0",
|
"version": "2.16.2",
|
||||||
"description": "The Old School Runescape API wrapper that does more!",
|
"description": "The Old School Runescape API wrapper that does more!",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"types": "lib/index.d.ts",
|
"types": "lib/index.d.ts",
|
||||||
@@ -67,7 +67,10 @@
|
|||||||
],
|
],
|
||||||
"ignorePatterns": [
|
"ignorePatterns": [
|
||||||
"**/@types/*"
|
"**/@types/*"
|
||||||
]
|
],
|
||||||
|
"rules": {
|
||||||
|
"max-classes-per-file": "off"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"prettier": {
|
"prettier": {
|
||||||
"trailingComma": "none",
|
"trailingComma": "none",
|
||||||
@@ -92,7 +95,7 @@
|
|||||||
"testEnvironment": "node"
|
"testEnvironment": "node"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^0.21.1",
|
"axios": "^1.6.2",
|
||||||
"jsdom": "^22.1.0",
|
"jsdom": "^22.1.0",
|
||||||
"useragent-generator": "^1.1.0"
|
"useragent-generator": "^1.1.0"
|
||||||
},
|
},
|
||||||
|
273
src/hiscores.ts
273
src/hiscores.ts
@@ -1,4 +1,4 @@
|
|||||||
import { AxiosRequestConfig, AxiosResponse } from 'axios';
|
import axios, { AxiosRequestConfig } from 'axios';
|
||||||
import { BinaryData, JSDOM } from 'jsdom';
|
import { BinaryData, JSDOM } from 'jsdom';
|
||||||
import {
|
import {
|
||||||
Player,
|
Player,
|
||||||
@@ -14,7 +14,8 @@ import {
|
|||||||
ActivityName,
|
ActivityName,
|
||||||
PlayerActivityRow,
|
PlayerActivityRow,
|
||||||
Bosses,
|
Bosses,
|
||||||
GetStatsOptions
|
GetStatsOptions,
|
||||||
|
HiscoresResponse
|
||||||
} from './types';
|
} from './types';
|
||||||
import {
|
import {
|
||||||
getStatsURL,
|
getStatsURL,
|
||||||
@@ -30,10 +31,50 @@ import {
|
|||||||
getActivityPageURL,
|
getActivityPageURL,
|
||||||
httpGet,
|
httpGet,
|
||||||
BOSSES,
|
BOSSES,
|
||||||
INVALID_FORMAT_ERROR,
|
InvalidFormatError,
|
||||||
validateRSN
|
PlayerNotFoundError,
|
||||||
|
HiScoresError,
|
||||||
|
validateRSN,
|
||||||
|
FORMATTED_SKILL_NAMES,
|
||||||
|
FORMATTED_BH_NAMES,
|
||||||
|
FORMATTED_CLUE_NAMES,
|
||||||
|
FORMATTED_BOSS_NAMES,
|
||||||
|
FORMATTED_LEAGUE_POINTS,
|
||||||
|
FORMATTED_LMS,
|
||||||
|
FORMATTED_PVP_ARENA,
|
||||||
|
FORMATTED_SOUL_WARS,
|
||||||
|
FORMATTED_RIFTS_CLOSED,
|
||||||
|
FORMATTED_DEADMAN_POINTS
|
||||||
} from './utils';
|
} from './utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a player's stats from the official OSRS JSON endpoint.
|
||||||
|
*
|
||||||
|
* @param rsn Username of the player.
|
||||||
|
* @param mode Gamemode to fetch ranks for.
|
||||||
|
* @param config Optional axios request config object.
|
||||||
|
* @returns Official JSON stats object.
|
||||||
|
*/
|
||||||
|
export async function getOfficialStats(
|
||||||
|
rsn: string,
|
||||||
|
mode: Gamemode = 'main',
|
||||||
|
config?: AxiosRequestConfig
|
||||||
|
): Promise<HiscoresResponse> {
|
||||||
|
validateRSN(rsn);
|
||||||
|
|
||||||
|
const url = getStatsURL(mode, rsn, true);
|
||||||
|
try {
|
||||||
|
const response = await httpGet<HiscoresResponse>(url, config);
|
||||||
|
return response.data;
|
||||||
|
} catch (err) {
|
||||||
|
if (!axios.isAxiosError(err)) throw err;
|
||||||
|
|
||||||
|
if (err.response?.status === 404) throw new PlayerNotFoundError();
|
||||||
|
|
||||||
|
throw new HiScoresError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Screen scrapes the hiscores to get the formatted rsn of a player.
|
* Screen scrapes the hiscores to get the formatted rsn of a player.
|
||||||
*
|
*
|
||||||
@@ -60,12 +101,84 @@ export async function getRSNFormat(
|
|||||||
if (anchor) {
|
if (anchor) {
|
||||||
return rsnFromElement(anchor);
|
return rsnFromElement(anchor);
|
||||||
}
|
}
|
||||||
throw Error('Player not found');
|
throw new PlayerNotFoundError();
|
||||||
} catch {
|
} catch {
|
||||||
throw Error('Player not found');
|
throw new HiScoresError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses official JSON object of raw stats and returns a stats object.
|
||||||
|
*
|
||||||
|
* @param csv Raw JSON from the official OSRS API.
|
||||||
|
* @returns Parsed stats object.
|
||||||
|
*/
|
||||||
|
export function parseJsonStats(json: HiscoresResponse): Stats {
|
||||||
|
const getActivity = (formattedName: string): Activity => {
|
||||||
|
const hiscoresActivity = json.activities.find(
|
||||||
|
// We must match on name here since id is not guaranteed to be the same between updates
|
||||||
|
({ name }) => name.toLowerCase() === formattedName.toLowerCase()
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
rank: hiscoresActivity?.rank ?? -1,
|
||||||
|
score: hiscoresActivity?.score ?? -1
|
||||||
|
};
|
||||||
|
};
|
||||||
|
const reduceActivity = <Key extends string, Reduced = Record<Key, Activity>>(
|
||||||
|
keys: Key[],
|
||||||
|
formattedNames: Record<Key, string>
|
||||||
|
): Reduced =>
|
||||||
|
keys.reduce<Reduced>(
|
||||||
|
(reducer, key) => ({
|
||||||
|
...reducer,
|
||||||
|
[key]: getActivity(formattedNames[key])
|
||||||
|
}),
|
||||||
|
{} as Reduced
|
||||||
|
);
|
||||||
|
|
||||||
|
const skills = SKILLS.reduce<Skills>((skillsObject, skillName) => {
|
||||||
|
const hiscoresSkill = json.skills.find(
|
||||||
|
// We must match on name here since id is not guaranteed to be the same between updates
|
||||||
|
({ name }) =>
|
||||||
|
name.toLowerCase() === FORMATTED_SKILL_NAMES[skillName].toLowerCase()
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
...skillsObject,
|
||||||
|
[skillName]: {
|
||||||
|
rank: hiscoresSkill?.rank ?? -1,
|
||||||
|
level: hiscoresSkill?.level ?? -1,
|
||||||
|
xp: hiscoresSkill?.xp ?? -1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, {} as Skills);
|
||||||
|
|
||||||
|
const bountyHunter = reduceActivity(BH_MODES, FORMATTED_BH_NAMES);
|
||||||
|
const clues = reduceActivity(CLUES, FORMATTED_CLUE_NAMES);
|
||||||
|
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 stats: Stats = {
|
||||||
|
skills,
|
||||||
|
leaguePoints,
|
||||||
|
deadmanPoints,
|
||||||
|
bountyHunter,
|
||||||
|
lastManStanding,
|
||||||
|
pvpArena,
|
||||||
|
soulWarsZeal,
|
||||||
|
riftsClosed,
|
||||||
|
clues,
|
||||||
|
bosses
|
||||||
|
};
|
||||||
|
|
||||||
|
return stats;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses CSV string of raw stats and returns a stats object.
|
* Parses CSV string of raw stats and returns a stats object.
|
||||||
*
|
*
|
||||||
@@ -78,11 +191,8 @@ export function parseStats(csv: string): Stats {
|
|||||||
.filter((entry) => !!entry)
|
.filter((entry) => !!entry)
|
||||||
.map((stat) => stat.split(','));
|
.map((stat) => stat.split(','));
|
||||||
|
|
||||||
if (
|
if (splitCSV.length !== SKILLS.length + ACTIVITIES.length) {
|
||||||
splitCSV.length !==
|
throw new InvalidFormatError();
|
||||||
SKILLS.length + BH_MODES.length + CLUES.length + BOSSES.length + 5
|
|
||||||
) {
|
|
||||||
throw Error(INVALID_FORMAT_ERROR);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const skillObjects: Skill[] = splitCSV
|
const skillObjects: Skill[] = splitCSV
|
||||||
@@ -108,7 +218,7 @@ export function parseStats(csv: string): Stats {
|
|||||||
return activity;
|
return activity;
|
||||||
});
|
});
|
||||||
|
|
||||||
const [leaguePoints] = activityObjects.splice(0, 1);
|
const [leaguePoints, deadmanPoints] = activityObjects.splice(0, 2);
|
||||||
const bhObjects = activityObjects.splice(0, BH_MODES.length);
|
const bhObjects = activityObjects.splice(0, BH_MODES.length);
|
||||||
const clueObjects = activityObjects.splice(0, CLUES.length);
|
const clueObjects = activityObjects.splice(0, CLUES.length);
|
||||||
const [lastManStanding, pvpArena, soulWarsZeal, riftsClosed] =
|
const [lastManStanding, pvpArena, soulWarsZeal, riftsClosed] =
|
||||||
@@ -142,6 +252,7 @@ export function parseStats(csv: string): Stats {
|
|||||||
const stats: Stats = {
|
const stats: Stats = {
|
||||||
skills,
|
skills,
|
||||||
leaguePoints,
|
leaguePoints,
|
||||||
|
deadmanPoints,
|
||||||
bountyHunter,
|
bountyHunter,
|
||||||
lastManStanding,
|
lastManStanding,
|
||||||
pvpArena,
|
pvpArena,
|
||||||
@@ -175,91 +286,70 @@ export async function getStats(
|
|||||||
];
|
];
|
||||||
const shouldGetFormattedRsn = options?.shouldGetFormattedRsn ?? true;
|
const shouldGetFormattedRsn = options?.shouldGetFormattedRsn ?? true;
|
||||||
|
|
||||||
const mainRes = await httpGet<string>(
|
const main = await getOfficialStats(rsn, 'main', options?.axiosConfigs?.main);
|
||||||
getStatsURL('main', rsn),
|
|
||||||
options?.axiosConfigs?.main
|
const getModeStats = async (
|
||||||
);
|
mode: Extract<Gamemode, 'ironman' | 'hardcore' | 'ultimate'>
|
||||||
if (mainRes.status === 200) {
|
): Promise<HiscoresResponse | undefined> =>
|
||||||
const emptyResponse: AxiosResponse<string> = {
|
otherGamemodes.includes(mode)
|
||||||
status: 404,
|
? getOfficialStats(rsn, mode, options?.axiosConfigs?.[mode]).catch(
|
||||||
data: '',
|
|
||||||
statusText: '',
|
|
||||||
headers: {},
|
|
||||||
config: {}
|
|
||||||
};
|
|
||||||
const getModeStats = async (
|
|
||||||
mode: Extract<Gamemode, 'ironman' | 'hardcore' | 'ultimate'>
|
|
||||||
): Promise<AxiosResponse<string>> =>
|
|
||||||
otherGamemodes.includes(mode)
|
|
||||||
? httpGet<string>(
|
|
||||||
getStatsURL(mode, rsn),
|
|
||||||
options?.axiosConfigs?.[mode]
|
|
||||||
).catch((err) => err)
|
|
||||||
: emptyResponse;
|
|
||||||
const formattedName = shouldGetFormattedRsn
|
|
||||||
? await getRSNFormat(rsn, options?.axiosConfigs?.rsn).catch(
|
|
||||||
() => undefined
|
() => undefined
|
||||||
)
|
)
|
||||||
: undefined;
|
: undefined;
|
||||||
|
const formattedName = shouldGetFormattedRsn
|
||||||
|
? await getRSNFormat(rsn, options?.axiosConfigs?.rsn).catch(() => undefined)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
const player: Player = {
|
const player: Player = {
|
||||||
name: formattedName ?? rsn,
|
name: formattedName ?? rsn,
|
||||||
mode: 'main',
|
mode: 'main',
|
||||||
dead: false,
|
dead: false,
|
||||||
deulted: false,
|
deulted: false,
|
||||||
deironed: false
|
deironed: false
|
||||||
};
|
};
|
||||||
player.main = parseStats(mainRes.data);
|
player.main = parseJsonStats(main);
|
||||||
|
|
||||||
const ironRes = await getModeStats('ironman');
|
const iron = await getModeStats('ironman');
|
||||||
if (ironRes.status === 200) {
|
if (iron) {
|
||||||
player.ironman = parseStats(ironRes.data);
|
player.ironman = parseJsonStats(iron);
|
||||||
const hcRes = await getModeStats('hardcore');
|
const hc = await getModeStats('hardcore');
|
||||||
const ultRes = await getModeStats('ultimate');
|
const ult = await getModeStats('ultimate');
|
||||||
if (hcRes.status === 200) {
|
if (hc) {
|
||||||
player.mode = 'hardcore';
|
player.mode = 'hardcore';
|
||||||
player.hardcore = parseStats(hcRes.data);
|
player.hardcore = parseJsonStats(hc);
|
||||||
if (
|
if (
|
||||||
player.ironman.skills.overall.xp !== player.hardcore.skills.overall.xp
|
player.ironman.skills.overall.xp !== player.hardcore.skills.overall.xp
|
||||||
) {
|
) {
|
||||||
player.dead = true;
|
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 = parseStats(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 {
|
|
||||||
player.mode = 'ironman';
|
player.mode = 'ironman';
|
||||||
if (
|
}
|
||||||
player.main.skills.overall.xp !== player.ironman.skills.overall.xp
|
if (player.main.skills.overall.xp !== player.ironman.skills.overall.xp) {
|
||||||
) {
|
player.deironed = true;
|
||||||
player.deironed = true;
|
player.mode = 'main';
|
||||||
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');
|
|
||||||
|
return player;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -279,11 +369,8 @@ export async function getStatsByGamemode(
|
|||||||
if (!GAMEMODES.includes(mode)) {
|
if (!GAMEMODES.includes(mode)) {
|
||||||
throw Error('Invalid game mode');
|
throw Error('Invalid game mode');
|
||||||
}
|
}
|
||||||
const response = await httpGet<string>(getStatsURL(mode, rsn), config);
|
const response = await getOfficialStats(rsn, mode, config);
|
||||||
if (response.status !== 200) {
|
const stats = parseJsonStats(response);
|
||||||
throw Error('Player not found');
|
|
||||||
}
|
|
||||||
const stats = parseStats(response.data);
|
|
||||||
|
|
||||||
return stats;
|
return stats;
|
||||||
}
|
}
|
||||||
|
46
src/types.ts
46
src/types.ts
@@ -130,6 +130,7 @@ export type Bosses = { [Type in Boss]: Activity };
|
|||||||
|
|
||||||
export type ActivityName =
|
export type ActivityName =
|
||||||
| 'leaguePoints'
|
| 'leaguePoints'
|
||||||
|
| 'deadmanPoints'
|
||||||
| 'hunterBHV2'
|
| 'hunterBHV2'
|
||||||
| 'rogueBHV2'
|
| 'rogueBHV2'
|
||||||
| 'hunterBH'
|
| 'hunterBH'
|
||||||
@@ -150,7 +151,14 @@ export type ActivityName =
|
|||||||
export interface Stats {
|
export interface Stats {
|
||||||
skills: Skills;
|
skills: Skills;
|
||||||
clues: Clues;
|
clues: Clues;
|
||||||
|
/**
|
||||||
|
* Will only contain rank and score data for the `seasonal` gamemode.
|
||||||
|
*/
|
||||||
leaguePoints: Activity;
|
leaguePoints: Activity;
|
||||||
|
/**
|
||||||
|
* Will only contain rank and score data for the `tournament` gamemode.
|
||||||
|
*/
|
||||||
|
deadmanPoints: Activity;
|
||||||
bountyHunter: BH;
|
bountyHunter: BH;
|
||||||
lastManStanding: Activity;
|
lastManStanding: Activity;
|
||||||
pvpArena: Activity;
|
pvpArena: Activity;
|
||||||
@@ -199,3 +207,41 @@ export interface GetStatsOptions {
|
|||||||
rsn?: AxiosRequestConfig;
|
rsn?: AxiosRequestConfig;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface HiscoresCommon {
|
||||||
|
/**
|
||||||
|
* This field behaves more like an index than a true unique ID.
|
||||||
|
*/
|
||||||
|
id: number;
|
||||||
|
/**
|
||||||
|
* The display name of this skill / activity.
|
||||||
|
*/
|
||||||
|
name: string;
|
||||||
|
/**
|
||||||
|
* The player's official hiscores rank in this skill / activity.
|
||||||
|
*/
|
||||||
|
rank: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HiscoresSkill extends HiscoresCommon {
|
||||||
|
/**
|
||||||
|
* The player's current level in this skill.
|
||||||
|
*/
|
||||||
|
level: number;
|
||||||
|
/**
|
||||||
|
* The player's current experience in this skill.
|
||||||
|
*/
|
||||||
|
xp: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HiscoresActivity extends HiscoresCommon {
|
||||||
|
/**
|
||||||
|
* The player's current score in this activity.
|
||||||
|
*/
|
||||||
|
score: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HiscoresResponse {
|
||||||
|
skills: HiscoresSkill[];
|
||||||
|
activities: HiscoresActivity[];
|
||||||
|
}
|
||||||
|
@@ -9,6 +9,7 @@ import {
|
|||||||
|
|
||||||
export const BASE_URL = 'https://secure.runescape.com/m=hiscore_oldschool';
|
export const BASE_URL = 'https://secure.runescape.com/m=hiscore_oldschool';
|
||||||
export const STATS_URL = 'index_lite.ws?player=';
|
export const STATS_URL = 'index_lite.ws?player=';
|
||||||
|
export const JSON_STATS_URL = 'index_lite.json?player=';
|
||||||
export const SCORES_URL = 'overall.ws?';
|
export const SCORES_URL = 'overall.ws?';
|
||||||
|
|
||||||
export type GamemodeUrl = {
|
export type GamemodeUrl = {
|
||||||
@@ -134,6 +135,7 @@ export const BOSSES: Boss[] = [
|
|||||||
];
|
];
|
||||||
export const ACTIVITIES: ActivityName[] = [
|
export const ACTIVITIES: ActivityName[] = [
|
||||||
'leaguePoints',
|
'leaguePoints',
|
||||||
|
'deadmanPoints',
|
||||||
'hunterBHV2',
|
'hunterBHV2',
|
||||||
'rogueBHV2',
|
'rogueBHV2',
|
||||||
'hunterBH',
|
'hunterBH',
|
||||||
@@ -188,7 +190,7 @@ export const FORMATTED_BOSS_NAMES: FormattedBossNames = {
|
|||||||
krilTsutsaroth: "K'ril Tsutsaroth",
|
krilTsutsaroth: "K'ril Tsutsaroth",
|
||||||
mimic: 'Mimic',
|
mimic: 'Mimic',
|
||||||
nex: 'Nex',
|
nex: 'Nex',
|
||||||
nightmare: 'The Nightmare of Ashihama',
|
nightmare: 'Nightmare',
|
||||||
phosanisNightmare: "Phosani's Nightmare",
|
phosanisNightmare: "Phosani's Nightmare",
|
||||||
obor: 'Obor',
|
obor: 'Obor',
|
||||||
phantomMuspah: 'Phantom Muspah',
|
phantomMuspah: 'Phantom Muspah',
|
||||||
@@ -273,10 +275,49 @@ export const FORMATTED_BH_NAMES: FormattedBHNames = {
|
|||||||
hunterV2: 'Bounty Hunter - Hunter'
|
hunterV2: 'Bounty Hunter - Hunter'
|
||||||
};
|
};
|
||||||
|
|
||||||
export const FORMATTED_LMS = 'Last Man Standing';
|
export const FORMATTED_LMS = 'LMS - Rank';
|
||||||
export const FORMATTED_PVP_ARENA = 'PvP Arena';
|
export const FORMATTED_PVP_ARENA = 'PvP Arena - Rank';
|
||||||
export const FORMATTED_SOUL_WARS = 'Soul Wars Zeal';
|
export const FORMATTED_SOUL_WARS = 'Soul Wars Zeal';
|
||||||
export const FORMATTED_LEAGUE_POINTS = 'League Points';
|
export const FORMATTED_LEAGUE_POINTS = 'League Points';
|
||||||
export const FORMATTED_RIFTS_CLOSED = 'Rifts Closed';
|
export const FORMATTED_DEADMAN_POINTS = 'Deadman Points';
|
||||||
|
export const FORMATTED_RIFTS_CLOSED = 'Rifts closed';
|
||||||
|
|
||||||
export const INVALID_FORMAT_ERROR = 'Invalid hiscores format';
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -6,7 +6,9 @@ import {
|
|||||||
STATS_URL,
|
STATS_URL,
|
||||||
SCORES_URL,
|
SCORES_URL,
|
||||||
SKILLS,
|
SKILLS,
|
||||||
ACTIVITIES
|
ACTIVITIES,
|
||||||
|
JSON_STATS_URL,
|
||||||
|
InvalidRSNError
|
||||||
} from './constants';
|
} from './constants';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -14,10 +16,13 @@ import {
|
|||||||
*
|
*
|
||||||
* @param gamemode Gamemode to fetch ranks for.
|
* @param gamemode Gamemode to fetch ranks for.
|
||||||
* @param rsn Username of the player.
|
* @param rsn Username of the player.
|
||||||
|
* @param json If the JSON endpoint is desired instead of CSV.
|
||||||
* @returns Encoded stats URL.
|
* @returns Encoded stats URL.
|
||||||
*/
|
*/
|
||||||
export const getStatsURL = (gamemode: Gamemode, rsn: string) =>
|
export const getStatsURL = (gamemode: Gamemode, rsn: string, json = false) =>
|
||||||
`${GAMEMODE_URL[gamemode]}${STATS_URL}${encodeURIComponent(rsn)}`;
|
`${GAMEMODE_URL[gamemode]}${
|
||||||
|
json ? JSON_STATS_URL : STATS_URL
|
||||||
|
}${encodeURIComponent(rsn)}`;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will generate a player table URL for the official OSRS hiscores website.
|
* Will generate a player table URL for the official OSRS hiscores website.
|
||||||
@@ -115,10 +120,10 @@ export const httpGet = <Response>(
|
|||||||
*/
|
*/
|
||||||
export const validateRSN = (rsn: string) => {
|
export const validateRSN = (rsn: string) => {
|
||||||
if (typeof 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)) {
|
} 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) {
|
} 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');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
117
yarn.lock
117
yarn.lock
@@ -29,6 +29,14 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@babel/highlight" "^7.22.5"
|
"@babel/highlight" "^7.22.5"
|
||||||
|
|
||||||
|
"@babel/code-frame@^7.22.13":
|
||||||
|
version "7.22.13"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e"
|
||||||
|
integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==
|
||||||
|
dependencies:
|
||||||
|
"@babel/highlight" "^7.22.13"
|
||||||
|
chalk "^2.4.2"
|
||||||
|
|
||||||
"@babel/compat-data@^7.22.9":
|
"@babel/compat-data@^7.22.9":
|
||||||
version "7.22.9"
|
version "7.22.9"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.9.tgz#71cdb00a1ce3a329ce4cbec3a44f9fef35669730"
|
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.9.tgz#71cdb00a1ce3a329ce4cbec3a44f9fef35669730"
|
||||||
@@ -55,7 +63,7 @@
|
|||||||
json5 "^2.2.2"
|
json5 "^2.2.2"
|
||||||
semver "^6.3.1"
|
semver "^6.3.1"
|
||||||
|
|
||||||
"@babel/generator@^7.22.7", "@babel/generator@^7.22.9", "@babel/generator@^7.7.2":
|
"@babel/generator@^7.22.9", "@babel/generator@^7.7.2":
|
||||||
version "7.22.9"
|
version "7.22.9"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.22.9.tgz#572ecfa7a31002fa1de2a9d91621fd895da8493d"
|
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.22.9.tgz#572ecfa7a31002fa1de2a9d91621fd895da8493d"
|
||||||
integrity sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw==
|
integrity sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw==
|
||||||
@@ -65,6 +73,16 @@
|
|||||||
"@jridgewell/trace-mapping" "^0.3.17"
|
"@jridgewell/trace-mapping" "^0.3.17"
|
||||||
jsesc "^2.5.1"
|
jsesc "^2.5.1"
|
||||||
|
|
||||||
|
"@babel/generator@^7.23.0":
|
||||||
|
version "7.23.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.0.tgz#df5c386e2218be505b34837acbcb874d7a983420"
|
||||||
|
integrity sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==
|
||||||
|
dependencies:
|
||||||
|
"@babel/types" "^7.23.0"
|
||||||
|
"@jridgewell/gen-mapping" "^0.3.2"
|
||||||
|
"@jridgewell/trace-mapping" "^0.3.17"
|
||||||
|
jsesc "^2.5.1"
|
||||||
|
|
||||||
"@babel/helper-compilation-targets@^7.22.9":
|
"@babel/helper-compilation-targets@^7.22.9":
|
||||||
version "7.22.9"
|
version "7.22.9"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.9.tgz#f9d0a7aaaa7cd32a3f31c9316a69f5a9bcacb892"
|
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.9.tgz#f9d0a7aaaa7cd32a3f31c9316a69f5a9bcacb892"
|
||||||
@@ -76,18 +94,23 @@
|
|||||||
lru-cache "^5.1.1"
|
lru-cache "^5.1.1"
|
||||||
semver "^6.3.1"
|
semver "^6.3.1"
|
||||||
|
|
||||||
|
"@babel/helper-environment-visitor@^7.22.20":
|
||||||
|
version "7.22.20"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167"
|
||||||
|
integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==
|
||||||
|
|
||||||
"@babel/helper-environment-visitor@^7.22.5":
|
"@babel/helper-environment-visitor@^7.22.5":
|
||||||
version "7.22.5"
|
version "7.22.5"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz#f06dd41b7c1f44e1f8da6c4055b41ab3a09a7e98"
|
resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz#f06dd41b7c1f44e1f8da6c4055b41ab3a09a7e98"
|
||||||
integrity sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==
|
integrity sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==
|
||||||
|
|
||||||
"@babel/helper-function-name@^7.22.5":
|
"@babel/helper-function-name@^7.23.0":
|
||||||
version "7.22.5"
|
version "7.23.0"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz#ede300828905bb15e582c037162f99d5183af1be"
|
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759"
|
||||||
integrity sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==
|
integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/template" "^7.22.5"
|
"@babel/template" "^7.22.15"
|
||||||
"@babel/types" "^7.22.5"
|
"@babel/types" "^7.23.0"
|
||||||
|
|
||||||
"@babel/helper-hoist-variables@^7.22.5":
|
"@babel/helper-hoist-variables@^7.22.5":
|
||||||
version "7.22.5"
|
version "7.22.5"
|
||||||
@@ -148,6 +171,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed"
|
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed"
|
||||||
integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==
|
integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==
|
||||||
|
|
||||||
|
"@babel/helper-validator-identifier@^7.22.20":
|
||||||
|
version "7.22.20"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0"
|
||||||
|
integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==
|
||||||
|
|
||||||
"@babel/helper-validator-identifier@^7.22.5":
|
"@babel/helper-validator-identifier@^7.22.5":
|
||||||
version "7.22.5"
|
version "7.22.5"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz#9544ef6a33999343c8740fa51350f30eeaaaf193"
|
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz#9544ef6a33999343c8740fa51350f30eeaaaf193"
|
||||||
@@ -176,6 +204,15 @@
|
|||||||
chalk "^2.0.0"
|
chalk "^2.0.0"
|
||||||
js-tokens "^4.0.0"
|
js-tokens "^4.0.0"
|
||||||
|
|
||||||
|
"@babel/highlight@^7.22.13":
|
||||||
|
version "7.22.20"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.20.tgz#4ca92b71d80554b01427815e06f2df965b9c1f54"
|
||||||
|
integrity sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==
|
||||||
|
dependencies:
|
||||||
|
"@babel/helper-validator-identifier" "^7.22.20"
|
||||||
|
chalk "^2.4.2"
|
||||||
|
js-tokens "^4.0.0"
|
||||||
|
|
||||||
"@babel/highlight@^7.22.5":
|
"@babel/highlight@^7.22.5":
|
||||||
version "7.22.5"
|
version "7.22.5"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.5.tgz#aa6c05c5407a67ebce408162b7ede789b4d22031"
|
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.5.tgz#aa6c05c5407a67ebce408162b7ede789b4d22031"
|
||||||
@@ -195,6 +232,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.7.tgz#df8cf085ce92ddbdbf668a7f186ce848c9036cae"
|
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.7.tgz#df8cf085ce92ddbdbf668a7f186ce848c9036cae"
|
||||||
integrity sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==
|
integrity sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==
|
||||||
|
|
||||||
|
"@babel/parser@^7.22.15", "@babel/parser@^7.23.0":
|
||||||
|
version "7.23.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719"
|
||||||
|
integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==
|
||||||
|
|
||||||
"@babel/plugin-syntax-async-generators@^7.8.4":
|
"@babel/plugin-syntax-async-generators@^7.8.4":
|
||||||
version "7.8.4"
|
version "7.8.4"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d"
|
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d"
|
||||||
@@ -293,6 +335,15 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-plugin-utils" "^7.22.5"
|
"@babel/helper-plugin-utils" "^7.22.5"
|
||||||
|
|
||||||
|
"@babel/template@^7.22.15":
|
||||||
|
version "7.22.15"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38"
|
||||||
|
integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==
|
||||||
|
dependencies:
|
||||||
|
"@babel/code-frame" "^7.22.13"
|
||||||
|
"@babel/parser" "^7.22.15"
|
||||||
|
"@babel/types" "^7.22.15"
|
||||||
|
|
||||||
"@babel/template@^7.22.5":
|
"@babel/template@^7.22.5":
|
||||||
version "7.22.5"
|
version "7.22.5"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.5.tgz#0c8c4d944509875849bd0344ff0050756eefc6ec"
|
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.5.tgz#0c8c4d944509875849bd0344ff0050756eefc6ec"
|
||||||
@@ -312,18 +363,18 @@
|
|||||||
"@babel/types" "^7.12.7"
|
"@babel/types" "^7.12.7"
|
||||||
|
|
||||||
"@babel/traverse@^7.22.6", "@babel/traverse@^7.22.8":
|
"@babel/traverse@^7.22.6", "@babel/traverse@^7.22.8":
|
||||||
version "7.22.8"
|
version "7.23.2"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.8.tgz#4d4451d31bc34efeae01eac222b514a77aa4000e"
|
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8"
|
||||||
integrity sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw==
|
integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/code-frame" "^7.22.5"
|
"@babel/code-frame" "^7.22.13"
|
||||||
"@babel/generator" "^7.22.7"
|
"@babel/generator" "^7.23.0"
|
||||||
"@babel/helper-environment-visitor" "^7.22.5"
|
"@babel/helper-environment-visitor" "^7.22.20"
|
||||||
"@babel/helper-function-name" "^7.22.5"
|
"@babel/helper-function-name" "^7.23.0"
|
||||||
"@babel/helper-hoist-variables" "^7.22.5"
|
"@babel/helper-hoist-variables" "^7.22.5"
|
||||||
"@babel/helper-split-export-declaration" "^7.22.6"
|
"@babel/helper-split-export-declaration" "^7.22.6"
|
||||||
"@babel/parser" "^7.22.7"
|
"@babel/parser" "^7.23.0"
|
||||||
"@babel/types" "^7.22.5"
|
"@babel/types" "^7.23.0"
|
||||||
debug "^4.1.0"
|
debug "^4.1.0"
|
||||||
globals "^11.1.0"
|
globals "^11.1.0"
|
||||||
|
|
||||||
@@ -345,6 +396,15 @@
|
|||||||
"@babel/helper-validator-identifier" "^7.22.5"
|
"@babel/helper-validator-identifier" "^7.22.5"
|
||||||
to-fast-properties "^2.0.0"
|
to-fast-properties "^2.0.0"
|
||||||
|
|
||||||
|
"@babel/types@^7.22.15", "@babel/types@^7.23.0":
|
||||||
|
version "7.23.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.0.tgz#8c1f020c9df0e737e4e247c0619f58c68458aaeb"
|
||||||
|
integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==
|
||||||
|
dependencies:
|
||||||
|
"@babel/helper-string-parser" "^7.22.5"
|
||||||
|
"@babel/helper-validator-identifier" "^7.22.20"
|
||||||
|
to-fast-properties "^2.0.0"
|
||||||
|
|
||||||
"@bcoe/v8-coverage@^0.2.3":
|
"@bcoe/v8-coverage@^0.2.3":
|
||||||
version "0.2.3"
|
version "0.2.3"
|
||||||
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
|
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
|
||||||
@@ -1227,12 +1287,14 @@ available-typed-arrays@^1.0.5:
|
|||||||
resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7"
|
resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7"
|
||||||
integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==
|
integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==
|
||||||
|
|
||||||
axios@^0.21.1:
|
axios@^1.6.2:
|
||||||
version "0.21.2"
|
version "1.6.2"
|
||||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.2.tgz#21297d5084b2aeeb422f5d38e7be4fbb82239017"
|
resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.2.tgz#de67d42c755b571d3e698df1b6504cde9b0ee9f2"
|
||||||
integrity sha512-87otirqUw3e8CzHTMO+/9kh/FSgXt/eVDvipijwDtEuwbkySWZ9SBm6VEubmJ/kLKEoLQV/POhxXFb66bfekfg==
|
integrity sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==
|
||||||
dependencies:
|
dependencies:
|
||||||
follow-redirects "^1.14.0"
|
follow-redirects "^1.15.0"
|
||||||
|
form-data "^4.0.0"
|
||||||
|
proxy-from-env "^1.1.0"
|
||||||
|
|
||||||
babel-jest@^29.6.1:
|
babel-jest@^29.6.1:
|
||||||
version "29.6.1"
|
version "29.6.1"
|
||||||
@@ -2366,10 +2428,10 @@ flatted@^3.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.1.1.tgz#c4b489e80096d9df1dfc97c79871aea7c617c469"
|
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.1.1.tgz#c4b489e80096d9df1dfc97c79871aea7c617c469"
|
||||||
integrity sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==
|
integrity sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==
|
||||||
|
|
||||||
follow-redirects@^1.14.0:
|
follow-redirects@^1.15.0:
|
||||||
version "1.14.8"
|
version "1.15.3"
|
||||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.8.tgz#016996fb9a11a100566398b1c6839337d7bfa8fc"
|
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.3.tgz#fe2f3ef2690afce7e82ed0b44db08165b207123a"
|
||||||
integrity sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==
|
integrity sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==
|
||||||
|
|
||||||
for-each@^0.3.3:
|
for-each@^0.3.3:
|
||||||
version "0.3.3"
|
version "0.3.3"
|
||||||
@@ -4671,6 +4733,11 @@ prompts@^2.0.1:
|
|||||||
kleur "^3.0.3"
|
kleur "^3.0.3"
|
||||||
sisteransi "^1.0.5"
|
sisteransi "^1.0.5"
|
||||||
|
|
||||||
|
proxy-from-env@^1.1.0:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
|
||||||
|
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
|
||||||
|
|
||||||
psl@^1.1.33:
|
psl@^1.1.33:
|
||||||
version "1.8.0"
|
version "1.8.0"
|
||||||
resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24"
|
resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24"
|
||||||
|
Reference in New Issue
Block a user