gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] 02/05: update api


From: gnunet
Subject: [taler-wallet-core] 02/05: update api
Date: Thu, 19 Oct 2023 07:56:24 +0200

This is an automated email from the git hooks/post-receive script.

sebasjm pushed a commit to branch master
in repository wallet-core.

commit f89e27a4e39412c4863fe26f821988a65ecec1b9
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Thu Oct 19 02:44:28 2023 -0300

    update api
---
 .../taler-util/src/http-client/authentication.ts   |  83 ++++++
 packages/taler-util/src/http-client/bank-core.ts   | 284 +++++++++++----------
 .../taler-util/src/http-client/bank-integration.ts |   2 +-
 .../taler-util/src/http-client/bank-revenue.ts     |   5 +-
 packages/taler-util/src/http-client/bank-wire.ts   |   8 +-
 packages/taler-util/src/http-client/types.ts       |  56 +++-
 packages/taler-util/src/http-client/utils.ts       | 110 ++------
 packages/taler-util/src/http-common.ts             |  31 ---
 8 files changed, 314 insertions(+), 265 deletions(-)

diff --git a/packages/taler-util/src/http-client/authentication.ts 
b/packages/taler-util/src/http-client/authentication.ts
new file mode 100644
index 000000000..0c59c9308
--- /dev/null
+++ b/packages/taler-util/src/http-client/authentication.ts
@@ -0,0 +1,83 @@
+/*
+ This file is part of GNU Taler
+ (C) 2022 Taler Systems S.A.
+
+ GNU Taler is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+import { HttpStatusCode } from "../http-status-codes.js";
+import { HttpRequestLibrary, createPlatformHttpLib, makeBasicAuthHeader } from 
"../http.js";
+import { LibtoolVersion } from "../libtool-version.js";
+import { AccessToken, TalerAuthentication, UserAndPassword, UserAndToken, 
codecForTokenSuccessResponse } from "./types.js";
+import { makeBearerTokenAuthHeader, opEmptySuccess, opKnownFailure, opSuccess, 
opUnknownFailure } from "./utils.js";
+
+export class TalerAuthenticationHttpClient {
+  public readonly PROTOCOL_VERSION = "0:0:0";
+
+  httpLib: HttpRequestLibrary;
+
+  constructor(
+    readonly baseUrl: string,
+    readonly username: string,
+    httpClient?: HttpRequestLibrary,
+  ) {
+    this.httpLib = httpClient ?? createPlatformHttpLib();
+  }
+
+  isCompatible(version: string): boolean {
+    const compare = LibtoolVersion.compare(this.PROTOCOL_VERSION, version)
+    return compare?.compatible ?? false
+  }
+
+  /**
+   * 
https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-token
+   * 
+   * @returns 
+   */
+  async createAccessToken(
+    password: string,
+    body: TalerAuthentication.TokenRequest,
+  ) {
+    const url = new URL(`token`, this.baseUrl);
+    const resp = await this.httpLib.fetch(url.href, {
+      method: "POST",
+      headers: {
+        Authorization: makeBasicAuthHeader(this.username, password),
+      },
+      body
+    });
+    switch (resp.status) {
+      case HttpStatusCode.Ok: return opSuccess(resp, 
codecForTokenSuccessResponse())
+      //FIXME: missing in docs
+      case HttpStatusCode.Unauthorized: return 
opKnownFailure("wrong-credentials", resp)
+      case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp)
+      default: return opUnknownFailure(resp, await resp.text())
+    }
+  }
+
+  async deleteAccessToken(token: AccessToken) {
+    const url = new URL(`token`, this.baseUrl);
+    const resp = await this.httpLib.fetch(url.href, {
+      method: "DELETE",
+      headers: {
+        Authorization: makeBearerTokenAuthHeader(token),
+      }
+    });
+    switch (resp.status) {
+      case HttpStatusCode.Ok: return opEmptySuccess()
+      //FIXME: missing in docs
+      case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp)
+      default: return opUnknownFailure(resp, await resp.text())
+    }
+  }
+
+}
\ No newline at end of file
diff --git a/packages/taler-util/src/http-client/bank-core.ts 
b/packages/taler-util/src/http-client/bank-core.ts
index 7b4bb53d4..593daa2c3 100644
--- a/packages/taler-util/src/http-client/bank-core.ts
+++ b/packages/taler-util/src/http-client/bank-core.ts
@@ -18,63 +18,50 @@ import {
   AmountJson,
   Amounts,
   HttpStatusCode,
-  Logger
+  LibtoolVersion
 } from "@gnu-taler/taler-util";
 import {
   HttpRequestLibrary,
-  createPlatformHttpLib,
-  expectSuccessResponseOrThrow,
-  readSuccessResponseJsonOrThrow
+  createPlatformHttpLib
 } from "@gnu-taler/taler-util/http";
 import { TalerBankIntegrationHttpClient } from "./bank-integration.js";
 import { TalerRevenueHttpClient } from "./bank-revenue.js";
 import { TalerWireGatewayHttpClient } from "./bank-wire.js";
-import { AccessToken, TalerAuthentication, TalerCorebankApi, 
codecForAccountData, codecForBankAccountCreateWithdrawalResponse, 
codecForBankAccountGetWithdrawalResponse, codecForBankAccountTransactionInfo, 
codecForBankAccountTransactionsResponse, codecForCashoutConversionResponse, 
codecForCashoutPending, codecForCashoutStatusResponse, codecForCashouts, 
codecForConversionRatesResponse, codecForCoreBankConfig, 
codecForGlobalCashouts, codecForListBankAccountsResponse, 
codecForMonitorResponse [...]
-import { PaginationParams, UserAndPassword, UserAndToken, addPaginationParams, 
httpEmptySuccess, httpSuccess, knownFailure, makeBasicAuthHeader, 
makeBearerTokenAuthHeader, unknownFailure } from "./utils.js";
+import { AccessToken, OperationOk, PaginationParams, TalerCorebankApi, 
UserAndToken, codecForAccountData, codecForBankAccountCreateWithdrawalResponse, 
codecForBankAccountGetWithdrawalResponse, codecForBankAccountTransactionInfo, 
codecForBankAccountTransactionsResponse, codecForCashoutConversionResponse, 
codecForCashoutPending, codecForCashoutStatusResponse, codecForCashouts, 
codecForConversionRatesResponse, codecForCoreBankConfig, 
codecForGlobalCashouts, codecForListBankAccountsResponse, [...]
+import { addPaginationParams, opFixedSuccess, opEmptySuccess, opSuccess, 
opKnownFailure, makeBearerTokenAuthHeader, opUnknownFailure } from "./utils.js";
+import { TalerAuthenticationHttpClient } from "./authentication.js";
 
-const logger = new Logger("http-client/core-bank.ts");
 
+type props = keyof TalerCoreBankHttpClient
+
+export type TalerCoreBankResultByMethod<p extends props> = 
TalerCoreBankHttpClient[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 TalerCoreBankErrorsByMethod<p extends props> = 
Exclude<TalerCoreBankResultByMethod<p>, OperationOk<any>>
+
+/**
+ * Protocol version spoken with the bank.
+ *
+ * Uses libtool's current:revision:age versioning.
+ */
 export class TalerCoreBankHttpClient {
+  public readonly PROTOCOL_VERSION = "0:0:0";
+
   httpLib: HttpRequestLibrary;
 
   constructor(
-    private baseUrl: string,
+    readonly baseUrl: string,
     httpClient?: HttpRequestLibrary,
   ) {
     this.httpLib = httpClient ?? createPlatformHttpLib();
   }
 
-  /**
-   * 
https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-token
-   * 
-   * @returns 
-   */
-  async createAccessToken(
-    auth: UserAndPassword,
-    body: TalerAuthentication.TokenRequest,
-  ): Promise<TalerAuthentication.TokenSuccessResponse> {
-    const url = new URL(`accounts/${auth.username}/token`, this.baseUrl);
-    const resp = await this.httpLib.fetch(url.href, {
-      method: "POST",
-      headers: {
-        Authorization: makeBasicAuthHeader(auth.username, auth.password),
-      },
-      body
-    });
-    return readSuccessResponseJsonOrThrow(resp, 
codecForTokenSuccessResponse());
-  }
-
-  async deleteAccessToken(
-    auth: UserAndToken,
-  ): Promise<void> {
-    const url = new URL(`accounts/${auth.username}/token`, this.baseUrl);
-    const resp = await this.httpLib.fetch(url.href, {
-      method: "DELETE",
-      headers: {
-        Authorization: makeBearerTokenAuthHeader(auth.token),
-      }
-    });
-    return expectSuccessResponseOrThrow(resp);
+  isCompatible(version: string): boolean {
+    const compare = LibtoolVersion.compare(this.PROTOCOL_VERSION, version)
+    return compare?.compatible ?? false
   }
 
   /**
@@ -88,8 +75,8 @@ export class TalerCoreBankHttpClient {
     });
     switch (resp.status) {
       //FIXME: missing in docs
-      case HttpStatusCode.Ok: return httpSuccess(resp, 
codecForCoreBankConfig())
-      default: return unknownFailure(url, resp)
+      case HttpStatusCode.Ok: return opSuccess(resp, codecForCoreBankConfig())
+      default: return opUnknownFailure(resp, await resp.text())
     }
   }
 
@@ -111,17 +98,19 @@ export class TalerCoreBankHttpClient {
       },
     });
     switch (resp.status) {
-      case HttpStatusCode.NoContent: return httpEmptySuccess()
-      case HttpStatusCode.BadRequest: return knownFailure("invalid-input", 
resp);
+      //FIXME: NOT IN THE DOOOCS
+      case HttpStatusCode.Created: return opEmptySuccess()
+      case HttpStatusCode.NoContent: return opEmptySuccess()
+      case HttpStatusCode.BadRequest: return opKnownFailure("invalid-input", 
resp);
       case HttpStatusCode.Forbidden: {
         if (body.username === "bank" || body.username === "admin") {
-          return knownFailure("unable-to-create", resp);
+          return opKnownFailure("unable-to-create", resp);
         } else {
-          return knownFailure("unauthorized", resp);
+          return opKnownFailure("unauthorized", resp);
         }
       }
-      case HttpStatusCode.Conflict: return knownFailure("already-exist", resp);
-      default: return unknownFailure(url, resp)
+      case HttpStatusCode.Conflict: return opKnownFailure("already-exist", 
resp);
+      default: return opUnknownFailure(resp, await resp.text())
     }
   }
   /**
@@ -137,17 +126,17 @@ export class TalerCoreBankHttpClient {
       },
     });
     switch (resp.status) {
-      case HttpStatusCode.NoContent: return httpEmptySuccess()
-      case HttpStatusCode.NotFound: return knownFailure("not-found", resp);
+      case HttpStatusCode.NoContent: return opEmptySuccess()
+      case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp);
       case HttpStatusCode.Forbidden: {
         if (auth.username === "bank" || auth.username === "admin") {
-          return knownFailure("unable-to-delete", resp);
+          return opKnownFailure("unable-to-delete", resp);
         } else {
-          return knownFailure("unauthorized", resp);
+          return opKnownFailure("unauthorized", resp);
         }
       }
-      case HttpStatusCode.PreconditionFailed: return 
knownFailure("balance-not-zero", resp);
-      default: return unknownFailure(url, resp)
+      case HttpStatusCode.PreconditionFailed: return 
opKnownFailure("balance-not-zero", resp);
+      default: return opUnknownFailure(resp, await resp.text())
     }
   }
 
@@ -165,10 +154,10 @@ export class TalerCoreBankHttpClient {
       },
     });
     switch (resp.status) {
-      case HttpStatusCode.NoContent: return httpEmptySuccess()
-      case HttpStatusCode.NotFound: return knownFailure("not-found", resp);
-      case HttpStatusCode.Forbidden: return knownFailure("unauthorized", resp);
-      default: return unknownFailure(url, resp)
+      case HttpStatusCode.NoContent: return opEmptySuccess()
+      case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp);
+      case HttpStatusCode.Forbidden: return opKnownFailure("unauthorized", 
resp);
+      default: return opUnknownFailure(resp, await resp.text())
     }
   }
 
@@ -186,12 +175,12 @@ export class TalerCoreBankHttpClient {
       },
     });
     switch (resp.status) {
-      case HttpStatusCode.NoContent: return httpEmptySuccess()
+      case HttpStatusCode.NoContent: return opEmptySuccess()
       //FIXME: missing in docs
-      case HttpStatusCode.NotFound: return knownFailure("not-found", resp);
+      case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp);
       //FIXME: missing in docs
-      case HttpStatusCode.Forbidden: return knownFailure("unauthorized", resp);
-      default: return unknownFailure(url, resp)
+      case HttpStatusCode.Forbidden: return opKnownFailure("unauthorized", 
resp);
+      default: return opUnknownFailure(resp, await resp.text())
     }
   }
 
@@ -199,8 +188,10 @@ export class TalerCoreBankHttpClient {
    * https://docs.taler.net/core/get-$BANK_API_BASE_URL-public-accounts
    * 
    */
-  async getPublicAccounts() {
+  async getPublicAccounts(pagination?: PaginationParams) {
     const url = new URL(`public-accounts`, this.baseUrl);
+    //FIXME: missing pagination in docs
+    addPaginationParams(url, pagination)
     const resp = await this.httpLib.fetch(url.href, {
       method: "GET",
       headers: {
@@ -208,10 +199,10 @@ export class TalerCoreBankHttpClient {
     });
     switch (resp.status) {
       //FIXME: missing in docs
-      case HttpStatusCode.Ok: return httpSuccess(resp, 
codecForPublicAccountsResponse())
+      case HttpStatusCode.Ok: return opSuccess(resp, 
codecForPublicAccountsResponse())
       //FIXME: missing in docs
-      case HttpStatusCode.NoContent: return httpEmptySuccess()
-      default: return unknownFailure(url, resp)
+      case HttpStatusCode.NoContent: return opFixedSuccess({ public_accounts: 
[] })
+      default: return opUnknownFailure(resp, await resp.text())
     }
   }
 
@@ -219,8 +210,9 @@ export class TalerCoreBankHttpClient {
    * https://docs.taler.net/core/api-corebank.html#get--accounts
    * 
    */
-  async getAccounts(auth: AccessToken) {
+  async getAccounts(auth: AccessToken, pagination?: PaginationParams) {
     const url = new URL(`accounts`, this.baseUrl);
+    addPaginationParams(url, pagination)
     const resp = await this.httpLib.fetch(url.href, {
       method: "GET",
       headers: {
@@ -228,10 +220,10 @@ export class TalerCoreBankHttpClient {
       },
     });
     switch (resp.status) {
-      case HttpStatusCode.Ok: return httpSuccess(resp, 
codecForListBankAccountsResponse())
-      case HttpStatusCode.NoContent: return httpEmptySuccess()
-      case HttpStatusCode.Forbidden: return knownFailure("unauthorized", resp);
-      default: return unknownFailure(url, resp)
+      case HttpStatusCode.Ok: return opSuccess(resp, 
codecForListBankAccountsResponse())
+      case HttpStatusCode.NoContent: return opFixedSuccess({ accounts: [] })
+      case HttpStatusCode.Forbidden: return opKnownFailure("unauthorized", 
resp);
+      default: return opUnknownFailure(resp, await resp.text())
     }
   }
 
@@ -248,12 +240,12 @@ export class TalerCoreBankHttpClient {
       },
     });
     switch (resp.status) {
-      case HttpStatusCode.Ok: return httpSuccess(resp, codecForAccountData())
+      case HttpStatusCode.Ok: return opSuccess(resp, codecForAccountData())
       //FIXME: missing in docs
-      case HttpStatusCode.NotFound: return knownFailure("not-found", resp);
+      case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp);
       //FIXME: missing in docs
-      case HttpStatusCode.Forbidden: return knownFailure("unauthorized", resp);
-      default: return unknownFailure(url, resp)
+      case HttpStatusCode.Forbidden: return opKnownFailure("unauthorized", 
resp);
+      default: return opUnknownFailure(resp, await resp.text())
     }
   }
 
@@ -275,14 +267,14 @@ export class TalerCoreBankHttpClient {
       },
     });
     switch (resp.status) {
-      case HttpStatusCode.Ok: return httpSuccess(resp, 
codecForBankAccountTransactionsResponse())
+      case HttpStatusCode.Ok: return opSuccess(resp, 
codecForBankAccountTransactionsResponse())
       //FIXME: missing in docs
-      case HttpStatusCode.NoContent: return httpEmptySuccess()
+      case HttpStatusCode.NoContent: return opFixedSuccess({ transactions: [] 
})
       //FIXME: missing in docs
-      case HttpStatusCode.NotFound: return knownFailure("not-found", resp);
+      case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp);
       //FIXME: missing in docs
-      case HttpStatusCode.Forbidden: return knownFailure("unauthorized", resp);
-      default: return unknownFailure(url, resp)
+      case HttpStatusCode.Forbidden: return opKnownFailure("unauthorized", 
resp);
+      default: return opUnknownFailure(resp, await resp.text())
     }
   }
 
@@ -299,12 +291,12 @@ export class TalerCoreBankHttpClient {
       },
     });
     switch (resp.status) {
-      case HttpStatusCode.Ok: return httpSuccess(resp, 
codecForBankAccountTransactionInfo())
+      case HttpStatusCode.Ok: return opSuccess(resp, 
codecForBankAccountTransactionInfo())
       //FIXME: missing in docs
-      case HttpStatusCode.NotFound: return knownFailure("not-found", resp);
+      case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp);
       //FIXME: missing in docs
-      case HttpStatusCode.Forbidden: return knownFailure("unauthorized", resp);
-      default: return unknownFailure(url, resp)
+      case HttpStatusCode.Forbidden: return opKnownFailure("unauthorized", 
resp);
+      default: return opUnknownFailure(resp, await resp.text())
     }
   }
 
@@ -323,12 +315,12 @@ export class TalerCoreBankHttpClient {
     });
     switch (resp.status) {
       //FIXME: fix docs... it should be NoContent 
-      case HttpStatusCode.Ok: return httpEmptySuccess()
-      case HttpStatusCode.NoContent: return httpEmptySuccess()
-      case HttpStatusCode.BadRequest: return knownFailure("invalid-input", 
resp);
+      case HttpStatusCode.Ok: return opEmptySuccess()
+      case HttpStatusCode.NoContent: return opEmptySuccess()
+      case HttpStatusCode.BadRequest: return opKnownFailure("invalid-input", 
resp);
       //FIXME: missing in docs
-      case HttpStatusCode.Forbidden: return knownFailure("unauthorized", resp);
-      default: return unknownFailure(url, resp)
+      case HttpStatusCode.Forbidden: return opKnownFailure("unauthorized", 
resp);
+      default: return opUnknownFailure(resp, await resp.text())
     }
   }
 
@@ -351,9 +343,9 @@ export class TalerCoreBankHttpClient {
     });
     switch (resp.status) {
       //FIXME: missing in docs
-      case HttpStatusCode.Ok: return httpSuccess(resp, 
codecForBankAccountCreateWithdrawalResponse())
-      case HttpStatusCode.Forbidden: return knownFailure("insufficient-funds", 
resp);
-      default: return unknownFailure(url, resp)
+      case HttpStatusCode.Ok: return opSuccess(resp, 
codecForBankAccountCreateWithdrawalResponse())
+      case HttpStatusCode.Forbidden: return 
opKnownFailure("insufficient-funds", resp);
+      default: return opUnknownFailure(resp, await resp.text())
     }
   }
 
@@ -368,8 +360,9 @@ export class TalerCoreBankHttpClient {
     });
     switch (resp.status) {
       //FIXME: missing in docs
-      case HttpStatusCode.Ok: return httpSuccess(resp, 
codecForBankAccountGetWithdrawalResponse())
-      default: return unknownFailure(url, resp)
+      case HttpStatusCode.Ok: return opSuccess(resp, 
codecForBankAccountGetWithdrawalResponse())
+      case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp)
+      default: return opUnknownFailure(resp, await resp.text())
     }
   }
 
@@ -384,10 +377,10 @@ export class TalerCoreBankHttpClient {
     });
     switch (resp.status) {
       //FIXME: fix docs... it should be NoContent 
-      case HttpStatusCode.Ok: return httpEmptySuccess()
-      case HttpStatusCode.NoContent: return httpEmptySuccess()
-      case HttpStatusCode.Conflict: return 
knownFailure("previously-confirmed", resp);
-      default: return unknownFailure(url, resp)
+      case HttpStatusCode.Ok: return opEmptySuccess()
+      case HttpStatusCode.NoContent: return opEmptySuccess()
+      case HttpStatusCode.Conflict: return 
opKnownFailure("previously-confirmed", resp);
+      default: return opUnknownFailure(resp, await resp.text())
     }
   }
 
