speedruncom.js 1.3.1 → 2.0.1

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.
package/src/BaseClient.ts DELETED
@@ -1,108 +0,0 @@
1
- import axios, { AxiosResponse, AxiosInstance, AxiosError } from 'axios';
2
- import * as GetEndpoints from './endpoints/endpoints.get.js';
3
- import * as PostEndpoints from './endpoints/endpoints.post.js'
4
- import * as Responses from './responses.js';
5
-
6
- const BASE_USER_AGENT = 'speedruncom.js';
7
- const BASE_URL = 'https://www.speedrun.com/api/v2/';
8
- const HEADERS = {
9
- 'Accept-Language': 'en',
10
- 'Accept': 'application/json'
11
- }
12
-
13
- const isBrowser = typeof window !== 'undefined';
14
-
15
- const objectToBase64 = (obj: object) => {
16
- const jsonString = JSON.stringify(obj).replace(/\s+/g, '');
17
- return Buffer.from(jsonString).toString('base64');
18
- }
19
-
20
- export interface config {
21
- PHPSESSID?: string;
22
- userAgent?: string;
23
- }
24
-
25
- export class APIError extends Error {
26
- status: number;
27
-
28
- constructor(message: string, status: number) {
29
- super(message);
30
- this.message = message;
31
- this.status = status;
32
- }
33
- }
34
-
35
- export default class Client {
36
-
37
- /**
38
- * `AxiosInstance` used on instance-called methods (called with `POST`).
39
- */
40
- axiosClient = axios.create({
41
- baseURL: BASE_URL,
42
- method: 'POST',
43
- withCredentials: true,
44
- headers: HEADERS
45
- });
46
-
47
- /**
48
- * `AxiosInstance` used on Client-called methods (called with `GET`).
49
- */
50
- static axiosClient = axios.create({
51
- baseURL: BASE_URL,
52
- method: 'GET',
53
- headers: HEADERS
54
- });
55
-
56
- private username!: string;
57
- private password!: string;
58
-
59
- private headers = this.axiosClient.defaults.headers.common;
60
-
61
- constructor(config?: config) {
62
- if (config) this.config(config);
63
-
64
- this.axiosClient.interceptors.response.use(
65
- (response: AxiosResponse) => response,
66
- (error: AxiosError) => {
67
- const data = error.response.data as { error?: string };
68
- throw new APIError(data.error || 'Unknown error', error.response.status);
69
- }
70
- );
71
- }
72
-
73
- config(config: config) {
74
- if (!isBrowser) this.headers['User-Agent'] = BASE_USER_AGENT + (config.userAgent ? `/${config.userAgent}` : '');
75
-
76
- if (config.PHPSESSID) {
77
- if (isBrowser) {
78
- console.error('You cannot use a PHPSESSID to authenticate in a browser environment.');
79
- } else {
80
- this.headers['Cookie'] = `PHPSESSID=${config.PHPSESSID}`;
81
- }
82
- }
83
- }
84
-
85
- async request<T>(endpoint: string, params: object = {}): Promise<T> {
86
- const response = await this.axiosClient.post<T>(endpoint, params);
87
-
88
- const cookie = response.headers['set-cookie'];
89
- if (cookie && !isBrowser) this.headers['Cookie'] = cookie[0].split(';')[0];
90
-
91
- return response.data;
92
- }
93
-
94
- static async request<T>(endpoint: string, params: object = {}): Promise<T> {
95
- return (await this.axiosClient.get(`${endpoint}?_r=${objectToBase64(params)}`)).data;
96
- }
97
-
98
- /**
99
- * Attempts to remove the PHPSESSID cookie if using a browser, otherwise removes your Client's authentication.
100
- */
101
- async logout() {
102
- if (isBrowser) return await this.request('PutAuthLogout');
103
-
104
- delete this.headers['Cookie'];
105
- }
106
-
107
- // Endpoints (auto-generated with build-client)
108
- }
@@ -1,80 +0,0 @@
1
- import { Project, SourceFile, Node, OptionalKind, MethodDeclarationStructure } from 'ts-morph';
2
-
3
- const project = new Project({
4
- tsConfigFilePath: "tsconfig.json",
5
- });
6
-
7
- const isInterfaceEmpty = (interfaceName: string, sourceFile: SourceFile) => {
8
- const declarations = sourceFile.getExportedDeclarations().get(interfaceName);
9
- if (!declarations || declarations.length === 0) return false;
10
-
11
- const decl = declarations[0];
12
- if (!Node.isInterfaceDeclaration(decl)) return false;
13
-
14
- const type = decl.getType();
15
- const allProperties = type.getProperties();
16
-
17
- return allProperties.length === 0;
18
- };
19
-
20
-
21
- const isInterfaceAllOptional = (name: string, sourceFile: SourceFile) => {
22
- const iface = sourceFile.getInterface(name);
23
- if (iface) {
24
- return iface.getType().getProperties().every(p => p.isOptional());
25
- }
26
-
27
- const typeNode = sourceFile.getTypeAliasOrThrow(name).getType();
28
- return typeNode
29
- .getProperties()
30
- .every(p => p.isOptional());
31
- };
32
-
33
- const baseClient = project.getSourceFileOrThrow('src/BaseClient.ts');
34
- const clientFile = project.createSourceFile('src/Client.ts', baseClient.getFullText(), { overwrite: true });
35
- const clientClass = clientFile.getClasses()[1];
36
-
37
- const getEndpointsFile = project.getSourceFileOrThrow('src/endpoints/endpoints.get.ts');
38
- const postEndpointsFile = project.getSourceFileOrThrow('src/endpoints/endpoints.post.ts');
39
- const responsesFile = project.getSourceFileOrThrow('src/responses.ts');
40
-
41
- const getEndpointNames = Array.from(getEndpointsFile.getExportedDeclarations().keys());
42
- const postEndpointNames = Array.from(postEndpointsFile.getExportedDeclarations().keys());
43
-
44
- const responseNames = new Set(Array.from(responsesFile.getExportedDeclarations().keys()));
45
-
46
- const makeMethod = (name: string, isStatic: boolean, returnType: string, isEmpty: boolean, interfaces: string, isOptional: boolean) => {
47
- const method: OptionalKind<MethodDeclarationStructure> = {
48
- name,
49
- isStatic,
50
- isAsync: true,
51
- returnType,
52
- statements: [`return await this.request('${name}'${!isEmpty ? ', params' : ''});`]
53
- }
54
- if (!isEmpty) method.parameters = [{
55
- name: 'params',
56
- type: `${interfaces}.${name}`,
57
- hasQuestionToken: isOptional
58
- }];
59
-
60
- clientClass.addMethod(method);
61
- }
62
-
63
- for (const endpointName of getEndpointNames) {
64
- const returnType = responseNames.has(endpointName) ? `Promise<Readonly<Responses.${endpointName}>>` : 'Promise<void>';
65
- const isEmpty = isInterfaceEmpty(endpointName, getEndpointsFile);
66
- const isAllOptional = isInterfaceAllOptional(endpointName, getEndpointsFile);
67
-
68
- makeMethod(endpointName, false, returnType, isEmpty, 'GetEndpoints', isAllOptional);
69
- makeMethod(endpointName, true, returnType, isEmpty, 'GetEndpoints', isAllOptional);
70
- }
71
-
72
- for (const endpointName of postEndpointNames) {
73
- const returnType = responseNames.has(endpointName) ? `Promise<Readonly<Responses.${endpointName}>>` : 'Promise<void>';
74
- const isEmpty = isInterfaceEmpty(endpointName, postEndpointsFile);
75
- const isAllOptional = isInterfaceAllOptional(endpointName, postEndpointsFile);
76
-
77
- makeMethod(endpointName, false, returnType, isEmpty, 'PostEndpoints', isAllOptional);
78
- }
79
-
80
- clientFile.saveSync();
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes