Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/cuppachino/hexgate
LCU API wrapper for League of Legends
https://github.com/cuppachino/hexgate
esm hexgate javascript lcu lcu-api league-of-legends node-esm nodenext riot-games riot-games-api typescript typescript-library
Last synced: about 2 months ago
JSON representation
LCU API wrapper for League of Legends
- Host: GitHub
- URL: https://github.com/cuppachino/hexgate
- Owner: cuppachino
- License: gpl-3.0
- Created: 2023-03-19T01:42:16.000Z (almost 2 years ago)
- Default Branch: main
- Last Pushed: 2023-12-06T01:43:29.000Z (about 1 year ago)
- Last Synced: 2024-10-10T20:10:17.555Z (2 months ago)
- Topics: esm, hexgate, javascript, lcu, lcu-api, league-of-legends, node-esm, nodenext, riot-games, riot-games-api, typescript, typescript-library
- Language: TypeScript
- Homepage: https://hexgate.app/
- Size: 885 KB
- Stars: 19
- Watchers: 1
- Forks: 0
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
- awesome-league - hexgate - A TypeScript LCU wrapper available on NPM. (Developer Tools)
README
# Hexgate
[![Discord](https://img.shields.io/discord/1080840305441525766?color=5865f2\&label=\&logo=discord\&logoColor=ffffff)](https://discord.gg/HEd72YnzVq)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/f9cec6d6f8cf407fb2ef8a4ab82af87c)](https://app.codacy.com/gh/cuppachino/hexgate?utm_source=github.com\&utm_medium=referral\&utm_content=cuppachino/hexgate\&utm_campaign=Badge_Grade)
[![Release](https://github.com/cuppachino/hexgate/actions/workflows/release.yml/badge.svg?branch=main)](https://github.com/cuppachino/hexgate/actions/workflows/release.yml)
[![License](https://img.shields.io/github/license/cuppachino/hexgate?color=ffca4a)](https://github.com/cuppachino/hexgate/blob/528f647166eddef82e0ceb15ac8feafb56e97773/LICENSE)
[![npm (scoped)](https://img.shields.io/npm/v/hexgate?color=%23fb3e44)](https://www.npmjs.com/package/hexgate)[Hexgate](https://www.npmjs.com/package/hexgate) is a work-in-progress LCU suite. It is **not** endorsed by Riot Games. You can find out more about what that means [here](https://www.riotgames.com/en/legal). Thank you Riot ❤️ for keeping the LCU open. If you have any questions, feel free to join the [cuppachino discord](https://discord.gg/HEd72YnzVq).
Please refer to the [wiki](https://github.com/cuppachino/hexgate/wiki) for more info.
## Installation
Add it to your own project using your favorite package manager.
```shell
pnpm add hexgate
``````shell
npm i hexgate
``````shell
yarn add hexgate
```### ESM
```ts
import { ... } from "hexgate"
```### CJS
```ts
import hexgate = require("hexgate")
const { ... } = hexgate
```## Authentication
Wait for the client by passing the [`auth`](https://github.com/cuppachino/hexgate/blob/main/src/modules/auth/index.ts) function to the [`poll`](https://github.com/cuppachino/hexgate/blob/main/src/utils/poll.ts) utility.
```ts
import { auth, poll } from "hexgate"const credentials = await poll(auth)
```Opt-out of safe authentication by explicity passing an `undefined` certifcate.
```ts
const unsafeCredentials = await auth({ certificate: undefined })
```Once you have the credentials, you can create a new [`Hexgate`](./src/modules/hexgate/index.ts) and [`LcuClient`](./src/modules/websocket/index.ts).
```ts
import { Hexgate as HttpsClient, LcuClient as WsClient } from "hexgate"const httpsClient = new HttpsClient(credentials)
const websocketClient = new WsClient(credentials)
```Working with multiple clients? Get get `all` credentials.
```ts
import { auth, createHexgate, createLcuClient, poll, zip } from 'hexgate'const credentials = await poll(() => auth({ all: true }))
// ~ some multi-connection interface
const clients = new Set(
zip(
credentials.map(createHexgate),
credentials.map(createLcuClient)
)
)
```## Builder API
The simplest way of getting started is to "`.build`" a request function. The builder uses generics to infer the parameters and return type of the request.
```ts
import { Hexgate as HttpsClient } from 'hexgate'const https = new HttpsClient(credentials)
// (arg: string[], init?: any) => Promise>
const getSummonersFromNames = https
.build('/lol-summoner/v2/summoners/names')
.method('post')
.create()const summoner = await getSummonersByName(['dubbleignite'])
console.log(summoner.data)
```## Websocket Events
Subscribe to LCU events through the client.
```ts
import { LcuClient as WsClient } from 'hexgate'const ws = new WsClient(credentials)
ws.subscribe(
'OnJsonApiEvent_lol-champ-select_v1_session',
({ data, eventType, uri }) => {
// side effects
}
)
```> Note: Since many endpoints will subscribe you to multiple uris, its difficult to provide meaningful type inference for the data property. Import `LcuComponents` type when necessary and/or open a PR to improve typings - which would be greatly appreciated! I'm just improving types as I need them.
## ⚡️ Connection
The [`Connection`](https://github.com/cuppachino/hexgate/blob/main/src/modules/connection/index.ts) class further abstracts `Hexgate` & `LcuClient` and handles authentication between client shutdowns. Configuration is optional.
```ts
import { Connection } from 'hexgate'const client = new Connection({
// Recipe API (createRecipe or recipe)
createRecipe({ build, unwrap }) {
return {
getCurrentSummoner: unwrap(
build('/lol-summoner/v1/current-summoner').method('get').create()
)
}
},
// Propagate status to browser windows.
onStatusChange(status) {
emit('status', status)
},
// Init
async onConnect(con) {
con.ws.subscribe('OnJsonApiEvent_lol-champ-select_v1_session', handleChampSelect)
const summoner = await con.recipe.getCurrentSummoner()
con.logger.info(summoner, `Welcome, ${summoner.displayName}`)
},
// Automatically reconnect
async onDisconnect(discon) {
await sleep(4000)
discon.connect()
},
// Authentication interval
interval: 2000,
// Bring any logger
logger: pino({
name: 'main' as const
})
})client.connect()
```The `Connection` class supports recipes, define a `recipe: Recipe` or a `createRecipe: RecipeApiFn` method in the `ConnectionConfig` constructor argument.
```ts
import { Connection, createRecipe } from 'hexgate'const recipe = createRecipe(({ build }) => ({/*...*/}))
const client = new Connection({
recipe
})
``````ts
import { Connection } from 'hexgate'const client = new Connection({
createRecipe({ build }) { return {/*...*/} }
})
```
## Recipe API
[`createRecipe`](https://github.com/cuppachino/hexgate/blob/main/src/modules/recipe/index.ts#L78) is a higher-order function for transforming a request's parameters and response. It is a useful tool for morphing the LCU's API into your own. There are several ways to use the functions provided by the callback, and we'll take a look at each one.
### Intro
#### Step 1: Create a recipe
This is identical to the builder API, except the request function isn't built until a hexgate instance is given to the recipe. This is useful for modeling requests ahead of time for usage in other places.
```ts
import { createRecipe } from "hexgate"/**
* (httpsClient: T) =>
* (arg: string[], init?: RequestInit) =>
* Promise>
*/
const getSummonersFromNamesRecipe = createRecipe(({ build }) =>
build('/lol-summoner/v2/summoners/names')
.method('post')
.create()
)
```#### Step 2: Once you have a recipe, you just need to pass it a `Hexgate`.
```ts
const getSummonersFromNames = getSummonersFromNamesRecipe(httpsClient)const summoners = await getSummonersFromNames(['dubbleignite'])
console.table(summoners.data)
```### 🦋 Transforming requests
Use [`wrap`](https://github.com/cuppachino/hexgate/blob/main/src/utils/proxy-function.ts#L51), `from`, `to`, and `unwrap` to design your api.
```ts
const summonersRecipe = createRecipe(({ build, wrap, from, to, unwrap }) => ({
getSummoners: {
/**
* Default for reference.
* (arg: { ids?: string; }, init?: RequestInit) => Promise>
*/
v2SummonersDefault: build('/lol-summoner/v2/summoners')
.method('get')
.create(),/**
* unwrap extracts the data property from an ApiResponse.
* (arg: { ids?: string }, init?: RequestInit) => Promise<{...}>
*/
v2SummonersAwaited: unwrap(
build('/lol-summoner/v2/summoners').method('get').create(),
),/**
* wrap let's us overwrite the parameters type by supplying conversion functions.
* (summonerIds: (number | `${number}`)[], init?: RequestInit | undefined) => Promise<{...}>
*/
fromSummonerIds: wrap(
build('/lol-summoner/v2/summoners').method('get').create(),
)({
// The return type of `from` is constrained by the expected return type of the function being wrapped.
from(summonerIds: Array<`${number}` | number>, init?) {
return [{ ids: JSON.stringify(summonerIds) }, init];
},
// awaits data similarly to `unwrap`
to,
}),
},
}));
```### ⚒️ `Recipe`, `RecipeApiFn`, and `CreateWithRecipe`
Some features have options that accept a [`Recipe`](https://github.com/cuppachino/hexgate/blob/main/src/modules/recipe/index.ts#L8), the product of `createRecipe`, or a [`RecipeApiFn`](https://github.com/cuppachino/hexgate/blob/main/src/modules/recipe/index.ts#16), the api argument expected by `createRecipe`. You can achieve similar functionality in your own code by extending [`CreateWithRecipe`](https://github.com/cuppachino/hexgate/blob/main/src/modules/recipe/index.ts#L40) or implementing its overloaded constructor signature.
```ts
import type { CreateWithRecipe } from 'hexgate'class Foo extends CreateWithRecipe {}
new Foo(recipe)
new Foo((recipeApi) => "your recipe" as const)
```### Exporting recipes
If you want to export a recipe, you *might* get a type error. This is because the return type of `createRecipe` is inferred with references to `@cuppachino/openapi-fetch` and `node-fetch-commonjs`. To fix this, install the packages as dev dependencies and apply one of the following solutions to your `tsconfig.json`:
#### Map paths (Recommended)
Use this option if you are making a library.
```json
{
"compilerOptions": {
"paths": {
"@cuppachino/openapi-fetch": ["./node_modules/@cuppachino/openapi-fetch"],
"node-fetch-commonjs": ["./node_modules/node-fetch-commonjs"]
}
}
}
```#### Add types to the global scope (apps)
This *can* be used in applications, but it's not recommended.
```json
{
"compilerOptions": {
"types": ["@cuppachino/openapi-fetch", "node-fetch-commonjs"]
}
}
```## Additional features
### LcuValue
The [`LcuValue`](https://github.com/cuppachino/hexgate/blob/main/src/modules/lcu-value/index.ts) class implements [`Update`](https://github.com/cuppachino/hexgate/blob/main/src/types/update.ts) and [`CreateWithRecipe`](https://github.com/cuppachino/hexgate/blob/main/src/modules/recipe/index.ts#L40). It's useful for caching data retrieved from the LCU.
```ts
import { Connection, LcuValue, type OperationResponses } from 'hexgate'type LolOwnedChampionsMinimal =
OperationResponses<'GetLolChampionsV1OwnedChampionsMinimal'>class ChampionLookup extends LcuValue {
constructor() {
super(({ build, unwrap }) =>
unwrap(
build('/lol-champions/v1/owned-champions-minimal')
.method('get')
.create()
)
)
}championById(id: string | number | undefined) {
return this.inner?.find((c) => c.id === Number(id ?? 0))
}
}const champions = new ChampionLookup()
const client = new Connection({
async onConnect(con) {
await champions.update(con.https)
con.logger.info(
champions.championById(1) satisfies
| Partial[number]
)
}
})client.connect()
```## Development
This package uses [pnpm](https://pnpm.io) to manage dependencies. If you don't have pnpm, it can be installed globally using `npm`, `yarn`, `brew`, or `scoop`, as well as some other options. Check out the [pnpm documentation](https://pnpm.io/installation) for more information.
```ps1
pnpm i
```