diff --git a/README.md b/README.md
index 680e5716..c1ddcdc6 100644
--- a/README.md
+++ b/README.md
@@ -1,231 +1,401 @@
-# Twisted
-League of Legends API Wrapper
-
+
-# Simple example
-RIOT:
-```js
+# 🎮 Twisted
+
+### A fully‑typed Riot Games API wrapper for Node.js
+
+League of Legends · Teamfight Tactics · Riot Account · Data Dragon
+
+[](https://www.npmjs.com/package/twisted)
+[](https://www.npmjs.com/package/twisted)
+[](https://nodejs.org)
+[](https://www.typescriptlang.org)
+[](./LICENSE)
+
+
+
+---
+
+## ✨ Highlights
+
+- 🧩 **Complete coverage** — League of Legends, Teamfight Tactics, Riot Account and Data Dragon in one package.
+- 🪶 **Lightweight** — built on the **native `fetch`** API. No `axios`, no `lodash`, no `dotenv`.
+- 🔤 **First‑class TypeScript** — every endpoint, parameter and response is typed. Great autocompletion out of the box.
+- 🔁 **Automatic rate‑limit retries** — `429`/`503` responses are retried honoring Riot's `Retry-After` header.
+- 🚦 **Concurrency control** — cap how many requests hit Riot in parallel.
+- 🧪 **Battle‑tested** — used in production by real projects.
+
+> [!IMPORTANT]
+> **v1.80** drops the `axios`, `lodash` and `dotenv` dependencies in favor of the platform.
+> The minimum supported Node.js version is now **18** (the first LTS shipping a global `fetch`).
+> See [Migrating to v1.80](#-migrating-to-v180).
+
+---
+
+## 📚 Table of contents
+
+- [Installation](#-installation)
+- [Quick start](#-quick-start)
+- [Core concepts](#-core-concepts)
+- [Configuration](#%EF%B8%8F-configuration)
+- [Rate limiting & retries](#-rate-limiting--retries)
+- [Error handling](#-error-handling)
+- [Data Dragon](#-data-dragon)
+- [Examples](#-examples)
+- [Endpoint coverage](#-endpoint-coverage)
+- [Migrating to v1.80](#-migrating-to-v180)
+- [Contributing](#-contributing)
+
+---
+
+## 📦 Installation
+
+```bash
+npm install twisted
+# or
+yarn add twisted
+# or
+pnpm add twisted
+```
+
+**Requirements:** Node.js **≥ 18**. Get your API key at the [Riot Developer Portal](https://developer.riotgames.com/).
+
+---
+
+## 🚀 Quick start
+
+The three entry points are `RiotApi` (account), `LolApi` (League of Legends) and `TftApi` (Teamfight Tactics).
+Every call returns `{ response, rateLimits }` — your data lives in `response`.
+
+
+Riot Account — resolve a Riot ID into a PUUID
+
+```ts
import { RiotApi, Constants } from 'twisted'
-const api = new RiotApi()
+const api = new RiotApi({ key: 'RGAPI-xxxxxxxx' })
-export async function getAccount () {
- // Recommended to use the nearest routing value to your server: americas, asia, europe
- return (await api.Account.getByRiotId("Hide on bush", "KR1", Constants.RegionGroups.AMERICAS)).response
+async function getAccount () {
+ // Use the routing value closest to your server: AMERICAS, ASIA or EUROPE
+ const { response } = await api.Account.getByRiotId(
+ 'Hide on bush', // gameName
+ 'KR1', // tagLine (the part after the #)
+ Constants.RegionGroups.ASIA
+ )
+ return response // -> { puuid, gameName, tagLine }
}
```
-LOL:
-```js
+
+
+
+
+League of Legends — summoner, ranked & matches
+
+```ts
import { LolApi, Constants } from 'twisted'
-const api = new LolApi()
+const api = new LolApi({ key: 'RGAPI-xxxxxxxx' })
+
+async function getRanked (puuid: string) {
+ const summoner = (await api.Summoner.getByPUUID(puuid, Constants.Regions.KOREA)).response
+ const ranked = (await api.League.byPUUID(puuid, Constants.Regions.KOREA)).response
+
+ const matchIds = (await api.MatchV5.list(puuid, Constants.RegionGroups.ASIA, { count: 5 })).response
+ const lastGame = (await api.MatchV5.get(matchIds[0], Constants.RegionGroups.ASIA)).response
-export async function getSummoner () {
- const user = await getAccount()
- return await api.Summoner.getByPUUID(user.puuid, Constants.Regions.KOREA)
+ return { summoner, ranked, lastGame }
}
```
-TFT:
-```js
+
+
+
+
+Teamfight Tactics — TFT summoner & matches
+
+```ts
import { TftApi, Constants } from 'twisted'
-const api = new TftApi()
+const api = new TftApi({ key: 'RGAPI-xxxxxxxx' })
-export async function matchListTft () {
- const user = await getAccount()
- return api.Match.list(user.puuid, Constants.RegionGroups.KOREA)
+async function tftHistory (puuid: string) {
+ const summoner = (await api.Summoner.getByPUUID(puuid, Constants.Regions.AMERICA_NORTH)).response
+ const matchIds = (await api.Match.list(puuid, Constants.RegionGroups.AMERICAS, { count: 5 })).response
+ return { summoner, matchIds }
}
+```
+
+
+
+---
+
+## 🧠 Core concepts
+
+### Response shape
+
+Every API method (except Data Dragon) resolves to an `ApiResponseDTO`:
+
+```ts
+{
+ response: T // the parsed payload
+ rateLimits: { // parsed from Riot's response headers
+ AppRateLimit, AppRateLimitCount,
+ MethodRateLimit, MethodRatelimitCount,
+ RetryAfter, Type, EdgeTraceId
+ }
+}
+```
+
+### Regions vs. region groups
+
+Riot exposes three different routing concepts. Twisted enforces the right one at the **type level**, so the compiler tells you when you pass the wrong kind.
+
+| Concept | Type | Values | Used by |
+| --- | --- | --- | --- |
+| **Platform region** | `Regions` | `NA1`, `EUW1`, `KR`, `BR1`, … | Summoner, League, Champion Mastery, Spectator, Status |
+| **Region group** | `RegionGroups` | `AMERICAS`, `ASIA`, `EUROPE`, `SEA` | Match‑V5, TFT Match |
+| **Account routing** | `AccountAPIRegionGroups` | `AMERICAS`, `ASIA`, `EUROPE` | Account‑V1 |
+
+```ts
+import { Constants } from 'twisted'
+
+Constants.Regions.EU_WEST // 'EUW1' — platform region
+Constants.RegionGroups.EUROPE // 'EUROPE' — routing value
+```
+
+### Providing your API key
+The key is read from `process.env.RIOT_API_KEY`, or you can pass it explicitly:
+
+```ts
+new LolApi('RGAPI-xxxxxxxx') // shorthand
+new LolApi({ key: 'RGAPI-xxxxxxxx' }) // with options
```
-[More examples](https://github.com/justadev-afk/twisted/tree/master/example)
-# Automatic rate limits reattempts
-```js
+> Since `dotenv` is no longer bundled, load a `.env` file with Node's built‑in flag
+> (Node ≥ 20.6): `node --env-file=.env app.js`, or set the variable in your shell.
+
+---
+
+## ⚙️ Configuration
+
+```ts
import { LolApi } from 'twisted'
const api = new LolApi({
- /**
- * If api response is 429 (rate limits) try reattempt after needed time (default true)
- */
- rateLimitRetry: true
- /**
- * Number of time to retry after rate limit response (default 1)
- */
- rateLimitRetryAttempts: 1
- /**
- * Concurrency calls to riot (default infinity)
- * Concurrency per method (example: summoner api, match api, etc)
- */
+ key: 'RGAPI-xxxxxxxx',
+ rateLimitRetry: true,
+ rateLimitRetryAttempts: 1,
concurrency: undefined,
- /**
- * Riot games api key
- */
- key: '',
- /**
- * BaseURL for a rate limiting proxy (default: "https://$(region).api.riotgames.com/:game")
- * Using this field is for a very advanced use case and in most cases not necessary
- * ${region} and :game are expected but not required variables
- */
- baseURL: "http://localhost:8080/${region}/:game",
- /**
- * Debug methods
- */
debug: {
- /**
- * Log methods execution time (default false)
- */
- logTime: false
- /**
- * Log urls (default false)
- */
- logUrls: false
- /**
- * Log when is waiting for rate limits (default false)
- */
- logRatelimit?: false
+ logTime: false,
+ logUrls: false,
+ logRatelimits: false
}
})
```
-# Endpoints
-Everything should be in the same order as in the official docs.
-
-# Riot Endpoints
-## ACCOUNT-V1
-- [x] `Get account by puuid`
-- [ ] `Get account by puuid - ESPORTS`
-- [x] `Get account by riot id`
-- [ ] `Get account by riot id - ESPORTS`
-- [ ] `Get active shard for a player`
-- [x] `Get active region (lol and tft)`
-- [ ] `Get account by access token`
-- [ ] `Get account by access token - ESPORTS`
-
-# LOL Endpoints
-## CHAMPION-MASTERY-V4
-- [x] `Get all champion mastery entries sorted by number of champion points descending.`
-- [x] `Get a champion mastery by player ID and champion ID.`
-- [x] `Get a player's total champion mastery score, which is the sum of individual champion mastery levels.`
-## CHAMPION-V3
-- [x] `Retrieve all champions.`
-- [x] `Retrieve champion by ID.`
-## CLASH
-- [x] `Get players by summoner id`
-- [x] `Get team`
-- [x] `Get tournaments`
-- [x] `Get tournaments by team id`
-- [x] `Get tournament by id`
-## MATCH-V5
-- [x] `Get match by id`
-- [x] `Get matches by summoner id`
-- [x] `Get match timeline by id`
-- [x] `Get available match replays by PUUID.`
-## MATCH-V4 (deprecated)
-- [x] `Get matches id by tournament code`
-- [x] `Get match by id`
-- [x] `Get match by tournament code`
-- [x] `Get matches by summoner id`
-- [x] `Get match timeline by id`
-## LEAGUE-V4
-- [x] `Get the challenger league for given queue.`
-- [x] `Get league entries in all queues by PUUID.`
-- [x] `Get league entries in all queues for a given summoner ID.`
-- [x] `Get all the league entries.`
-- [x] `Get the grandmaster league of a specific queue.`
-- [x] `Get league with given ID, including inactive entries.`
-- [x] `Get the master league for given queue.`
-- [x] `Get the queues that have positional ranks enabled.` (deprecated June 17th and in `v0.9.10`)
-- [x] `Get league positions in all queues for a given summoner ID.` (deprecated June 17th and in `v0.9.10`)
-- [x] `Get all the positional league entries.` (deprecated June 17th and in `v0.9.10`)
-## LOL-CHALLENGES-V1
-- [x] `Get all challenge configurations.`
-- [x] `Get all challenge percentile distributions.`
-- [x] `Get a challenge configuration.`
-- [x] `Get Leaderboards for a challenge (Chall, GM, Masters).`
-- [x] `Get a challenge percentile distribution.`
-- [x] `Get player challenge information.`
-## LOL-STATUS-V3
-- [x] `Get League of Legends status for the given shard.`
-- [x] `Get matchlist for games played on given account ID and platform ID and filtered using given filter parameters, if any.`
-- [x] `Get match timeline by match ID.`
-- [x] `Get match IDs by tournament code.`
-- [x] `Get match by match ID and tournament code.`
-## LOL-STATUS-V4
-- [x] `Get League of Legends status for the given platform.`
-## SPECTATOR-V5
-- [x] `Get current game information for the given summoner ID.`
-- [x] `Get list of featured games.`
-## SPECTATOR-V4 (deprecated [April 5](https://twitter.com/RiotGamesDevRel/status/1764780016640852222?t=pHB1GpVotgKnNYU-OH_1HQ&s=19))
-- [x] `Get current game information for the given summoner ID.`
-- [x] `Get list of featured games.`
-## SUMMONER-V4
-- [x] `Get a summoner by account ID.`
-- [x] `Get a summoner by summoner name.` (deprecated Oct 16th, 2023)
-- [x] `Get a summoner by PUUID.`
-- [x] `Get a summoner by summoner ID.`
-## TOURNAMENT-STUB-V4
-- [ ] `Create a mock tournament code for the given tournament.`
-- [ ] `Gets a mock list of lobby events by tournament code.`
-- [ ] `Creates a mock tournament provider and returns its ID.`
-- [ ] `Creates a mock tournament and returns its ID.`
-## TOURNAMENT-V4
-- [ ] `Create a tournament code for the given tournament.`
-- [ ] `Returns the tournament code DTO associated with a tournament code string.`
-- [ ] `Update the pick type, map, spectator type, or allowed summoners for a code.`
-- [ ] `Gets a list of lobby events by tournament code.`
-- [ ] `Creates a tournament provider and returns its ID.`
-- [ ] `Creates a tournament and returns its ID.`
-
-# TFT Endpoints
-## TFT-SPECTATOR-V5
-- [x] `Get current game information for the given puuid.`
-- [x] `Get list of featured games.`
-## TFT-SUMMONER-V1
-- [x] `Get a summoner by account ID.`
-- [x] `Get a summoner by summoner name.` (deprecated Oct 16th, 2023)
-- [x] `Get a summoner by PUUID.`
-- [x] `Get a summoner by summoner ID.`
-## TFT-MATCH-V1
-- [x] `Get match list by summoner PUUID.`
-- [x] `Get match list details.`
-## TFT-LEAGUE-V1
-- [x] `Get the challenger league for given queue.`
-- [x] `Get the grandmaster league for given queue.`
-- [x] `Get the master league for given queue.`
-- [x] `Get league entries in all queues for a given summoner ID.`
-- [ ] `Get all the league entries.`
-- [ ] `Get league with given ID, including inactive entries.`
-
-# Run all examples
-
-Download code from git and:
-
-## Simple
-```$ RIOT_API_KEY={YOUR_KEY} yarn example```
-
-## Specific examples
-```$ RIOT_API_KEY={YOUR_KEY} yarn example {exampleFunctionName}```
-
-## With docker
-Edit docker-compose.yml with your api key and:
-```$ docker-compose up```
-
-## Real project
-We did a project based on a "twisted" package, this project is not finished but it is a very good example
-Github: https://github.com/twisted-gg
-
-# Options
-
-The following environment variables can be set either in the ```.env``` file or as shown in the examples:
-
-## ```RIOT_API_KEY```
-
-Obtained from the Riot Games developer page(https://developer.riotgames.com/)
-Necessary to use this library.
-
-## ```UPDATE_CHAMPION_IDS```
-
-This library has an option to fetch an actual version of champion IDs regularly. This is useful in case a new champion
-gets added, while the application runs. E.g. data crawlers, or services which aren't supposed to be restarted regularly.
-
-Set the value to ```true``` or ```1``` to enable this feature.
+| Option | Type | Default | Description |
+| --- | --- | --- | --- |
+| `key` | `string` | `process.env.RIOT_API_KEY` | Your Riot Games API key. |
+| `rateLimitRetry` | `boolean` | `true` | Retry the request when Riot answers `429` / `503`. |
+| `rateLimitRetryAttempts` | `number` | `1` | How many times to retry after a rate‑limit response. |
+| `concurrency` | `number` | `Infinity` | Max concurrent requests **per service** (Summoner, Match, …). |
+| `baseURL` | `string` | `https://$(region).api.riotgames.com/:game` | Point requests at a rate‑limiting proxy. `$(region)` and `:game` are substituted. |
+| `debug.logTime` | `boolean` | `false` | Log each method's execution time. |
+| `debug.logUrls` | `boolean` | `false` | Log the URL of every request. |
+| `debug.logRatelimits` | `boolean` | `false` | Log whenever the client is waiting on a rate limit. |
+
+---
+
+## 🔁 Rate limiting & retries
+
+When Riot returns **`429 Too Many Requests`** or **`503 Service Unavailable`**, Twisted automatically waits
+(honoring the `Retry-After` header) and re‑issues the request up to `rateLimitRetryAttempts` times — query
+parameters included. Disable it with `rateLimitRetry: false` if you manage limits yourself.
+
+### Concurrency
+
+```ts
+// Never fire more than 10 concurrent requests per service
+const api = new LolApi({ key, concurrency: 10 })
+```
+
+---
+
+## 🧯 Error handling
+
+Failed requests throw typed errors you can branch on:
+
+```ts
+import { LolApi, Constants, GenericError, RateLimitError, ServiceUnavailable, ApiKeyNotFound } from 'twisted'
+
+try {
+ await api.Summoner.getByPUUID(puuid, Constants.Regions.KOREA)
+} catch (e) {
+ if (e instanceof RateLimitError) { /* 429 — retries exhausted */ }
+ if (e instanceof ServiceUnavailable) { /* 503 */ }
+ if (e instanceof ApiKeyNotFound) { /* missing key */ }
+ if (e instanceof GenericError) { console.log(e.status, e.body) }
+}
+```
+
+| Error | When |
+| --- | --- |
+| `ApiKeyNotFound` | No API key was provided. |
+| `RateLimitError` | `429` and retries are exhausted/disabled. |
+| `ServiceUnavailable` | `503` from the Riot API. |
+| `GenericError` | Any other non‑2xx response (`status` and `body` attached). |
+
+---
+
+## 🐉 Data Dragon
+
+Static game assets (champions, items, runes, versions…). Data Dragon hits the public CDN directly — **no API key,
+no rate limiting** — so these methods return the raw payload instead of an `ApiResponseDTO`.
+
+```ts
+const api = new LolApi()
+
+const versions = await api.DataDragon.getVersions() // ['15.x.1', …]
+const champs = await api.DataDragon.getChampionList() // all champions
+const aatrox = await api.DataDragon.getChampion(Constants.Champions.AATROX)
+const runes = await api.DataDragon.getRunesReforged()
+```
+
+---
+
+## 💡 Examples
+
+A runnable example exists for **every endpoint** under [`/example`](./example).
+
+```bash
+# Run them all
+RIOT_API_KEY=RGAPI-xxxx yarn example
+
+# Run a subset by (case-insensitive) name match
+RIOT_API_KEY=RGAPI-xxxx yarn example summoner
+```
+
+---
+
+## 📋 Endpoint coverage
+
+> Listed in the same order as the [official Riot documentation](https://developer.riotgames.com/apis).
+
+
+Riot Account
+
+#### ACCOUNT-V1
+- [x] Get account by puuid
+- [x] Get account by riot id
+- [x] Get active region (lol and tft)
+- [ ] Get account by puuid — ESPORTS
+- [ ] Get account by riot id — ESPORTS
+- [ ] Get active shard for a player
+- [ ] Get account by access token
+
+
+
+
+League of Legends
+
+#### CHAMPION-MASTERY-V4
+- [x] All champion mastery entries
+- [x] Champion mastery by player & champion id
+- [x] Total champion mastery score
+
+#### CHAMPION-V3
+- [x] Champion rotation
+
+#### CLASH
+- [x] Players by summoner id · Team · Tournaments · Tournament by team id · Tournament by id
+
+#### MATCH-V5
+- [x] Match by id · Matches by puuid · Match timeline · Available replays by puuid
+
+#### MATCH-V4 *(deprecated)*
+- [x] Matches by tournament code · Match by id · Match by tournament code · Matches by summoner id · Match timeline
+
+#### LEAGUE-V4
+- [x] Challenger / Grandmaster / Master leagues by queue
+- [x] League entries by PUUID · by summoner id · all entries
+- [x] League by id · Experimental league entries
+
+#### LOL-CHALLENGES-V1
+- [x] Config · Percentiles · Challenge config · Leaderboards · Challenge percentiles · Player challenges
+
+#### LOL-STATUS-V4
+- [x] Platform status (v4) · Shard status (v3, deprecated)
+
+#### SPECTATOR-V5
+- [x] Current game by summoner id · Featured games *(v4 deprecated)*
+
+#### SUMMONER-V4
+- [x] By account id · By PUUID · By summoner id
+
+#### TOURNAMENT(-STUB)-V4
+- [ ] Not yet implemented
+
+
+
+
+Teamfight Tactics
+
+#### TFT-SUMMONER-V1
+- [x] By account id · By PUUID · By summoner id
+
+#### TFT-MATCH-V1
+- [x] Match list by PUUID · Match details
+
+#### TFT-LEAGUE-V1
+- [x] Challenger / Grandmaster / Master leagues
+- [x] Entries by summoner id · By tier & division
+- [ ] All entries · League by id
+
+#### TFT-SPECTATOR-V5
+- [x] Current game by puuid · Featured games
+
+
+
+---
+
+## 🔀 Migrating to v1.80
+
+This release removes three runtime dependencies in favor of native platform features:
+
+| Removed | Replaced by |
+| --- | --- |
+| `axios` | Native `fetch` (Node ≥ 18) |
+| `lodash` | Native JS (`Object.entries`, spreads, …) |
+| `dotenv` | `node --env-file=.env` or your own loader |
+
+**What you need to do**
+
+- Run on **Node 18 or newer**.
+- If you relied on Twisted auto‑loading a `.env`, load it yourself — e.g. `node --env-file=.env`, or pass `new LolApi({ key })`.
+
+The public API is otherwise **unchanged** — your existing calls keep working.
+
+---
+
+## 🤝 Contributing
+
+```bash
+yarn install # install dependencies
+yarn build # compile TypeScript -> dist/
+yarn lint # eslint
+yarn jest # run the test suite (coverage is always collected)
+```
+
+PRs are welcome! For new endpoints: declare it in `src/endpoints`, add the service method, model the response DTO,
+add an example, and wire it into the relevant entry class.
+
+A larger real‑world project built on Twisted lives at [twisted‑gg](https://github.com/twisted-gg).
+
+---
+
+
+
+Released under the [MIT License](./LICENSE).
+
+
diff --git a/example/README.md b/example/README.md
index 7de2e550..e52aa00e 100644
--- a/example/README.md
+++ b/example/README.md
@@ -1,3 +1,52 @@
-# Examples
+# Twisted Examples
-Here you are example of each api endpoint of league of legends
+A runnable example for (almost) every Riot API endpoint that [`twisted`](../) wraps —
+League of Legends, Teamfight Tactics, Riot Account, Data Dragon and Clash.
+
+Each file exports a single named `async` function that performs a small, self-contained
+call and logs a friendly summary of the result. They double as living documentation:
+read them to see the exact shape of a request and its response.
+
+## How to run
+
+Examples need a Riot API key, read from `process.env.RIOT_API_KEY`. Grab one from the
+[Riot Developer Portal](https://developer.riotgames.com/).
+
+```bash
+# Run every example
+RIOT_API_KEY=RGAPI-xxxx yarn example
+
+# Run a single example by name (case-insensitive substring match)
+RIOT_API_KEY=RGAPI-xxxx yarn example account
+RIOT_API_KEY=RGAPI-xxxx yarn example datadragon
+```
+
+When you pass a name, the runner matches every exported function whose name *contains*
+it, runs them, and prints the JSON they return. With no argument, it runs them all in
+sequence (with a short delay between calls to stay friendly to rate limits).
+
+> **Use your own account.** The examples target a few demo Riot IDs defined in
+> [`config/config.ts`](./config/config.ts). Edit that file to point at your own
+> account (`summonerName` / `tagLine` / `region` / `regionGroup`) before running.
+
+## What's inside
+
+| Folder | Category | Examples | Highlights |
+| --- | --- | --- | --- |
+| [`riot/`](./riot) | **Riot Account** (Account-V1) | 2 | Resolve a Riot ID ↔ PUUID; the entry point for everything else. Routed by region *group*. |
+| [`lol/`](./lol) | **League of Legends** | 19 | Summoner, League/ranked, Champion mastery & rotation, Match-V5, Spectator-V5, Challenges, Status. |
+| [`lol/*.DataDragon.ts`](./lol) | **Data Dragon** (static CDN) | 12 | Champions, runes, maps, queues, versions and more — no API key, no rate limits. |
+| [`lol/deprecated/`](./lol/deprecated) | **LoL (deprecated)** | 11 | Older endpoints kept for reference (summoner-by-name, Match-V4, Spectator-V4, …). Prefer the current ones. |
+| [`tft/`](./tft) | **Teamfight Tactics** | 9 | Summoner, league by tier/summoner, Match-V1, Spectator, static files. |
+| [`clash/`](./clash) | **Clash** | 2 | List tournaments and fetch one by id. |
+
+## Regions vs region groups
+
+Riot uses two routing concepts, both demonstrated in the examples and documented in
+[`config/config.ts`](./config/config.ts):
+
+- **`Regions`** — platform routing (`EUW1`, `KR`, `NA1`, …) used by most LoL/TFT endpoints.
+- **`RegionGroups`** — routing groups (`AMERICAS`, `ASIA`, `EUROPE`, `SEA`) used by
+ Match-V5, TFT-Match and the Account API.
+
+The library's types enforce which one each endpoint accepts.
diff --git a/example/clash/ClashTournamentById.example.ts b/example/clash/ClashTournamentById.example.ts
index 220ddd52..05040f16 100644
--- a/example/clash/ClashTournamentById.example.ts
+++ b/example/clash/ClashTournamentById.example.ts
@@ -1,16 +1,32 @@
import { LolApi } from '../../src'
import { config } from '../config/config'
-const api = new LolApi()
-
+/**
+ * CLASH-V1 — Fetch a single Clash tournament by its id.
+ *
+ * There is no fixed tournament id to demo, so we first list the active
+ * tournaments and reuse the first one's id. Clash is often idle, so we guard
+ * against an empty list. This endpoint uses the platform `Regions` value.
+ */
export async function clashTournamentById () {
- const { region } = config
- const {
- response: [
- {
- id
- }
- ]
- } = await api.Clash.getTournaments(region)
- return api.Clash.getTournamentById(id, region)
+ const lolApi = new LolApi()
+
+ // 1. List the active Clash tournaments to discover a valid id
+ const { response: tournaments } = await lolApi.Clash.getTournaments(config.region)
+
+ // 2. Bail out gracefully when no tournament is currently scheduled
+ if (tournaments.length === 0) {
+ console.log(`No active Clash tournaments on ${config.region} right now.`)
+ return null
+ }
+
+ // 3. Reuse the first tournament's id to fetch its full detail
+ const [{ id }] = tournaments
+ const { response: tournament } = await lolApi.Clash.getTournamentById(id, config.region)
+
+ console.log(`Tournament #${tournament.id} — ${tournament.nameKey}`)
+ console.log(`Theme : ${tournament.themeId}`)
+ console.log(`Schedule: ${tournament.schedule.length} phase(s)`)
+
+ return tournament
}
diff --git a/example/clash/ClashTournamentList.example.ts b/example/clash/ClashTournamentList.example.ts
index aaff1708..60e5d401 100644
--- a/example/clash/ClashTournamentList.example.ts
+++ b/example/clash/ClashTournamentList.example.ts
@@ -1,12 +1,24 @@
import { LolApi } from '../../src'
import { config } from '../config/config'
-const api = new LolApi()
-
+/**
+ * CLASH-V1 — List the active Clash tournaments for a platform region.
+ *
+ * Clash is a scheduled competitive mode, so the list is often empty when no
+ * tournament is running. This endpoint uses the platform `Regions` value.
+ */
export async function clashTournamentList () {
- const { region } = config
- const {
- response
- } = await api.Clash.getTournaments(region)
- return response
+ const lolApi = new LolApi()
+
+ // 1. Fetch every active/scheduled Clash tournament on the platform region
+ const { response: tournaments } = await lolApi.Clash.getTournaments(config.region)
+
+ console.log(`Active Clash tournaments on ${config.region}: ${tournaments.length}`)
+
+ // 2. Print a short summary for each tournament (id + theme)
+ for (const tournament of tournaments) {
+ console.log(`#${tournament.id} — themeId ${tournament.themeId} (${tournament.nameKey})`)
+ }
+
+ return tournaments
}
diff --git a/example/config/config.ts b/example/config/config.ts
index 259ab4cb..86dd1279 100644
--- a/example/config/config.ts
+++ b/example/config/config.ts
@@ -1,14 +1,42 @@
import { Constants } from '../../src'
+import { Regions, RegionGroups, AccountAPIRegionGroups } from '../../src/constants'
import { Levels } from '../../src/constants/levels'
-export const config = {
+/**
+ * Shared configuration used across the examples.
+ *
+ * Riot IDs are made of a `gameName` + `tagLine` (the value after the `#`),
+ * e.g. `Thebausffs#COOL`.
+ *
+ * Three different "region" concepts show up in the Riot API:
+ * - `Regions` (platform routing, e.g. `EUW1`, `KR`, `NA1`) — most LoL/TFT endpoints.
+ * - `RegionGroups` (`AMERICAS` | `ASIA` | `EUROPE` | `SEA`) — Match-V5 / TFT-Match.
+ * - `AccountAPIRegionGroups` (`RegionGroups` without `SEA`) — the Account-V1 API.
+ */
+interface ExampleAccount {
+ /** Riot ID game name (the part before the `#`). */
+ summonerName: string
+ /** Riot ID tag line (the part after the `#`). */
+ tagLine: string
+ /** Platform region for LoL/TFT platform endpoints. */
+ region: Regions
+ /** Routing value for the Account-V1 API (americas / asia / europe). */
+ regionGroup: AccountAPIRegionGroups
+}
+
+export const config: ExampleAccount = {
summonerName: 'Thebausffs',
tagLine: 'COOL',
region: Constants.Regions.EU_WEST,
- regionGroup: Constants.RegionGroups.AMERICAS,
+ regionGroup: Constants.RegionGroups.EUROPE
+}
+
+interface ExampleTftAccount extends ExampleAccount {
+ /** Routing value for the TFT Match-V1 API. */
+ tftRegion: RegionGroups
}
-export const configTft = {
+export const configTft: ExampleTftAccount = {
summonerName: 'Meinya',
tagLine: 'NA1',
region: Constants.Regions.AMERICA_NORTH,
@@ -16,12 +44,19 @@ export const configTft = {
tftRegion: Constants.RegionGroups.AMERICAS
}
+interface ExampleChallengesAccount extends ExampleAccount {
+ /** A challenge id (see the Challenges-V1 config endpoint). */
+ challengeId: number
+ /** Tier used when querying challenge leaderboards. */
+ level: Levels
+}
+
// Used for challengeID
-export const configChallenges = {
+export const configChallenges: ExampleChallengesAccount = {
summonerName: 'Night Owl',
tagLine: 'ryi',
region: Constants.Regions.AMERICA_NORTH,
regionGroup: Constants.RegionGroups.AMERICAS,
challengeId: 101106, // ARAM Eradication
level: Levels.CHALLENGER
-}
\ No newline at end of file
+}
diff --git a/example/lol/ChallengerLeagueByQueue.example.ts b/example/lol/ChallengerLeagueByQueue.example.ts
index 6fde91fd..40362b37 100644
--- a/example/lol/ChallengerLeagueByQueue.example.ts
+++ b/example/lol/ChallengerLeagueByQueue.example.ts
@@ -1,9 +1,29 @@
-import { LolApi } from '../../src'
+import { LolApi, Constants } from '../../src'
import { config } from '../config/config'
-import { Queues } from '../../src/constants'
-
-const api = new LolApi()
+/**
+ * LEAGUE-V4 — Get the Challenger league for a given ranked queue.
+ *
+ * Returns the single apex league for the region/queue, with every Challenger
+ * player listed under `entries`.
+ */
export async function challengerLeagueByQueueExample () {
- return await api.League.getChallengerLeaguesByQueue(Queues.RANKED_SOLO_5x5, config.region)
+ const lolApi = new LolApi()
+
+ // Fetch the Challenger ladder for solo/duo queue on this region
+ const { response: league } = await lolApi.League.getChallengerLeaguesByQueue(
+ Constants.Queues.RANKED_SOLO_5x5,
+ config.region
+ )
+
+ console.log(`Challenger league "${league.name}" (${league.queue})`)
+ console.log(`Players: ${league.entries.length}`)
+
+ // Highlight the highest-LP player in the ladder
+ const top = [...league.entries].sort((a, b) => b.leaguePoints - a.leaguePoints)[0]
+ if (top) {
+ console.log(`Top player: ${top.leaguePoints} LP — ${top.wins}W/${top.losses}L`)
+ }
+
+ return league
}
diff --git a/example/lol/Challenges.example.ts b/example/lol/Challenges.example.ts
index c6c84435..a8c2d104 100644
--- a/example/lol/Challenges.example.ts
+++ b/example/lol/Challenges.example.ts
@@ -1,28 +1,65 @@
-import { RiotApi } from '../../src'
-import { LolApi } from '../../src/apis/lol/lol'
+import { LolApi, RiotApi } from '../../src'
import { configChallenges } from '../config/config'
-export async function challengesV1Example() {
- const rApi = new RiotApi()
- const api = new LolApi()
+/**
+ * LOL-CHALLENGES-V1 — Explore the Challenges system.
+ *
+ * Challenges are achievement-style goals with levels (IRON … CHALLENGER) and
+ * leaderboards. This example walks the main read endpoints:
+ * - PlayerChallenges : a single player's progress (needs a PUUID)
+ * - Leaderboards : the top players for one challenge at a level
+ * - Configs : the static config for every challenge
+ * - ChallengeConfig : the static config for one challenge
+ * - Percentiles : value distribution across ALL challenges
+ * - ChallengePercentiles: value distribution for one challenge
+ */
+export async function challengesV1Example () {
+ const riotApi = new RiotApi()
+ const lolApi = new LolApi()
- const { response: { puuid } } = await rApi.Account.getByRiotId(configChallenges.summonerName, configChallenges.tagLine, configChallenges.regionGroup)
+ // 1. Resolve the Riot ID into a PUUID (PlayerChallenges is keyed by PUUID)
+ const { response: account } = await riotApi.Account.getByRiotId(
+ configChallenges.summonerName,
+ configChallenges.tagLine,
+ configChallenges.regionGroup
+ )
- const playerChallenges = (await api.Challenges.PlayerChallenges(puuid, configChallenges.region)).response
- // console.log('Found total challenge points:', playerChallenges.totalPoints)
+ // 2. The player's own challenge progress and summed points
+ const { response: playerChallenges } = await lolApi.Challenges.PlayerChallenges(
+ account.puuid,
+ configChallenges.region
+ )
+ console.log(`${account.gameName}#${account.tagLine} total points: ${playerChallenges.totalPoints.current}/${playerChallenges.totalPoints.max} (${playerChallenges.totalPoints.level})`)
- const leaderboards = (await api.Challenges.Leaderboards(configChallenges.challengeId, configChallenges.level, configChallenges.region, { limit: 5 })).response
- // console.log(`Top 5 ${configChallenges.level} for ARAM Eradication for `, leaderboards)
+ // 3. Top 5 players for our example challenge at the configured level
+ const { response: leaderboards } = await lolApi.Challenges.Leaderboards(
+ configChallenges.challengeId,
+ configChallenges.level,
+ configChallenges.region,
+ { limit: 5 }
+ )
+ console.log(`Leaderboard entries for challenge ${configChallenges.challengeId}: ${leaderboards.length}`)
- const configs = (await api.Challenges.Configs(configChallenges.region)).response
- // console.log("Config thresholds for the first of all basic challenges:", configs[0])
+ // 4. Static config for every challenge on this region
+ const { response: configs } = await lolApi.Challenges.Configs(configChallenges.region)
+ console.log(`Total challenges configured: ${configs.length}`)
- const config = (await api.Challenges.ChallengeConfig(configChallenges.challengeId, configChallenges.region)).response
- // console.log('Challenge Configuration for ARAM Eradication', config)
+ // 5. Static config for just our example challenge
+ const { response: challengeConfig } = await lolApi.Challenges.ChallengeConfig(
+ configChallenges.challengeId,
+ configChallenges.region
+ )
+ console.log(`Challenge ${challengeConfig.id} has leaderboard: ${challengeConfig.leaderboard}`)
- const distributions = (await api.Challenges.Percentiles(configChallenges.region)).response
- // console.log("Distribution for ARAM Eradication:", distributions[configChallenges.challengeId])
+ // 6. Value distribution across ALL challenges, then narrowed to our challenge
+ const { response: percentiles } = await lolApi.Challenges.Percentiles(configChallenges.region)
+ console.log(`Percentile data available for ${Object.keys(percentiles).length} challenges`)
- const distribution = (await api.Challenges.ChallengePercentiles(configChallenges.challengeId, configChallenges.region)).response
- // console.log("Distribution for ARAM Eradication:", distribution)
-}
\ No newline at end of file
+ const { response: challengePercentiles } = await lolApi.Challenges.ChallengePercentiles(
+ configChallenges.challengeId,
+ configChallenges.region
+ )
+ console.log(`Levels with a percentile for challenge ${configChallenges.challengeId}: ${Object.keys(challengePercentiles).join(', ')}`)
+
+ return playerChallenges
+}
diff --git a/example/lol/ChampionMasteryByPUUID.example.ts b/example/lol/ChampionMasteryByPUUID.example.ts
index d8d2f38d..19bf0f67 100644
--- a/example/lol/ChampionMasteryByPUUID.example.ts
+++ b/example/lol/ChampionMasteryByPUUID.example.ts
@@ -1,11 +1,34 @@
-import { RiotApi } from '../../src'
-import { LolApi } from '../../src'
+import { LolApi, RiotApi } from '../../src'
import { config } from '../config/config'
-const rApi = new RiotApi()
-const api = new LolApi()
-
+/**
+ * CHAMPION-MASTERY-V4 — Get all champion mastery entries for a player by PUUID.
+ *
+ * Mastery is keyed by PUUID, so we first resolve the account's PUUID through
+ * the Riot Account API, then fetch every champion the player has points on.
+ */
export async function championMasteryByPUUID () {
- const { response: { puuid } } = await rApi.Account.getByRiotId(config.summonerName, config.tagLine, config.regionGroup)
- return await api.Champion.masteryByPUUID(puuid, config.region)
+ const riotApi = new RiotApi()
+ const lolApi = new LolApi()
+
+ // 1. Resolve the Riot ID (gameName#tagLine) into a PUUID
+ const { response: account } = await riotApi.Account.getByRiotId(
+ config.summonerName,
+ config.tagLine,
+ config.regionGroup
+ )
+
+ // 2. Fetch every champion mastery entry on the player's platform region
+ const { response: masteries } = await lolApi.Champion.masteryByPUUID(account.puuid, config.region)
+
+ console.log(`Player : ${account.gameName}#${account.tagLine}`)
+ console.log(`Champions : ${masteries.length}`)
+
+ // 3. The API already returns the list sorted by championPoints (highest first)
+ const top = masteries[0]
+ if (top) {
+ console.log(`Top champion : id ${top.championId} (level ${top.championLevel}, ${top.championPoints} pts)`)
+ }
+
+ return masteries
}
diff --git a/example/lol/ChampionMasteryByPUUIDChampion.example.ts b/example/lol/ChampionMasteryByPUUIDChampion.example.ts
index 30b1e54d..ab9983e1 100644
--- a/example/lol/ChampionMasteryByPUUIDChampion.example.ts
+++ b/example/lol/ChampionMasteryByPUUIDChampion.example.ts
@@ -1,11 +1,37 @@
-import { RiotApi } from '../../src'
-import { LolApi } from '../../src'
+import { LolApi, RiotApi } from '../../src'
import { config } from '../config/config'
-const rApi = new RiotApi()
-const api = new LolApi()
-
+/**
+ * CHAMPION-MASTERY-V4 — Get a single champion's mastery for a player by PUUID.
+ *
+ * Like the full-list endpoint, this is keyed by PUUID, so we resolve the
+ * account first and then ask for one specific champion id (here: Annie, id 1).
+ */
export async function championMasteryByPUUIDByChampion () {
- const { response: { puuid } } = await rApi.Account.getByRiotId(config.summonerName, config.tagLine, config.regionGroup)
- return await api.Champion.masteryByPUUIDChampion(puuid, 1, config.region)
+ const riotApi = new RiotApi()
+ const lolApi = new LolApi()
+
+ const championId = 1 // Annie
+
+ // 1. Resolve the Riot ID (gameName#tagLine) into a PUUID
+ const { response: account } = await riotApi.Account.getByRiotId(
+ config.summonerName,
+ config.tagLine,
+ config.regionGroup
+ )
+
+ // 2. Fetch this single champion's mastery on the player's platform region
+ const { response: mastery } = await lolApi.Champion.masteryByPUUIDChampion(
+ account.puuid,
+ championId,
+ config.region
+ )
+
+ console.log(`Player : ${account.gameName}#${account.tagLine}`)
+ console.log(`Champion id : ${mastery.championId}`)
+ console.log(`Mastery level : ${mastery.championLevel}`)
+ console.log(`Mastery points : ${mastery.championPoints}`)
+ console.log(`Until next level : ${mastery.championPointsUntilNextLevel}`)
+
+ return mastery
}
diff --git a/example/lol/ChampionRotation.example.ts b/example/lol/ChampionRotation.example.ts
index 47a567cf..04d39257 100644
--- a/example/lol/ChampionRotation.example.ts
+++ b/example/lol/ChampionRotation.example.ts
@@ -1,7 +1,30 @@
import { LolApi } from '../../src'
-import { Regions } from '../../src/constants'
+import { config } from '../config/config'
+/** Shape of the CHAMPION-V3 rotation payload (the call itself is untyped on the wire). */
+interface ChampionRotation {
+ freeChampionIds: number[]
+ freeChampionIdsForNewPlayers: number[]
+ maxNewPlayerLevel: number[]
+}
+
+/**
+ * CHAMPION-V3 — Get the current free champion rotation.
+ *
+ * Returns the champions that are free-to-play this week (for all players and
+ * for players who have not yet reached level 11), keyed by numeric champion id.
+ */
export async function championRotationExample () {
const api = new LolApi()
- return await api.Champion.rotation(Regions.LAT_NORTH)
+
+ // Champion rotation is a platform endpoint, so it takes a platform `Regions` value.
+ // `rotation()` is untyped on the wire, so we annotate the expected DTO here.
+ const { response } = await api.Champion.rotation(config.region)
+ const rotation = response as ChampionRotation
+
+ console.log(`Free champions this week : ${rotation.freeChampionIds.length}`)
+ console.log(`Free for new players (<11) : ${rotation.freeChampionIdsForNewPlayers.length}`)
+ console.log(`Max new player levels : ${rotation.maxNewPlayerLevel.join(', ')}`)
+
+ return rotation
}
diff --git a/example/lol/ChampionsScore.example.ts b/example/lol/ChampionsScore.example.ts
index c1ecd1b6..c1b0270b 100644
--- a/example/lol/ChampionsScore.example.ts
+++ b/example/lol/ChampionsScore.example.ts
@@ -1,11 +1,32 @@
-import { RiotApi } from '../../src'
-import { LolApi } from '../../src'
+import { LolApi, RiotApi } from '../../src'
import { config } from '../config/config'
-const rApi = new RiotApi()
-const api = new LolApi()
-
+/**
+ * CHAMPION-MASTERY-V4 — Get a player's total champion mastery score by PUUID.
+ *
+ * The mastery score is the sum of a player's individual champion mastery
+ * levels. We resolve the account's PUUID first, then read the score.
+ *
+ * Note: `championsScore` returns the `ChampionsScoreDTO` directly (no
+ * `{ response }` wrapper).
+ */
export async function championsScoreExample () {
- const { response: { puuid } } = await rApi.Account.getByRiotId(config.summonerName, config.region, config.regionGroup)
- return await api.Champion.championsScore(puuid, config.region)
+ const riotApi = new RiotApi()
+ const lolApi = new LolApi()
+
+ // 1. Resolve the Riot ID (gameName#tagLine) into a PUUID.
+ // getByRiotId takes (gameName, tagLine, accountRegionGroup).
+ const { response: account } = await riotApi.Account.getByRiotId(
+ config.summonerName,
+ config.tagLine,
+ config.regionGroup
+ )
+
+ // 2. Fetch the total mastery score on the player's platform region
+ const score = await lolApi.Champion.championsScore(account.puuid, config.region)
+
+ console.log(`Player : ${account.gameName}#${account.tagLine}`)
+ console.log(`Mastery score : ${score.score}`)
+
+ return score
}
diff --git a/example/lol/GameModes.DataDragon.ts b/example/lol/GameModes.DataDragon.ts
index 22db7c43..ccd98650 100644
--- a/example/lol/GameModes.DataDragon.ts
+++ b/example/lol/GameModes.DataDragon.ts
@@ -1,7 +1,21 @@
import { LolApi } from '../../src'
-const api = new LolApi()
-
+/**
+ * DATA DRAGON — Game modes (static).
+ *
+ * Returns the static game-mode reference: each `gameMode` code mapped to a
+ * human description (e.g. CLASSIC -> "Classic Summoner's Rift and Twisted
+ * Treeline games"). Served from the static CDN: no key, no rate limits.
+ */
export async function gameModesDataDragon () {
- return api.DataDragon.getGameModes()
+ // Data Dragon needs no key
+ const api = new LolApi()
+
+ // 1. Fetch the static game-mode table
+ const gameModes = await api.DataDragon.getGameModes()
+
+ console.log(`Game modes defined: ${gameModes.length}`)
+ console.log(`Codes : ${gameModes.map((g) => g.gameMode).join(', ')}`)
+
+ return gameModes
}
diff --git a/example/lol/GameTypes.DataDragon.ts b/example/lol/GameTypes.DataDragon.ts
index 7f59edf4..75795145 100644
--- a/example/lol/GameTypes.DataDragon.ts
+++ b/example/lol/GameTypes.DataDragon.ts
@@ -1,7 +1,21 @@
import { LolApi } from '../../src'
-const api = new LolApi()
-
+/**
+ * DATA DRAGON — Game types (static).
+ *
+ * Returns the static game-type reference: each `gametype` code mapped to a
+ * human description (e.g. CUSTOM_GAME, MATCHED_GAME, TUTORIAL_GAME).
+ * Served from the static CDN: no key, no rate limits.
+ */
export async function gameTypessDataDragon () {
- return api.DataDragon.getGameTypes()
+ // Data Dragon needs no key
+ const api = new LolApi()
+
+ // 1. Fetch the static game-type table
+ const gameTypes = await api.DataDragon.getGameTypes()
+
+ console.log(`Game types defined: ${gameTypes.length}`)
+ console.log(`Codes : ${gameTypes.map((g) => g.gametype).join(', ')}`)
+
+ return gameTypes
}
diff --git a/example/lol/GetChampion.DataDragon.ts b/example/lol/GetChampion.DataDragon.ts
index f7b23e1f..abe0d9d6 100644
--- a/example/lol/GetChampion.DataDragon.ts
+++ b/example/lol/GetChampion.DataDragon.ts
@@ -1,8 +1,23 @@
-import { LolApi } from '../../src'
-import { RealmServers, Champions } from '../../src/constants'
-
-const api = new LolApi()
+import { LolApi, Constants } from '../../src'
+/**
+ * DATA DRAGON — Single champion details.
+ *
+ * Passing a `Constants.Champions` value returns the *full* champion blob for
+ * that one champion: lore, spells, passive, skins and base stats. Raw CDN
+ * data: no key, no rate limits and no `{ response }` wrapper.
+ */
export async function getChampionDetailsDataDragon () {
- return api.DataDragon.getChampion(Champions.TWISTED_FATE)
+ // Data Dragon needs no key
+ const api = new LolApi()
+
+ // 1. Fetch the detailed payload for a single champion (Twisted Fate here)
+ const champion = await api.DataDragon.getChampion(Constants.Champions.TWISTED_FATE)
+
+ console.log(`Champion: ${champion.name} — ${champion.title}`)
+ console.log(`Tags : ${champion.tags.join(', ')}`)
+ console.log(`Spells : ${champion.spells.map((s) => s.name).join(', ')}`)
+ console.log(`Skins : ${champion.skins.length}`)
+
+ return champion
}
diff --git a/example/lol/GetChampionList.DataDragon.ts b/example/lol/GetChampionList.DataDragon.ts
index 115a919f..bfcc0a56 100644
--- a/example/lol/GetChampionList.DataDragon.ts
+++ b/example/lol/GetChampionList.DataDragon.ts
@@ -1,8 +1,25 @@
import { LolApi } from '../../src'
-import { RealmServers, Champions } from '../../src/constants'
-
-const api = new LolApi()
+/**
+ * DATA DRAGON — Champion list.
+ *
+ * Calling `getChampion()` with no argument returns the *summary* list of all
+ * champions for the latest patch, keyed by champion id under `data`. Each
+ * entry is a lightweight blurb (no spells/skins). Raw CDN data: no key.
+ */
export async function getChampionListDataDragon () {
- return api.DataDragon.getChampion()
+ // Data Dragon needs no key
+ const api = new LolApi()
+
+ // 1. Fetch the full champion roster for the latest patch
+ const championList = await api.DataDragon.getChampion()
+
+ // 2. `data` is an object keyed by champion id (e.g. "Aatrox", "Ahri", ...)
+ const ids = Object.keys(championList.data)
+
+ console.log(`Patch : ${championList.version}`)
+ console.log(`Champions : ${ids.length}`)
+ console.log(`First few : ${ids.slice(0, 5).join(', ')}`)
+
+ return championList
}
diff --git a/example/lol/GrandMasterLeagueByQueue.example.ts b/example/lol/GrandMasterLeagueByQueue.example.ts
index 74bc55ea..26264c6a 100644
--- a/example/lol/GrandMasterLeagueByQueue.example.ts
+++ b/example/lol/GrandMasterLeagueByQueue.example.ts
@@ -1,9 +1,29 @@
-import { LolApi } from '../../src'
+import { LolApi, Constants } from '../../src'
import { config } from '../config/config'
-import { Queues } from '../../src/constants'
-
-const api = new LolApi()
+/**
+ * LEAGUE-V4 — Get the Grandmaster league for a given ranked queue.
+ *
+ * Returns the single apex league for the region/queue, with every Grandmaster
+ * player listed under `entries`.
+ */
export async function grandmasterLeagueByQueueExample () {
- return await api.League.getGrandMasterLeagueByQueue(Queues.RANKED_SOLO_5x5, config.region)
+ const lolApi = new LolApi()
+
+ // Fetch the Grandmaster ladder for solo/duo queue on this region
+ const { response: league } = await lolApi.League.getGrandMasterLeagueByQueue(
+ Constants.Queues.RANKED_SOLO_5x5,
+ config.region
+ )
+
+ console.log(`Grandmaster league "${league.name}" (${league.queue})`)
+ console.log(`Players: ${league.entries.length}`)
+
+ // Highlight the highest-LP player in the ladder
+ const top = [...league.entries].sort((a, b) => b.leaguePoints - a.leaguePoints)[0]
+ if (top) {
+ console.log(`Top player: ${top.leaguePoints} LP — ${top.wins}W/${top.losses}L`)
+ }
+
+ return league
}
diff --git a/example/lol/Languages.DataDragon.ts b/example/lol/Languages.DataDragon.ts
index 85d65275..efe10877 100644
--- a/example/lol/Languages.DataDragon.ts
+++ b/example/lol/Languages.DataDragon.ts
@@ -1,7 +1,21 @@
import { LolApi } from '../../src'
-const api = new LolApi()
-
+/**
+ * DATA DRAGON — Languages.
+ *
+ * Returns the list of locale codes (e.g. `en_US`, `es_ES`, `ko_KR`) that
+ * Data Dragon ships localized data for. Pass any of these as the `lang`
+ * argument of `getChampion`, `getChampionList`, etc. Raw CDN data: no key.
+ */
export async function languagesDataDragon () {
- return api.DataDragon.getLanguages()
+ // Data Dragon needs no key
+ const api = new LolApi()
+
+ // 1. Fetch every supported locale code
+ const languages = await api.DataDragon.getLanguages()
+
+ console.log(`Locales available: ${languages.length}`)
+ console.log(`Examples : ${languages.slice(0, 5).join(', ')}`)
+
+ return languages
}
diff --git a/example/lol/League.example.ts b/example/lol/League.example.ts
index b4a8eeb6..6ddefdb3 100644
--- a/example/lol/League.example.ts
+++ b/example/lol/League.example.ts
@@ -1,14 +1,40 @@
-import { RiotApi } from '../../src'
-import { LolApi } from '../../src'
+import { LolApi, RiotApi } from '../../src'
import { config } from '../config/config'
-const rApi = new RiotApi()
-const api = new LolApi()
-
+/**
+ * LEAGUE-V4 — Get a full league by its leagueId.
+ *
+ * A leagueId identifies a whole division group; the response lists every
+ * member in it. To find a leagueId we resolve our account, look up its ranked
+ * entries, and then fetch the league one of those entries belongs to.
+ */
export async function leagueExample () {
- const { response: { puuid } } = await rApi.Account.getByRiotId(config.summonerName, config.tagLine, config.regionGroup)
- const { response: { id }} = await api.Summoner.getByPUUID(puuid, config.region)
- // For below, response does not guarantee order for { response: [league]} destructuring
- const league = (await api.League.bySummoner(id, config.region)).response.find(o => o.leagueId)
- return league ? await api.League.get(league.leagueId, config.region) : null
+ const riotApi = new RiotApi()
+ const lolApi = new LolApi()
+
+ // 1. Resolve the Riot ID into a PUUID, then into a summonerId
+ const { response: account } = await riotApi.Account.getByRiotId(
+ config.summonerName,
+ config.tagLine,
+ config.regionGroup
+ )
+ const { response: summoner } = await lolApi.Summoner.getByPUUID(account.puuid, config.region)
+
+ // 2. Fetch the player's ranked entries and pick one that exposes a leagueId.
+ // The order of entries is not guaranteed, so search rather than destructure.
+ const { response: entries } = await lolApi.League.bySummoner(summoner.id, config.region)
+ const entry = entries.find(o => o.leagueId)
+
+ if (!entry) {
+ console.log(`${account.gameName}#${account.tagLine} has no ranked league entries.`)
+ return null
+ }
+
+ // 3. Fetch the full league that entry belongs to
+ const { response: league } = await lolApi.League.get(entry.leagueId, config.region)
+
+ console.log(`League "${league.name}" — ${league.tier} (${league.queue})`)
+ console.log(`Members: ${league.entries.length}`)
+
+ return league
}
diff --git a/example/lol/LeagueByPUUID.example.ts b/example/lol/LeagueByPUUID.example.ts
index 490c0a5a..ad5b024c 100644
--- a/example/lol/LeagueByPUUID.example.ts
+++ b/example/lol/LeagueByPUUID.example.ts
@@ -1,12 +1,32 @@
import { LolApi, RiotApi } from '../../src'
-import { Regions } from '../../src/constants'
import { config } from '../config/config'
-export async function leaguesByPUUIDExample() {
- const api = new LolApi()
- const rApi = new RiotApi()
+/**
+ * LEAGUE-V4 — Get ranked entries for a summoner by PUUID.
+ *
+ * This is the modern replacement for the summonerId-based lookup: resolve the
+ * account's PUUID through ACCOUNT-V1, then read its ranked entries directly.
+ */
+export async function leaguesByPUUIDExample () {
+ const riotApi = new RiotApi()
+ const lolApi = new LolApi()
- const { response: { puuid }} = await rApi.Account.getByRiotId(config.summonerName, config.tagLine, config.regionGroup)
- const { response: data } = await api.League.byPUUID(puuid, Regions.EU_WEST)
- return data;
+ // 1. Resolve the Riot ID into a PUUID
+ const { response: account } = await riotApi.Account.getByRiotId(
+ config.summonerName,
+ config.tagLine,
+ config.regionGroup
+ )
+
+ // 2. Fetch every ranked entry for that PUUID (one per ranked queue)
+ const { response: leagues } = await lolApi.League.byPUUID(account.puuid, config.region)
+
+ console.log(`Ranked entries for ${account.gameName}#${account.tagLine}: ${leagues.length}`)
+ for (const league of leagues) {
+ console.log(
+ ` ${league.queueType}: ${league.tier} ${league.rank} (${league.leaguePoints} LP)`
+ )
+ }
+
+ return leagues
}
diff --git a/example/lol/LeagueEntries.example.ts b/example/lol/LeagueEntries.example.ts
index 0f5a0cc9..8dc76eeb 100644
--- a/example/lol/LeagueEntries.example.ts
+++ b/example/lol/LeagueEntries.example.ts
@@ -1,9 +1,27 @@
-import { LolApi } from '../../src'
-import { Queues, Tiers, Divisions, Regions } from '../../src/constants'
+import { LolApi, Constants } from '../../src'
+import { config } from '../config/config'
+/**
+ * LEAGUE-V4 — Get all (paginated) league entries for a queue / tier / division.
+ *
+ * Unlike LEAGUE-EXP-V4, this endpoint does not cover the apex tiers
+ * (MASTER / GRANDMASTER / CHALLENGER); use the *ByQueue helpers for those.
+ */
export async function leagueEntriesExample () {
- const api = new LolApi()
- const { response: entries } = await api.League.entries(Queues.RANKED_SOLO_5x5, Tiers.BRONZE, Divisions.I, Regions.LAT_NORTH)
+ const lolApi = new LolApi()
- return entries;
+ // Fetch page 1 of every Bronze I solo-queue player on this region
+ const { response: entries } = await lolApi.League.entries(
+ Constants.Queues.RANKED_SOLO_5x5,
+ Constants.Tiers.BRONZE,
+ Constants.Divisions.I,
+ config.region
+ )
+
+ console.log(`Bronze I (${Constants.Queues.RANKED_SOLO_5x5}) entries on page 1: ${entries.length}`)
+ for (const entry of entries.slice(0, 5)) {
+ console.log(` ${entry.leaguePoints} LP — ${entry.wins}W/${entry.losses}L (puuid ${entry.puuid})`)
+ }
+
+ return entries
}
diff --git a/example/lol/LeagueExp.example.ts b/example/lol/LeagueExp.example.ts
index 858c445b..8c21e6c9 100644
--- a/example/lol/LeagueExp.example.ts
+++ b/example/lol/LeagueExp.example.ts
@@ -1,7 +1,29 @@
-import { LolApi } from '../../src'
-import { Queues, Tiers, Divisions, Regions } from '../../src/constants'
+import { LolApi, Constants } from '../../src'
+import { config } from '../config/config'
+/**
+ * LEAGUE-EXP-V4 — Experimental, paginated league entries for a given
+ * queue / tier / division.
+ *
+ * Same data shape as LEAGUE-V4 entries, but this endpoint also returns the
+ * apex tiers (MASTER / GRANDMASTER / CHALLENGER), which the classic entries
+ * endpoint does not.
+ */
export async function leagueExpExample () {
- const api = new LolApi()
- return await api.League.exp(Queues.RANKED_SOLO_5x5, Tiers.BRONZE, Divisions.I, Regions.AMERICA_NORTH)
+ const lolApi = new LolApi()
+
+ // Query page 1 of every Bronze I solo-queue player on this region
+ const { response: entries } = await lolApi.League.exp(
+ Constants.Queues.RANKED_SOLO_5x5,
+ Constants.Tiers.BRONZE,
+ Constants.Divisions.I,
+ config.region
+ )
+
+ console.log(`Bronze I (${Constants.Queues.RANKED_SOLO_5x5}) entries on page 1: ${entries.length}`)
+ for (const entry of entries.slice(0, 5)) {
+ console.log(` ${entry.leaguePoints} LP — ${entry.wins}W/${entry.losses}L (puuid ${entry.puuid})`)
+ }
+
+ return entries
}
diff --git a/example/lol/Maps.DataDragon.ts b/example/lol/Maps.DataDragon.ts
index d8b95f18..f653042b 100644
--- a/example/lol/Maps.DataDragon.ts
+++ b/example/lol/Maps.DataDragon.ts
@@ -1,7 +1,21 @@
import { LolApi } from '../../src'
-const api = new LolApi()
-
+/**
+ * DATA DRAGON — Maps (static).
+ *
+ * Returns the static map reference: each `mapId` mapped to its name
+ * (e.g. 11 -> "Summoner's Rift", 12 -> "Howling Abyss"). Useful for decoding
+ * the `mapId` on matches. Served from the static CDN: no key.
+ */
export async function mapsDataDragon () {
- return api.DataDragon.getMaps()
+ // Data Dragon needs no key
+ const api = new LolApi()
+
+ // 1. Fetch the static map table
+ const maps = await api.DataDragon.getMaps()
+
+ console.log(`Maps defined: ${maps.length}`)
+ maps.forEach((m) => console.log(` ${m.mapId} -> ${m.mapName}`))
+
+ return maps
}
diff --git a/example/lol/MasterLeagueByQueue.example.ts b/example/lol/MasterLeagueByQueue.example.ts
index 86383684..de3c3822 100644
--- a/example/lol/MasterLeagueByQueue.example.ts
+++ b/example/lol/MasterLeagueByQueue.example.ts
@@ -1,9 +1,29 @@
-import { LolApi } from '../../src'
+import { LolApi, Constants } from '../../src'
import { config } from '../config/config'
-import { Queues } from '../../src/constants'
-
-const api = new LolApi()
+/**
+ * LEAGUE-V4 — Get the Master league for a given ranked queue.
+ *
+ * Returns the single apex league for the region/queue, with every Master
+ * player listed under `entries`.
+ */
export async function masterLeagueByQueue () {
- return await api.League.getMasterLeagueByQueue(Queues.RANKED_SOLO_5x5, config.region)
+ const lolApi = new LolApi()
+
+ // Fetch the Master ladder for solo/duo queue on this region
+ const { response: league } = await lolApi.League.getMasterLeagueByQueue(
+ Constants.Queues.RANKED_SOLO_5x5,
+ config.region
+ )
+
+ console.log(`Master league "${league.name}" (${league.queue})`)
+ console.log(`Players: ${league.entries.length}`)
+
+ // Highlight the highest-LP player in the ladder
+ const top = [...league.entries].sort((a, b) => b.leaguePoints - a.leaguePoints)[0]
+ if (top) {
+ console.log(`Top player: ${top.leaguePoints} LP — ${top.wins}W/${top.losses}L`)
+ }
+
+ return league
}
diff --git a/example/lol/MatchV5Replays.example.ts b/example/lol/MatchV5Replays.example.ts
index 35e101f5..589eec6a 100644
--- a/example/lol/MatchV5Replays.example.ts
+++ b/example/lol/MatchV5Replays.example.ts
@@ -1,15 +1,32 @@
-import { RiotApi } from '../../src'
-import { LolApi } from '../../src'
-import { AccountAPIRegionGroups, RegionGroups } from '../../src/constants'
+import { LolApi, RiotApi } from '../../src'
import { config } from '../config/config'
-export async function matchV5ReplaysExample() {
- const api = new LolApi()
- const rApi = new RiotApi()
+/**
+ * MATCH-V5 — Get replay (ROFL) file URLs for a player's recent matches.
+ *
+ * Replays are routed by region group (AMERICAS / ASIA / EUROPE), so we resolve
+ * the account's PUUID via the Account API, then request the downloadable
+ * replay file URLs.
+ */
+export async function matchV5ReplaysExample () {
+ const riotApi = new RiotApi()
+ const lolApi = new LolApi()
- const { response: { puuid }} = await rApi.Account.getByRiotId(config.summonerName, config.tagLine, config.regionGroup as AccountAPIRegionGroups)
- const { response: data } = await api.MatchV5.replays(puuid, RegionGroups.EUROPE)
- console.log(data);
-}
+ // 1. Resolve the Riot ID (gameName#tagLine) into a PUUID
+ const { response: account } = await riotApi.Account.getByRiotId(
+ config.summonerName,
+ config.tagLine,
+ config.regionGroup
+ )
+
+ // 2. Replays are a Match-V5 endpoint -> use the account's region GROUP
+ const { response: replays } = await lolApi.MatchV5.replays(account.puuid, config.regionGroup)
-matchV5ReplaysExample()
+ console.log(`Player : ${account.gameName}#${account.tagLine}`)
+ console.log(`Replay files : ${replays.total}`)
+ if (replays.matchFileURLs[0]) {
+ console.log(`First replay : ${replays.matchFileURLs[0]}`)
+ }
+
+ return replays
+}
diff --git a/example/lol/MatchV5TimelineLatestMatch.example.ts b/example/lol/MatchV5TimelineLatestMatch.example.ts
index 268db9aa..7ec4f931 100644
--- a/example/lol/MatchV5TimelineLatestMatch.example.ts
+++ b/example/lol/MatchV5TimelineLatestMatch.example.ts
@@ -1,22 +1,46 @@
-import { LolApi } from '../../src/apis/lol/lol'
-import { Regions, RegionGroups } from '../../src/constants'
+import { LolApi, RiotApi } from '../../src'
+import { config } from '../config/config'
-export async function matchV5TimelineLatestMatchExample() {
- const api = new LolApi()
+/**
+ * MATCH-V5 — Walk from a Riot ID to a match timeline.
+ *
+ * Summoner-V4 no longer accepts a name, so we resolve the PUUID through the
+ * Account API and then chain the Match-V5 endpoints:
+ * list (match ids) -> get (match details) -> timeline (per-frame events).
+ * Match-V5 is routed by region GROUP (AMERICAS / ASIA / EUROPE).
+ */
+export async function matchV5TimelineLatestMatchExample () {
+ const riotApi = new RiotApi()
+ const lolApi = new LolApi()
- const summonerName = "Cookie Hater"
- const summoner = (await api.Summoner.getByName(summonerName, Regions.EU_WEST)).response
- console.log("Found summoner:", summoner.puuid)
+ // 1. Resolve the Riot ID (gameName#tagLine) into a PUUID
+ const { response: account } = await riotApi.Account.getByRiotId(
+ config.summonerName,
+ config.tagLine,
+ config.regionGroup
+ )
+ console.log(`Player : ${account.gameName}#${account.tagLine}`)
- const matchlist = (await api.MatchV5.list(summoner.puuid, RegionGroups.EUROPE, { queue: 450 })).response
- console.log("Matchlist length:", matchlist.length)
+ // 2. List the player's most recent ARAM matches (queue 450), routed by region group
+ const { response: matchIds } = await lolApi.MatchV5.list(account.puuid, config.regionGroup, {
+ queue: 450,
+ count: 5
+ })
+ console.log(`Match ids : ${matchIds.length}`)
- const matchId = matchlist[0]
- const match = (await api.MatchV5.get(matchId, RegionGroups.EUROPE)).response
- console.log("Found match with id:", match.metadata.matchId)
+ const matchId = matchIds[0]
+ if (!matchId) {
+ console.log('No matches found for this player')
+ return undefined
+ }
- const timeline = (await api.MatchV5.timeline(matchId, RegionGroups.EUROPE)).response
- console.log("Timeline length:", timeline.info.frames.length)
-}
+ // 3. Fetch the match details for the most recent match
+ const { response: match } = await lolApi.MatchV5.get(matchId, config.regionGroup)
+ console.log(`Match : ${match.metadata.matchId} (queue ${match.info.queueId}, ${match.info.gameDuration}s)`)
+
+ // 4. Fetch the timeline (frames of per-participant state and events)
+ const { response: timeline } = await lolApi.MatchV5.timeline(matchId, config.regionGroup)
+ console.log(`Frames : ${timeline.info.frames.length}`)
-matchV5TimelineLatestMatchExample()
+ return timeline
+}
diff --git a/example/lol/Queues.DataDragon.ts b/example/lol/Queues.DataDragon.ts
index 3aee8faf..9acb5556 100644
--- a/example/lol/Queues.DataDragon.ts
+++ b/example/lol/Queues.DataDragon.ts
@@ -1,7 +1,24 @@
import { LolApi } from '../../src'
-const api = new LolApi()
-
+/**
+ * DATA DRAGON — Queues (static).
+ *
+ * Returns the static queue reference: every `queueId` mapped to the map it is
+ * played on plus a human description (e.g. 420 -> "5v5 Ranked Solo games").
+ * Served from the static CDN: no key, no rate limits.
+ */
export async function queuesDataDragon () {
- return api.DataDragon.getQueues()
+ // Data Dragon needs no key
+ const api = new LolApi()
+
+ // 1. Fetch the static queue table
+ const queues = await api.DataDragon.getQueues()
+
+ console.log(`Queues defined: ${queues.length}`)
+ const ranked = queues.find((q) => q.queueId === 420)
+ if (ranked) {
+ console.log(`Queue 420 : ${ranked.description ?? 'n/a'} on ${ranked.map}`)
+ }
+
+ return queues
}
diff --git a/example/lol/Realms.DataDragon.ts b/example/lol/Realms.DataDragon.ts
index 9065f06e..d0c879f3 100644
--- a/example/lol/Realms.DataDragon.ts
+++ b/example/lol/Realms.DataDragon.ts
@@ -1,8 +1,23 @@
-import { LolApi } from '../../src'
-import { RealmServers } from '../../src/constants'
-
-const api = new LolApi()
+import { LolApi, Constants } from '../../src'
+/**
+ * DATA DRAGON — Realms.
+ *
+ * Returns the per-server Data Dragon realm config: the live data version,
+ * the CDN base URL and the latest patch used for each asset family.
+ * Raw CDN data, so no API key, no rate limits and no `{ response }` wrapper.
+ */
export async function realmsDataDragon () {
- return api.DataDragon.getRealms(RealmServers.AMERICA_NORTH)
+ // Data Dragon needs no key — instantiate the client and read straight from the CDN
+ const api = new LolApi()
+
+ // 1. Fetch the realm config for a specific server (here North America)
+ const realm = await api.DataDragon.getRealms(Constants.RealmServers.AMERICA_NORTH)
+
+ console.log(`Data version : ${realm.v}`)
+ console.log(`Default lang : ${realm.l}`)
+ console.log(`CDN base : ${realm.cdn}`)
+ console.log(`Champion patch: ${realm.n.champion}`)
+
+ return realm
}
diff --git a/example/lol/RunesReforged.DataDragon.ts b/example/lol/RunesReforged.DataDragon.ts
index c839f90e..1e0a604f 100644
--- a/example/lol/RunesReforged.DataDragon.ts
+++ b/example/lol/RunesReforged.DataDragon.ts
@@ -1,7 +1,24 @@
import { LolApi } from '../../src'
-const api = new LolApi()
-
+/**
+ * DATA DRAGON — Runes Reforged (perks).
+ *
+ * Returns the rune trees (Precision, Domination, Sorcery, Resolve, Inspiration)
+ * for the latest patch. Each tree exposes `slots`, each slot a list of runes.
+ * Raw CDN data: no key, no rate limits and no `{ response }` wrapper.
+ */
export async function runesReforgedDataDragon () {
- return api.DataDragon.getRunesReforged()
+ // Data Dragon needs no key
+ const api = new LolApi()
+
+ // 1. Fetch the rune trees (defaults to the latest patch + en_US locale)
+ const trees = await api.DataDragon.getRunesReforged()
+
+ console.log(`Rune trees: ${trees.length}`)
+ trees.forEach((tree) => {
+ const runeCount = tree.slots.reduce((total, slot) => total + slot.runes.length, 0)
+ console.log(` ${tree.name} (${tree.key}) — ${runeCount} runes`)
+ })
+
+ return trees
}
diff --git a/example/lol/Seasons.DataDragon.ts b/example/lol/Seasons.DataDragon.ts
index a4021921..ce9e170e 100644
--- a/example/lol/Seasons.DataDragon.ts
+++ b/example/lol/Seasons.DataDragon.ts
@@ -1,7 +1,21 @@
import { LolApi } from '../../src'
-const api = new LolApi()
-
+/**
+ * DATA DRAGON — Seasons (static).
+ *
+ * Returns the static season reference: each numeric `id` mapped to its season
+ * label (e.g. `{ id: 0, season: "PRESEASON 3" }`). Useful for decoding the
+ * `seasonId` found on matches. Served from the static CDN: no key.
+ */
export async function seasonsDataDragon () {
- return api.DataDragon.getSeasons()
+ // Data Dragon needs no key
+ const api = new LolApi()
+
+ // 1. Fetch the static season table
+ const seasons = await api.DataDragon.getSeasons()
+
+ console.log(`Seasons defined: ${seasons.length}`)
+ console.log(`Latest season : ${seasons[seasons.length - 1]?.season}`)
+
+ return seasons
}
diff --git a/example/lol/SeedMatches.DataDragon.ts b/example/lol/SeedMatches.DataDragon.ts
index 23ce42db..9cc254f0 100644
--- a/example/lol/SeedMatches.DataDragon.ts
+++ b/example/lol/SeedMatches.DataDragon.ts
@@ -1,8 +1,27 @@
import { LolApi } from '../../src'
-const api = new LolApi()
-
+/**
+ * DATA DRAGON — Seed match data.
+ *
+ * Riot ships 10 sample match-v4 payload files (ids 1..10) for testing without
+ * burning real API quota. `Seed.matches(id)` returns `{ matches }` raw — no
+ * key, no rate limits and no `{ response }` wrapper.
+ */
export async function matchesSeedData () {
+ // Seed data needs no key
+ const api = new LolApi()
+
+ // 1. Pick one of the 10 seed files (valid ids are 1..10)
const id = 1
- return api.Seed.matches(id)
+
+ // 2. Fetch it — the payload is wrapped in a `matches` array
+ const { matches } = await api.Seed.matches(id)
+
+ console.log(`Seed file ${id}: ${matches.length} matches`)
+ const first = matches[0]
+ if (first) {
+ console.log(`First match: gameId ${first.gameId} (${first.gameMode}, queue ${first.queueId})`)
+ }
+
+ return matches
}
diff --git a/example/lol/SpectatorFeaturedGamesV5.example.ts b/example/lol/SpectatorFeaturedGamesV5.example.ts
index cb9831b7..b0c7839d 100644
--- a/example/lol/SpectatorFeaturedGamesV5.example.ts
+++ b/example/lol/SpectatorFeaturedGamesV5.example.ts
@@ -1,7 +1,26 @@
import { LolApi } from '../../src'
-import { Regions } from '../../src/constants'
+import { config } from '../config/config'
+/**
+ * SPECTATOR-V5 — List the featured games currently being played on a platform.
+ *
+ * Riot picks a handful of live games (no key-specific player needed) that can
+ * be spectated. Also returns the suggested polling interval.
+ */
export async function spectatorV5FeaturedGames () {
const api = new LolApi()
- return await api.SpectatorV5.featuredGames(Regions.LAT_NORTH)
+
+ // Featured games is a platform endpoint, so it takes a platform `Regions` value
+ const { response: featured } = await api.SpectatorV5.featuredGames(config.region)
+
+ console.log(`Featured games : ${featured.gameList.length}`)
+ console.log(`Refresh interval : ${featured.clientRefreshInterval}s`)
+
+ // Highlight the first featured game, if any
+ const first = featured.gameList[0]
+ if (first) {
+ console.log(`First game : ${first.gameMode} on map ${first.mapId} (${first.participants.length} players)`)
+ }
+
+ return featured
}
diff --git a/example/lol/SpectatorSummonerV5.example.ts b/example/lol/SpectatorSummonerV5.example.ts
index 97a7199a..24e7103d 100644
--- a/example/lol/SpectatorSummonerV5.example.ts
+++ b/example/lol/SpectatorSummonerV5.example.ts
@@ -1,10 +1,36 @@
-import { RiotApi } from '../../src'
-import { LolApi } from '../../src'
+import { LolApi, RiotApi } from '../../src'
import { config } from '../config/config'
+/**
+ * SPECTATOR-V5 — Get the active (live) game for a player by PUUID.
+ *
+ * We resolve the account's PUUID through the Account API, then ask the
+ * spectator endpoint for the game they are currently in. When the player is
+ * NOT in a game the endpoint returns 404, so the call is wrapped in try/catch.
+ */
export async function spectatorV5SummonerExample () {
- const rApi = new RiotApi()
- const api = new LolApi()
- const { response: { puuid } } = await rApi.Account.getByRiotId(config.summonerName, config.region, config.regionGroup)
- return await api.SpectatorV5.activeGame(puuid, config.region)
+ const riotApi = new RiotApi()
+ const lolApi = new LolApi()
+
+ // 1. Resolve the Riot ID (gameName#tagLine) into a PUUID
+ const { response: account } = await riotApi.Account.getByRiotId(
+ config.summonerName,
+ config.tagLine,
+ config.regionGroup
+ )
+
+ // 2. Ask for the live game — this 404s when the player is not currently playing
+ try {
+ const { response: game } = await lolApi.SpectatorV5.activeGame(account.puuid, config.region)
+
+ console.log(`${account.gameName}#${account.tagLine} is in a live game`)
+ console.log(`Game id : ${game.gameId}`)
+ console.log(`Game mode : ${game.gameMode}`)
+ console.log(`Players : ${game.participants.length}`)
+
+ return game
+ } catch (e) {
+ console.log(`${account.gameName}#${account.tagLine} is not currently in a game`)
+ return undefined
+ }
}
diff --git a/example/lol/StatusV4.example.ts b/example/lol/StatusV4.example.ts
index 3d245b0d..46373ca8 100644
--- a/example/lol/StatusV4.example.ts
+++ b/example/lol/StatusV4.example.ts
@@ -1,11 +1,22 @@
-import { LolApi } from "../../src/apis/lol/lol";
-import { Regions } from "../../src/constants";
+import { LolApi } from '../../src'
+import { config } from '../config/config'
-export async function statusV4Example() {
- const api = new LolApi();
+/**
+ * LOL-STATUS-V4 — Get the platform status for a region.
+ *
+ * Reports the server's supported locales plus any ongoing maintenances and
+ * incidents (useful for surfacing "servers are down" messages to users).
+ */
+export async function statusV4Example () {
+ const api = new LolApi()
- const status = (await api.StatusV4.get(Regions.EU_WEST)).response;
- console.log(status.locales);
- console.log(status.maintenances)
- console.log(status.incidents)
+ // Platform status is a platform endpoint, so it takes a platform `Regions` value
+ const { response: status } = await api.StatusV4.get(config.region)
+
+ console.log(`Region : ${status.name} (${status.id})`)
+ console.log(`Locales : ${status.locales.join(', ')}`)
+ console.log(`Maintenance : ${status.maintenances.maintenance_status ?? 'none'}`)
+ console.log(`Incident sev. : ${status.incidents.incident_severity ?? 'none'}`)
+
+ return status
}
diff --git a/example/lol/SummonerByPUUID.example.ts b/example/lol/SummonerByPUUID.example.ts
index 8f6cbe95..aa0a39e1 100644
--- a/example/lol/SummonerByPUUID.example.ts
+++ b/example/lol/SummonerByPUUID.example.ts
@@ -1,11 +1,31 @@
-import { RiotApi } from '../../src'
-import { LolApi } from '../../src'
+import { LolApi, RiotApi } from '../../src'
import { config } from '../config/config'
-const rApi = new RiotApi()
-const api = new LolApi()
-
+/**
+ * SUMMONER-V4 — Get a summoner by PUUID.
+ *
+ * Summoner-V4 no longer accepts a name, so we first resolve the account's
+ * PUUID through the Riot Account API (ACCOUNT-V1), then look the summoner up
+ * on its platform region.
+ */
export async function summonerByPUUIDExample () {
- const { response: { puuid }} = await rApi.Account.getByRiotId(config.summonerName, config.tagLine, config.regionGroup)
- return await api.Summoner.getByPUUID(puuid, config.region)
+ const riotApi = new RiotApi()
+ const lolApi = new LolApi()
+
+ // 1. Resolve the Riot ID (gameName#tagLine) into a PUUID via ACCOUNT-V1
+ const { response: account } = await riotApi.Account.getByRiotId(
+ config.summonerName,
+ config.tagLine,
+ config.regionGroup
+ )
+
+ // 2. Fetch the summoner on its platform region using that PUUID
+ const { response: summoner } = await lolApi.Summoner.getByPUUID(account.puuid, config.region)
+
+ console.log(`Summoner : ${account.gameName}#${account.tagLine}`)
+ console.log(`PUUID : ${summoner.puuid}`)
+ console.log(`Level : ${summoner.summonerLevel}`)
+ console.log(`Profile icon: ${summoner.profileIconId}`)
+
+ return summoner
}
diff --git a/example/lol/SummonerLeague.example.ts b/example/lol/SummonerLeague.example.ts
index 7dee6651..823019cc 100644
--- a/example/lol/SummonerLeague.example.ts
+++ b/example/lol/SummonerLeague.example.ts
@@ -1,12 +1,36 @@
-import { RiotApi } from '../../src'
-import { LolApi } from '../../src'
+import { LolApi, RiotApi } from '../../src'
import { config } from '../config/config'
-const rApi = new RiotApi()
-const api = new LolApi()
-
+/**
+ * LEAGUE-V4 — Get ranked entries for a summoner (bySummoner).
+ *
+ * This is the legacy lookup keyed by the encrypted summonerId. We first
+ * resolve the account's PUUID (ACCOUNT-V1), then the summonerId (SUMMONER-V4),
+ * and finally fetch every ranked queue the player has entries in.
+ */
export async function summonerLeagueExample () {
- const { response: { puuid } } = await rApi.Account.getByRiotId(config.summonerName, config.tagLine, config.regionGroup)
- const { response: { id }} = await api.Summoner.getByPUUID(puuid, config.region)
- return await api.League.bySummoner(id, config.region)
+ const riotApi = new RiotApi()
+ const lolApi = new LolApi()
+
+ // 1. Resolve the Riot ID into a PUUID
+ const { response: account } = await riotApi.Account.getByRiotId(
+ config.summonerName,
+ config.tagLine,
+ config.regionGroup
+ )
+
+ // 2. Resolve the summoner to obtain its encrypted summonerId
+ const { response: summoner } = await lolApi.Summoner.getByPUUID(account.puuid, config.region)
+
+ // 3. Fetch all ranked entries for that summoner (one per ranked queue)
+ const { response: leagues } = await lolApi.League.bySummoner(summoner.id, config.region)
+
+ console.log(`Ranked entries for ${account.gameName}#${account.tagLine}: ${leagues.length}`)
+ for (const league of leagues) {
+ console.log(
+ ` ${league.queueType}: ${league.tier} ${league.rank} (${league.leaguePoints} LP) — ${league.wins}W/${league.losses}L`
+ )
+ }
+
+ return leagues
}
diff --git a/example/lol/Versions.DataDragon.ts b/example/lol/Versions.DataDragon.ts
index 71003ddb..31cdd42c 100644
--- a/example/lol/Versions.DataDragon.ts
+++ b/example/lol/Versions.DataDragon.ts
@@ -1,7 +1,21 @@
import { LolApi } from '../../src'
-const api = new LolApi()
-
+/**
+ * DATA DRAGON — Versions.
+ *
+ * Returns the full list of Data Dragon versions, newest first. The first
+ * entry (`[0]`) is the latest patch and is what every other Data Dragon
+ * asset is fetched against. Raw CDN data: no key, no rate limits.
+ */
export async function versionsDataDragon () {
- return api.DataDragon.getVersions()
+ // Data Dragon needs no key
+ const api = new LolApi()
+
+ // 1. Fetch every published Data Dragon version (descending order)
+ const versions = await api.DataDragon.getVersions()
+
+ console.log(`Versions available: ${versions.length}`)
+ console.log(`Latest patch : ${versions[0]}`)
+
+ return versions
}
diff --git a/example/lol/deprecated/LolStatus.example.ts b/example/lol/deprecated/LolStatus.example.ts
index cf18beac..72ea65cb 100644
--- a/example/lol/deprecated/LolStatus.example.ts
+++ b/example/lol/deprecated/LolStatus.example.ts
@@ -1,7 +1,21 @@
-import { LolApi } from '../../src'
-import { Regions } from '../../src/constants'
+import { LolApi, Constants } from '../../../src'
+/**
+ * DEPRECATED — LOL-STATUS-V3 (`/lol/status/v3/shard-data`).
+ *
+ * This shard-data endpoint has been removed by Riot in favour of
+ * `lol-status-v4` (use `LolApi.StatusV4.get` instead). It returned the
+ * platform name, hostname and the per-service status for a given region.
+ */
export async function lolStatusExample () {
- const api = new LolApi()
- return await api.Status.get(Regions.LAT_NORTH)
+ const lolApi = new LolApi()
+
+ // 1. Query the (deprecated) shard status for a platform region
+ const { response: status } = await lolApi.Status.get(Constants.Regions.LAT_NORTH)
+
+ console.log(`Platform : ${status.name} (${status.slug})`)
+ console.log(`Hostname : ${status.hostname}`)
+ console.log(`Locales : ${status.locales.join(', ')}`)
+
+ return status
}
diff --git a/example/lol/deprecated/Match.example.ts b/example/lol/deprecated/Match.example.ts
index 9b75dbae..630260ff 100644
--- a/example/lol/deprecated/Match.example.ts
+++ b/example/lol/deprecated/Match.example.ts
@@ -1,19 +1,37 @@
-import { LolApi } from '../../src'
-import { config } from '../config/config'
+import { LolApi, RiotApi } from '../../../src'
+import { config } from '../../config/config'
+/**
+ * DEPRECATED — MATCH-V4 (`/lol/match/v4/matches/{matchId}`).
+ *
+ * Match-V4 was replaced by Match-V5 (use `LolApi.MatchV5`). It is kept here
+ * for reference: note that V4 keys games by a numeric `gameId`, whereas V5
+ * uses string match ids. We resolve the account through the Riot Account API
+ * (Summoner name lookup was removed) and read its match history.
+ */
export async function matchExample () {
- const api = new LolApi()
+ const riotApi = new RiotApi()
+ const lolApi = new LolApi()
const { region } = config
- const user = await api.Summoner.getByName(config.summonerName, region)
- console.log()
- const {
- response: {
- matches
- }
- } = await api.Match.list(user.response.accountId, region)
- const { gameId } = matches[0]
- const match = await api.Match.get(gameId, region)
+
+ // 1. Resolve the Riot ID into a PUUID, then load the summoner
+ const { response: account } = await riotApi.Account.getByRiotId(
+ config.summonerName,
+ config.tagLine,
+ config.regionGroup
+ )
+ const { response: summoner } = await lolApi.Summoner.getByPUUID(account.puuid, region)
+
+ // 2. List the match history for this account (V4 uses the encrypted accountId)
+ const { response: listing } = await lolApi.Match.list(summoner.accountId, region)
+ console.log(`Found ${listing.matches.length} matches (total ${listing.totalGames})`)
+
+ // 3. Fetch the full details of the most recent game (V4 get takes a numeric gameId)
+ const { gameId } = listing.matches[0]
+ const { response: match } = await lolApi.Match.get(gameId, region)
+
+ console.log(`Game ${match.gameId} | mode ${match.gameMode} | queue ${match.queueId}`)
+ console.log(`Duration: ${Math.round(match.gameDuration / 60)} min | ${match.participants.length} players`)
+
return match
}
-
-matchExample()
diff --git a/example/lol/deprecated/MatchListing.example.ts b/example/lol/deprecated/MatchListing.example.ts
index 73bd3c4a..8178da8d 100644
--- a/example/lol/deprecated/MatchListing.example.ts
+++ b/example/lol/deprecated/MatchListing.example.ts
@@ -1,11 +1,35 @@
-import { LolApi } from '../../src'
-import { config } from '../config/config'
-
-const api = new LolApi()
+import { LolApi, RiotApi } from '../../../src'
+import { config } from '../../config/config'
+/**
+ * DEPRECATED — MATCH-V4 match listing (`/lol/match/v4/matchlists/by-account/{accountId}`).
+ *
+ * Replaced by Match-V5 `LolApi.MatchV5.list(puuid, ...)`, which returns plain
+ * string match ids. The V4 listing instead returns rich reference objects
+ * (gameId, champion, queue, role, lane, timestamp...) keyed by the encrypted
+ * accountId, which we resolve via the Riot Account API.
+ */
export async function matchListingExample () {
+ const riotApi = new RiotApi()
+ const lolApi = new LolApi()
const { region } = config
- const user = await api.Summoner.getByName(config.summonerName, region)
- const matchList = await api.Match.list(user.response.accountId, region)
- return matchList
+
+ // 1. Resolve the Riot ID into a PUUID, then load the summoner
+ const { response: account } = await riotApi.Account.getByRiotId(
+ config.summonerName,
+ config.tagLine,
+ config.regionGroup
+ )
+ const { response: summoner } = await lolApi.Summoner.getByPUUID(account.puuid, region)
+
+ // 2. List the match history (V4 keys this by the encrypted accountId)
+ const { response: listing } = await lolApi.Match.list(summoner.accountId, region)
+
+ console.log(`Returned ${listing.matches.length} of ${listing.totalGames} games`)
+ const first = listing.matches[0]
+ if (first) {
+ console.log(`Most recent: game ${first.gameId} | champion ${first.champion} | queue ${first.queue}`)
+ }
+
+ return listing
}
diff --git a/example/lol/deprecated/MatchListingFiltering.example.ts b/example/lol/deprecated/MatchListingFiltering.example.ts
index 8decf16a..81533250 100644
--- a/example/lol/deprecated/MatchListingFiltering.example.ts
+++ b/example/lol/deprecated/MatchListingFiltering.example.ts
@@ -1,16 +1,36 @@
-import { LolApi } from '../../src'
-import { config } from '../config/config'
-import { Champions } from '../../src/constants'
-import { MatchQueryDTO } from '../../src/models-dto'
-
-const api = new LolApi()
+import { LolApi, RiotApi, Constants } from '../../../src'
+import { config } from '../../config/config'
+import { MatchQueryDTO } from '../../../src/models-dto'
+/**
+ * DEPRECATED — MATCH-V4 match listing with filters.
+ *
+ * Replaced by Match-V5 `LolApi.MatchV5.list`. The V4 listing accepted a rich
+ * query (`MatchQueryDTO`) letting you filter by champion, queue, season and a
+ * time window — here we ask only for games played on a specific champion.
+ */
export async function matchListingFilteringExample () {
+ const riotApi = new RiotApi()
+ const lolApi = new LolApi()
const { region } = config
- const user = await api.Summoner.getByName(config.summonerName, region)
+
+ // 1. Resolve the Riot ID into a PUUID, then load the summoner
+ const { response: account } = await riotApi.Account.getByRiotId(
+ config.summonerName,
+ config.tagLine,
+ config.regionGroup
+ )
+ const { response: summoner } = await lolApi.Summoner.getByPUUID(account.puuid, region)
+
+ // 2. Build a filter: only games where the player picked Twisted Fate
const filter: MatchQueryDTO = {
- champion: Champions.TWISTED_FATE
+ champion: Constants.Champions.TWISTED_FATE
}
- const matchList = await api.Match.list(user.response.accountId, region, filter)
- return matchList
+
+ // 3. List the filtered match history (V4 keys this by the encrypted accountId)
+ const { response: listing } = await lolApi.Match.list(summoner.accountId, region, filter)
+
+ console.log(`Twisted Fate games: ${listing.matches.length}`)
+
+ return listing
}
diff --git a/example/lol/deprecated/MatchTimeline.example.ts b/example/lol/deprecated/MatchTimeline.example.ts
index 1f526b0c..b30f21b2 100644
--- a/example/lol/deprecated/MatchTimeline.example.ts
+++ b/example/lol/deprecated/MatchTimeline.example.ts
@@ -1,17 +1,35 @@
-import { LolApi } from '../../src'
-import { config } from '../config/config'
-
-const api = new LolApi()
+import { LolApi, RiotApi } from '../../../src'
+import { config } from '../../config/config'
+/**
+ * DEPRECATED — MATCH-V4 timeline (`/lol/match/v4/timelines/by-match/{matchId}`).
+ *
+ * Replaced by Match-V5 `LolApi.MatchV5.timeline`. The timeline breaks a game
+ * into fixed-interval frames (events + per-participant state), and V4 keys it
+ * by the same numeric `gameId` used by the match listing.
+ */
export async function matchTimeLineExample () {
+ const riotApi = new RiotApi()
+ const lolApi = new LolApi()
const { region } = config
- const user = await api.Summoner.getByName(config.summonerName, region)
- const {
- response: {
- matches
- }
- } = await api.Match.list(user.response.accountId, region)
- const { gameId } = matches[0]
- const matchTimeline = await api.Match.timeline(gameId, region)
- return matchTimeline
+
+ // 1. Resolve the Riot ID into a PUUID, then load the summoner
+ const { response: account } = await riotApi.Account.getByRiotId(
+ config.summonerName,
+ config.tagLine,
+ config.regionGroup
+ )
+ const { response: summoner } = await lolApi.Summoner.getByPUUID(account.puuid, region)
+
+ // 2. Find the most recent game id from the match listing
+ const { response: listing } = await lolApi.Match.list(summoner.accountId, region)
+ const { gameId } = listing.matches[0]
+
+ // 3. Fetch the timeline for that game (V4 timeline takes the numeric gameId)
+ const { response: timeline } = await lolApi.Match.timeline(gameId, region)
+
+ console.log(`Timeline for game ${gameId}`)
+ console.log(`Frames: ${timeline.frames.length} | interval: ${timeline.frameInterval}ms`)
+
+ return timeline
}
diff --git a/example/lol/deprecated/SpectatorFeaturedGames.example.ts b/example/lol/deprecated/SpectatorFeaturedGames.example.ts
index a1383b8b..cc08b4e9 100644
--- a/example/lol/deprecated/SpectatorFeaturedGames.example.ts
+++ b/example/lol/deprecated/SpectatorFeaturedGames.example.ts
@@ -1,7 +1,25 @@
-import { LolApi } from '../../src'
-import { Regions } from '../../src/constants'
+import { LolApi, Constants } from '../../../src'
+/**
+ * DEPRECATED — SPECTATOR-V4 featured games.
+ *
+ * Use `LolApi.SpectatorV5.featuredGames` instead. This returns a small list
+ * of currently live games that Riot is highlighting for the given platform
+ * region, plus the suggested refresh interval.
+ */
export async function spectatorFeaturedGames () {
- const api = new LolApi()
- return await api.Spectator.featuredGames(Regions.LAT_NORTH)
+ const lolApi = new LolApi()
+
+ // 1. Fetch the featured (live) games for a platform region
+ const { response: featured } = await lolApi.Spectator.featuredGames(Constants.Regions.LAT_NORTH)
+
+ console.log(`Featured games: ${featured.gameList.length}`)
+ console.log(`Refresh in : ${featured.clientRefreshInterval}s`)
+
+ const first = featured.gameList[0]
+ if (first) {
+ console.log(`First game: id ${first.gameId} | mode ${first.gameMode} | ${first.participants.length} players`)
+ }
+
+ return featured
}
diff --git a/example/lol/deprecated/SpectatorSummoner.example.ts b/example/lol/deprecated/SpectatorSummoner.example.ts
index 7fb8479f..6d25a595 100644
--- a/example/lol/deprecated/SpectatorSummoner.example.ts
+++ b/example/lol/deprecated/SpectatorSummoner.example.ts
@@ -1,12 +1,43 @@
-import { LolApi } from '../../src'
-import { config } from '../config/config'
+import { LolApi, RiotApi } from '../../../src'
+import { config } from '../../config/config'
+/**
+ * DEPRECATED — SPECTATOR-V4 active game (`/lol/spectator/v4/active-games/by-summoner/{summonerId}`).
+ *
+ * Use `LolApi.SpectatorV5.activeGame(puuid, region)` instead. The V4 endpoint
+ * looked a player up by their encrypted summoner id and returned their live
+ * game — or nothing when the player is not currently in a game.
+ */
export async function spectatorSummonerExample () {
- const api = new LolApi()
- const { summonerName, region } = config
- const { response: { id } } = await api.Summoner.getByName(summonerName, region)
+ const riotApi = new RiotApi()
+ const lolApi = new LolApi()
+ const { region } = config
- return await api.Spectator.activeGame(id, region)
-}
+ // 1. Resolve the Riot ID into a PUUID, then load the summoner (for its id)
+ const { response: account } = await riotApi.Account.getByRiotId(
+ config.summonerName,
+ config.tagLine,
+ config.regionGroup
+ )
+ const { response: summoner } = await lolApi.Summoner.getByPUUID(account.puuid, region)
+
+ // 2. Look up the live game by the encrypted summoner id.
+ // The deprecated wrapper returns a "not available" object when not in a game;
+ // a found game is returned wrapped as { response, rateLimits }.
+ try {
+ const result = await lolApi.Spectator.activeGame(summoner.id, region)
-spectatorSummonerExample()
+ if ('response' in result) {
+ const game = result.response
+ console.log(`${account.gameName} is in game ${game.gameId} (mode ${game.gameMode})`)
+ console.log(`Players: ${game.participants.length} | live for ${game.gameLength}s`)
+ return game
+ }
+
+ console.log(`${account.gameName} is not currently in a game (${result.message})`)
+ return result
+ } catch (e) {
+ console.log('Could not fetch active game (player likely offline / not in game)')
+ return null
+ }
+}
diff --git a/example/lol/deprecated/SummonerByAccountID.example.ts b/example/lol/deprecated/SummonerByAccountID.example.ts
index 1589387c..80e87ce1 100644
--- a/example/lol/deprecated/SummonerByAccountID.example.ts
+++ b/example/lol/deprecated/SummonerByAccountID.example.ts
@@ -1,14 +1,35 @@
-import { RiotApi } from '../../../src'
-import { LolApi } from '../../../src'
+import { LolApi, RiotApi } from '../../../src'
import { config } from '../../config/config'
-const rApi = new RiotApi()
-const api = new LolApi()
-
+/**
+ * DEPRECATED-style lookup — SUMMONER-V4 by account id
+ * (`/lol/summoner/v4/summoners/by-account/{accountId}`).
+ *
+ * The encrypted accountId is a legacy identifier (the modern key is the PUUID).
+ * Since name lookup was removed, we first resolve the account through the Riot
+ * Account API to obtain a PUUID, fetch the summoner to read its `accountId`,
+ * then demonstrate the by-account lookup.
+ */
export async function summonerByAccountIDExample () {
+ const riotApi = new RiotApi()
+ const lolApi = new LolApi()
const { region } = config
- // const { response: { accountId } } = await api.Summoner.getByName(config.summonerName, region)
- const { response: { puuid } } = await rApi.Account.getByRiotId(config.summonerName, config.tagLine, config.regionGroup)
- const { response: { accountId } } = await api.Summoner.getByPUUID(puuid, region)
- return await api.Summoner.getByAccountID(accountId, region)
+
+ // 1. Resolve the Riot ID into a PUUID
+ const { response: account } = await riotApi.Account.getByRiotId(
+ config.summonerName,
+ config.tagLine,
+ config.regionGroup
+ )
+
+ // 2. Fetch the summoner by PUUID to obtain its encrypted accountId
+ const { response: byPuuid } = await lolApi.Summoner.getByPUUID(account.puuid, region)
+
+ // 3. Look the same summoner up by its accountId (the deprecated identifier)
+ const { response: summoner } = await lolApi.Summoner.getByAccountID(byPuuid.accountId, region)
+
+ console.log(`Summoner: ${account.gameName}#${account.tagLine}`)
+ console.log(`Level : ${summoner.summonerLevel} | accountId ${summoner.accountId}`)
+
+ return summoner
}
diff --git a/example/lol/deprecated/SummonerById.example.ts b/example/lol/deprecated/SummonerById.example.ts
index 87540293..3de66f14 100644
--- a/example/lol/deprecated/SummonerById.example.ts
+++ b/example/lol/deprecated/SummonerById.example.ts
@@ -1,12 +1,35 @@
-import { RiotApi } from '../../../src'
-import { LolApi } from '../../../src'
+import { LolApi, RiotApi } from '../../../src'
import { config } from '../../config/config'
-const rApi = new RiotApi()
-const api = new LolApi()
-
+/**
+ * DEPRECATED-style lookup — SUMMONER-V4 by summoner id
+ * (`/lol/summoner/v4/summoners/{summonerId}`).
+ *
+ * The encrypted summoner id is a legacy identifier (the modern key is the
+ * PUUID). Since name lookup was removed, we resolve the account through the
+ * Riot Account API, fetch the summoner by PUUID to obtain its `id`, then
+ * demonstrate the by-id lookup.
+ */
export async function summonerByIdExample () {
- const { response: { puuid } } = await rApi.Account.getByRiotId(config.summonerName, config.region, config.regionGroup)
- const { response: { id } } = await api.Summoner.getByPUUID(puuid, config.region)
- return await api.Summoner.getById(id, config.region)
+ const riotApi = new RiotApi()
+ const lolApi = new LolApi()
+ const { region } = config
+
+ // 1. Resolve the Riot ID into a PUUID (Account API uses a region GROUP)
+ const { response: account } = await riotApi.Account.getByRiotId(
+ config.summonerName,
+ config.tagLine,
+ config.regionGroup
+ )
+
+ // 2. Fetch the summoner by PUUID to obtain its encrypted summoner id
+ const { response: byPuuid } = await lolApi.Summoner.getByPUUID(account.puuid, region)
+
+ // 3. Look the same summoner up by its id (the deprecated identifier)
+ const { response: summoner } = await lolApi.Summoner.getById(byPuuid.id, region)
+
+ console.log(`Summoner: ${account.gameName}#${account.tagLine}`)
+ console.log(`Level : ${summoner.summonerLevel} | id ${summoner.id}`)
+
+ return summoner
}
diff --git a/example/lol/deprecated/SummonerByName.example.ts b/example/lol/deprecated/SummonerByName.example.ts
index c06b7a30..d73017e7 100644
--- a/example/lol/deprecated/SummonerByName.example.ts
+++ b/example/lol/deprecated/SummonerByName.example.ts
@@ -1,14 +1,30 @@
-import { LolApi } from '../../src'
-import { config } from '../config/config'
-
-const api = new LolApi({
- debug: {
- logRatelimits: true,
- logTime: true,
- logUrls: true
- }
-})
+import { LolApi, RiotApi } from '../../../src'
+import { config } from '../../config/config'
+/**
+ * DEPRECATED — SUMMONER-V4 by name (`/lol/summoner/v4/summoners/by-name/{name}`).
+ *
+ * Riot REMOVED summoner-name lookup: `LolApi.Summoner.getByName` no longer
+ * exists. The modern replacement is to resolve the Riot ID (gameName#tagLine)
+ * to a PUUID through the Account API, then fetch the summoner by PUUID. This
+ * example demonstrates that replacement flow.
+ */
export async function summonerByNameExample () {
- return await api.Summoner.getByName(config.summonerName, config.region)
+ const riotApi = new RiotApi()
+ const lolApi = new LolApi()
+
+ // 1. Resolve the Riot ID (gameName#tagLine) into a PUUID via the Account API
+ const { response: account } = await riotApi.Account.getByRiotId(
+ config.summonerName,
+ config.tagLine,
+ config.regionGroup
+ )
+
+ // 2. Fetch the summoner on its platform region using the PUUID
+ const { response: summoner } = await lolApi.Summoner.getByPUUID(account.puuid, config.region)
+
+ console.log(`Summoner: ${account.gameName}#${account.tagLine}`)
+ console.log(`Level : ${summoner.summonerLevel}`)
+
+ return summoner
}
diff --git a/example/lol/deprecated/ThirdPartyCode.example.ts b/example/lol/deprecated/ThirdPartyCode.example.ts
index 8cdfbbbf..9132af5c 100644
--- a/example/lol/deprecated/ThirdPartyCode.example.ts
+++ b/example/lol/deprecated/ThirdPartyCode.example.ts
@@ -1,13 +1,41 @@
-import { LolApi } from '../../src'
-import { config } from '../config/config'
+import { LolApi, RiotApi } from '../../../src'
+import { config } from '../../config/config'
+// NOTE: ThirdPartyCode is a sunset endpoint and is NOT wired into `LolApi`,
+// so it is not reachable from the package barrel — we import the service class
+// from its module to demonstrate the (now removed) call.
+import { ThirdPartyCode } from '../../../src/apis/lol/thirdPartyCode/thirdPartyCode'
+/**
+ * DEPRECATED — THIRD-PARTY-CODE-V4
+ * (`/lol/platform/v4/third-party-code/by-summoner/{summonerId}`).
+ *
+ * This endpoint was sunset by Riot on March 11th, 2024 and is no longer
+ * available. It returned the verification code a player had set so third-party
+ * apps could prove account ownership. It was keyed by the encrypted summoner
+ * id, which we resolve via the Account API -> Summoner-by-PUUID flow.
+ */
export async function thirdPartyExample () {
- const riot = new LolApi()
- const { response: { id } } = await riot.Summoner.getByName(config.summonerName, config.region)
+ const riotApi = new RiotApi()
+ const lolApi = new LolApi()
+ const thirdPartyApi = new ThirdPartyCode()
+ const { region } = config
+
+ // 1. Resolve the Riot ID into a PUUID, then load the summoner (for its id)
+ const { response: account } = await riotApi.Account.getByRiotId(
+ config.summonerName,
+ config.tagLine,
+ config.regionGroup
+ )
+ const { response: summoner } = await lolApi.Summoner.getByPUUID(account.puuid, region)
+
+ // 2. Read the third-party verification code by summoner id.
+ // Wrapped in try/catch since the endpoint is sunset / commonly 404s.
try {
- return await riot.ThirdPartyCode.get(id, config.region)
+ const { response: thirdParty } = await thirdPartyApi.get(summoner.id, region)
+ console.log(`Verification code: ${thirdParty.code ?? '(none set / endpoint unavailable)'}`)
+ return thirdParty
} catch (e) {
- console.error(e)
- return {}
+ console.log('Third-party-code endpoint is no longer available (sunset 2024-03-11)')
+ return { code: null }
}
}
diff --git a/example/lol/index.ts b/example/lol/index.ts
index 2ab1621b..ddc5f91d 100644
--- a/example/lol/index.ts
+++ b/example/lol/index.ts
@@ -14,6 +14,8 @@ export * from './ChampionMasteryByPUUIDChampion.example'
export * from './ChampionsScore.example'
export * from './SpectatorFeaturedGamesV5.example'
export * from './SpectatorSummonerV5.example'
+export * from './MatchV5TimelineLatestMatch.example'
+export * from './MatchV5Replays.example'
export * from './Realms.DataDragon'
export * from './Versions.DataDragon'
export * from './Languages.DataDragon'
diff --git a/example/riot/Account.examples.ts b/example/riot/Account.examples.ts
index 7b3a58f3..c0c23193 100644
--- a/example/riot/Account.examples.ts
+++ b/example/riot/Account.examples.ts
@@ -1,13 +1,34 @@
-import { RiotApi } from '../../src/apis/riot/riot'
-import { RegionGroups } from '../../src/constants'
+import { RiotApi, Constants } from '../../src'
import { config } from '../config/config'
-export async function accountV1Examples() {
- const api = new RiotApi()
+/**
+ * ACCOUNT-V1 — Look up a Riot account.
+ *
+ * The Riot Account API is the entry point for almost everything else: it maps a
+ * human-friendly Riot ID (gameName#tagLine) to the stable PUUID used by every
+ * other endpoint. Here we resolve an account both ways: by Riot ID and by PUUID.
+ *
+ * Account endpoints are routed by region GROUP (AMERICAS / ASIA / EUROPE),
+ * never by platform region.
+ */
+export async function accountV1Examples () {
+ const riotApi = new RiotApi()
- const resByRiotId = (await api.Account.getByRiotId(config.summonerName, config.tagLine, RegionGroups.AMERICAS)).response
- console.log('Account info by Riot Id: ', resByRiotId)
+ // 1. Resolve the Riot ID (gameName#tagLine) into an account (and its PUUID)
+ const { response: byRiotId } = await riotApi.Account.getByRiotId(
+ config.summonerName,
+ config.tagLine,
+ config.regionGroup
+ )
+ console.log(`Riot ID : ${byRiotId.gameName}#${byRiotId.tagLine}`)
+ console.log(`PUUID : ${byRiotId.puuid}`)
- const resByPuuid = (await api.Account.getByPUUID(resByRiotId.puuid, RegionGroups.AMERICAS)).response
- console.log('Account info by PUUID: ', resByPuuid)
-}
\ No newline at end of file
+ // 2. Reverse the lookup: fetch the same account from its PUUID
+ const { response: byPuuid } = await riotApi.Account.getByPUUID(
+ byRiotId.puuid,
+ config.regionGroup
+ )
+ console.log(`Round-trip Riot ID: ${byPuuid.gameName}#${byPuuid.tagLine}`)
+
+ return byPuuid
+}
diff --git a/example/riot/AccountRegion.examples.ts b/example/riot/AccountRegion.examples.ts
index 7f1d6fe5..4f715e8e 100644
--- a/example/riot/AccountRegion.examples.ts
+++ b/example/riot/AccountRegion.examples.ts
@@ -1,11 +1,34 @@
-import { RiotApi } from '../../src/apis/riot/riot'
-import { RegionGroups, Games } from '../../src/constants'
+import { RiotApi, Constants } from '../../src'
import { config } from '../config/config'
-export async function accountRegionV1Examples() {
- const api = new RiotApi()
+/**
+ * ACCOUNT-V1 — Get the active shard / region for a player and game.
+ *
+ * Given a PUUID and a game (LoL / TFT / LoR), this returns the platform region
+ * where that player is currently active. Useful when you only know a Riot ID
+ * but not which shard the account lives on.
+ *
+ * Like the rest of Account-V1, it is routed by region GROUP (AMERICAS / ASIA /
+ * EUROPE), not by platform region.
+ */
+export async function accountRegionV1Examples () {
+ const riotApi = new RiotApi()
- const { puuid } = (await api.Account.getByRiotId(config.summonerName, config.tagLine, RegionGroups.AMERICAS)).response
+ // 1. Resolve the Riot ID (gameName#tagLine) into a PUUID
+ const { puuid } = (
+ await riotApi.Account.getByRiotId(config.summonerName, config.tagLine, config.regionGroup)
+ ).response
- return (await api.Account.getActiveRegion(puuid, Games.LOL, RegionGroups.AMERICAS)).response
-}
\ No newline at end of file
+ // 2. Ask which region this PUUID is active in for League of Legends
+ const { response: activeRegion } = await riotApi.Account.getActiveRegion(
+ puuid,
+ Constants.Games.LOL,
+ config.regionGroup
+ )
+
+ console.log(`Account : ${config.summonerName}#${config.tagLine}`)
+ console.log(`Game : ${activeRegion.game}`)
+ console.log(`Active region: ${activeRegion.region}`)
+
+ return activeRegion
+}
diff --git a/example/tft/StaticFiles.example.ts b/example/tft/StaticFiles.example.ts
index f1dd3f3b..0d04a5fa 100644
--- a/example/tft/StaticFiles.example.ts
+++ b/example/tft/StaticFiles.example.ts
@@ -1,11 +1,30 @@
import { TftApi } from '../../src'
+/**
+ * TFT STATIC FILES — Local Teamfight Tactics game data.
+ *
+ * Unlike every other endpoint, `StaticFiles` reads bundled JSON shipped with
+ * the library. The methods are SYNCHRONOUS (no `await`, no API key, no rate
+ * limits): champions, hexes, items and traits for the current set.
+ */
export function staticFilesExample () {
- const api = new TftApi().StaticFiles
- return [
- api.Champions(),
- api.Hexes(),
- api.Items(),
- api.Traits()
- ]
+ const staticFiles = new TftApi().StaticFiles
+
+ // All four readers return arrays straight from local JSON
+ const champions = staticFiles.Champions()
+ const hexes = staticFiles.Hexes()
+ const items = staticFiles.Items()
+ const traits = staticFiles.Traits()
+
+ console.log(`Champions: ${champions.length}`)
+ console.log(`Hexes : ${hexes.length}`)
+ console.log(`Items : ${items.length}`)
+ console.log(`Traits : ${traits.length}`)
+
+ // Peek at one champion to show the shape of the data
+ if (champions[0]) {
+ console.log(`Example champion: ${champions[0].champion} (cost ${champions[0].cost})`)
+ }
+
+ return { champions, hexes, items, traits }
}
diff --git a/example/tft/SummonerTFT.example.ts b/example/tft/SummonerTFT.example.ts
index eb010785..6f3b4fe2 100644
--- a/example/tft/SummonerTFT.example.ts
+++ b/example/tft/SummonerTFT.example.ts
@@ -1,11 +1,30 @@
-import { RiotApi } from '../../src'
-import { TftApi } from '../../src'
+import { RiotApi, TftApi } from '../../src'
import { configTft } from '../config/config'
-const rApi = new RiotApi()
-const api = new TftApi()
-
+/**
+ * TFT-SUMMONER-V1 — Get a Teamfight Tactics summoner by PUUID.
+ *
+ * The summoner endpoint is platform-region based (e.g. NA1), so we resolve
+ * the PUUID through the Account API and then look the summoner up on its
+ * platform region.
+ */
export async function getSummonerTft () {
- const { response: { puuid } } = await rApi.Account.getByRiotId(configTft.summonerName, configTft.region, configTft.regionGroup)
- return api.Summoner.getByPUUID(puuid, configTft.region)
+ const riotApi = new RiotApi()
+ const tftApi = new TftApi()
+
+ // 1. Resolve the Riot ID (gameName#tagLine) into a PUUID
+ const { response: account } = await riotApi.Account.getByRiotId(
+ configTft.summonerName,
+ configTft.tagLine,
+ configTft.regionGroup
+ )
+
+ // 2. Fetch the TFT summoner on its platform region (NOT the region group)
+ const { response: summoner } = await tftApi.Summoner.getByPUUID(account.puuid, configTft.region)
+
+ console.log(`Summoner : ${account.gameName}#${account.tagLine}`)
+ console.log(`Level : ${summoner.summonerLevel}`)
+ console.log(`Icon id : ${summoner.profileIconId}`)
+
+ return summoner
}
diff --git a/example/tft/TftLeagueBySummoner.example.ts b/example/tft/TftLeagueBySummoner.example.ts
index 91fb8431..6d704169 100644
--- a/example/tft/TftLeagueBySummoner.example.ts
+++ b/example/tft/TftLeagueBySummoner.example.ts
@@ -1,12 +1,32 @@
-import { RiotApi } from '../../src'
-import { TftApi } from '../../src'
+import { RiotApi, TftApi } from '../../src'
import { configTft } from '../config/config'
-const rApi = new RiotApi()
-const api = new TftApi()
-
+/**
+ * TFT-LEAGUE-V1 — Get the ranked league entries for a player.
+ *
+ * We resolve the PUUID via the Account API and read the ranked entries with
+ * `getByPUUID` (the non-deprecated counterpart of the summoner-id based call).
+ * League entries are platform-region based, so we use `configTft.region`.
+ */
export async function TftLeagueBySummoner () {
- const { response: { puuid } } = await rApi.Account.getByRiotId(configTft.summonerName, configTft.region, configTft.regionGroup)
- const { response: { id } } = await api.Summoner.getByPUUID(puuid, configTft.region)
- const league = await api.League.get(id, configTft.region)
+ const riotApi = new RiotApi()
+ const tftApi = new TftApi()
+
+ // 1. Resolve the Riot ID into a PUUID
+ const { response: account } = await riotApi.Account.getByRiotId(
+ configTft.summonerName,
+ configTft.tagLine,
+ configTft.regionGroup
+ )
+
+ // 2. Fetch every ranked TFT league entry for this PUUID on its platform region
+ const { response: entries } = await tftApi.League.getByPUUID(account.puuid, configTft.region)
+
+ console.log(`Player : ${account.gameName}#${account.tagLine}`)
+ console.log(`Ranked queues: ${entries.length}`)
+ for (const entry of entries) {
+ console.log(` ${entry.queueType}: ${entry.tier} ${entry.rank} - ${entry.leaguePoints} LP (${entry.wins}W/${entry.losses}L)`)
+ }
+
+ return entries
}
diff --git a/example/tft/TftLeagueByTierDivision.example.ts b/example/tft/TftLeagueByTierDivision.example.ts
index ad055193..58de8989 100644
--- a/example/tft/TftLeagueByTierDivision.example.ts
+++ b/example/tft/TftLeagueByTierDivision.example.ts
@@ -1,14 +1,31 @@
-import { TftApi } from "../../src";
-import { configTft } from "../config/config";
-import { Tiers } from "../../src/constants";
-import { Divisions } from "../../src/constants";
+import { TftApi, Constants } from '../../src'
+import { configTft } from '../config/config'
-const api = new TftApi();
+/**
+ * TFT-LEAGUE-V1 — List the ranked entries for a given tier + division.
+ *
+ * This returns a page of players sitting in the requested bracket
+ * (e.g. DIAMOND I) on the given platform region.
+ */
+export async function TftLeagueByTierDivision () {
+ const tftApi = new TftApi()
-export async function TftLeagueByTierDivision() {
- const league = await api.League.getByTierDivision(
+ // Page through the DIAMOND I ladder on the configured platform region.
+ // Signature: getByTierDivision(region, tier, division, page = 1, queue = 'RANKED_TFT')
+ const { response: entries } = await tftApi.League.getByTierDivision(
configTft.region,
- Tiers.DIAMOND,
- Divisions.I
- );
+ Constants.Tiers.DIAMOND,
+ Constants.Divisions.I
+ )
+
+ console.log(`Bracket: DIAMOND I (${configTft.region})`)
+ console.log(`Entries: ${entries.length}`)
+
+ // Show the top few players on this page by league points
+ const top = [...entries].sort((a, b) => b.leaguePoints - a.leaguePoints).slice(0, 5)
+ for (const entry of top) {
+ console.log(` ${entry.leaguePoints} LP - ${entry.wins}W/${entry.losses}L`)
+ }
+
+ return entries
}
diff --git a/example/tft/TftMatchDetails.example.ts b/example/tft/TftMatchDetails.example.ts
index cd94135b..96ec4e88 100644
--- a/example/tft/TftMatchDetails.example.ts
+++ b/example/tft/TftMatchDetails.example.ts
@@ -1,13 +1,44 @@
-import { RiotApi } from '../../src'
-import { TftApi } from '../../src'
+import { RiotApi, TftApi } from '../../src'
import { configTft } from '../config/config'
-const rApi = new RiotApi()
-const api = new TftApi()
-
+/**
+ * TFT-MATCH-V1 — Get the full detail of a single Teamfight Tactics match.
+ *
+ * We resolve the account, grab its most recent match id, then fetch the
+ * match info (participants, placements, set number, ...).
+ */
export async function matchDetailsTft () {
- const { response: { puuid } } = await rApi.Account.getByRiotId(configTft.summonerName, configTft.region, configTft.regionGroup)
- const { response: [matchId] } = await api.Match.list(puuid, configTft.tftRegion)
- console.log(matchId)
- return api.Match.get(matchId, configTft.tftRegion)
+ const riotApi = new RiotApi()
+ const tftApi = new TftApi()
+
+ // 1. Resolve the Riot ID into a PUUID
+ const { response: account } = await riotApi.Account.getByRiotId(
+ configTft.summonerName,
+ configTft.tagLine,
+ configTft.regionGroup
+ )
+
+ // 2. List the match ids and pick the most recent one
+ const { response: matchIds } = await tftApi.Match.list(account.puuid, configTft.tftRegion)
+ const [matchId] = matchIds
+ if (!matchId) {
+ console.log('No TFT matches found for this player.')
+ return undefined
+ }
+
+ // 3. Fetch the full match detail (same RegionGroups routing as the list)
+ const { response: match } = await tftApi.Match.get(matchId, configTft.tftRegion)
+
+ console.log(`Match id : ${match.metadata.match_id}`)
+ console.log(`Set number : ${match.info.tft_set_number}`)
+ console.log(`Game length : ${Math.round(match.info.game_length)}s`)
+ console.log(`Participants : ${match.info.participants.length}`)
+
+ // Find our player's row to show their placement
+ const me = match.info.participants.find(p => p.puuid === account.puuid)
+ if (me) {
+ console.log(`Your placement: #${me.placement} (level ${me.level})`)
+ }
+
+ return match
}
diff --git a/example/tft/TftMatchList.example.ts b/example/tft/TftMatchList.example.ts
index 365b60c3..f99a77d8 100644
--- a/example/tft/TftMatchList.example.ts
+++ b/example/tft/TftMatchList.example.ts
@@ -1,13 +1,29 @@
-import { RiotApi } from '../../src'
-import { TftApi } from '../../src'
+import { RiotApi, TftApi } from '../../src'
import { configTft } from '../config/config'
-const rApi = new RiotApi()
-const api = new TftApi()
-
+/**
+ * TFT-MATCH-V1 — List a player's recent Teamfight Tactics match ids.
+ *
+ * TFT matches are routed by `RegionGroups` (AMERICAS / ASIA / EUROPE / SEA),
+ * but the account still has to be resolved through the Account API first.
+ */
export async function matchListTft () {
- const { response: { puuid } } = await rApi.Account.getByRiotId(configTft.summonerName, configTft.region, configTft.regionGroup)
- const x = await api.Match.list(puuid, configTft.tftRegion)
- console.log(puuid)
- console.log(x)
+ const riotApi = new RiotApi()
+ const tftApi = new TftApi()
+
+ // 1. Resolve the Riot ID (gameName#tagLine) into a PUUID via the Account API
+ const { response: account } = await riotApi.Account.getByRiotId(
+ configTft.summonerName,
+ configTft.tagLine,
+ configTft.regionGroup
+ )
+
+ // 2. Fetch the match ids on the TFT routing region (a RegionGroups value)
+ const { response: matchIds } = await tftApi.Match.list(account.puuid, configTft.tftRegion)
+
+ console.log(`Player : ${account.gameName}#${account.tagLine}`)
+ console.log(`Match ids : ${matchIds.length} found`)
+ console.log(`Most recent: ${matchIds[0] ?? 'no matches'}`)
+
+ return matchIds
}
diff --git a/example/tft/TftMatchListDetails.example.ts b/example/tft/TftMatchListDetails.example.ts
index 7ddd916e..6f8a25b7 100644
--- a/example/tft/TftMatchListDetails.example.ts
+++ b/example/tft/TftMatchListDetails.example.ts
@@ -1,11 +1,35 @@
-import { RiotApi } from '../../src'
-import { TftApi } from '../../src'
+import { RiotApi, TftApi } from '../../src'
import { configTft } from '../config/config'
-const rApi = new RiotApi()
-const api = new TftApi()
-
+/**
+ * TFT-MATCH-V1 — List a player's recent matches WITH their full detail.
+ *
+ * `listWithDetails` is a convenience helper: it lists the match ids and then
+ * fetches each match, so you get an array of full match objects in one call.
+ */
export async function matchListDetailsTft () {
- const { response: { puuid } } = await rApi.Account.getByRiotId(configTft.summonerName, configTft.region, configTft.regionGroup)
- return api.Match.listWithDetails(puuid, configTft.tftRegion)
+ const riotApi = new RiotApi()
+ const tftApi = new TftApi()
+
+ // 1. Resolve the Riot ID into a PUUID
+ const { response: account } = await riotApi.Account.getByRiotId(
+ configTft.summonerName,
+ configTft.tagLine,
+ configTft.regionGroup
+ )
+
+ // 2. Fetch the recent matches already expanded to their full detail.
+ // Note: listWithDetails returns the match array DIRECTLY (no { response } wrapper).
+ const matches = await tftApi.Match.listWithDetails(account.puuid, configTft.tftRegion)
+
+ console.log(`Player : ${account.gameName}#${account.tagLine}`)
+ console.log(`Matches loaded: ${matches.length}`)
+
+ // Summarise this player's placement in each loaded match
+ for (const match of matches) {
+ const me = match.info.participants.find(p => p.puuid === account.puuid)
+ console.log(` ${match.metadata.match_id} -> placement #${me?.placement ?? '?'}`)
+ }
+
+ return matches
}
diff --git a/example/tft/TftSpectatorActiveGames.example.ts b/example/tft/TftSpectatorActiveGames.example.ts
index a8eec642..16228df8 100644
--- a/example/tft/TftSpectatorActiveGames.example.ts
+++ b/example/tft/TftSpectatorActiveGames.example.ts
@@ -1,11 +1,32 @@
-import { RiotApi } from '../../src'
-import { TftApi } from '../../src'
-import { RegionGroups, Regions } from '../../src/constants'
+import { RiotApi, TftApi } from '../../src'
+import { configTft } from '../config/config'
+/**
+ * TFT-SPECTATOR-V5 — Get the live game a player is currently in.
+ *
+ * This 404s when the player is not in a game, so the call is wrapped in a
+ * try/catch. The active-game endpoint is platform-region based.
+ */
export async function tftSpectatorActiveGames () {
- const rApi = new RiotApi()
- const tApi = new TftApi()
+ const riotApi = new RiotApi()
+ const tftApi = new TftApi()
- const { puuid } = (await rApi.Account.getByRiotId('Mimoru', '6129', RegionGroups.AMERICAS)).response
- return await tApi.SpectatorV5.activeGame(puuid, Regions.AMERICA_NORTH)
+ // 1. Resolve the Riot ID into a PUUID
+ const { response: account } = await riotApi.Account.getByRiotId(
+ configTft.summonerName,
+ configTft.tagLine,
+ configTft.regionGroup
+ )
+
+ // 2. Look up the player's current game (404 if they are not in one)
+ try {
+ const { response: game } = await tftApi.SpectatorV5.activeGame(account.puuid, configTft.region)
+ console.log(`${account.gameName}#${account.tagLine} is in game ${game.gameId}`)
+ console.log(`Mode : ${game.gameMode} (queue ${game.gameQueueConfigId})`)
+ console.log(`Players: ${game.participants.length}`)
+ return game
+ } catch (e) {
+ console.log(`${account.gameName}#${account.tagLine} is not currently in a TFT game.`)
+ return undefined
+ }
}
diff --git a/example/tft/TftSpectatorFeaturedGames.example.ts b/example/tft/TftSpectatorFeaturedGames.example.ts
index 69dc4cc0..e8e884fc 100644
--- a/example/tft/TftSpectatorFeaturedGames.example.ts
+++ b/example/tft/TftSpectatorFeaturedGames.example.ts
@@ -1,7 +1,23 @@
import { TftApi } from '../../src'
-import { Regions } from '../../src/constants'
+import { configTft } from '../config/config'
-export async function spectatorTFTV5FeaturedGames() {
- const api = new TftApi()
- return await api.SpectatorV5.featuredGames(Regions.AMERICA_NORTH)
-}
\ No newline at end of file
+/**
+ * TFT-SPECTATOR-V5 — List the games Riot is currently featuring.
+ *
+ * Featured games are platform-region based and need no account: Riot returns
+ * a curated list of in-progress games plus a suggested refresh interval.
+ */
+export async function spectatorTFTV5FeaturedGames () {
+ const tftApi = new TftApi()
+
+ // Fetch the featured games on the configured platform region
+ const { response: featured } = await tftApi.SpectatorV5.featuredGames(configTft.region)
+
+ console.log(`Featured games : ${featured.gameList.length}`)
+ console.log(`Refresh interval: ${featured.clientRefreshInterval}s`)
+ for (const game of featured.gameList) {
+ console.log(` game ${game.gameId} - ${game.participants.length} players (queue ${game.gameQueueConfigId})`)
+ }
+
+ return featured
+}
diff --git a/package.json b/package.json
index d06c1d1d..bcb4deba 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "twisted",
- "version": "1.75.1",
+ "version": "1.80.0",
"description": "Fetching riot games api data",
"main": "dist/index.js",
"types": "dist/index.d.ts",
@@ -14,7 +14,7 @@
"prepublishOnly": "npm run build"
},
"engines": {
- "node": ">=8.6.0"
+ "node": ">=18.0.0"
},
"keywords": [
"riot",
@@ -41,9 +41,7 @@
"license": "MIT",
"devDependencies": {
"@types/chai": "^4.3.11",
- "@types/dotenv": "^6.1.1",
"@types/jest": "^29.5.10",
- "@types/lodash": "^4.14.202",
"@types/node": "^20.10.0",
"@types/promise-queue": "^2.2.3",
"@types/sinon": "^17.0.2",
@@ -58,10 +56,7 @@
"typescript": "^5.3.2"
},
"dependencies": {
- "axios": "^1.6.2",
- "dotenv": "^16.3.1",
"http-status-codes": "^2.3.0",
- "lodash": "^4.17.21",
"promise-queue": "^2.2.5",
"uuid": "^14.0.0"
},
diff --git a/runExamples.ts b/runExamples.ts
index 3461c79d..1875ca70 100644
--- a/runExamples.ts
+++ b/runExamples.ts
@@ -1,5 +1,4 @@
import * as allExamples from './example'
-import * as _ from 'lodash'
const interval = 1000
@@ -17,7 +16,7 @@ async function runExamples () {
console.log('------------------------------------------------')
for (const key of examples) {
console.log(`Run ${key}`)
- const method = _.get(allExamples, key)
+ const method = (allExamples as Record)[key]
if (typeof method !== 'function') {
console.error(`Method ${key} isn't a function`)
continue
diff --git a/src/apis/lol/dataDragon/DataDragonService.ts b/src/apis/lol/dataDragon/DataDragonService.ts
index 5351ac71..233c67c1 100644
--- a/src/apis/lol/dataDragon/DataDragonService.ts
+++ b/src/apis/lol/dataDragon/DataDragonService.ts
@@ -1,4 +1,3 @@
-import Axios, { AxiosRequestConfig } from 'axios'
import { DataDragonEnum } from '../../../constants/dataDragon'
import { RealmServers } from '../../../constants/realmServers'
import { RealmDTO, ChampionsDataDragon, QueuesDataDragonDTO, GameModesDataDragonDTO } from '../../../models-dto'
@@ -18,11 +17,11 @@ const defaultLang = 'en_US'
export class DataDragonService {
// Internal methods
private async request (path: string, base: DataDragonEnum = DataDragonEnum.BASE): Promise {
- const options: AxiosRequestConfig = {
- url: `${base}/${path}`,
- method: 'GET'
+ const response = await fetch(`${base}/${path}`)
+ if (!response.ok) {
+ throw new Error(`Data Dragon request failed (${response.status} ${response.statusText}): ${base}/${path}`)
}
- return (await Axios(options)).data
+ return await response.json() as T
}
// Riot requests
// Data dragon
diff --git a/src/apis/lol/seed/seed.ts b/src/apis/lol/seed/seed.ts
index eda1a4e4..c35aa3ad 100644
--- a/src/apis/lol/seed/seed.ts
+++ b/src/apis/lol/seed/seed.ts
@@ -1,4 +1,3 @@
-import Axios, { AxiosRequestConfig } from 'axios'
import { DataSeed } from '../../../constants/dataSeed'
import { MatchDto } from '../../../models-dto/matches/match/match.dto'
@@ -7,11 +6,11 @@ export class SeedApi {
private async request (path: string): Promise {
const url = `${this.baseUrl}/${path}`
- const options: AxiosRequestConfig = {
- url,
- method: 'GET'
+ const response = await fetch(url)
+ if (!response.ok) {
+ throw new Error(`Seed request failed (${response.status} ${response.statusText}): ${url}`)
}
- return (await Axios(options)).data
+ return await response.json() as T
}
async matches (id: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10): Promise<{ matches: MatchDto[] }> {
diff --git a/src/apis/lol/summoner/summoner.ts b/src/apis/lol/summoner/summoner.ts
index c9ad477b..dd31cac0 100644
--- a/src/apis/lol/summoner/summoner.ts
+++ b/src/apis/lol/summoner/summoner.ts
@@ -1,4 +1,3 @@
-import * as _ from 'lodash'
import { endpointsV4, IEndpoint } from '../../../endpoints/endpoints'
import { SummonerV4DTO } from '../../../models-dto/summoners/summoner.dto'
import { Regions } from '../../../constants'
@@ -17,7 +16,7 @@ export class SummonerApi extends BaseApiLol {
return path
}
private genericRequest (by: FindSummonerBy, value: string, region: Regions) {
- const endpoint = _.cloneDeep(endpointsV4.Summoner)
+ const endpoint = { ...endpointsV4.Summoner }
endpoint.path = this.parsePath(endpoint, by)
const params = {
summonerName: value,
diff --git a/src/apis/tft/summoner/summoner.ts b/src/apis/tft/summoner/summoner.ts
index 00186d03..8dafaa99 100644
--- a/src/apis/tft/summoner/summoner.ts
+++ b/src/apis/tft/summoner/summoner.ts
@@ -1,4 +1,3 @@
-import * as _ from 'lodash'
import { endpointsTFTV1, IEndpoint } from '../../../endpoints/endpoints'
import { SummonerV4DTO } from '../../../models-dto/summoners/summoner.dto'
import { Regions } from '../../../constants'
@@ -17,7 +16,7 @@ export class SummonerTftApi extends BaseApiTft {
return path
}
private genericRequest (by: FindSummonerBy, value: string, region: Regions) {
- const endpoint = _.cloneDeep(endpointsTFTV1.Summoner)
+ const endpoint = { ...endpointsTFTV1.Summoner }
endpoint.path = this.parsePath(endpoint, by)
const params = {
summonerName: value,
diff --git a/src/base/base.ts b/src/base/base.ts
index a31c310c..10a1003c 100644
--- a/src/base/base.ts
+++ b/src/base/base.ts
@@ -1,22 +1,17 @@
-import { AxiosRequestConfig, AxiosResponse } from 'axios'
-import * as _ from 'lodash'
import { ApiKeyNotFound } from '../errors'
import { IEndpoint } from '../endpoints'
import { TOO_MANY_REQUESTS, SERVICE_UNAVAILABLE } from 'http-status-codes'
-import { config } from 'dotenv'
import { ApiResponseDTO } from '../models-dto/api-response/api-response'
import { RateLimitDto } from '../models-dto/rate-limit/rate-limit.dto'
import { GenericError } from '../errors/Generic.error'
import { RateLimitError } from '../errors/rate-limit.error'
-import { IBaseApiParams, IParams, waiter } from './base.utils'
+import { IBaseApiParams, IParams, RequestOptions, waiter } from './base.utils'
import { ServiceUnavailable } from '../errors/service-unavailable.error'
import { BaseConstants, BaseApiGames } from './base.const'
import { Logger } from './logger.base'
-import { RequestBase } from './request.base'
+import { RequestBase, HttpResponse } from './request.base'
import { RegionGroups } from '../constants'
-config()
-
export class BaseApi {
protected readonly game: BaseApiGames = BaseApiGames.LOL
private baseUrl: string = BaseConstants.BASE_URL
@@ -58,13 +53,13 @@ export class BaseApi {
}
if (typeof param.debug !== 'undefined') {
if (typeof param.debug.logTime !== 'undefined') {
- _.set(this.debug, 'logTime', param.debug.logTime)
+ this.debug.logTime = param.debug.logTime
}
if (typeof param.debug.logUrls !== 'undefined') {
- _.set(this.debug, 'logUrls', param.debug.logUrls)
+ this.debug.logUrls = param.debug.logUrls
}
if (typeof param.debug.logRatelimits !== 'undefined') {
- _.set(this.debug, 'logRatelimits', param.debug.logRatelimits)
+ this.debug.logRatelimits = param.debug.logRatelimits
}
}
if(typeof param.baseURL !== 'undefined') {
@@ -79,14 +74,15 @@ export class BaseApi {
}
private getRateLimits (headers: any): RateLimitDto {
+ const h = headers || {}
return {
- Type: _.get(headers, 'x-rate-limit-type', null),
- AppRateLimit: _.get(headers, 'x-app-rate-limit', null),
- AppRateLimitCount: _.get(headers, 'x-app-rate-limit-count', null),
- MethodRateLimit: _.get(headers, 'x-method-rate-limit'),
- MethodRatelimitCount: _.get(headers, 'x-method-rate-limit-count', null),
- RetryAfter: +_.get(headers, 'retry-after', 0),
- EdgeTraceId: _.get(headers, 'x-riot-edge-trace-id')
+ Type: h['x-rate-limit-type'] ?? null,
+ AppRateLimit: h['x-app-rate-limit'] ?? null,
+ AppRateLimitCount: h['x-app-rate-limit-count'] ?? null,
+ MethodRateLimit: h['x-method-rate-limit'],
+ MethodRatelimitCount: h['x-method-rate-limit-count'] ?? null,
+ RetryAfter: +(h['retry-after'] ?? 0),
+ EdgeTraceId: h['x-riot-edge-trace-id']
}
}
@@ -129,7 +125,7 @@ export class BaseApi {
}
private getError (e: any) {
- const headers = this.getRateLimits(_.get(e, 'response.headers'))
+ const headers = this.getRateLimits(e?.response?.headers)
if (this.isRateLimitError(e)) {
return new RateLimitError(headers)
}
@@ -140,7 +136,7 @@ export class BaseApi {
return new GenericError(headers, e)
}
- private internalRequest (options: AxiosRequestConfig): Promise {
+ private internalRequest (options: RequestOptions): Promise {
return RequestBase.request(options)
}
@@ -208,7 +204,7 @@ export class BaseApi {
if (this.debug.logTime) {
Logger.start(endpoint, url)
}
- const options: AxiosRequestConfig = {
+ const options: RequestOptions = {
url,
method: 'GET',
headers: {
@@ -220,7 +216,7 @@ export class BaseApi {
Logger.uri(options, endpoint)
}
try {
- const apiResponse = await this.internalRequest>(options)
+ const apiResponse = await this.internalRequest>(options)
const { data, headers } = apiResponse
return {
rateLimits: this.getRateLimits(headers),
diff --git a/src/base/base.utils.ts b/src/base/base.utils.ts
index bf7cfa75..736563e9 100644
--- a/src/base/base.utils.ts
+++ b/src/base/base.utils.ts
@@ -1,10 +1,21 @@
-import { AxiosRequestConfig } from 'axios'
-import qs from 'querystring'
-
export interface IParams {
[key: string]: string | number
}
+/**
+ * Minimal request options shared across the request pipeline.
+ * Replaces axios' `AxiosRequestConfig` now that the library uses native `fetch`.
+ */
+export interface RequestOptions {
+ url: string
+ method?: string
+ headers?: Record
+ /**
+ * Query string values. Serialized with {@link stringifyParams}.
+ */
+ params?: Record
+}
+
export interface IBaseApiParams {
/**
* If api response is 429 (rate limits) try reattempt after needed time (default true)
@@ -55,11 +66,41 @@ export function waiter (ms: number) {
})
}
-export function getUrlFromOptions (options: AxiosRequestConfig): string {
- let uri = options.url as string
+/**
+ * Serialize query params into a query string.
+ *
+ * - `null`/`undefined` values are skipped (matching axios behaviour).
+ * - Arrays are expanded into repeated keys (`queue=420&queue=440`), which is
+ * the format the Riot API expects.
+ */
+export function stringifyParams (params: Record): string {
+ const search = new URLSearchParams()
+ for (const key of Object.keys(params)) {
+ const value = params[key]
+ if (value === undefined || value === null) {
+ continue
+ }
+ if (Array.isArray(value)) {
+ for (const item of value) {
+ if (item === undefined || item === null) {
+ continue
+ }
+ search.append(key, String(item))
+ }
+ } else {
+ search.append(key, String(value))
+ }
+ }
+ return search.toString()
+}
+
+export function getUrlFromOptions (options: RequestOptions): string {
+ let uri = options.url
if (options.params) {
- uri += '?'
- uri += qs.stringify(options.params)
+ const query = stringifyParams(options.params)
+ if (query) {
+ uri += `?${query}`
+ }
}
return uri
}
diff --git a/src/base/logger.base.ts b/src/base/logger.base.ts
index b745336e..a3fba473 100644
--- a/src/base/logger.base.ts
+++ b/src/base/logger.base.ts
@@ -1,6 +1,5 @@
import { IEndpoint } from '../endpoints/endpoints'
-import { AxiosRequestConfig } from 'axios'
-import { getUrlFromOptions } from './base.utils'
+import { RequestOptions, getUrlFromOptions } from './base.utils'
export class Logger {
// Private methods
@@ -22,7 +21,7 @@ export class Logger {
console.timeEnd(name)
}
- static uri (options: AxiosRequestConfig, endpoint: IEndpoint) {
+ static uri (options: RequestOptions, endpoint: IEndpoint) {
const uri = getUrlFromOptions(options)
console.log(`Calling method url: ${uri} (${endpoint.path})`)
}
diff --git a/src/base/request.base.ts b/src/base/request.base.ts
index 4f46bd33..c181ff89 100644
--- a/src/base/request.base.ts
+++ b/src/base/request.base.ts
@@ -1,15 +1,74 @@
-import Axios, { AxiosRequestConfig } from 'axios'
import PromiseQueue from 'promise-queue'
+import { RequestOptions, getUrlFromOptions } from './base.utils'
+
+/**
+ * Successful response shape returned by the request pipeline.
+ * Mirrors the small subset of axios' response that the library relies on.
+ */
+export interface HttpResponse {
+ data: T
+ headers: Record
+ status: number
+}
+
+/**
+ * Error thrown when the Riot API responds with a non 2xx status code.
+ * Keeps the same shape the rest of the codebase used to read from axios errors
+ * (`error.status` and `error.response.{status,data,headers}`).
+ */
+export class HttpError extends Error {
+ readonly status: number
+ readonly response: {
+ status: number
+ data: any
+ headers: Record
+ }
+
+ constructor (status: number, statusText: string, data: any, headers: Record) {
+ super(statusText || `Request failed with status code ${status}`)
+ this.name = 'HttpError'
+ this.status = status
+ this.response = { status, data, headers }
+ Object.setPrototypeOf(this, HttpError.prototype)
+ }
+}
+
+function headersToObject (headers: Headers): Record {
+ const result: Record = {}
+ headers.forEach((value, key) => {
+ result[key] = value
+ })
+ return result
+}
+
+async function parseBody (response: Response): Promise {
+ const text = await response.text()
+ if (!text) {
+ return undefined
+ }
+ try {
+ return JSON.parse(text)
+ } catch (e) {
+ // Some endpoints (e.g. third party code) reply with plain text
+ return text
+ }
+}
export class RequestBase {
static queue: PromiseQueue
- private static sendRequest (options: AxiosRequestConfig) {
- return new Promise((resolve, reject) => {
- Axios(options)
- .then(resolve)
- .catch(reject)
+ private static async sendRequest (options: RequestOptions): Promise> {
+ const url = getUrlFromOptions(options)
+ const response = await fetch(url, {
+ method: options.method || 'GET',
+ headers: options.headers
})
+ const headers = headersToObject(response.headers)
+ const data = await parseBody(response)
+ if (!response.ok) {
+ throw new HttpError(response.status, response.statusText, data, headers)
+ }
+ return { data, headers, status: response.status }
}
private static getQueue () {
@@ -23,7 +82,7 @@ export class RequestBase {
RequestBase.queue = new PromiseQueue(concurrency, Infinity)
}
- static request (options: AxiosRequestConfig): Promise {
+ static request (options: RequestOptions): Promise {
return RequestBase.getQueue().add(() => RequestBase.sendRequest(options) as any)
}
}
diff --git a/src/constants/champions.ts b/src/constants/champions.ts
index f96b44b8..2ea307d6 100644
--- a/src/constants/champions.ts
+++ b/src/constants/champions.ts
@@ -1,7 +1,3 @@
-import { invert } from 'lodash'
-import Axios from 'axios'
-import _ from 'lodash'
-
/**
* Champions - Used as fallback
*/
@@ -180,7 +176,26 @@ export enum Champions {
YUNARA = 804
}
-const championIdMap = invert(Champions)
+/**
+ * Bidirectional id <-> name map (replaces lodash `invert`):
+ * a numeric enum produces both `ANNIE -> 1` and `1 -> ANNIE` entries, so the
+ * resulting map can resolve a champion in either direction.
+ */
+const championIdMap: { [key: string]: string } = {}
+for (const [key, value] of Object.entries(Champions)) {
+ championIdMap[String(value)] = key
+}
+
+/**
+ * camelCase a snake_case / spaced string (replaces lodash `camelCase`).
+ */
+function camelCase (value: string): string {
+ return value
+ .split(/[^a-zA-Z0-9]+/)
+ .filter((part) => part.length > 0)
+ .map((part, index) => (index === 0 ? part : part.charAt(0).toUpperCase() + part.slice(1)))
+ .join('')
+}
/**
* Fetching champion IDs from CommunityDragon's PBE content. See https://www.communitydragon.org/
@@ -188,20 +203,20 @@ const championIdMap = invert(Champions)
if (process.env.UPDATE_CHAMPION_IDS) {
const updateChampionIDs = () => {
const CD_CHAMPIONS = 'https://raw.communitydragon.org/pbe/plugins/rcp-be-lol-game-data/global/default/v1/champion-summary.json'
- try {
- void Axios(CD_CHAMPIONS)
- .then(({ data: cdChamps }) => {
- cdChamps.forEach(({ id, alias }: {id: number, alias: string}) => {
- const championAlias = alias.replace(/[a-z][A-Z]/g, letter => letter[0] + '_' + letter[1]).toUpperCase()
- if (!championIdMap[id]) {
- championIdMap[id] = championIdMap[id] || championAlias
- championIdMap[championAlias] = championIdMap[championAlias] || '' + id
- }
- })
- })
- } catch (e) {
- console.warn('Updating champion IDs failed')
- }
+ void fetch(CD_CHAMPIONS)
+ .then((response) => response.json())
+ .then((cdChamps: { id: number, alias: string }[]) => {
+ cdChamps.forEach(({ id, alias }) => {
+ const championAlias = alias.replace(/[a-z][A-Z]/g, letter => letter[0] + '_' + letter[1]).toUpperCase()
+ if (!championIdMap[id]) {
+ championIdMap[id] = championIdMap[id] || championAlias
+ championIdMap[championAlias] = championIdMap[championAlias] || '' + id
+ }
+ })
+ })
+ .catch(() => {
+ console.warn('Updating champion IDs failed')
+ })
}
// Schedule once every day.
setInterval(updateChampionIDs, 1000 * 60 * 60 * 24)
@@ -224,7 +239,7 @@ export function getChampionName (champ: number): string {
*/
export function getChampionNameCapital (champ: number | string): string {
let name = typeof champ === 'number' ? getChampionName(champ) : champ
- name = _.camelCase(name.toLowerCase())
+ name = camelCase(name.toLowerCase())
name = name.charAt(0).toUpperCase() + name.slice(1)
switch (name) {
case 'Reksai':
diff --git a/src/errors/Generic.error.ts b/src/errors/Generic.error.ts
index 1ad5765e..9104a021 100644
--- a/src/errors/Generic.error.ts
+++ b/src/errors/Generic.error.ts
@@ -1,10 +1,16 @@
import { IErrors } from '.'
import { RateLimitDto } from '../models-dto/rate-limit/rate-limit.dto'
-import * as Axios from 'axios'
import HttpStatusCodes from 'http-status-codes'
const message = 'Generic error'
+interface HttpErrorLike extends Error {
+ response?: {
+ status?: number
+ data?: any
+ }
+}
+
/**
* Not api key found
*/
@@ -15,7 +21,7 @@ export class GenericError extends Error implements IErrors {
readonly body?: any
readonly name = 'GenericError'
- constructor (rateLimits: RateLimitDto, error: Axios.AxiosError) {
+ constructor (rateLimits: RateLimitDto, error: HttpErrorLike) {
super(error.message || message)
this.status = error.response?.status || HttpStatusCodes.INTERNAL_SERVER_ERROR
this.body = error.response?.data
diff --git a/src/index.ts b/src/index.ts
index d0808f4e..17582c1a 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -2,5 +2,6 @@ import * as constants from './constants'
import * as dto from './models-dto'
export * from './apis'
+export * from './errors'
export const Constants = constants
export const Dto = dto
diff --git a/test/live.test.ts b/test/live.test.ts
index 80164fc0..1fbc4140 100644
--- a/test/live.test.ts
+++ b/test/live.test.ts
@@ -1,9 +1,9 @@
import { LolApi, RiotApi } from '../src/index';
import { Regions, AccountAPIRegionGroups, regionToRegionGroupForAccountAPI } from '../src/constants/regions';
-import * as dotenv from 'dotenv';
import * as fs from 'fs';
import * as path from 'path';
import { CurrentGameInfoDTO } from '../src/models-dto';
+import { loadEnv } from './utils/loadEnv';
describe('Live API Tests', () => {
let RIOT_API_KEY: string;
@@ -24,7 +24,7 @@ describe('Live API Tests', () => {
throw new Error(`Missing .env file at ${envPath}. Please create it with RIOT_API_KEY, RIOT_GAME_NAME, RIOT_TAG, RIOT_REGION.`);
}
- dotenv.config({ path: envPath });
+ loadEnv(envPath);
RIOT_API_KEY = process.env.RIOT_API_KEY as string;
RIOT_GAME_NAME = process.env.RIOT_GAME_NAME as string;
diff --git a/test/utils/loadEnv.ts b/test/utils/loadEnv.ts
new file mode 100644
index 00000000..d81c135f
--- /dev/null
+++ b/test/utils/loadEnv.ts
@@ -0,0 +1,30 @@
+import * as fs from 'fs'
+
+/**
+ * Minimal `.env` loader shared across the test suite (replaces the `dotenv`
+ * dependency).
+ *
+ * Parses `KEY=value` lines and populates `process.env` without overriding
+ * variables that are already set. Blank lines and `#` comments are ignored,
+ * and surrounding single/double quotes are stripped from values.
+ *
+ * @param envPath Absolute path to the `.env` file.
+ */
+export function loadEnv (envPath: string): void {
+ const content = fs.readFileSync(envPath, 'utf-8')
+ for (const rawLine of content.split('\n')) {
+ const line = rawLine.trim()
+ if (!line || line.startsWith('#')) {
+ continue
+ }
+ const eqIndex = line.indexOf('=')
+ if (eqIndex === -1) {
+ continue
+ }
+ const key = line.slice(0, eqIndex).trim()
+ const value = line.slice(eqIndex + 1).trim().replace(/^["']|["']$/g, '')
+ if (!(key in process.env)) {
+ process.env[key] = value
+ }
+ }
+}
diff --git a/yarn.lock b/yarn.lock
index 1db48fa3..023c96bd 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -715,13 +715,6 @@
resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.11.tgz#e95050bf79a932cb7305dd130254ccdf9bde671c"
integrity sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ==
-"@types/dotenv@^6.1.1":
- version "6.1.1"
- resolved "https://registry.yarnpkg.com/@types/dotenv/-/dotenv-6.1.1.tgz#f7ce1cc4fe34f0a4373ba99fefa437b0bec54b46"
- integrity sha512-ftQl3DtBvqHl9L16tpqqzA4YzCSXZfi7g8cQceTz5rOlYtk/IZbFjAv3mLOQlNIgOaylCQWQoBdDQHPgEBJPHg==
- dependencies:
- "@types/node" "*"
-
"@types/graceful-fs@^4.1.3":
version "4.1.9"
resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4"
@@ -766,11 +759,6 @@
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==
-"@types/lodash@^4.14.202":
- version "4.14.202"
- resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.202.tgz#f09dbd2fb082d507178b2f2a5c7e74bd72ff98f8"
- integrity sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==
-
"@types/node@*", "@types/node@^20.10.0":
version "20.10.0"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.10.0.tgz#16ddf9c0a72b832ec4fcce35b8249cf149214617"
@@ -1061,25 +1049,11 @@ arraybuffer.prototype.slice@^1.0.2:
is-array-buffer "^3.0.2"
is-shared-array-buffer "^1.0.2"
-asynckit@^0.4.0:
- version "0.4.0"
- resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
- integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
-
available-typed-arrays@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7"
integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==
-axios@^1.6.2:
- version "1.16.0"
- resolved "https://registry.yarnpkg.com/axios/-/axios-1.16.0.tgz#f8e5dd931cef2a5f8c32216d5784eda2f8750eb7"
- integrity sha512-6hp5CwvTPlN2A31g5dxnwAX0orzM7pmCRDLnZSX772mv8WDqICwFjowHuPs04Mc8deIld1+ejhtaMn5vp6b+1w==
- dependencies:
- follow-redirects "^1.16.0"
- form-data "^4.0.5"
- proxy-from-env "^2.1.0"
-
babel-jest@^29.7.0:
version "29.7.0"
resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5"
@@ -1194,14 +1168,6 @@ builtin-modules@^3.3.0:
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6"
integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==
-call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6"
- integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==
- dependencies:
- es-errors "^1.3.0"
- function-bind "^1.1.2"
-
call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.4, call-bind@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.5.tgz#6fa2b7845ce0ea49bf4d8b9ef64727a2c2e2e513"
@@ -1306,13 +1272,6 @@ color-name@~1.1.4:
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
-combined-stream@^1.0.8:
- version "1.0.8"
- resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
- integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
- dependencies:
- delayed-stream "~1.0.0"
-
comment-parser@1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-1.4.1.tgz#bdafead37961ac079be11eb7ec65c4d021eaf9cc"
@@ -1402,11 +1361,6 @@ define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0:
has-property-descriptors "^1.0.0"
object-keys "^1.1.1"
-delayed-stream@~1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
- integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
-
detect-newline@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651"
@@ -1443,20 +1397,6 @@ doctrine@^3.0.0:
dependencies:
esutils "^2.0.2"
-dotenv@^16.3.1:
- version "16.3.1"
- resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.3.1.tgz#369034de7d7e5b120972693352a3bf112172cc3e"
- integrity sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==
-
-dunder-proto@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a"
- integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==
- dependencies:
- call-bind-apply-helpers "^1.0.1"
- es-errors "^1.3.0"
- gopd "^1.2.0"
-
electron-to-chromium@^1.4.535:
version "1.4.595"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.595.tgz#fa33309eb9aabb7426915f8e166ec60f664e9ad4"
@@ -1524,23 +1464,6 @@ es-abstract@^1.22.1:
unbox-primitive "^1.0.2"
which-typed-array "^1.1.13"
-es-define-property@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa"
- integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==
-
-es-errors@^1.3.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f"
- integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==
-
-es-object-atoms@^1.0.0, es-object-atoms@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1"
- integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==
- dependencies:
- es-errors "^1.3.0"
-
es-set-tostringtag@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz#11f7cc9f63376930a5f20be4915834f4bc74f9c9"
@@ -1550,16 +1473,6 @@ es-set-tostringtag@^2.0.1:
has-tostringtag "^1.0.0"
hasown "^2.0.0"
-es-set-tostringtag@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d"
- integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==
- dependencies:
- es-errors "^1.3.0"
- get-intrinsic "^1.2.6"
- has-tostringtag "^1.0.2"
- hasown "^2.0.2"
-
es-shim-unscopables@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763"
@@ -1860,11 +1773,6 @@ flatted@^3.2.9:
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.9.tgz#7eb4c67ca1ba34232ca9d2d93e9886e611ad7daf"
integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==
-follow-redirects@^1.16.0:
- version "1.16.0"
- resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.16.0.tgz#28474a159d3b9d11ef62050a14ed60e4df6d61bc"
- integrity sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==
-
for-each@^0.3.3:
version "0.3.3"
resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e"
@@ -1872,17 +1780,6 @@ for-each@^0.3.3:
dependencies:
is-callable "^1.1.3"
-form-data@^4.0.5:
- version "4.0.5"
- resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.5.tgz#b49e48858045ff4cbf6b03e1805cebcad3679053"
- integrity sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==
- dependencies:
- asynckit "^0.4.0"
- combined-stream "^1.0.8"
- es-set-tostringtag "^2.1.0"
- hasown "^2.0.2"
- mime-types "^2.1.12"
-
fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
@@ -1933,35 +1830,11 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@
has-symbols "^1.0.3"
hasown "^2.0.0"
-get-intrinsic@^1.2.6:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01"
- integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==
- dependencies:
- call-bind-apply-helpers "^1.0.2"
- es-define-property "^1.0.1"
- es-errors "^1.3.0"
- es-object-atoms "^1.1.1"
- function-bind "^1.1.2"
- get-proto "^1.0.1"
- gopd "^1.2.0"
- has-symbols "^1.1.0"
- hasown "^2.0.2"
- math-intrinsics "^1.1.0"
-
get-package-type@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a"
integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==
-get-proto@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1"
- integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==
- dependencies:
- dunder-proto "^1.0.1"
- es-object-atoms "^1.0.0"
-
get-stream@^6.0.0:
version "6.0.1"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7"
@@ -2039,11 +1912,6 @@ gopd@^1.0.1:
dependencies:
get-intrinsic "^1.1.3"
-gopd@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1"
- integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==
-
graceful-fs@^4.2.9:
version "4.2.11"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
@@ -2086,11 +1954,6 @@ has-symbols@^1.0.2, has-symbols@^1.0.3:
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
-has-symbols@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338"
- integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==
-
has-tostringtag@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25"
@@ -2098,13 +1961,6 @@ has-tostringtag@^1.0.0:
dependencies:
has-symbols "^1.0.2"
-has-tostringtag@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc"
- integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==
- dependencies:
- has-symbols "^1.0.3"
-
hasown@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c"
@@ -2112,13 +1968,6 @@ hasown@^2.0.0:
dependencies:
function-bind "^1.1.2"
-hasown@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003"
- integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==
- dependencies:
- function-bind "^1.1.2"
-
html-escaper@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453"
@@ -2866,11 +2715,6 @@ lodash.merge@^4.6.2:
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
-lodash@^4.17.21:
- version "4.17.23"
- resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.23.tgz#f113b0378386103be4f6893388c73d0bde7f2c5a"
- integrity sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==
-
lru-cache@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
@@ -2904,11 +2748,6 @@ makeerror@1.0.12:
dependencies:
tmpl "1.0.5"
-math-intrinsics@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9"
- integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==
-
merge-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
@@ -2927,18 +2766,6 @@ micromatch@^4.0.4:
braces "^3.0.3"
picomatch "^2.3.1"
-mime-db@1.52.0:
- version "1.52.0"
- resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
- integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
-
-mime-types@^2.1.12:
- version "2.1.35"
- resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
- integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
- dependencies:
- mime-db "1.52.0"
-
mimic-fn@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
@@ -3191,11 +3018,6 @@ prompts@^2.0.1:
kleur "^3.0.3"
sisteransi "^1.0.5"
-proxy-from-env@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-2.1.0.tgz#a7487568adad577cfaaa7e88c49cab3ab3081aba"
- integrity sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==
-
punycode@^2.1.0:
version "2.3.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5"