speedruncom.js 2.0.7 → 2.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,7 @@
1
1
  on:
2
2
  push:
3
- branches:
4
- - main
5
- workflow_dispatch:
3
+ tags:
4
+ - 'v*'
6
5
 
7
6
  permissions:
8
7
  id-token: write
package/README.md CHANGED
@@ -1,13 +1,5 @@
1
- # About
1
+ # speedruncom.js
2
2
 
3
3
  Speedrun.com has two API versions. Version 1 is officially documented, REST, public and directly exposed to users. Version 2 is a pre-production RPC API designed only for internal use of site functions, and is much more complicated and less user-friendly, especially regarding authentication and browser CORS.
4
4
 
5
- Version 1 is mainly read-only, and when it isn't read only it may just be broken. If you want to use any of the modern features of the site now, you'll use version 2. This is a NodeJS wrapper for Speedrun API version 2, with parameters and responses all documented in TypeScript and JSDoc.
6
-
7
- This module isn't intended to give any helper functions to the user; it's more of an index of the params and responses of the site endpoints, to be used for type checking on a more user-friendly module.
8
-
9
- # Usage
10
-
11
- **`npm i speedruncom.js`**
12
-
13
- `Client` is the default export, and enums and interfaces are the named exports for TypeScript users.
5
+ Version 1 is mainly read-only, and when it isn't read only it may just be broken. If you want to use any of the modern features of the site now, you'll use version 2. This package consists of types that make up this undocumented api, and a small utility for calling GET and POST.
package/bun.lock CHANGED
@@ -1,68 +1,20 @@
1
1
  {
2
2
  "lockfileVersion": 1,
3
+ "configVersion": 0,
3
4
  "workspaces": {
4
5
  "": {
5
6
  "name": "speedruncom.js",
6
- "dependencies": {
7
- "axios": "^1.9.0",
8
- },
9
7
  "devDependencies": {
10
- "@types/node": "^25.5.0",
11
- "typescript": "^5.8.3",
8
+ "@types/node": "^25.9.3",
9
+ "typescript": "^6.0.3",
12
10
  },
13
11
  },
14
12
  },
15
13
  "packages": {
16
- "@types/node": ["@types/node@25.5.0", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw=="],
17
-
18
- "asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="],
19
-
20
- "axios": ["axios@1.13.5", "", { "dependencies": { "follow-redirects": "^1.15.11", "form-data": "^4.0.5", "proxy-from-env": "^1.1.0" } }, "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q=="],
21
-
22
- "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="],
23
-
24
- "combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="],
25
-
26
- "delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="],
27
-
28
- "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
29
-
30
- "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="],
31
-
32
- "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="],
33
-
34
- "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="],
35
-
36
- "es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="],
37
-
38
- "follow-redirects": ["follow-redirects@1.15.11", "", {}, "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ=="],
39
-
40
- "form-data": ["form-data@4.0.5", "", { "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" } }, "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w=="],
41
-
42
- "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
43
-
44
- "get-intrinsic": ["get-intrinsic@1.3.0", "", { "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" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="],
45
-
46
- "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="],
47
-
48
- "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="],
49
-
50
- "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="],
51
-
52
- "has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="],
53
-
54
- "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
55
-
56
- "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
57
-
58
- "mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
59
-
60
- "mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
61
-
62
- "proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="],
14
+ "@types/node": ["@types/node@25.9.3", "", { "dependencies": { "undici-types": ">=7.24.0 <7.24.7" } }, "sha512-603BddQMv3pUcr4U2dhujk83N2tTDVr/34wII2B6bJy6g+8WD6yUb11jszNs0gdi4PesVWl7ABt8nYMVpnLUcg=="],
63
15
 
64
- "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
16
+ "typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="],
65
17
 
66
- "undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="],
18
+ "undici-types": ["undici-types@7.24.6", "", {}, "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg=="],
67
19
  }
68
20
  }
@@ -391,6 +391,11 @@ export default interface POSTEndpoints {
391
391
  verified?: Enums.RunStatus;
392
392
  verifiedById?: string;
393
393
  videoState?: Enums.VideoState;
394
+ /**
395
+ * The maximum amount of moderation runs per page.
396
+ *
397
+ * @max 100
398
+ */
394
399
  limit: number;
395
400
  page: number;
396
401
  };
@@ -1,4 +1,3 @@
1
1
  export * from './enums.js';
2
2
  export * from './interfaces.js';
3
- import Client from './Client.js';
4
- export default Client;
3
+ export * from './requests.js';
@@ -1,4 +1,3 @@
1
1
  export * from './enums.js';
2
2
  export * from './interfaces.js';
