{"id":13632999,"url":"https://github.com/cuppachino/hexgate","last_synced_at":"2026-02-28T08:32:49.727Z","repository":{"id":179276823,"uuid":"615896088","full_name":"cuppachino/hexgate","owner":"cuppachino","description":" LCU API wrapper for League of Legends","archived":false,"fork":false,"pushed_at":"2023-12-06T01:43:29.000Z","size":906,"stargazers_count":19,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-28T03:19:41.117Z","etag":null,"topics":["esm","hexgate","javascript","lcu","lcu-api","league-of-legends","node-esm","nodenext","riot-games","riot-games-api","typescript","typescript-library"],"latest_commit_sha":null,"homepage":"https://hexgate.app/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cuppachino.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2023-03-19T01:42:16.000Z","updated_at":"2024-07-16T07:23:57.000Z","dependencies_parsed_at":null,"dependency_job_id":"e09050f3-7cf4-4b11-b677-343dfbe24aa7","html_url":"https://github.com/cuppachino/hexgate","commit_stats":null,"previous_names":["cuppachino/hexgate"],"tags_count":48,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cuppachino%2Fhexgate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cuppachino%2Fhexgate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cuppachino%2Fhexgate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cuppachino%2Fhexgate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cuppachino","download_url":"https://codeload.github.com/cuppachino/hexgate/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243878408,"owners_count":20362431,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["esm","hexgate","javascript","lcu","lcu-api","league-of-legends","node-esm","nodenext","riot-games","riot-games-api","typescript","typescript-library"],"created_at":"2024-08-01T23:00:22.694Z","updated_at":"2026-02-28T08:32:44.702Z","avatar_url":"https://github.com/cuppachino.png","language":"TypeScript","funding_links":[],"categories":["Developer Tools"],"sub_categories":[],"readme":"# Hexgate\n\n[![Discord](https://img.shields.io/discord/1080840305441525766?color=5865f2\\\u0026label=\\\u0026logo=discord\\\u0026logoColor=ffffff)](https://discord.gg/HEd72YnzVq)\n[![Codacy Badge](https://api.codacy.com/project/badge/Grade/f9cec6d6f8cf407fb2ef8a4ab82af87c)](https://app.codacy.com/gh/cuppachino/hexgate?utm_source=github.com\\\u0026utm_medium=referral\\\u0026utm_content=cuppachino/hexgate\\\u0026utm_campaign=Badge_Grade)\n[![Release](https://github.com/cuppachino/hexgate/actions/workflows/release.yml/badge.svg?branch=main)](https://github.com/cuppachino/hexgate/actions/workflows/release.yml)\n[![License](https://img.shields.io/github/license/cuppachino/hexgate?color=ffca4a)](https://github.com/cuppachino/hexgate/blob/528f647166eddef82e0ceb15ac8feafb56e97773/LICENSE)\n[![npm (scoped)](https://img.shields.io/npm/v/hexgate?color=%23fb3e44)](https://www.npmjs.com/package/hexgate)\n\n[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).\n\nPlease refer to the [wiki](https://github.com/cuppachino/hexgate/wiki) for more info.\n\n\u003c!-- todo: add more info --\u003e\n\n## Installation\n\nAdd it to your own project using your favorite package manager.\n\n```shell\npnpm add hexgate\n```\n\n```shell\nnpm i hexgate\n```\n\n```shell\nyarn add hexgate\n```\n\n### ESM\n\n```ts\nimport { ... } from \"hexgate\"\n```\n\n### CJS\n\n```ts\nimport hexgate = require(\"hexgate\")\nconst { ... } = hexgate\n```\n\n## Authentication\n\nWait 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.\n\n```ts\nimport { auth, poll } from \"hexgate\"\n\nconst credentials = await poll(auth)\n```\n\nOpt-out of safe authentication by explicity passing an `undefined` certifcate.\n\n```ts\nconst unsafeCredentials = await auth({ certificate: undefined })\n```\n\nOnce you have the credentials, you can create a new [`Hexgate`](./src/modules/hexgate/index.ts) and [`LcuClient`](./src/modules/websocket/index.ts).\n\n```ts\nimport { Hexgate as HttpsClient, LcuClient as WsClient } from \"hexgate\"\n\nconst httpsClient = new HttpsClient(credentials)\nconst websocketClient = new WsClient(credentials)\n```\n\nWorking with multiple clients? Get get `all` credentials.\n\n```ts\nimport { auth, createHexgate, createLcuClient, poll, zip } from 'hexgate'\n\nconst credentials = await poll(() =\u003e auth({ all: true }))\n\n// ~ some multi-connection interface\nconst clients = new Set(\n  zip(\n    credentials.map(createHexgate),\n    credentials.map(createLcuClient)\n  )\n)\n```\n\n## Builder API\n\nThe 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.\n\n```ts\nimport { Hexgate as HttpsClient } from 'hexgate'\n\nconst https = new HttpsClient(credentials)\n\n// (arg: string[], init?: any) =\u003e Promise\u003cApiResponse\u003c{ ... }\u003e\u003e\nconst getSummonersFromNames = https\n  .build('/lol-summoner/v2/summoners/names')\n  .method('post')\n  .create()\n\nconst summoner = await getSummonersByName(['dubbleignite'])\nconsole.log(summoner.data)\n```\n\n## Websocket Events\n\nSubscribe to LCU events through the client.\n\n```ts\nimport { LcuClient as WsClient } from 'hexgate'\n\nconst ws = new WsClient(credentials)\n\nws.subscribe(\n  'OnJsonApiEvent_lol-champ-select_v1_session',\n  ({ data, eventType, uri }) =\u003e {\n    // side effects\n  }\n)\n```\n\n\u003e 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.\n\n## ⚡️ Connection\n\nThe [`Connection`](https://github.com/cuppachino/hexgate/blob/main/src/modules/connection/index.ts) class further abstracts `Hexgate` \u0026 `LcuClient` and handles authentication between client shutdowns. Configuration is optional.\n\n```ts\nimport { Connection } from 'hexgate'\n\nconst client = new Connection({\n  // Recipe API (createRecipe or recipe)\n  createRecipe({ build, unwrap }) {\n    return {\n      getCurrentSummoner: unwrap(\n        build('/lol-summoner/v1/current-summoner').method('get').create()\n      )\n    }\n  },\n  // Propagate status to browser windows.\n  onStatusChange(status) {\n    emit('status', status)\n  },\n  // Init\n  async onConnect(con) {\n    con.ws.subscribe('OnJsonApiEvent_lol-champ-select_v1_session', handleChampSelect)\n    const summoner = await con.recipe.getCurrentSummoner()\n    con.logger.info(summoner, `Welcome, ${summoner.displayName}`)\n  },\n  // Automatically reconnect\n  async onDisconnect(discon) {\n    await sleep(4000)\n    discon.connect()\n  },\n  // Authentication interval\n  interval: 2000,\n  // Bring any logger\n  logger: pino({\n    name: 'main' as const\n  })\n})\n\nclient.connect()\n```\n\nThe `Connection` class supports recipes, define a `recipe: Recipe` or a `createRecipe: RecipeApiFn` method in the `ConnectionConfig` constructor argument.\n\n```ts\nimport { Connection, createRecipe } from 'hexgate'\n\nconst recipe = createRecipe(({ build }) =\u003e ({/*...*/}))\nconst client = new Connection({\n  recipe\n})\n```\n\n```ts\nimport { Connection } from 'hexgate'\n\nconst client = new Connection({\n  createRecipe({ build }) { return {/*...*/} }\n})\n```\n\n\u003cp align='center'\u003e\n  \u003cimg src=\"connection.excalidraw.png\" width=600/\u003e\n\u003c/p\u003e\n\n## Recipe API\n\n[`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.\n\n### Intro\n\n#### Step 1: Create a recipe\n\nThis 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.\n\n```ts\nimport { createRecipe } from \"hexgate\"\n\n/**\n * \u003cT extends HttpsClient\u003e(httpsClient: T) =\u003e \n *   (arg: string[], init?: RequestInit) =\u003e \n *     Promise\u003cApiResponse\u003c{...}\u003e\u003e\n */\nconst getSummonersFromNamesRecipe = createRecipe(({ build }) =\u003e\n  build('/lol-summoner/v2/summoners/names')\n    .method('post')\n    .create()\n)\n```\n\n#### Step 2: Once you have a recipe, you just need to pass it a `Hexgate`.\n\n```ts\nconst getSummonersFromNames = getSummonersFromNamesRecipe(httpsClient)\n\nconst summoners = await getSummonersFromNames(['dubbleignite'])\nconsole.table(summoners.data)\n```\n\n### 🦋 Transforming requests\n\nUse [`wrap`](https://github.com/cuppachino/hexgate/blob/main/src/utils/proxy-function.ts#L51), `from`, `to`, and `unwrap` to design your api.\n\n```ts\nconst summonersRecipe = createRecipe(({ build, wrap, from, to, unwrap }) =\u003e ({\n  getSummoners: {\n    /**\n     * Default for reference.\n     * (arg: { ids?: string; }, init?: RequestInit) =\u003e Promise\u003cApiResponse\u003c{...}\u003e\u003e\n     */\n    v2SummonersDefault: build('/lol-summoner/v2/summoners')\n      .method('get')\n      .create(),\n\n    /**\n     * unwrap extracts the data property from an ApiResponse.\n     * (arg: { ids?: string }, init?: RequestInit) =\u003e Promise\u003c{...}\u003e\n     */\n    v2SummonersAwaited: unwrap(\n      build('/lol-summoner/v2/summoners').method('get').create(),\n    ),\n\n    /**\n     * wrap let's us overwrite the parameters type by supplying conversion functions.\n     * (summonerIds: (number | `${number}`)[], init?: RequestInit | undefined) =\u003e Promise\u003c{...}\u003e\n     */\n    fromSummonerIds: wrap(\n      build('/lol-summoner/v2/summoners').method('get').create(),\n    )({\n      // The return type of `from` is constrained by the expected return type of the function being wrapped.\n      from(summonerIds: Array\u003c`${number}` | number\u003e, init?) {\n        return [{ ids: JSON.stringify(summonerIds) }, init];\n      },\n      // awaits data similarly to `unwrap`\n      to,\n    }),\n  },\n}));\n```\n\n### ⚒️ `Recipe`, `RecipeApiFn`, and `CreateWithRecipe`\n\nSome 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.\n\n```ts\nimport type { CreateWithRecipe } from 'hexgate'\n\nclass Foo\u003cT\u003e extends CreateWithRecipe\u003cT\u003e {}\nnew Foo(recipe)\nnew Foo((recipeApi) =\u003e \"your recipe\" as const)\n```\n\n### Exporting recipes\n\nIf 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`:\n\n#### Map paths (Recommended)\n\nUse this option if you are making a library.\n\n```json\n{\n  \"compilerOptions\": {\n    \"paths\": {\n      \"@cuppachino/openapi-fetch\": [\"./node_modules/@cuppachino/openapi-fetch\"],\n      \"node-fetch-commonjs\": [\"./node_modules/node-fetch-commonjs\"]\n    }\n  }\n}\n```\n\n#### Add types to the global scope (apps)\n\nThis *can* be used in applications, but it's not recommended.\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"@cuppachino/openapi-fetch\", \"node-fetch-commonjs\"]\n  }\n}\n```\n\n## Additional features\n\n### LcuValue\n\nThe [`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.\n\n```ts\nimport { Connection, LcuValue, type OperationResponses } from 'hexgate'\n\ntype LolOwnedChampionsMinimal =\n  OperationResponses\u003c'GetLolChampionsV1OwnedChampionsMinimal'\u003e\n\nclass ChampionLookup extends LcuValue\u003cLolOwnedChampionsMinimal\u003e {\n  constructor() {\n    super(({ build, unwrap }) =\u003e\n      unwrap(\n        build('/lol-champions/v1/owned-champions-minimal')\n          .method('get')\n          .create()\n      )\n    )\n  }\n\n  championById(id: string | number | undefined) {\n    return this.inner?.find((c) =\u003e c.id === Number(id ?? 0))\n  }\n}\n\nconst champions = new ChampionLookup()\n\nconst client = new Connection({\n  async onConnect(con) {\n    await champions.update(con.https)\n    con.logger.info(\n    champions.championById(1) satisfies\n        | Partial\u003cLolOwnedChampionsMinimal\u003e[number]\n    )\n  }\n})\n\nclient.connect()\n```\n\n## Development\n\nThis 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.\n\n```ps1\npnpm i\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcuppachino%2Fhexgate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcuppachino%2Fhexgate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcuppachino%2Fhexgate/lists"}