@@ -402,11 +395,11 @@ export class TalerCoreBankHttpClient {
     });
     switch (resp.status) {
       //FIXME: fix docs... it should be NoContent 
-      case HttpStatusCode.Ok: return httpEmptySuccess()
-      case HttpStatusCode.NoContent: return httpEmptySuccess()
-      case HttpStatusCode.Conflict: return knownFailure("previously-aborted", 
resp);
-      case HttpStatusCode.UnprocessableEntity: return 
knownFailure("no-exchange-or-reserve-selected", resp);
-      default: return unknownFailure(url, resp)
+      case HttpStatusCode.Ok: return opEmptySuccess()
+      case HttpStatusCode.NoContent: return opEmptySuccess()
+      case HttpStatusCode.Conflict: return 
opKnownFailure("previously-aborted", resp);
+      case HttpStatusCode.UnprocessableEntity: return 
opKnownFailure("no-exchange-or-reserve-selected", resp);
+      default: return opUnknownFailure(resp, await resp.text())
     }
   }
 
@@ -428,11 +421,17 @@ export class TalerCoreBankHttpClient {
       body,
     });
     switch (resp.status) {
-      case HttpStatusCode.Accepted: return httpSuccess(resp, 
codecForCashoutPending())
+      case HttpStatusCode.Accepted: return opSuccess(resp, 
codecForCashoutPending())
       //FIXME: it should be precondition-failed
-      case HttpStatusCode.Conflict: return knownFailure("invalid-state", resp);
-      case HttpStatusCode.ServiceUnavailable: return 
knownFailure("tan-not-supported", resp);
-      default: return unknownFailure(url, resp)
+      case HttpStatusCode.Conflict: return opKnownFailure("no-contact-info", 
resp);
+      //FIXME: missing in the docs
+      case HttpStatusCode.Forbidden: return opKnownFailure("no-allowed", resp);
+      //FIXME: missing in the docs
+      case HttpStatusCode.PreconditionFailed: return 
opKnownFailure("no-enough-balance", resp);
+      //FIXME: missing in the docs
+      case HttpStatusCode.BadRequest: return 
opKnownFailure("incorrect-exchange-rate", resp);
+      case HttpStatusCode.ServiceUnavailable: return 
opKnownFailure("tan-not-supported", resp);
+      default: return opUnknownFailure(resp, await resp.text())
     }
   }
 
@@ -449,10 +448,10 @@ export class TalerCoreBankHttpClient {
       },
     });
     switch (resp.status) {
-      case HttpStatusCode.NoContent: return httpEmptySuccess()
-      case HttpStatusCode.NotFound: return knownFailure("not-found", resp);
-      case HttpStatusCode.Conflict: return knownFailure("already-confirmed", 
resp);
-      default: return unknownFailure(url, resp)
+      case HttpStatusCode.NoContent: return opEmptySuccess()
+      case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp);
+      case HttpStatusCode.Conflict: return opKnownFailure("already-confirmed", 
resp);
+      default: return opUnknownFailure(resp, await resp.text())
     }
   }
 
@@ -470,11 +469,11 @@ export class TalerCoreBankHttpClient {
       body,
     });
     switch (resp.status) {
-      case HttpStatusCode.NoContent: return httpEmptySuccess()
-      case HttpStatusCode.Forbidden: return 
knownFailure("wrong-tan-or-credential", resp);
-      case HttpStatusCode.NotFound: return knownFailure("not-found", resp);
-      case HttpStatusCode.Conflict: return 
knownFailure("cashout-address-changed", resp);
-      default: return unknownFailure(url, resp)
+      case HttpStatusCode.NoContent: return opEmptySuccess()
+      case HttpStatusCode.Forbidden: return 
opKnownFailure("wrong-tan-or-credential", resp);
+      case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp);
+      case HttpStatusCode.Conflict: return 
opKnownFailure("cashout-address-changed", resp);
+      default: return opUnknownFailure(resp, await resp.text())
     }
   }
 
@@ -494,10 +493,10 @@ export class TalerCoreBankHttpClient {
       method: "GET",
     });
     switch (resp.status) {
-      case HttpStatusCode.Ok: return httpSuccess(resp, 
codecForCashoutConversionResponse())
-      case HttpStatusCode.BadRequest: return knownFailure("wrong-calculation", 
resp);
-      case HttpStatusCode.NotFound: return knownFailure("not-supported", resp);
-      default: return unknownFailure(url, resp)
+      case HttpStatusCode.Ok: return opSuccess(resp, 
codecForCashoutConversionResponse())
+      case HttpStatusCode.BadRequest: return 
opKnownFailure("wrong-calculation", resp);
+      case HttpStatusCode.NotFound: return opKnownFailure("not-supported", 
resp);
+      default: return opUnknownFailure(resp, await resp.text())
     }
   }
 
@@ -514,9 +513,9 @@ export class TalerCoreBankHttpClient {
       },
     });
     switch (resp.status) {
-      case HttpStatusCode.Ok: return httpSuccess(resp, codecForCashouts())
-      case HttpStatusCode.NoContent: return httpEmptySuccess();
-      default: return unknownFailure(url, resp)
+      case HttpStatusCode.Ok: return opSuccess(resp, codecForCashouts())
+      case HttpStatusCode.NoContent: return opFixedSuccess({ cashouts: [] });
+      default: return opUnknownFailure(resp, await resp.text())
     }
   }
 
@@ -533,9 +532,9 @@ export class TalerCoreBankHttpClient {
       },
     });
     switch (resp.status) {
-      case HttpStatusCode.Ok: return httpSuccess(resp, 
codecForGlobalCashouts())
-      case HttpStatusCode.NoContent: return httpEmptySuccess();
-      default: return unknownFailure(url, resp)
+      case HttpStatusCode.Ok: return opSuccess(resp, codecForGlobalCashouts())
+      case HttpStatusCode.NoContent: return opFixedSuccess({ cashouts: [] });
+      default: return opUnknownFailure(resp, await resp.text())
     }
   }
 
@@ -553,9 +552,9 @@ export class TalerCoreBankHttpClient {
     });
     switch (resp.status) {
       //FIXME: missing in docs
-      case HttpStatusCode.Ok: return httpSuccess(resp, 
codecForCashoutStatusResponse())
-      case HttpStatusCode.NotFound: return knownFailure("already-aborted", 
resp);
-      default: return unknownFailure(url, resp)
+      case HttpStatusCode.Ok: return opSuccess(resp, 
codecForCashoutStatusResponse())
+      case HttpStatusCode.NotFound: return opKnownFailure("already-aborted", 
resp);
+      default: return opUnknownFailure(resp, await resp.text())
     }
   }
 
@@ -573,9 +572,9 @@ export class TalerCoreBankHttpClient {
       method: "GET",
     });
     switch (resp.status) {
-      case HttpStatusCode.Ok: return httpSuccess(resp, 
codecForConversionRatesResponse())
-      case HttpStatusCode.NotFound: return knownFailure("not-supported", resp);
-      default: return unknownFailure(url, resp)
+      case HttpStatusCode.Ok: return opSuccess(resp, 
codecForConversionRatesResponse())
+      case HttpStatusCode.NotFound: return opKnownFailure("not-supported", 
resp);
+      default: return opUnknownFailure(resp, await resp.text())
     }
   }
 
@@ -595,10 +594,10 @@ export class TalerCoreBankHttpClient {
       method: "GET",
     });
     switch (resp.status) {
-      case HttpStatusCode.Ok: return httpSuccess(resp, 
codecForMonitorResponse())
-      case HttpStatusCode.NotFound: return knownFailure("not-supported", resp);
-      case HttpStatusCode.BadRequest: return knownFailure("invalid-input", 
resp);
-      default: return unknownFailure(url, resp)
+      case HttpStatusCode.Ok: return opSuccess(resp, codecForMonitorResponse())
+      case HttpStatusCode.NotFound: return opKnownFailure("not-supported", 
resp);
+      case HttpStatusCode.BadRequest: return opKnownFailure("invalid-input", 
resp);
+      default: return opUnknownFailure(resp, await resp.text())
     }
   }
 
@@ -611,7 +610,7 @@ export class TalerCoreBankHttpClient {
    * 
    */
   getIntegrationAPI(): TalerBankIntegrationHttpClient {
-    const url = new URL(`taler-integration`, this.baseUrl);
+    const url = new URL(`taler-integration/`, this.baseUrl);
     return new TalerBankIntegrationHttpClient(url.href, this.httpLib)
   }
 
@@ -620,7 +619,7 @@ export class TalerCoreBankHttpClient {
    * 
    */
   getWireGatewayAPI(username: string): TalerWireGatewayHttpClient {
-    const url = new URL(`accounts/${username}/taler-wire-gateway`, 
this.baseUrl);
+    const url = new URL(`accounts/${username}/taler-wire-gateway/`, 
this.baseUrl);
     return new TalerWireGatewayHttpClient(url.href, username, this.httpLib)
   }
 
@@ -629,9 +628,16 @@ export class TalerCoreBankHttpClient {
   * 
   */
   getRevenueAPI(username: string): TalerRevenueHttpClient {
-    const url = new URL(`accounts/${username}/taler-revenue`, this.baseUrl);
+    const url = new URL(`accounts/${username}/taler-revenue/`, this.baseUrl);
     return new TalerRevenueHttpClient(url.href, username, this.httpLib,)
   }
 
+  /**
+   * 
https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-token
+  * 
+  */
+  getAuthenticationAPI(username: string): TalerAuthenticationHttpClient {
+    const url = new URL(`accounts/${username}/`, this.baseUrl);
+    return new TalerAuthenticationHttpClient(url.href, username, this.httpLib,)
+  }
 }
-
diff --git a/packages/taler-util/src/http-client/bank-integration.ts 
b/packages/taler-util/src/http-client/bank-integration.ts
index cd6462417..521b6e34c 100644
--- a/packages/taler-util/src/http-client/bank-integration.ts
+++ b/packages/taler-util/src/http-client/bank-integration.ts
@@ -10,7 +10,7 @@ export class TalerBankIntegrationHttpClient {
   httpLib: HttpRequestLibrary;
 
   constructor(
-    private baseUrl: string,
+    readonly baseUrl: string,
     httpClient?: HttpRequestLibrary,
   ) {
     this.httpLib = httpClient ?? createPlatformHttpLib();
diff --git a/packages/taler-util/src/http-client/bank-revenue.ts 
b/packages/taler-util/src/http-client/bank-revenue.ts
index 99ff71457..d594da574 100644
--- a/packages/taler-util/src/http-client/bank-revenue.ts
+++ b/packages/taler-util/src/http-client/bank-revenue.ts
@@ -1,14 +1,13 @@
 import { HttpRequestLibrary, makeBasicAuthHeader, 
readSuccessResponseJsonOrThrow } from "../http-common.js";
 import { createPlatformHttpLib } from "../http.js";
 import { TalerRevenueApi, codecForMerchantIncomingHistory } from "./types.js";
-import { UserAndPassword } from "./utils.js";
 
 export class TalerRevenueHttpClient {
   httpLib: HttpRequestLibrary;
 
   constructor(
-    private baseUrl: string,
-    private username: string,
+    readonly baseUrl: string,
+    readonly username: string,
     httpClient?: HttpRequestLibrary,
   ) {
     this.httpLib = httpClient ?? createPlatformHttpLib();
diff --git a/packages/taler-util/src/http-client/bank-wire.ts 
b/packages/taler-util/src/http-client/bank-wire.ts
index 9f2b859ed..0a032cc61 100644
--- a/packages/taler-util/src/http-client/bank-wire.ts
+++ b/packages/taler-util/src/http-client/bank-wire.ts
@@ -1,7 +1,7 @@
 import { HttpRequestLibrary, makeBasicAuthHeader, 
readSuccessResponseJsonOrThrow } from "../http-common.js";
 import { createPlatformHttpLib } from "../http.js";
-import { TalerWireGatewayApi, codecForAddIncomingResponse, 
codecForIncomingHistory, codecForOutgoingHistory, codecForTransferResponse } 
from "./types.js";
-import { PaginationParams, UserAndPassword, addPaginationParams } from 
"./utils.js";
+import { PaginationParams, TalerWireGatewayApi, codecForAddIncomingResponse, 
codecForIncomingHistory, codecForOutgoingHistory, codecForTransferResponse } 
from "./types.js";
+import { addPaginationParams } from "./utils.js";
 
 /**
  * The API is used by the exchange to trigger transactions and query 
@@ -14,8 +14,8 @@ export class TalerWireGatewayHttpClient {
   httpLib: HttpRequestLibrary;
 
   constructor(
-    private baseUrl: string,
-    private username: string,
+    readonly baseUrl: string,
+    readonly username: string,
     httpClient?: HttpRequestLibrary,
   ) {
     this.httpLib = httpClient ?? createPlatformHttpLib();
diff --git a/packages/taler-util/src/http-client/types.ts 
b/packages/taler-util/src/http-client/types.ts
index 66ac39f59..5a76981df 100644
--- a/packages/taler-util/src/http-client/types.ts
+++ b/packages/taler-util/src/http-client/types.ts
@@ -1,6 +1,58 @@
 import { codecForAmountString } from "../amounts.js";
 import { Codec, buildCodecForObject, buildCodecForUnion, codecForBoolean, 
codecForConstString, codecForEither, codecForList, codecForMap, codecForNumber, 
codecForString, codecOptional } from "../codec.js";
 import { codecForTimestamp } from "../time.js";
+import { TalerErrorDetail } from "../wallet-types.js";
+
+
+export type UserAndPassword = {
+  username: string,
+  password: string,
+}
+
+export type UserAndToken = {
+  username: string,
+  token: AccessToken,
+}
+
+export type PaginationParams = {
+  /**
+   * row identifier as the starting point of the query
+   */
+  offset?: string,
+  /**
+   * max number of element in the result response
+   * always greater than 0
+   */
+  limit?: number,
+  /**
+   * milliseconds the server should wait for at least one result to be shown
+   */
+  timoutMs?: number,
+  /**
+   * order
+   */
+  order: "asc" | "dec"
+}
+
+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,
+}
 
 
 ///
@@ -502,14 +554,14 @@ export const codecForAddIncomingResponse =
 
 type EmailAddress = string;
 type PhoneNumber = string;
-type DecimalNumber = string;
+type DecimalNumber = number;
 
 const codecForURL = codecForString
 const codecForLibtoolVersion = codecForString
 const codecForCurrencyName = codecForString
 const codecForPaytoURI = codecForString
 const codecForTalerWithdrawalURI = codecForString
-const codecForDecimalNumber = codecForString
+const codecForDecimalNumber = codecForNumber
 
 enum TanChannel {
   SMS = "sms",
diff --git a/packages/taler-util/src/http-client/utils.ts 
b/packages/taler-util/src/http-client/utils.ts
index f4af5ae03..3be5d6e89 100644
--- a/packages/taler-util/src/http-client/utils.ts
+++ b/packages/taler-util/src/http-client/utils.ts
@@ -1,10 +1,8 @@
 import { base64FromArrayBuffer } from "../base64.js";
-import { HttpResponse, readErrorResponse, readSuccessResponseJsonOrThrow, 
readTalerErrorResponse } from "../http-common.js";
-import { HttpStatusCode } from "../http-status-codes.js";
-import { Codec } from "../index.js";
+import { HttpResponse, readSuccessResponseJsonOrThrow, readTalerErrorResponse 
} from "../http-common.js";
+import { Codec, TalerError, TalerErrorCode } from "../index.js";
 import { stringToBytes } from "../taler-crypto.js";
-import { TalerErrorDetail } from "../wallet-types.js";
-import { AccessToken } from "./types.js";
+import { AccessToken, OperationFail, OperationOk, PaginationParams } from 
"./types.js";
 
 /**
  * Helper function to generate the "Authorization" HTTP header.
@@ -41,91 +39,33 @@ export function addPaginationParams(url: URL, pagination?: 
PaginationParams) {
   url.searchParams.set("delta", String(order * limit))
 }
 
-export type UserAndPassword = {
-  username: string,
-  password: string,
-}
-
-export type UserAndToken = {
-  username: string,
-  token: AccessToken,
-}
 
-export type PaginationParams = {
-  /**
-   * row identifier as the starting point of the query
-   */
-  offset?: string,
-  /**
-   * max number of element in the result response
-   * always greater than 0
-   */
-  limit?: number,
-  /**
-   * milliseconds the server should wait for at least one result to be shown
-   */
-  timoutMs?: number,
-  /**
-   * order
-   */
-  order: "asc" | "dec"
-}
-
-export type HttpResult<Body, ErrorEnum> =
-  | HttpOk<Body>
-  | HttpKnownFail<ErrorEnum>
-  | HttpUnkownFail;
-
-/**
- * 200 < status < 204 
- */
-export interface HttpOk<T> {
-  type: "ok",
-  body: T;
+//////
+// Operation Helper Constructors
+//////
+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 }
 }
-
-/**
- * 400 < status < 409
- * and error documented 
- */
-export interface HttpKnownFail<T> {
-  type: "fail",
-  case: T,
-  detail: TalerErrorDetail,
+export function opFixedSuccess<T>(body: T): OperationOk<T> {
+  return { type: "ok" as const, body }
 }
-
-/**
- * 400 < status < 599
- * and error NOT documented 
- * undefined behavior on this responses
- */
-export interface HttpUnkownFail {
-  type: "fail-unknown",
-  url: URL;
-  status: HttpStatusCode;
-
-  // read from the body if exist
-  detail?: TalerErrorDetail;
-  body?: string;
+export function opEmptySuccess(): OperationOk<void> {
+  return { type: "ok" as const, body: void 0 }
 }
-
-export async function knownFailure<T extends string>(s: T, resp: 
HttpResponse): Promise<HttpKnownFail<T>> {
+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 async function httpSuccess<T>(resp: HttpResponse, codec: Codec<T>): 
Promise<HttpOk<T>> {
-  const body = await readSuccessResponseJsonOrThrow(resp, codec)
-  return { type: "ok" as const, body }
-}
-export function httpEmptySuccess(): HttpOk<void> {
-  return { type: "ok" as const, body: void 0 }
-}
-export async function unknownFailure(url: URL, resp: HttpResponse): 
Promise<HttpUnkownFail> {
-  if (resp.status >= 400 && resp.status < 500) {
-    const detail = await readTalerErrorResponse(resp)
-    return { type: "fail-unknown", url, status: resp.status, detail }
-  } else {
-    const { detail, body } = await readErrorResponse(resp)
-    return { type: "fail-unknown", url, status: resp.status, detail, body }
-  }
+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`,
+  );
 }
diff --git a/packages/taler-util/src/http-common.ts 
b/packages/taler-util/src/http-common.ts
index 817f2367f..da2fbb9da 100644
--- a/packages/taler-util/src/http-common.ts
+++ b/packages/taler-util/src/http-common.ts
@@ -180,37 +180,6 @@ export async function readTalerErrorResponse(
   return errJson;
 }
 
-export async function readErrorResponse(
-  httpResponse: HttpResponse,
-): Promise<{ detail: TalerErrorDetail | undefined, body: string }> {
-  let errString: string;
-  try {
-    errString = await httpResponse.text();
-  } catch (e: any) {
-    throw TalerError.fromDetail(
-      TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
-      {
-        requestUrl: httpResponse.requestUrl,
-        requestMethod: httpResponse.requestMethod,
-        httpStatusCode: httpResponse.status,
-        validationError: e.toString(),
-      },
-      "Couldn't parse JSON format from error response",
-    );
-  }
-  let errJson;
-  try {
-    errJson = JSON.parse(errString)
-  } catch (e) {
-    errJson = undefined
-  }
-
-  const talerErrorCode = errJson && errJson.code;
-  if (typeof talerErrorCode === "number") {
-    return { detail: errJson, body: errString }
-  }
-  return { detail: undefined, body: errString };
-}
 export async function readUnexpectedResponseDetails(
   httpResponse: HttpResponse,
 ): Promise<TalerErrorDetail> {

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]