diff --git a/hwe/ts/util/callSammoAPI.ts b/hwe/ts/util/callSammoAPI.ts index e1e11390..5ef164eb 100644 --- a/hwe/ts/util/callSammoAPI.ts +++ b/hwe/ts/util/callSammoAPI.ts @@ -1,157 +1,270 @@ -import ky from 'ky'; +import ky from "ky"; import { isArray, isEmpty } from "lodash"; export type ValidResponse = { - result: true -} + 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; -} - + result: false; + reason: string; + recovery?: APIRecoveryType; + recovery_arg?: string | number; +}; export type RawArgType = Record | Record[] | undefined; -interface BasicAPICallT { - (args: ArgType): Promise; - (args: ArgType, returnError: false): Promise; - (args: ArgType, returnError: true): Promise; +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; + (): 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; + ArgType extends RawArgType, + ResultType extends ValidResponse = ValidResponse, + ErrorType extends InvalidResponse = InvalidResponse +> = ArgType extends undefined ? EmptyAPICallT : BasicAPICallT; -type HttpMethod = 'get' | 'post' | 'put' | 'patch' | 'head' | 'delete'; +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'], + [GET, "get"], + [POST, "post"], + [PUT, "put"], + [PATCH, "patch"], + [HEAD, "head"], + [DELETE, "delete"], ]); export function extractHttpMethod(tail: APITail): HttpMethod { - return httpMethodMap.get(tail) ?? 'post'; + return httpMethodMap.get(tail) ?? "post"; } -const apiTarget = 'api.php'; +const apiTarget = "api.php"; let apiPath = apiTarget; export function setSammoAPIPrefix(prefix: string) { - apiPath = `${prefix}/${apiTarget}`; + 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('/'); +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", + }, + }); } + return ky("api.php", { + searchParams: { + ...paramArgs, + path, + }, + method, + json: args, + headers: { + "content-type": "application/json", + }, + }); + })().json()) as ErrorType | ResultType; - if (args && isEmpty(args)) { - args = undefined; + if (!result.result) { + if (returnError) { + return result; } - - const result = await (() => { - if (method == 'get') { - return ky(apiPath, { - searchParams: { - ...paramArgs, - ...(args as typeof paramArgs), - path, - }, - method, - headers: { - 'content-type': 'application/json' - } - }); - } - return ky('api.php', { - searchParams: { - ...paramArgs, - path, - }, - method, - json: args, - headers: { - 'content-type': 'application/json' - } - }); - })().json() as ErrorType | ResultType; - - if (!result.result) { - if (returnError) { - return result; - } - throw result.reason; - } - 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(args: ArgType | undefined, returnError: true): Promise; -export async function GET(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 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(args: ArgType | undefined, returnError: true): Promise; -export async function POST(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 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(args: ArgType | undefined, returnError: true): Promise; -export async function PUT(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 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(args: ArgType | undefined, returnError: true): Promise; -export async function PATCH(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 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(args: ArgType | undefined, returnError: true): Promise; -export async function HEAD(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 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(args: ArgType | undefined, returnError: true): Promise; -export async function DELETE(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); -} \ No newline at end of file +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); +}