gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] 04/07: update to the new bank api breaking changes


From: gnunet
Subject: [taler-wallet-core] 04/07: update to the new bank api breaking changes
Date: Fri, 03 Nov 2023 23:13:54 +0100

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

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

commit 08898c7aa32b5a4dbc40c2fecd82a5a652126705
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Fri Nov 3 18:59:27 2023 -0300

    update to the new bank api breaking changes
---
 packages/taler-util/src/http-client/bank-core.ts | 207 +++++++++++++----------
 packages/taler-util/src/http-client/types.ts     |  86 +++++++---
 packages/taler-util/src/operation.ts             |  23 ++-
 packages/taler-util/src/wallet-types.ts          |   2 +-
 4 files changed, 202 insertions(+), 116 deletions(-)

diff --git a/packages/taler-util/src/http-client/bank-core.ts 
b/packages/taler-util/src/http-client/bank-core.ts
index 35f216220..1107a3c93 100644
--- a/packages/taler-util/src/http-client/bank-core.ts
+++ b/packages/taler-util/src/http-client/bank-core.ts
@@ -18,7 +18,9 @@ import {
   AmountJson,
   Amounts,
   HttpStatusCode,
-  LibtoolVersion
+  LibtoolVersion,
+  TalerErrorCode,
+  codecForTalerErrorDetail
 } from "@gnu-taler/taler-util";
 import {
   HttpRequestLibrary,
@@ -92,16 +94,19 @@ export class TalerCoreBankHttpClient {
     });
     switch (resp.status) {
       case HttpStatusCode.Created: return opEmptySuccess()
-      case HttpStatusCode.BadRequest: return opKnownFailure("invalid-input", 
resp);
-      //FIXME: check when the server add code spec
-      case HttpStatusCode.Forbidden: {
-        if (body.username === "bank" || body.username === "admin") {
-          return opKnownFailure("unable-to-create", resp);
-        } else {
-          return opKnownFailure("unauthorized", resp);
+      case HttpStatusCode.BadRequest: return 
opKnownFailure("invalid-phone-or-email", resp);
+      case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", 
resp);
+      case HttpStatusCode.Conflict: {
+        const body = await resp.json()
+        const details = codecForTalerErrorDetail().decode(body)
+        switch (details.code) {
+          case TalerErrorCode.BANK_REGISTER_USERNAME_REUSE: return 
opKnownFailure("username-already-exists", resp);
+          case TalerErrorCode.BANK_REGISTER_PAYTO_URI_REUSE: return 
opKnownFailure("payto-already-exists", resp);
+          case TalerErrorCode.BANK_UNALLOWED_DEBIT: return 
opKnownFailure("insufficient-funds", resp);
+          case TalerErrorCode.BANK_RESERVED_USERNAME_CONFLICT: return 
opKnownFailure("username-reserved", resp);
+          default: return opUnknownFailure(resp, body)
         }
       }
-      case HttpStatusCode.Conflict: return opKnownFailure("already-exist", 
resp);
       default: return opUnknownFailure(resp, await resp.text())
     }
   }
@@ -120,19 +125,16 @@ export class TalerCoreBankHttpClient {
     switch (resp.status) {
       case HttpStatusCode.NoContent: return opEmptySuccess()
       case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp);
-      //FIXME: check when the server add code spec
-      case HttpStatusCode.Forbidden: {
-        if (auth.username === "bank" || auth.username === "admin") {
-          return opKnownFailure("unable-to-delete", resp);
-        } else {
-          return opKnownFailure("unauthorized", resp);
+      case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", 
resp);
+      case HttpStatusCode.Conflict: {
+        const body = await resp.json()
+        const details = codecForTalerErrorDetail().decode(body)
+        switch (details.code) {
+          case TalerErrorCode.BANK_RESERVED_USERNAME_CONFLICT: return 
opKnownFailure("username-reserved", resp);
+          case TalerErrorCode.BANK_ACCOUNT_BALANCE_NOT_ZERO: return 
opKnownFailure("balance-not-zero", resp);
+          default: return opUnknownFailure(resp, body)
         }
       }
-      //FIXME: this should be forbidden
-      case HttpStatusCode.Unauthorized: {
-        return opKnownFailure("unauthorized", resp);
-      }
-      case HttpStatusCode.Conflict: return opKnownFailure("balance-not-zero", 
resp);
       default: return opUnknownFailure(resp, await resp.text())
     }
   }
@@ -223,10 +225,7 @@ export class TalerCoreBankHttpClient {
     switch (resp.status) {
       case HttpStatusCode.Ok: return opSuccess(resp, 
codecForListBankAccountsResponse())
       case HttpStatusCode.NoContent: return opFixedSuccess({ accounts: [] })
-      case HttpStatusCode.Forbidden: return opKnownFailure("no-rights", resp);
-      case HttpStatusCode.Unauthorized: {
-        return opKnownFailure("unauthorized", resp);
-      }
+      case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", 
resp);
       default: return opUnknownFailure(resp, await resp.text())
     }
   }
@@ -247,7 +246,6 @@ export class TalerCoreBankHttpClient {
       case HttpStatusCode.Ok: return opSuccess(resp, codecForAccountData())
       case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", 
resp);
       case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp);
-      case HttpStatusCode.Forbidden: return opKnownFailure("no-rights", resp);
       default: return opUnknownFailure(resp, await resp.text())
     }
   }
@@ -312,14 +310,21 @@ export class TalerCoreBankHttpClient {
       body,
     });
     switch (resp.status) {
-      //FIXME: return txid
-      //FIXME: remove this after server has been updated 
-      case HttpStatusCode.Ok: return opEmptySuccess()
+      //FIXME: expect txid as response
       case HttpStatusCode.NoContent: return opEmptySuccess()
-      case HttpStatusCode.NotFound: return opKnownFailure("account-not-found", 
resp);
-      //FIXME: check when the server add codes spec
       case HttpStatusCode.BadRequest: return opKnownFailure("invalid-input", 
resp);
       case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", 
resp);
+      case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp);
+      case HttpStatusCode.Conflict: {
+        const body = await resp.json()
+        const details = codecForTalerErrorDetail().decode(body)
+        switch (details.code) {
+          case TalerErrorCode.BANK_SAME_ACCOUNT: return 
opKnownFailure("creditor-same", resp);
+          case TalerErrorCode.BANK_UNKNOWN_CREDITOR: return 
opKnownFailure("creditor-not-found", resp);
+          case TalerErrorCode.BANK_UNALLOWED_DEBIT: return 
opKnownFailure("insufficient-funds", resp);
+          default: return opUnknownFailure(resp, body)
+        }
+      }
       default: return opUnknownFailure(resp, await resp.text())
     }
   }
@@ -343,69 +348,74 @@ export class TalerCoreBankHttpClient {
     });
     switch (resp.status) {
       case HttpStatusCode.Ok: return opSuccess(resp, 
codecForBankAccountCreateWithdrawalResponse())
+      case HttpStatusCode.NotFound: return opKnownFailure("account-not-found", 
resp);
       case HttpStatusCode.Conflict: return 
opKnownFailure("insufficient-funds", resp);
       case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", 
resp);
-      case HttpStatusCode.NotFound: return opKnownFailure("account-not-found", 
resp);
-      //FIXME: remove when server is updated
-      case HttpStatusCode.Forbidden: return 
opKnownFailure("insufficient-funds", resp);
       default: return opUnknownFailure(resp, await resp.text())
     }
   }
 
   /**
-   * 
https://docs.taler.net/core/api-corebank.html#post-$BANK_API_BASE_URL-accounts-$account_name-withdrawals
+   * 
https://docs.taler.net/core/api-corebank.html#post-$BANK_API_BASE_URL-withdrawals-$withdrawal_id-abort
    * 
    */
-  async getWithdrawalById(wid: string) {
-    const url = new URL(`withdrawals/${wid}`, this.baseUrl);
+  async abortWithdrawalById(wid: string) {
+    const url = new URL(`withdrawals/${wid}/abort`, this.baseUrl);
     const resp = await this.httpLib.fetch(url.href, {
-      method: "GET",
+      method: "POST",
     });
     switch (resp.status) {
-      case HttpStatusCode.Ok: return opSuccess(resp, 
codecForBankAccountGetWithdrawalResponse())
+      case HttpStatusCode.NoContent: return opEmptySuccess()
+      //FIXME: missing in docs
       case HttpStatusCode.BadRequest: return opKnownFailure("invalid-id", resp)
       case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp)
+      case HttpStatusCode.Conflict: return 
opKnownFailure("previously-confirmed", resp);
       default: return opUnknownFailure(resp, await resp.text())
     }
   }
 
   /**
-   * 
https://docs.taler.net/core/api-corebank.html#post-$BANK_API_BASE_URL-withdrawals-$withdrawal_id-abort
+   * 
https://docs.taler.net/core/api-corebank.html#post-$BANK_API_BASE_URL-withdrawals-$withdrawal_id-confirm
    * 
    */
