// This file was auto-generated by @insertish/oapi! import type { APIRoutes } from "./routes.js"; export type { APIRoutes } from "./routes.js"; export * from "./types.js"; import { defaultBaseURL } from "./baseURL.js"; import { pathResolve, queryParams } from "./params.js"; import { JSONParse, JSONStringify } from 'json-with-bigint'; type Methods = APIRoutes["method"]; type PickRoutes = APIRoutes & { method: Method }; type GetRoutes = PickRoutes<"get">; type PatchRoutes = PickRoutes<"patch">; type PutRoutes = PickRoutes<"put">; type DeleteRoutes = PickRoutes<"delete">; type PostRoutes = PickRoutes<"post">; type Count< Str extends string, SubStr extends string, Matches extends null[] = [] > = Str extends `${infer _}${SubStr}${infer After}` ? Count : Matches["length"]; /** * Get the specific path name of any given path. * @param anyPath Any path * @returns Specific path */ export function getPathName(anyPath: string) { const segments = anyPath.split("/"); const list = (pathResolve as unknown as Record)[ (segments.length - 1).toString() ] || []; for (const entry of list) { let i = 1; let copy = [...segments]; for (i; i < segments.length; i++) { if (Array.isArray(entry[i - 1])) { copy[i] = entry[i - 1]; continue; } else if (entry[i - 1] !== segments[i]) break; } if (i === segments.length) return copy.join("/"); } } /** * Client configuration options */ export interface Options { /** * Base URL of the Revolt node */ baseURL: string; /** * Additional headers to apply to requests */ headers?: Record; /** * Authentication used for requests */ authentication: { rauth?: string | undefined; revolt?: { token: string } | string | undefined; headers?: Record; }; } /** * Request options */ export interface RequestOptions { /** * The base URL used for this request */ baseURL?: string; /** * The type of response given */ responseType?: "blob" | "json" | "text" | "arrayBuffer"; /** * Headers to apply for this request */ headers?: Record; } /** * API Client */ export class API { private baseURL: Options["baseURL"]; private authentication: Options["authentication"]; private headers: Options["headers"]; constructor({ baseURL, authentication, headers }: Partial = {}) { this.baseURL = baseURL || defaultBaseURL; this.authentication = authentication || {}; this.headers = headers || {}; } /** * Generate authentication options. */ get auth(): Record { if (this.authentication.rauth) { if (typeof this.authentication.rauth === "string") { return { "X-Session-Token": this.authentication.rauth, }; } } else if (this.authentication.revolt) { switch (typeof this.authentication.revolt) { case "string": { return { "X-Bot-Token": this.authentication.revolt, }; } case "object": { return { "X-Session-Token": this.authentication.revolt.token, }; } } } else if (this.authentication.headers) { return this.authentication.headers; } return {}; } /** * Generate config to pass through to API. */ get config(): RequestOptions { return { baseURL: this.baseURL, headers: { ...this.auth, ...this.headers, }, }; } /** * Send any arbitrary request. * @param method HTTP Method * @param path Path * @param params Body or Query Parameters * @param config Request configuration * @returns Typed Response Data */ async req< Method extends Methods, Routes extends PickRoutes, Path extends Routes["path"], Route extends Routes & { path: Path; parts: Count } >( method: Method, path: Path, params: Route["params"], config?: RequestOptions ): Promise { let query = new URLSearchParams(); let body = {} as Record; let named = getPathName(path); // If we are aware of this route, then match the parameters given. if (named && typeof params === "object") { const route = queryParams[named as keyof typeof queryParams]; const allowed_query = (route as unknown as Record)[ method ]; // Map each parameter to the correct object. for (const parameter of Object.keys(params)) { // omit undefined values if (typeof (params as Record)[parameter] !== "undefined") { if (allowed_query?.includes(parameter)) { query.append(parameter, (params as Record)[parameter]); } else { body[parameter] = (params as Record)[parameter]; } } } } const passbody = ["head", "get"].includes(method) ? undefined : JSONStringify(body); let fetchpath = `${path}?${query.toString()}`; if (fetchpath.startsWith("/")) { fetchpath = (config?.baseURL || this.baseURL) + fetchpath; } const fetchdata = await fetch(new URL(fetchpath).toString(), { method: method.toUpperCase(), headers: { ...(config?.headers || {}), ...(this.config.headers || {}), } as HeadersInit, body: passbody, }); const respType = config?.responseType || "json"; const data = fetchdata.status === 204 ? null : await fetchdata[respType === 'json' ? 'text' : respType](); if (fetchdata.ok) { return respType === 'json' ? JSONParse(data as string) : data as never; } else { throw data; } } /** * Send HTTP GET request. * @param path Path * @param params Body or Query Parameters * @param config Axios configuration * @returns Typed Response Data */ get< Path extends GetRoutes["path"], Route extends GetRoutes & { path: Path; parts: Count } >( path: Path, params: Route["params"], config?: RequestOptions ): Promise; /** * Send HTTP GET request. * @param path Path * @returns Typed Response Data */ get< Path extends (GetRoutes & { params: undefined })["path"], Route extends GetRoutes & { path: Path; parts: Count } >(path: Path): Promise; get(path: any, params?: any, config?: RequestOptions): Promise { // @ts-ignore-next-line return this.req("get", path, params, config); } /** * Send HTTP PATCH request. * @param path Path * @param params Body or Query Parameters * @param config Axios configuration * @returns Typed Response Data */ patch< Path extends PatchRoutes["path"], Route extends PatchRoutes & { path: Path; parts: Count } >( path: Path, params: Route["params"], config?: RequestOptions ): Promise; /** * Send HTTP PATCH request. * @param path Path * @returns Typed Response Data */ patch< Path extends (PatchRoutes & { params: undefined })["path"], Route extends PatchRoutes & { path: Path; parts: Count } >(path: Path): Promise; patch(path: any, params?: any, config?: RequestOptions): Promise { // @ts-ignore-next-line return this.req("patch", path, params, config); } /** * Send HTTP PUT request. * @param path Path * @param params Body or Query Parameters * @param config Axios configuration * @returns Typed Response Data */ put< Path extends PutRoutes["path"], Route extends PutRoutes & { path: Path; parts: Count } >( path: Path, params: Route["params"], config?: RequestOptions ): Promise; /** * Send HTTP PUT request. * @param path Path * @returns Typed Response Data */ put< Path extends (PutRoutes & { params: undefined })["path"], Route extends PutRoutes & { path: Path; parts: Count } >(path: Path): Promise; put(path: any, params?: any, config?: RequestOptions): Promise { // @ts-ignore-next-line return this.req("put", path, params, config); } /** * Send HTTP DELETE request. * @param path Path * @param params Body or Query Parameters * @param config Axios configuration * @returns Typed Response Data */ delete< Path extends DeleteRoutes["path"], Route extends DeleteRoutes & { path: Path; parts: Count } >( path: Path, params?: any, config?: RequestOptions ): Promise; /** * Send HTTP DELETE request. * @param path Path * @param params Body or Query Parameters * @returns Typed Response Data */ delete< Path extends (DeleteRoutes & { params: undefined })["path"], Route extends DeleteRoutes & { path: Path; parts: Count } >(path: Path, params?: any): Promise; delete(path: any, params?: any, config?: RequestOptions): Promise { // @ts-ignore-next-line return this.req("delete", path, params, config); } /** * Send HTTP POST request. * @param path Path * @param params Body or Query Parameters * @param config Axios configuration * @returns Typed Response Data */ post< Path extends PostRoutes["path"], Route extends PostRoutes & { path: Path; parts: Count } >( path: Path, params: Route["params"], config?: RequestOptions ): Promise; /** * Send HTTP POST request. * @param path Path * @returns Typed Response Data */ post< Path extends (PostRoutes & { params: undefined })["path"], Route extends PostRoutes & { path: Path; parts: Count } >(path: Path): Promise; post(path: any, params?: any, config?: RequestOptions): Promise { // @ts-ignore-next-line return this.req("post", path, params, config); } }