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);
};
};