-  async abortWithdrawalById(wid: string) {
-    const url = new URL(`withdrawals/${wid}/abort`, this.baseUrl);
+  async confirmWithdrawalById(wid: string) {
+    const url = new URL(`withdrawals/${wid}/confirm`, this.baseUrl);
     const resp = await this.httpLib.fetch(url.href, {
       method: "POST",
     });
     switch (resp.status) {
-      //FIXME: remove when the server is fixed
-      case HttpStatusCode.Ok: return opEmptySuccess()
       case HttpStatusCode.NoContent: return opEmptySuccess()
+      //FIXME: missing in docs
       case HttpStatusCode.BadRequest: return opKnownFailure("invalid-id", resp)
       case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp)
-      case HttpStatusCode.Conflict: return 
opKnownFailure("previously-confirmed", resp);
+      case HttpStatusCode.Conflict: {
+        const body = await resp.json()
+        const details = codecForTalerErrorDetail().decode(body)
+        switch (details.code) {
+          case TalerErrorCode.BANK_UNALLOWED_DEBIT: return 
opKnownFailure("insufficient-funds", resp);
+          case TalerErrorCode.BANK_CONFIRM_INCOMPLETE: return 
opKnownFailure("no-exchange-or-reserve-selected", resp);
+          case TalerErrorCode.BANK_CONFIRM_ABORT_CONFLICT: return 
opKnownFailure("previously-aborted", resp);
+          default: return opUnknownFailure(resp, body)
+        }
+      }
       default: return opUnknownFailure(resp, await resp.text())
     }
   }
 
   /**
-   * 
https://docs.taler.net/core/api-corebank.html#post-$BANK_API_BASE_URL-withdrawals-$withdrawal_id-confirm
+   * 
https://docs.taler.net/core/api-corebank.html#post-$BANK_API_BASE_URL-accounts-$account_name-withdrawals
    * 
    */
-  async confirmWithdrawalById(wid: string) {
-    const url = new URL(`withdrawals/${wid}/confirm`, this.baseUrl);
+  async getWithdrawalById(wid: string) {
+    const url = new URL(`withdrawals/${wid}`, this.baseUrl);
     const resp = await this.httpLib.fetch(url.href, {
-      method: "POST",
+      method: "GET",
     });
     switch (resp.status) {
-      //FIXME: remove when the server is fixed
-      case HttpStatusCode.Ok: return opEmptySuccess()
-      case HttpStatusCode.NoContent: return opEmptySuccess()
+      case HttpStatusCode.Ok: return opSuccess(resp, 
codecForBankAccountGetWithdrawalResponse())
+      //FIXME: missing in docs
       case HttpStatusCode.BadRequest: return opKnownFailure("invalid-id", resp)
       case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp)
-      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())
     }
   }
@@ -429,14 +439,18 @@ export class TalerCoreBankHttpClient {
     });
     switch (resp.status) {
       case HttpStatusCode.Accepted: return opSuccess(resp, 
codecForCashoutPending())
-      //FIXME: change when the server has been updated
-      case HttpStatusCode.Conflict: return opKnownFailure("no-contact-info", 
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);
-      //FIXME: check the code response to tell cashout or tan not supported
-      case HttpStatusCode.ServiceUnavailable: return 
opKnownFailure("cashout-or-tan-not-supported", resp);
+      case HttpStatusCode.NotFound: return opKnownFailure("account-not-found", 
resp)
+      case HttpStatusCode.Conflict: {
+        const body = await resp.json()
+        const details = codecForTalerErrorDetail().decode(body)
+        switch (details.code) {
+          case TalerErrorCode.BANK_BAD_CONVERSION: return 
opKnownFailure("incorrect-exchange-rate", resp);
+          case TalerErrorCode.BANK_MISSING_TAN_INFO: return 
opKnownFailure("no-contact-info", resp);
+          case TalerErrorCode.BANK_UNALLOWED_DEBIT: return 
opKnownFailure("no-enough-balance", resp);
+          default: return opUnknownFailure(resp, body)
+        }
+      }
+      case HttpStatusCode.ServiceUnavailable: return 
opKnownFailure("cashout-not-supported", resp);
       default: return opUnknownFailure(resp, await resp.text())
     }
   }
