aboutsummaryrefslogtreecommitdiff
path: root/packages/taler-util/src/operation.ts
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2023-10-26 11:15:45 -0300
committerSebastian <sebasjm@gmail.com>2023-10-26 11:15:45 -0300
commita4c7bc4b284fe7dc4c65ceaad96fc67c40c9a708 (patch)
treef407ad06733a3a82a7c5655d65a81fc3e5248cc1 /packages/taler-util/src/operation.ts
parente812eae32daddad372c7629867298ca28678a44c (diff)
downloadwallet-core-a4c7bc4b284fe7dc4c65ceaad96fc67c40c9a708.tar.xz
moving cli test to harness
Diffstat (limited to 'packages/taler-util/src/operation.ts')
-rw-r--r--packages/taler-util/src/operation.ts74
1 files changed, 74 insertions, 0 deletions
diff --git a/packages/taler-util/src/operation.ts b/packages/taler-util/src/operation.ts
new file mode 100644
index 000000000..aab5dc022
--- /dev/null
+++ b/packages/taler-util/src/operation.ts
@@ -0,0 +1,74 @@
+import { HttpResponse, readSuccessResponseJsonOrThrow, readTalerErrorResponse } from "./http-common.js";
+import { Codec, TalerError, TalerErrorCode, TalerErrorDetail } from "./index.js";
+
+export type OperationResult<Body, ErrorEnum> =
+ | OperationOk<Body>
+ | OperationFail<ErrorEnum>;
+
+export interface OperationOk<T> {
+ type: "ok",
+ body: T;
+}
+export function isOperationOk<T, E>(c: OperationResult<T, E>): c is OperationOk<T> {
+ return c.type === "ok"
+}
+export function isOperationFail<T, E>(c: OperationResult<T, E>): c is OperationFail<E> {
+ return c.type === "fail"
+}
+export interface OperationFail<T> {
+ type: "fail",
+ case: T,
+ detail: TalerErrorDetail,
+}
+
+export async function opSuccess<T>(resp: HttpResponse, codec: Codec<T>): Promise<OperationOk<T>> {
+ const body = await readSuccessResponseJsonOrThrow(resp, codec)
+ return { type: "ok" as const, body }
+}
+export function opFixedSuccess<T>(body: T): OperationOk<T> {
+ return { type: "ok" as const, body }
+}
+export function opEmptySuccess(): OperationOk<void> {
+ return { type: "ok" as const, body: void 0 }
+}
+export async function opKnownFailure<T extends string>(s: T, resp: HttpResponse): Promise<OperationFail<T>> {
+ 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<R, E>(cb: () => Promise<OperationResult<R, E>>): Promise<R> {
+ const resp = await cb()
+ if (resp.type === "ok") return resp.body
+ throw TalerError.fromUncheckedDetail({ ...resp.detail, case: resp.case })
+}
+export async function failOrThrow<E>(s: E, cb: () => Promise<OperationResult<unknown, E>>): Promise<TalerErrorDetail> {
+ 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 but case "${s}" was expected`))
+}
+
+
+
+export type ResultByMethod<TT extends object, p extends keyof TT> = TT[p] extends (...args: any[]) => infer Ret ?
+ Ret extends Promise<infer Result> ?
+ Result :
+ never : //api always use Promises
+ never; //error cases just for functions
+
+export type FailCasesByMethod<TT extends object, p extends keyof TT> = Exclude<ResultByMethod<TT, p>, OperationOk<any>>