import { HttpResponse, readSuccessResponseJsonOrThrow, readTalerErrorResponse } from "./http-common.js"; import { Codec, HttpStatusCode, TalerError, TalerErrorCode, TalerErrorDetail } from "./index.js"; export type OperationResult = | OperationOk | OperationFail; export interface OperationOk { type: "ok", body: T; } export function isOperationOk(c: OperationResult): c is OperationOk { return c.type === "ok" } export function isOperationFail(c: OperationResult): c is OperationFail { return c.type === "fail" } export interface OperationFail { type: "fail", case: T, detail: TalerErrorDetail, } export async function opSuccess(resp: HttpResponse, codec: Codec): Promise> { const body = await readSuccessResponseJsonOrThrow(resp, codec) return { type: "ok" as const, body } } export function opFixedSuccess(body: T): OperationOk { return { type: "ok" as const, body } } export function opEmptySuccess(): OperationOk { return { type: "ok" as const, body: void 0 } } export async function opKnownHttpFailure(s: T, resp: HttpResponse): Promise> { const detail = await readTalerErrorResponse(resp) return { type: "fail", case: s, detail } } export async function opKnownTalerFailure(s: T, resp: HttpResponse): Promise> { const detail = await readTalerErrorResponse(resp) return { type: "fail", case: s, detail } } export async function opKnownFailure(s: T, resp: HttpResponse): Promise> { const detail = await readTalerErrorResponse(resp) return { type: "fail", case: s, detail } } export function opUnknownFailure(resp: HttpResponse, text: string): never { throw TalerError.fromDetail( TalerErrorCode.WALLET_UNEXPECTED_REQUEST_ERROR, { requestUrl: resp.requestUrl, requestMethod: resp.requestMethod, httpStatusCode: resp.status, errorResponse: text, }, `Unexpected HTTP status ${resp.status} in response`, ); } export async function succeedOrThrow(cb: () => Promise>): Promise { const resp = await cb() if (resp.type === "ok") return resp.body throw TalerError.fromUncheckedDetail({ ...resp.detail, case: resp.case }) } export async function failOrThrow(s: E, cb: () => Promise>): Promise { const resp = await cb() if (resp.type === "ok") { throw TalerError.fromException(new Error(`request succeed but failure "${s}" was expected`)) } if (resp.case === s) { return resp.detail } throw TalerError.fromException(new Error(`request failed with "${resp.case}" but case "${s}" was expected`)) } export type ResultByMethod = TT[p] extends (...args: any[]) => infer Ret ? Ret extends Promise ? Result extends OperationResult ? Result : never : never : //api always use Promises never; //error cases just for functions export type FailCasesByMethod = Exclude, OperationOk> type MethodsOfOperations = keyof { [P in keyof T as //when the property is a function T[P] extends (...args: any[]) => infer Ret ? // that returns a promise Ret extends Promise ? // of an operation Result extends OperationResult ? P : never : never : never]: any } type AllKnownCases = "success" | FailCasesByMethod["case"] export type TestForApi = { [OpType in MethodsOfOperations as `test_${OpType & string}`]: { [c in AllKnownCases]: undefined | (() => Promise); }; };