@@ -457,6 +471,7 @@ export class TalerCoreBankHttpClient {
       case HttpStatusCode.NoContent: return opEmptySuccess()
       case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp);
       case HttpStatusCode.Conflict: return opKnownFailure("already-confirmed", 
resp);
+      //FIXME: should be 404 ?
       case HttpStatusCode.ServiceUnavailable: return 
opKnownFailure("cashout-not-supported", resp);
       default: return opUnknownFailure(resp, await resp.text())
     }
@@ -480,42 +495,40 @@ export class TalerCoreBankHttpClient {
       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);
+      //FIXME: should be 404 ?
       case HttpStatusCode.ServiceUnavailable: return 
opKnownFailure("cashout-not-supported", resp);
       default: return opUnknownFailure(resp, await resp.text())
     }
   }
 
   /**
-   * 
https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-cashouts-$CASHOUT_ID-confirm
+   * 
https://docs.taler.net/core/api-corebank.html#get--accounts-$USERNAME-cashouts
    * 
    */
-  async getCashoutRate(conversion: { debit?: AmountJson, credit?: AmountJson 
}) {
-    const url = new URL(`cashout-rate`, this.baseUrl);
-    if (conversion.debit) {
-      url.searchParams.set("amount_debit", Amounts.stringify(conversion.debit))
-    }
-    if (conversion.credit) {
-      url.searchParams.set("amount_debit", 
Amounts.stringify(conversion.credit))
-    }
+  async getAccountCashouts(auth: UserAndToken, pagination?: PaginationParams) {
+    const url = new URL(`accounts/${auth.username}/cashouts`, this.baseUrl);
+    addPaginationParams(url, pagination)
     const resp = await this.httpLib.fetch(url.href, {
       method: "GET",
+      headers: {
+        Authorization: makeBearerTokenAuthHeader(auth.token)
+      },
     });
     switch (resp.status) {
-      case HttpStatusCode.Ok: return opSuccess(resp, 
codecForCashoutConversionResponse())
-      case HttpStatusCode.BadRequest: return 
opKnownFailure("wrong-calculation", resp);
-      case HttpStatusCode.NotFound: return opKnownFailure("not-supported", 
resp);
+      case HttpStatusCode.Ok: return opSuccess(resp, codecForCashouts())
+      case HttpStatusCode.NoContent: return opFixedSuccess({ cashouts: [] });
+      case HttpStatusCode.NotFound: return opKnownFailure("account-not-found", 
resp);;
       case HttpStatusCode.ServiceUnavailable: return 
opKnownFailure("cashout-not-supported", resp);
       default: return opUnknownFailure(resp, await resp.text())
     }
   }
 
   /**
-   * 
https://docs.taler.net/core/api-corebank.html#get--accounts-$USERNAME-cashouts
+   * 
https://docs.taler.net/core/api-corebank.html#get--accounts-$USERNAME-cashouts-$CASHOUT_ID
    * 
    */
-  async getAccountCashouts(auth: UserAndToken, pagination?: PaginationParams) {
-    const url = new URL(`accounts/${auth.username}/cashouts`, this.baseUrl);
-    addPaginationParams(url, pagination)
+  async getCashoutById(auth: UserAndToken, cid: string) {
+    const url = new URL(`accounts/${auth.username}/cashouts/${cid}`, 
this.baseUrl);
     const resp = await this.httpLib.fetch(url.href, {
       method: "GET",
       headers: {
@@ -523,8 +536,8 @@ export class TalerCoreBankHttpClient {
       },
     });
     switch (resp.status) {
-      case HttpStatusCode.Ok: return opSuccess(resp, codecForCashouts())
-      case HttpStatusCode.NoContent: return opFixedSuccess({ cashouts: [] });
+      case HttpStatusCode.Ok: return opSuccess(resp, 
codecForCashoutStatusResponse())
+      case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp);
       case HttpStatusCode.ServiceUnavailable: return 
opKnownFailure("cashout-not-supported", resp);
       default: return opUnknownFailure(resp, await resp.text())
     }
@@ -552,20 +565,28 @@ export class TalerCoreBankHttpClient {
   }
 
   /**
-   * 
https://docs.taler.net/core/api-corebank.html#get--accounts-$USERNAME-cashouts-$CASHOUT_ID
+   * 
https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-cashouts-$CASHOUT_ID-confirm
    * 
    */
-  async getCashoutById(auth: UserAndToken, cid: string) {
-    const url = new URL(`accounts/${auth.username}/cashouts/${cid}`, 
this.baseUrl);
+  async getCashoutRate(conversion: { debit?: AmountJson, credit?: AmountJson 
}) {
+    const url = new URL(`cashout-rate`, this.baseUrl);
+    if (conversion.debit) {
+      url.searchParams.set("amount_debit", Amounts.stringify(conversion.debit))
+    }
+    if (conversion.credit) {
+      url.searchParams.set("amount_debit", 
Amounts.stringify(conversion.credit))
+    }
     const resp = await this.httpLib.fetch(url.href, {
       method: "GET",
-      headers: {
-        Authorization: makeBearerTokenAuthHeader(auth.token)
-      },
     });
     switch (resp.status) {
-      case HttpStatusCode.Ok: return opSuccess(resp, 
codecForCashoutStatusResponse())
-      case HttpStatusCode.NotFound: return opKnownFailure("already-aborted", 
resp);
+      case HttpStatusCode.Ok: return opSuccess(resp, 
codecForCashoutConversionResponse())
+      // FIXME: error code for
+      // * the requested currency was not supported
+      // * the calculation is not correct
+      case HttpStatusCode.BadRequest: return 
opKnownFailure("wrong-calculation", resp);
+      case HttpStatusCode.NotFound: return opKnownFailure("not-supported", 
resp);
+      //FIXME: should be 404 ?
       case HttpStatusCode.ServiceUnavailable: return 
opKnownFailure("cashout-not-supported", resp);
       default: return opUnknownFailure(resp, await resp.text())
     }
@@ -579,22 +600,26 @@ export class TalerCoreBankHttpClient {
    * https://docs.taler.net/core/api-corebank.html#get--monitor
    * 
    */
-  async getMonitor(params: { timeframe?: 
TalerCorebankApi.MonitorTimeframeParam, which?: number } = {}) {
+  async getMonitor(auth: AccessToken, params: { timeframe?: 
TalerCorebankApi.MonitorTimeframeParam, which?: number } = {}) {
     const url = new URL(`monitor`, this.baseUrl);
     if (params.timeframe) {
-      url.searchParams.set("timeframe", params.timeframe.toString())
+      url.searchParams.set("timeframe", 
TalerCorebankApi.MonitorTimeframeParam[params.timeframe])
     }
     if (params.which) {
       url.searchParams.set("which", String(params.which))
     }
     const resp = await this.httpLib.fetch(url.href, {
       method: "GET",
+      headers: {
+        Authorization: makeBearerTokenAuthHeader(auth)
+      },
     });
     switch (resp.status) {
       case HttpStatusCode.Ok: return opSuccess(resp, codecForMonitorResponse())
       case HttpStatusCode.BadRequest: return opKnownFailure("invalid-input", 
resp);
+      case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", 
resp);
       //FIXME remove when server is updated
-      case HttpStatusCode.NotFound: return 
opKnownFailure("monitor-not-supported", resp);
+      //FIXME: should be 404 ?
       case HttpStatusCode.ServiceUnavailable: return 
opKnownFailure("monitor-not-supported", resp);
       default: return opUnknownFailure(resp, await resp.text())
     }
@@ -641,5 +666,3 @@ export class TalerCoreBankHttpClient {
   }
 
 }
-
-
diff --git a/packages/taler-util/src/http-client/types.ts 
b/packages/taler-util/src/http-client/types.ts
index 1bb8f99c1..95d0f8dd6 100644
--- a/packages/taler-util/src/http-client/types.ts
+++ b/packages/taler-util/src/http-client/types.ts
@@ -192,9 +192,6 @@ export interface CurrencySpecification {
   // Name of the currency.
   name: string;
 
-  // Decimal separator for fractional digits.
-  decimal_separator: string;
-
   // how many digits the user may enter after the decimal_separator
   num_fractional_input_digits: Integer;
 
@@ -205,10 +202,6 @@ export interface CurrencySpecification {
   // padding with zeros.
   num_fractional_trailing_zero_digits: Integer;
 
-  // Whether the currency name should be rendered before (true) or
-  // after (false) the numeric value
-  is_currency_name_leading: boolean;
-
   // map of powers of 10 to alternative currency names / symbols, must
   // always have an entry under "0" that defines the base name,
   // e.g.  "0 => €" or "3 => k€". For BTC, would be "0 => BTC, -3 => mBTC".
@@ -228,11 +221,9 @@ export const codecForCurrencySpecificiation =
   (): Codec<CurrencySpecification> =>
     buildCodecForObject<CurrencySpecification>()
       .property("name", codecForString())
-      .property("decimal_separator", codecForString())
       .property("num_fractional_input_digits", codecForNumber())
       .property("num_fractional_normal_digits", codecForNumber())
       .property("num_fractional_trailing_zero_digits", codecForNumber())
-      .property("is_currency_name_leading", codecForBoolean())
       .property("alt_unit_names", codecForMap(codecForString()))
       .build("CurrencySpecification")
 
@@ -241,6 +232,8 @@ export const codecForCoreBankConfig =
     buildCodecForObject<TalerCorebankApi.Config>()
       .property("name", codecForString())
       .property("version", codecForString())
+      .property("allow_deletions", codecForBoolean())
+      .property("allow_registrations", codecForBoolean())
       .property("have_cashout", codecOptional(codecForBoolean()))
       .property("currency", codecForCurrencySpecificiation())
       .property("fiat_currency", 
codecOptional(codecForCurrencySpecificiation()))
@@ -398,16 +391,32 @@ export const codecForConversionRatesResponse =
       .property("sell_out_fee", codecForDecimalNumber())
       .build("TalerCorebankApi.ConversionRatesResponse");
 
-export const codecForMonitorResponse =
-  (): Codec<TalerCorebankApi.MonitorResponse> =>
-    buildCodecForObject<TalerCorebankApi.MonitorResponse>()
-      .property("cashinCount", codecOptional(codecForNumber()))
-      .property("cashinExternalVolume", codecOptional(codecForAmountString()))
-      .property("cashoutCount", codecOptional(codecForNumber()))
-      .property("cashoutExternalVolume", codecOptional(codecForAmountString()))
+
+export const codecForMonitorResponse = (): 
Codec<TalerCorebankApi.MonitorResponse> => 
buildCodecForUnion<TalerCorebankApi.MonitorResponse>()
+  .discriminateOn("type")
+  .alternative("just-payouts", codecForMonitorResponseJustPayout())
+  .alternative("with-cashout", codecForMonitorResponseWithCashout())
+  .build("TalerWireGatewayApi.IncomingBankTransaction");
+
+export const codecForMonitorResponseJustPayout =
+  (): Codec<TalerCorebankApi.MonitorJustPayouts> =>
+    buildCodecForObject<TalerCorebankApi.MonitorJustPayouts>()
+      .property("type", codecForConstString("just-payouts"))
       .property("talerPayoutCount", codecForNumber())
       .property("talerPayoutInternalVolume", codecForAmountString())
-      .build("TalerCorebankApi.MonitorResponse");
+      .build("TalerCorebankApi.MonitorJustPayouts");
+
+export const codecForMonitorResponseWithCashout =
+  (): Codec<TalerCorebankApi.MonitorWithCashout> =>
+    buildCodecForObject<TalerCorebankApi.MonitorWithCashout>()
+      .property("type", codecForConstString("with-cashout"))
+      .property("cashinCount", (codecForNumber()))
+      .property("cashinExternalVolume", (codecForAmountString()))
+      .property("cashoutCount", (codecForNumber()))
+      .property("cashoutExternalVolume", (codecForAmountString()))
+      .property("talerPayoutCount", codecForNumber())
+      .property("talerPayoutInternalVolume", codecForAmountString())
+      .build("TalerCorebankApi.MonitorWithCashout");
 
 export const codecForBankVersion =
   (): Codec<TalerBankIntegrationApi.BankVersion> =>
@@ -839,6 +848,14 @@ export namespace TalerCorebankApi {
     // API version in the form $n:$n:$n
     version: string;
 
+    // If 'true' anyone can register
+    // If 'false' only the admin can
+    allow_registrations: boolean;
+
+    // If 'true' account can delete themselves
+    // If 'false' only the admin can delete accounts
+    allow_deletions: boolean;
+
     // If 'true', the server provides local currency
     // conversion support.
     // If missing or false, some parts of the API
@@ -997,6 +1014,11 @@ export namespace TalerCorebankApi {
     // If present, change the is_exchange configuration.
     // See RegisterAccountRequest
     is_exchange?: boolean;
+
+    // If present, change the max debit allowed for this user
+    // Only admin can change this property.
+    debit_threshold?: AmountString
+
   }
 
 
@@ -1181,30 +1203,50 @@ export namespace TalerCorebankApi {
     hour, day, month, year, decade,
   }
 
-  export interface MonitorResponse {
+  export type MonitorResponse =
+    | MonitorJustPayouts
+    | MonitorWithCashout;
+
+  // Monitoring stats when conversion is not supported
+  export interface MonitorJustPayouts {
+    type: "just-payouts";
+
+    // This number identifies how many payments were made by a
+    // Taler exchange to a merchant bank account in the internal
+    // currency, in the timeframe specified in the request.
+    talerPayoutCount: number;
+
+    // This amount accounts the overall *internal* currency that
+    // has been paid by a Taler exchange to a merchant internal
+    // bank account, in the timeframe specified in the request.
+    talerPayoutInternalVolume: AmountString;
+  }
+  // Monitoring stats when conversion is supported
+  export interface MonitorWithCashout {
+    type: "with-cashout";
 
     // This number identifies how many cashin operations
     // took place in the timeframe specified in the request.
     // This number corresponds to how many withdrawals have
     // been initiated by a wallet owner.  Note: wallet owners
     // are NOT required to be customers of the libeufin-bank.
-    cashinCount?: number;
+    cashinCount: number;
 
     // This amount accounts how much external currency has been
     // spent to withdraw Taler coins in the internal currency.
     // The exact amount of internal currency being created can be
     // calculated using the advertised conversion rates.
-    cashinExternalVolume?: AmountString;
+    cashinExternalVolume: AmountString;
 
     // This number identifies how many cashout operations were
     // confirmed in the timeframe speficied in the request.
-    cashoutCount?: number;
+    cashoutCount: number;
 
     // This amount corresponds to how much *external* currency was
     // paid by the libeufin-bank administrator to fulfill all the
     // confirmed cashouts related to the timeframe specified in the
     // request.
-    cashoutExternalVolume?: AmountString;
+    cashoutExternalVolume: AmountString;
 
     // This number identifies how many payments were made by a
     // Taler exchange to a merchant bank account in the internal
diff --git a/packages/taler-util/src/operation.ts 
b/packages/taler-util/src/operation.ts
index 8adbbb0e2..9d7594d14 100644
--- a/packages/taler-util/src/operation.ts
+++ b/packages/taler-util/src/operation.ts
@@ -67,8 +67,29 @@ export async function failOrThrow<E>(s: E, cb: () => 
Promise<OperationResult<unk
 
 export type ResultByMethod<TT extends object, p extends keyof TT> = TT[p] 
extends (...args: any[]) => infer Ret ?
   Ret extends Promise<infer Result> ?
-  Result :
+  Result extends OperationResult<any, any> ? Result : never :
   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>>
+
+type MethodsOfOperations<T extends object> = 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<infer Result> ?
+  // of an operation
+  Result extends OperationResult<any, any> ?
+  P : never
+  : never
+  : never]: any
+}
+
+type AllKnownCases<t extends object, d extends keyof t> = "success" | 
FailCasesByMethod<t, d>["case"]
+
+export type TestForApi<ApiType extends object> = {
+  [OpType in MethodsOfOperations<ApiType> as `test_${OpType & string}`]: {
+    [c in AllKnownCases<ApiType, OpType>]: undefined | ((api: ApiType) => 
Promise<void>);
+  };
+};
diff --git a/packages/taler-util/src/wallet-types.ts 
b/packages/taler-util/src/wallet-types.ts
index 7503a4665..aaec09b66 100644
--- a/packages/taler-util/src/wallet-types.ts
+++ b/packages/taler-util/src/wallet-types.ts
@@ -592,7 +592,7 @@ export interface ConfirmPayResultPending {
 export const codecForTalerErrorDetail = (): Codec<TalerErrorDetail> =>
   buildCodecForObject<TalerErrorDetail>()
     .property("code", codecForNumber())
-    .property("when", codecForAbsoluteTime)
+    .property("when", codecOptional(codecForAbsoluteTime))
     .property("hint", codecOptional(codecForString()))
     .build("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]