import ky from "ky"; import { isArray, isEmpty } from "lodash-es"; export type ValidResponse = { result: true; }; export type APIRecoveryType = "login" | "2fa" | "gateway" | "game_login" | "game_quota"; export const APIRecoveryConst = { Login: 'login', TwoFactorAuth: '2fa', Gateway: 'gateway', GameLogin: 'game_login', GameQuota: 'game_quota', } as const; export type InvalidResponse = { result: false; reason: string; recovery?: APIRecoveryType; recovery_arg?: string | number; }; export type RawArgType = Record | Record[] | undefined; interface BasicAPICallT< ArgType extends RawArgType, ResultType extends ValidResponse, ErrorType extends InvalidResponse > { (args: ArgType): Promise; (args: ArgType, returnError: false): Promise; (args: ArgType, returnError: true): Promise; } interface EmptyAPICallT { (): Promise; (args: undefined): Promise; (args: undefined, returnError: false): Promise; (args: undefined, returnError: true): Promise; } // eslint-disable-next-line @typescript-eslint/no-explicit-any export type ArgTypeOf = T extends APICallT ? A : never; export type APICallT< ArgType extends RawArgType, ResultType extends ValidResponse = ValidResponse, ErrorType extends InvalidResponse = InvalidResponse > = ArgType extends undefined ? EmptyAPICallT : BasicAPICallT; type HttpMethod = "get" | "post" | "put" | "patch" | "head" | "delete"; export type APITail = typeof GET | typeof POST | typeof PUT | typeof PATCH | typeof HEAD | typeof DELETE; const httpMethodMap = new Map([ [GET, "get"], [POST, "post"], [PUT, "put"], [PATCH, "patch"], [HEAD, "head"], [DELETE, "delete"], ]); export function extractHttpMethod(tail: APITail): HttpMethod { return httpMethodMap.get(tail) ?? "post"; } const apiTarget = "api.php"; let apiPath = apiTarget; export function setSammoAPIPrefix(prefix: string) { apiPath = `${prefix}/${apiTarget}`; } export async function callSammoAPI( method: HttpMethod, path: string | string[], args: RawArgType, paramArgs: Record | undefined ): Promise; export async function callSammoAPI( method: HttpMethod, path: string | string[], args: RawArgType, paramArgs: Record | undefined, returnError: false ): Promise; export async function callSammoAPI( method: HttpMethod, path: string | string[], args: RawArgType, paramArgs: Record | undefined, returnError: true ): Promise; export async function callSammoAPI( method: HttpMethod, path: string | string[], args: RawArgType, paramArgs: Record | undefined, returnError = false ): Promise { if (isArray(path)) { path = path.join("/"); } if (args && isEmpty(args)) { args = undefined; } const result = (await (() => { if (method == "get") { return ky(apiPath, { searchParams: { ...paramArgs, ...(args as typeof paramArgs), path, }, method, headers: { "content-type": "application/json", }, timeout: 30000, retry: 0, }); } return ky("api.php", { searchParams: { ...paramArgs, path, }, method, json: args, headers: { "content-type": "application/json", }, timeout: 30000, retry: 0, }); })().json()) as ErrorType | ResultType; if (!result.result) { if (returnError) { return result; } throw result.reason; } return result; } export async function GET( args?: ArgType ): Promise; export async function GET( args: ArgType | undefined, returnError: false ): Promise; export async function GET< ResultType extends ValidResponse, ErrorType extends InvalidResponse, ArgType extends undefined = undefined >(args: ArgType | undefined, returnError: true): Promise; export async function GET< ResultType extends ValidResponse, ErrorType extends InvalidResponse, ArgType extends undefined = undefined >(args?: ArgType, returnError = false): Promise { console.error(`Can't directly call GET. ${args}, ${returnError}. Use auto-generated path API.`); return callSammoAPI("get", [], args, undefined, true); } export async function POST( args?: ArgType ): Promise; export async function POST( args: ArgType | undefined, returnError: false ): Promise; export async function POST< ResultType extends ValidResponse, ErrorType extends InvalidResponse, ArgType extends RawArgType = RawArgType >(args: ArgType | undefined, returnError: true): Promise; export async function POST< ResultType extends ValidResponse, ErrorType extends InvalidResponse, ArgType extends RawArgType = RawArgType >(args?: ArgType, returnError = false): Promise { console.error(`Can't directly call POST. ${args}, ${returnError}. Use auto-generated path API.`); return callSammoAPI("post", [], args, undefined, true); } export async function PUT( args?: ArgType ): Promise; export async function PUT( args: ArgType | undefined, returnError: false ): Promise; export async function PUT< ResultType extends ValidResponse, ErrorType extends InvalidResponse, ArgType extends RawArgType = RawArgType >(args: ArgType | undefined, returnError: true): Promise; export async function PUT< ResultType extends ValidResponse, ErrorType extends InvalidResponse, ArgType extends RawArgType = RawArgType >(args?: ArgType, returnError = false): Promise { console.error(`Can't directly call PUT. ${args}, ${returnError}. Use auto-generated path API.`); return callSammoAPI("put", [], args, undefined, true); } export async function PATCH( args?: ArgType ): Promise; export async function PATCH( args: ArgType | undefined, returnError: false ): Promise; export async function PATCH< ResultType extends ValidResponse, ErrorType extends InvalidResponse, ArgType extends RawArgType = RawArgType >(args: ArgType | undefined, returnError: true): Promise; export async function PATCH< ResultType extends ValidResponse, ErrorType extends InvalidResponse, ArgType extends RawArgType = RawArgType >(args?: ArgType, returnError = false): Promise { console.error(`Can't directly call PATCH. ${args}, ${returnError}. Use auto-generated path API.`); return callSammoAPI("patch", [], args, undefined, true); } export async function HEAD( args?: ArgType ): Promise; export async function HEAD( args: ArgType | undefined, returnError: false ): Promise; export async function HEAD< ResultType extends ValidResponse, ErrorType extends InvalidResponse, ArgType extends undefined = undefined >(args: ArgType | undefined, returnError: true): Promise; export async function HEAD< ResultType extends ValidResponse, ErrorType extends InvalidResponse, ArgType extends undefined = undefined >(args?: ArgType, returnError = false): Promise { console.error(`Can't directly call HEAD. ${args}, ${returnError}. Use auto-generated path API.`); return callSammoAPI("head", [], args, undefined, true); } export async function DELETE( args?: ArgType ): Promise; export async function DELETE( args: ArgType | undefined, returnError: false ): Promise; export async function DELETE< ResultType extends ValidResponse, ErrorType extends InvalidResponse, ArgType extends RawArgType = RawArgType >(args: ArgType | undefined, returnError: true): Promise; export async function DELETE< ResultType extends ValidResponse, ErrorType extends InvalidResponse, ArgType extends RawArgType = RawArgType >(args?: ArgType, returnError = false): Promise { console.error(`Can't directly call DELETE. ${args}, ${returnError}. Use auto-generated path API.`); return callSammoAPI("patch", [], args, undefined, true); }