3
- import Client from './Client.js';
4
- export default Client;
3
+ export * from './requests.js';
@@ -716,7 +716,7 @@ export interface Game {
716
716
  addedDate: number;
717
717
  touchDate: number;
718
718
  baseGameId?: string;
719
- coverPath: string;
719
+ coverPath?: string;
720
720
  trophy1stPath?: string;
721
721
  trophy2ndPath?: string;
722
722
  trophy3rdPath?: string;
@@ -0,0 +1,7 @@
1
+ import GETEndpoints from './endpoints/endpoints.get.js';
2
+ import POSTEndpoints from './endpoints/endpoints.post.js';
3
+ import Responses from './responses.js';
4
+ type Endpoints = GETEndpoints & POSTEndpoints;
5
+ export declare function get<E extends keyof GETEndpoints, P extends GETEndpoints[E]>(endpoint: E, params: P): Promise<Responses[E]>;
6
+ export declare function post<E extends keyof Endpoints, P extends Endpoints[E]>(endpoint: E, params: P): Promise<E extends keyof Responses ? Responses[E] : void>;
7
+ export {};
@@ -0,0 +1,17 @@
1
+ const objectToBase64 = (obj) => {
2
+ const jsonString = JSON.stringify(obj).replace(/\s+/g, '');
3
+ return Buffer.from(jsonString).toString('base64').replace(/=+$/, '');
4
+ };
5
+ const baseUrl = 'https://www.speedrun.com/api/v2';
6
+ export async function get(endpoint, params) {
7
+ const res = await fetch(`${baseUrl}/${endpoint}?_r=${objectToBase64(params)}`);
8
+ return await res.json();
9
+ }
10
+ export async function post(endpoint, params) {
11
+ const res = await fetch(`${baseUrl}/${endpoint}`, {
12
+ method: "POST",
13
+ headers: { "Content-Type": "application/json" },
14
+ body: JSON.stringify(params)
15
+ });
16
+ return await res.json();
17
+ }
package/package.json CHANGED
@@ -1,23 +1,21 @@
1
1
  {
2
2
  "name": "speedruncom.js",
3
- "version": "2.0.7",
4
- "description": "WIP NodeJS module for Speedrun's version 2 API.",
5
- "type": "module",
6
- "license": "MIT",
3
+ "version": "2.0.8",
7
4
  "author": "retrozy",
8
- "dependencies": {
9
- "axios": "^1.9.0"
10
- },
11
- "types": "lib/index.d.ts",
12
- "scripts": {
13
- "build": "tsc"
5
+ "repository": {
6
+ "url": "https://github.com/retrozy1/speedruncom.js"
14
7
  },
8
+ "main": "lib/index.js",
15
9
  "devDependencies": {
16
- "@types/node": "^25.5.0",
17
- "typescript": "^5.8.3"
10
+ "@types/node": "^25.9.3",
11
+ "typescript": "^6.0.3"
18
12
  },
19
- "main": "lib/index.js",
20
- "repository": {
21
- "url": "https://github.com/retrozy1/speedruncom.js"
22
- }
13
+ "description": "WIP NodeJS module for Speedrun's version 2 API.",
14
+ "license": "MIT",
15
+ "scripts": {
16
+ "build": "tsc",
17
+ "check": "tsc --noEmit"
18
+ },
19
+ "type": "module",
20
+ "types": "lib/index.d.ts"
23
21
  }
@@ -474,6 +474,12 @@ export default interface POSTEndpoints {
474
474
  verified?: Enums.RunStatus;
475
475
  verifiedById?: string;
476
476
  videoState?: Enums.VideoState;
477
+
478
+ /**
479
+ * The maximum amount of moderation runs per page.
480
+ *
481
+ * @max 100
482
+ */
477
483
  limit: number;
478
484
  page: number;
479
485
  };
package/src/index.ts CHANGED
@@ -1,6 +1,3 @@
1
1
  export * from './enums.js';
2
2
  export * from './interfaces.js';
3
-
4
- import Client from './Client.js';
5
-
6
- export default Client;
3
+ export * from './requests.js'
package/src/interfaces.ts CHANGED
@@ -853,7 +853,7 @@ export interface Game {
853
853
  addedDate: number;
854
854
  touchDate: number;
855
855
  baseGameId?: string;
856
- coverPath: string; //check if opt
856
+ coverPath?: string;
857
857
  trophy1stPath?: string;
858
858
  trophy2ndPath?: string;
859
859
  trophy3rdPath?: string;
@@ -0,0 +1,26 @@
1
+ import GETEndpoints from './endpoints/endpoints.get.js';
2
+ import POSTEndpoints from './endpoints/endpoints.post.js'
3
+ import Responses from './responses.js';
4
+
5
+ type Endpoints = GETEndpoints & POSTEndpoints;
6
+
7
+ const objectToBase64 = (obj: object) => {
8
+ const jsonString = JSON.stringify(obj).replace(/\s+/g, '');
9
+ return Buffer.from(jsonString).toString('base64').replace(/=+$/, '');
10
+ };
11
+
12
+ const baseUrl = 'https://www.speedrun.com/api/v2';
13
+
14
+ export async function get<E extends keyof GETEndpoints, P extends GETEndpoints[E]>(endpoint: E, params: P): Promise<Responses[E]> {
15
+ const res = await fetch(`${baseUrl}/${endpoint}?_r=${objectToBase64(params)}`);
16
+ return await res.json();
17
+ }
18
+
19
+ export async function post<E extends keyof Endpoints, P extends Endpoints[E]>(endpoint: E, params: P): Promise<E extends keyof Responses ? Responses[E] : void> {
20
+ const res = await fetch(`${baseUrl}/${endpoint}`, {
21
+ method: "POST",
22
+ headers: { "Content-Type": "application/json" },
23
+ body: JSON.stringify(params)
24
+ });
25
+ return await res.json();
26
+ }
package/tsconfig.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "compilerOptions": {
3
3
  "outDir": "./lib",
4
+ "rootDir": "./",
4
5
  "allowJs": true,
5
6
  "checkJs": false,
6
7
  "strict": false,
7
8
  "target": "ES2020",
8
9
  "module": "ESNext",
9
- "moduleResolution": "node",
10
- "esModuleInterop": true,
11
10
  "forceConsistentCasingInFileNames": true,
12
11
  "resolveJsonModule": true,
13
- "declaration": true
12
+ "declaration": true,
13
+ "types": ["node"]
14
14
  },
15
15
  "include": ["src/**/*"]
16
16
  }
package/lib/Client.d.ts DELETED
@@ -1,11 +0,0 @@
1
- import { AxiosRequestConfig } from 'axios';
2
- import GETEndpoints from './endpoints/endpoints.get.js';
3
- import POSTEndpoints from './endpoints/endpoints.post.js';
4
- import Responses from './responses.js';
5
- type Endpoints = GETEndpoints & POSTEndpoints;
6
- export default class Client {
7
- axiosClient: import("axios").AxiosInstance;
8
- get<E extends keyof GETEndpoints, P extends GETEndpoints[E]>(endpoint: E, params: P, axiosConfig?: AxiosRequestConfig): Promise<import("axios").AxiosResponse<Responses[E], any, {}>>;
9
- post<E extends keyof Endpoints, P extends Endpoints[E]>(endpoint: E, params: P, axiosConfig?: AxiosRequestConfig): Promise<import("axios").AxiosResponse<E extends keyof Responses ? Responses[E] : void, any, {}>>;
10
- }
11
- export {};
package/lib/Client.js DELETED
@@ -1,25 +0,0 @@
1
- import axios from 'axios';
2
- const objectToBase64 = (obj) => {
3
- const jsonString = JSON.stringify(obj).replace(/\s+/g, '');
4
- return Buffer.from(jsonString).toString('base64');
5
- };
6
- export default class Client {
7
- constructor() {
8
- this.axiosClient = axios.create({
9
- baseURL: 'https://www.speedrun.com/api/v2/',
10
- headers: {
11
- 'Accept-Language': 'en',
12
- '_': '',
13
- 'User-Agent': null
14
- },
15
- withCredentials: true,
16
- transformRequest: [data => typeof data === 'string' ? data : JSON.stringify(data)]
17
- });
18
- }
19
- async get(endpoint, params, axiosConfig) {
20
- return await this.axiosClient.get(`${endpoint}?_r=${objectToBase64(params)}`, axiosConfig);
21
- }
22
- async post(endpoint, params, axiosConfig) {
23
- return await this.axiosClient.post(endpoint, params, axiosConfig);
24
- }
25
- }
package/src/Client.ts DELETED
@@ -1,33 +0,0 @@
1
- import axios, { AxiosRequestConfig } from 'axios';
2
- import GETEndpoints from './endpoints/endpoints.get.js';
3
- import POSTEndpoints from './endpoints/endpoints.post.js'
4
- import Responses from './responses.js';
5
-
6
- type Endpoints = GETEndpoints & POSTEndpoints;
7
-
8
- const objectToBase64 = (obj: object) => {
9
- const jsonString = JSON.stringify(obj).replace(/\s+/g, '');
10
- return Buffer.from(jsonString).toString('base64');
11
- };
12
-
13
- export default class Client {
14
- axiosClient = axios.create({
15
- baseURL: 'https://www.speedrun.com/api/v2/',
16
- headers: {
17
- 'Accept-Language': 'en',
18
- '_': '',
19
- 'User-Agent': null
20
- },
21
- withCredentials: true,
22
- transformRequest: [data => typeof data === 'string' ? data : JSON.stringify(data)]
23
- });
24
-
25
-
26
- async get<E extends keyof GETEndpoints, P extends GETEndpoints[E]>(endpoint: E, params: P, axiosConfig?: AxiosRequestConfig) {
27
- return await this.axiosClient.get<Responses[E]>(`${endpoint}?_r=${objectToBase64(params)}`, axiosConfig);
28
- }
29
-
30
- async post<E extends keyof Endpoints, P extends Endpoints[E]>(endpoint: E, params: P, axiosConfig?: AxiosRequestConfig) {
31
- return await this.axiosClient.post<E extends keyof Responses ? Responses[E] : void>(endpoint, params, axiosConfig);
32
- }
33
- }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes