taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit b52b13ddae1dfcb2866f0e55de5617681165b7de
parent 5bdefcf53d0bbad5b3c9474fab9b0cfa6eafeae9
Author: Sebastian <sebasjm@gmail.com>
Date:   Mon,  2 Sep 2024 14:59:09 -0300

when error happen there is no garantee that taler error details is present, so undefined should be set

Diffstat:
Mpackages/bank-ui/src/Routing.tsx | 4++--
Mpackages/bank-ui/src/hooks/regional.ts | 32++++++++++++++++++++++++--------
Mpackages/bank-ui/src/pages/OperationState/views.tsx | 35+++++++++++++++++++++--------------
Mpackages/bank-ui/src/pages/PaytoWireTransferForm.tsx | 16++++++++--------
Mpackages/bank-ui/src/pages/SolveChallengePage.tsx | 18+++++++++---------
Mpackages/bank-ui/src/pages/WalletWithdrawForm.tsx | 6+++---
Mpackages/bank-ui/src/pages/WithdrawalConfirmationQuestion.tsx | 16++++++++--------
Mpackages/bank-ui/src/pages/account/ShowAccountDetails.tsx | 16++++++++--------
Mpackages/bank-ui/src/pages/account/UpdateAccountPassword.tsx | 8++++----
Mpackages/bank-ui/src/pages/admin/CreateNewAccount.tsx | 22+++++++++++-----------
Mpackages/bank-ui/src/pages/admin/DownloadStats.tsx | 4++--
Mpackages/bank-ui/src/pages/admin/RemoveAccount.tsx | 8++++----
Mpackages/bank-ui/src/pages/regional/ConversionConfig.tsx | 4++--
Mpackages/bank-ui/src/pages/regional/CreateCashout.tsx | 16++++++++--------
Mpackages/merchant-backoffice-ui/src/paths/admin/create/index.tsx | 2+-
Mpackages/merchant-backoffice-ui/src/paths/admin/list/index.tsx | 4++--
Mpackages/merchant-backoffice-ui/src/paths/instance/accounts/create/index.tsx | 6+++---
Mpackages/merchant-backoffice-ui/src/paths/instance/accounts/list/index.tsx | 2+-
Mpackages/merchant-backoffice-ui/src/paths/instance/accounts/update/index.tsx | 18+++++++++---------
Mpackages/merchant-backoffice-ui/src/paths/instance/categories/create/index.tsx | 2+-
Mpackages/merchant-backoffice-ui/src/paths/instance/categories/list/index.tsx | 2+-
Mpackages/merchant-backoffice-ui/src/paths/instance/orders/create/index.tsx | 12++++++------
Mpackages/merchant-backoffice-ui/src/paths/instance/orders/details/index.tsx | 2+-
Mpackages/merchant-backoffice-ui/src/paths/instance/orders/list/index.tsx | 2+-
Mpackages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/index.tsx | 2+-
Mpackages/merchant-backoffice-ui/src/paths/instance/otp_devices/list/index.tsx | 2+-
Mpackages/merchant-backoffice-ui/src/paths/instance/products/create/index.tsx | 2+-
Mpackages/merchant-backoffice-ui/src/paths/instance/products/list/index.tsx | 4++--
Mpackages/merchant-backoffice-ui/src/paths/instance/products/update/index.tsx | 2+-
Mpackages/merchant-backoffice-ui/src/paths/instance/templates/create/index.tsx | 2+-
Mpackages/merchant-backoffice-ui/src/paths/instance/templates/list/index.tsx | 2+-
Mpackages/merchant-backoffice-ui/src/paths/instance/templates/update/index.tsx | 2+-
Mpackages/merchant-backoffice-ui/src/paths/instance/templates/use/index.tsx | 12++++++------
Mpackages/merchant-backoffice-ui/src/paths/instance/token/index.tsx | 4++--
Mpackages/merchant-backoffice-ui/src/paths/instance/tokenfamilies/create/index.tsx | 2+-
Mpackages/merchant-backoffice-ui/src/paths/instance/tokenfamilies/list/index.tsx | 4++--
Mpackages/merchant-backoffice-ui/src/paths/instance/tokenfamilies/update/index.tsx | 2+-
Mpackages/merchant-backoffice-ui/src/paths/instance/transfers/create/index.tsx | 2+-
Mpackages/merchant-backoffice-ui/src/paths/instance/transfers/list/index.tsx | 2+-
Mpackages/merchant-backoffice-ui/src/paths/instance/webhooks/create/index.tsx | 2+-
Mpackages/merchant-backoffice-ui/src/paths/instance/webhooks/list/index.tsx | 2+-
Mpackages/merchant-backoffice-ui/src/paths/instance/webhooks/update/index.tsx | 2+-
Mpackages/taler-harness/src/index.ts | 4++--
Mpackages/taler-util/src/http-client/challenger.ts | 2+-
Mpackages/taler-util/src/http-client/exchange.ts | 31+++++++++++++++++++++++++------
Mpackages/taler-util/src/http-client/officer-account.ts | 35+----------------------------------
Mpackages/taler-util/src/http-common.ts | 4++--
Mpackages/taler-util/src/http-impl.node.ts | 4++++
Mpackages/taler-util/src/operation.ts | 67++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Mpackages/taler-util/src/types-taler-common.ts | 17++---------------
Mpackages/taler-wallet-core/src/pay-merchant.ts | 12+++++++-----
Mpackages/taler-wallet-core/src/withdraw.ts | 6+++++-
Mpackages/taler-wallet-webextension/src/wallet/AddExchange/index.ts | 18++++++++----------
Mpackages/taler-wallet-webextension/src/wallet/AddExchange/state.ts | 14+++++++-------
Mpackages/taler-wallet-webextension/src/wallet/AddExchange/views.tsx | 3++-
Mpackages/taler-wallet-webextension/src/wallet/History.tsx | 2--
Mpackages/web-util/src/context/bank-api.ts | 6+++++-
Mpackages/web-util/src/context/challenger-api.ts | 6+++++-
Mpackages/web-util/src/context/exchange-api.ts | 6+++++-
Mpackages/web-util/src/context/merchant-api.ts | 6+++++-
Mpackages/web-util/src/hooks/useNotifications.ts | 2+-
61 files changed, 301 insertions(+), 253 deletions(-)

diff --git a/packages/bank-ui/src/Routing.tsx b/packages/bank-ui/src/Routing.tsx @@ -128,7 +128,7 @@ function PublicRounting({ return notify({ type: "error", title: i18n.str`Wrong credentials for "${username}"`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -136,7 +136,7 @@ function PublicRounting({ return notify({ type: "error", title: i18n.str`Account not found`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); diff --git a/packages/bank-ui/src/hooks/regional.ts b/packages/bank-ui/src/hooks/regional.ts @@ -42,10 +42,10 @@ const useSWR = _useSWR as unknown as SWRHook; export type TransferCalculation = | { - debit: AmountJson; - credit: AmountJson; - beforeFee: AmountJson; - } + debit: AmountJson; + credit: AmountJson; + beforeFee: AmountJson; + } | "amount-is-too-small"; type EstimatorFunction = ( amount: AmountJson, @@ -109,7 +109,11 @@ export function useCashinEstimator(): ConversionEstimators { // this below can't happen case HttpStatusCode.NotImplemented: //it should not be able to call this function case HttpStatusCode.BadRequest: //we are using just one parameter - throw TalerError.fromDetail(resp.detail.code, {}, resp.detail.hint); + if (resp.detail) { + throw TalerError.fromUncheckedDetail(resp.detail); + } else { + throw TalerError.fromException(new Error("failed to get conversion cashin rate")) + } } } const credit = Amounts.parseOrThrow(resp.body.amount_credit); @@ -134,7 +138,11 @@ export function useCashinEstimator(): ConversionEstimators { // this below can't happen case HttpStatusCode.NotImplemented: //it should not be able to call this function case HttpStatusCode.BadRequest: //we are using just one parameter - throw TalerError.fromDetail(resp.detail.code, {}, resp.detail.hint); + if (resp.detail) { + throw TalerError.fromUncheckedDetail(resp.detail); + } else { + throw TalerError.fromException(new Error("failed to get conversion cashin rate")) + } } } const credit = Amounts.parseOrThrow(resp.body.amount_credit); @@ -167,7 +175,11 @@ export function useCashoutEstimator(): ConversionEstimators { // this below can't happen case HttpStatusCode.NotImplemented: //it should not be able to call this function case HttpStatusCode.BadRequest: //we are using just one parameter - throw TalerError.fromDetail(resp.detail.code, {}, resp.detail.hint); + if (resp.detail) { + throw TalerError.fromUncheckedDetail(resp.detail); + } else { + throw TalerError.fromException(new Error("failed to get conversion cashout rate")) + } } } const credit = Amounts.parseOrThrow(resp.body.amount_credit); @@ -192,7 +204,11 @@ export function useCashoutEstimator(): ConversionEstimators { // this below can't happen case HttpStatusCode.NotImplemented: //it should not be able to call this function case HttpStatusCode.BadRequest: //we are using just one parameter - throw TalerError.fromDetail(resp.detail.code, {}, resp.detail.hint); + if (resp.detail) { + throw TalerError.fromUncheckedDetail(resp.detail); + } else { + throw TalerError.fromException(new Error("failed to get conversion cashout rate")) + } } } const credit = Amounts.parseOrThrow(resp.body.amount_credit); diff --git a/packages/bank-ui/src/pages/OperationState/views.tsx b/packages/bank-ui/src/pages/OperationState/views.tsx @@ -80,7 +80,7 @@ export function NeedConfirmationView({ return notify({ type: "error", title: i18n.str`The reserve operation has been confirmed previously and can't be aborted`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -88,7 +88,7 @@ export function NeedConfirmationView({ return notify({ type: "error", title: i18n.str`The operation id is invalid.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -96,7 +96,7 @@ export function NeedConfirmationView({ return notify({ type: "error", title: i18n.str`The operation was not found.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -121,7 +121,7 @@ export function NeedConfirmationView({ return notify({ type: "error", title: i18n.str`The withdrawal has been aborted previously and can't be confirmed`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -129,7 +129,7 @@ export function NeedConfirmationView({ return notify({ type: "error", title: i18n.str`The withdrawal operation can't be confirmed before a wallet accepted the transaction.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -137,7 +137,7 @@ export function NeedConfirmationView({ return notify({ type: "error", title: i18n.str`The operation id is invalid.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -145,7 +145,7 @@ export function NeedConfirmationView({ return notify({ type: "error", title: i18n.str`The operation was not found.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -153,7 +153,7 @@ export function NeedConfirmationView({ return notify({ type: "error", title: i18n.str`Your balance is not enough.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -388,7 +388,9 @@ export function FailedView({ error }: State.Failed) { type="danger" title={i18n.str`Unauthorized to make the operation, maybe the session has expired or the password changed.`} > - <div class="mt-2 text-sm text-red-700">{error.detail.hint}</div> + {!error.detail ? undefined : + <div class="mt-2 text-sm text-red-700">{error.detail.hint}</div> + } </Attention> ); case HttpStatusCode.Conflict: @@ -397,7 +399,10 @@ export function FailedView({ error }: State.Failed) { type="danger" title={i18n.str`The operation was rejected due to insufficient funds.`} > - <div class="mt-2 text-sm text-red-700">{error.detail.hint}</div> + {!error.detail ? undefined : + + <div class="mt-2 text-sm text-red-700">{error.detail.hint}</div> + } </Attention> ); case HttpStatusCode.NotFound: @@ -406,7 +411,9 @@ export function FailedView({ error }: State.Failed) { type="danger" title={i18n.str`The operation was rejected due to insufficient funds.`} > - <div class="mt-2 text-sm text-red-700">{error.detail.hint}</div> + {!error.detail ? undefined : + <div class="mt-2 text-sm text-red-700">{error.detail.hint}</div> + } </Attention> ); default: @@ -528,7 +535,7 @@ export function ReadyView({ return notify({ type: "error", title: i18n.str`The reserve operation has been confirmed previously and can't be aborted`, - description: hasError.detail.hint as TranslatedString, + description: hasError.detail?.hint as TranslatedString, debug: hasError.detail, when: AbsoluteTime.now(), }); @@ -536,7 +543,7 @@ export function ReadyView({ return notify({ type: "error", title: i18n.str`The operation id is invalid.`, - description: hasError.detail.hint as TranslatedString, + description: hasError.detail?.hint as TranslatedString, debug: hasError.detail, when: AbsoluteTime.now(), }); @@ -544,7 +551,7 @@ export function ReadyView({ return notify({ type: "error", title: i18n.str`The operation was not found.`, - description: hasError.detail.hint as TranslatedString, + description: hasError.detail?.hint as TranslatedString, debug: hasError.detail, when: AbsoluteTime.now(), }); diff --git a/packages/bank-ui/src/pages/PaytoWireTransferForm.tsx b/packages/bank-ui/src/pages/PaytoWireTransferForm.tsx @@ -209,7 +209,7 @@ export function PaytoWireTransferForm({ return notify({ type: "error", title: i18n.str`The request was invalid or the payto://-URI used unacceptable features.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -217,7 +217,7 @@ export function PaytoWireTransferForm({ return notify({ type: "error", title: i18n.str`Not enough permission to complete the operation.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -225,7 +225,7 @@ export function PaytoWireTransferForm({ return notify({ type: "error", title: i18n.str`Bank administrator can't be the transfer creditor.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -235,7 +235,7 @@ export function PaytoWireTransferForm({ title: i18n.str`The destination account "${ acName ?? puri }" was not found.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -243,7 +243,7 @@ export function PaytoWireTransferForm({ return notify({ type: "error", title: i18n.str`The origin and the destination of the transfer can't be the same.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -251,7 +251,7 @@ export function PaytoWireTransferForm({ return notify({ type: "error", title: i18n.str`Your balance is not enough.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -259,7 +259,7 @@ export function PaytoWireTransferForm({ return notify({ type: "error", title: i18n.str`The origin account "${puri}" was not found.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -267,7 +267,7 @@ export function PaytoWireTransferForm({ return notify({ type: "error", title: i18n.str`Tried to create the transaction ${check.maxTries} times with different UID but failed.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); diff --git a/packages/bank-ui/src/pages/SolveChallengePage.tsx b/packages/bank-ui/src/pages/SolveChallengePage.tsx @@ -112,7 +112,7 @@ export function SolveChallengePage({ return notify({ type: "error", title: i18n.str`Cashout not found. It may be also mean that it was already aborted.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -120,7 +120,7 @@ export function SolveChallengePage({ return notify({ type: "error", title: i18n.str`Cashout not found. It may be also mean that it was already aborted.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -128,7 +128,7 @@ export function SolveChallengePage({ return notify({ type: "error", title: i18n.str`Cashout not found. It may be also mean that it was already aborted.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -154,7 +154,7 @@ export function SolveChallengePage({ return notify({ type: "error", title: i18n.str`Challenge not found.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -162,7 +162,7 @@ export function SolveChallengePage({ return notify({ type: "error", title: i18n.str`This user is not authorized to complete this challenge.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -170,7 +170,7 @@ export function SolveChallengePage({ return notify({ type: "error", title: i18n.str`Too many attempts, try another code.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -178,7 +178,7 @@ export function SolveChallengePage({ return notify({ type: "error", title: i18n.str`The confirmation code is wrong, try again.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -186,7 +186,7 @@ export function SolveChallengePage({ return notify({ type: "error", title: i18n.str`The operation expired.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -225,7 +225,7 @@ export function SolveChallengePage({ return notify({ type: "error", title: i18n.str`The operation failed.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); diff --git a/packages/bank-ui/src/pages/WalletWithdrawForm.tsx b/packages/bank-ui/src/pages/WalletWithdrawForm.tsx @@ -229,7 +229,7 @@ function OldWithdrawalForm({ notify({ type: "error", title: i18n.str`The operation was rejected due to insufficient funds`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -239,7 +239,7 @@ function OldWithdrawalForm({ notify({ type: "error", title: i18n.str`The operation was rejected due to insufficient funds`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -249,7 +249,7 @@ function OldWithdrawalForm({ notify({ type: "error", title: i18n.str`Account not found`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); diff --git a/packages/bank-ui/src/pages/WithdrawalConfirmationQuestion.tsx b/packages/bank-ui/src/pages/WithdrawalConfirmationQuestion.tsx @@ -103,7 +103,7 @@ export function WithdrawalConfirmationQuestion({ return notify({ type: "error", title: i18n.str`The withdrawal has been aborted previously and can't be confirmed`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -111,7 +111,7 @@ export function WithdrawalConfirmationQuestion({ return notify({ type: "error", title: i18n.str`The withdrawal operation can't be confirmed before a wallet accepted the transaction.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -119,7 +119,7 @@ export function WithdrawalConfirmationQuestion({ return notify({ type: "error", title: i18n.str`The operation id is invalid.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -127,7 +127,7 @@ export function WithdrawalConfirmationQuestion({ return notify({ type: "error", title: i18n.str`The operation was not found.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -135,7 +135,7 @@ export function WithdrawalConfirmationQuestion({ return notify({ type: "error", title: i18n.str`Your balance is not enough for the operation.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -173,7 +173,7 @@ export function WithdrawalConfirmationQuestion({ return notify({ type: "error", title: i18n.str`The reserve operation has been confirmed previously and can't be aborted`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -181,7 +181,7 @@ export function WithdrawalConfirmationQuestion({ return notify({ type: "error", title: i18n.str`The operation id is invalid.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -189,7 +189,7 @@ export function WithdrawalConfirmationQuestion({ return notify({ type: "error", title: i18n.str`The operation was not found.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); diff --git a/packages/bank-ui/src/pages/account/ShowAccountDetails.tsx b/packages/bank-ui/src/pages/account/ShowAccountDetails.tsx @@ -129,7 +129,7 @@ export function ShowAccountDetails({ return notify({ type: "error", title: i18n.str`The rights to change the account are not sufficient`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -137,7 +137,7 @@ export function ShowAccountDetails({ return notify({ type: "error", title: i18n.str`The username was not found`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -145,7 +145,7 @@ export function ShowAccountDetails({ return notify({ type: "error", title: i18n.str`You can't change the legal name, please contact the your account administrator.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -153,7 +153,7 @@ export function ShowAccountDetails({ return notify({ type: "error", title: i18n.str`You can't change the debt limit, please contact the your account administrator.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -161,7 +161,7 @@ export function ShowAccountDetails({ return notify({ type: "error", title: i18n.str`You can't change the cashout address, please contact the your account administrator.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -169,7 +169,7 @@ export function ShowAccountDetails({ return notify({ type: "error", title: i18n.str`No information for the selected authentication channel.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -187,7 +187,7 @@ export function ShowAccountDetails({ return notify({ type: "error", title: i18n.str`Authentication channel is not supported.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -196,7 +196,7 @@ export function ShowAccountDetails({ return notify({ type: "error", title: i18n.str`Only the administrator can change the minimum cashout limit.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); diff --git a/packages/bank-ui/src/pages/account/UpdateAccountPassword.tsx b/packages/bank-ui/src/pages/account/UpdateAccountPassword.tsx @@ -115,7 +115,7 @@ export function UpdateAccountPassword({ return notify({ type: "error", title: i18n.str`Not authorized to change the password, maybe the session is invalid.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -123,7 +123,7 @@ export function UpdateAccountPassword({ return notify({ type: "error", title: i18n.str`Account not found`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -131,7 +131,7 @@ export function UpdateAccountPassword({ return notify({ type: "error", title: i18n.str`You need to provide the old password. If you don't have it contact your account administrator.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -139,7 +139,7 @@ export function UpdateAccountPassword({ return notify({ type: "error", title: i18n.str`Your current password doesn't match, can't change to a new password.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); diff --git a/packages/bank-ui/src/pages/admin/CreateNewAccount.tsx b/packages/bank-ui/src/pages/admin/CreateNewAccount.tsx @@ -70,7 +70,7 @@ export function CreateNewAccount({ return notify({ type: "error", title: i18n.str`Server replied that phone or email is invalid`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -78,7 +78,7 @@ export function CreateNewAccount({ return notify({ type: "error", title: i18n.str`The rights to perform the operation are not sufficient`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -86,7 +86,7 @@ export function CreateNewAccount({ return notify({ type: "error", title: i18n.str`Account username is already taken`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -94,7 +94,7 @@ export function CreateNewAccount({ return notify({ type: "error", title: i18n.str`Account id is already taken`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -102,7 +102,7 @@ export function CreateNewAccount({ return notify({ type: "error", title: i18n.str`Bank ran out of bonus credit.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -110,7 +110,7 @@ export function CreateNewAccount({ return notify({ type: "error", title: i18n.str`Account username can't be used because is reserved`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -118,7 +118,7 @@ export function CreateNewAccount({ return notify({ type: "error", title: i18n.str`Only admin is allow to set debt limit.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -126,7 +126,7 @@ export function CreateNewAccount({ return notify({ type: "error", title: i18n.str`No information for the selected authentication channel.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -134,7 +134,7 @@ export function CreateNewAccount({ return notify({ type: "error", title: i18n.str`Authentication channel is not supported.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -142,7 +142,7 @@ export function CreateNewAccount({ return notify({ type: "error", title: i18n.str`Only admin can create accounts with second factor authentication.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -150,7 +150,7 @@ export function CreateNewAccount({ return notify({ type: "error", title: i18n.str`Only the administrator can change the minimum cashout limit.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); diff --git a/packages/bank-ui/src/pages/admin/DownloadStats.tsx b/packages/bank-ui/src/pages/admin/DownloadStats.tsx @@ -468,7 +468,7 @@ async function fetchAllStatus( : undefined; if (previous && previous.type === "fail" && options.endOnFirstFail) { - throw TalerError.fromUncheckedDetail(previous.detail); + return accumulatedMap; //skip } const current = await api.getMonitor(token, { @@ -477,7 +477,7 @@ async function fetchAllStatus( }); if (current.type === "fail" && options.endOnFirstFail) { - throw TalerError.fromUncheckedDetail(current.detail); + return accumulatedMap; //skip } const metricName = diff --git a/packages/bank-ui/src/pages/admin/RemoveAccount.tsx b/packages/bank-ui/src/pages/admin/RemoveAccount.tsx @@ -132,7 +132,7 @@ export function RemoveAccount({ return notify({ type: "error", title: i18n.str`No enough permission to delete the account.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -140,7 +140,7 @@ export function RemoveAccount({ return notify({ type: "error", title: i18n.str`The username was not found.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -148,7 +148,7 @@ export function RemoveAccount({ return notify({ type: "error", title: i18n.str`Can't delete a reserved username.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -156,7 +156,7 @@ export function RemoveAccount({ return notify({ type: "error", title: i18n.str`Can't delete an account with balance different than zero.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); diff --git a/packages/bank-ui/src/pages/regional/ConversionConfig.tsx b/packages/bank-ui/src/pages/regional/ConversionConfig.tsx @@ -205,7 +205,7 @@ function useComponentState({ return notify({ type: "error", title: i18n.str`Wrong credentials`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -214,7 +214,7 @@ function useComponentState({ return notify({ type: "error", title: i18n.str`Conversion is disabled`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); diff --git a/packages/bank-ui/src/pages/regional/CreateCashout.tsx b/packages/bank-ui/src/pages/regional/CreateCashout.tsx @@ -299,7 +299,7 @@ export function CreateCashout({ return notify({ type: "error", title: i18n.str`Account not found`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -307,7 +307,7 @@ export function CreateCashout({ return notify({ type: "error", title: i18n.str`Duplicated request detected, check if the operation succeeded or try again.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -315,7 +315,7 @@ export function CreateCashout({ return notify({ type: "error", title: i18n.str`The conversion rate was incorrectly applied`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -323,7 +323,7 @@ export function CreateCashout({ return notify({ type: "error", title: i18n.str`The account does not have sufficient funds`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -331,7 +331,7 @@ export function CreateCashout({ return notify({ type: "error", title: i18n.str`Cashout are disabled`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -339,7 +339,7 @@ export function CreateCashout({ return notify({ type: "error", title: i18n.str`Missing cashout URI in the profile`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -347,7 +347,7 @@ export function CreateCashout({ return notify({ type: "error", title: i18n.str`The amount is less than the minimum allowed.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); @@ -356,7 +356,7 @@ export function CreateCashout({ return notify({ type: "error", title: i18n.str`Sending the confirmation message failed, retry later or contact the administrator.`, - description: resp.detail.hint as TranslatedString, + description: resp.detail?.hint as TranslatedString , debug: resp.detail, when: AbsoluteTime.now(), }); diff --git a/packages/merchant-backoffice-ui/src/paths/admin/create/index.tsx b/packages/merchant-backoffice-ui/src/paths/admin/create/index.tsx @@ -53,7 +53,7 @@ export default function Create({ onBack, onConfirm, forceId }: Props): VNode { setNotif({ message: i18n.str`Failed to create instance`, type: "ERROR", - description: resp.detail.hint, + description: resp.detail?.hint, }); return; } diff --git a/packages/merchant-backoffice-ui/src/paths/admin/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/admin/list/index.tsx @@ -104,7 +104,7 @@ export default function Instances({ onCreate, onUpdate }: Props): VNode { setNotif({ message: i18n.str`Failed to delete instance`, type: "ERROR", - description: resp.detail.hint, + description: resp.detail?.hint, }); } } catch (error) { @@ -144,7 +144,7 @@ export default function Instances({ onCreate, onUpdate }: Props): VNode { setNotif({ message: i18n.str`Failed to purge instance`, type: "ERROR", - description: resp.detail.hint, + description: resp.detail?.hint, }); } } catch (error) { diff --git a/packages/merchant-backoffice-ui/src/paths/instance/accounts/create/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/accounts/create/index.tsx @@ -61,12 +61,12 @@ export default function CreateValidator({ onConfirm, onBack }: Props): VNode { onCreate={async (request: Entity) => { return lib.instance .addBankAccount(state.token, request) - .then((created) => { - if (created.type === "fail") { + .then((resp) => { + if (resp.type === "fail") { setNotif({ message: i18n.str`Could not create account`, type: "ERROR", - description: created.detail.hint, + description: resp.detail?.hint, }); return; } diff --git a/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/index.tsx @@ -102,7 +102,7 @@ export default function ListOtpDevices({ onCreate, onSelect }: Props): VNode { setNotif({ message: i18n.str`Could not delete the bank account`, type: "ERROR", - description: resp.detail.hint, + description: resp.detail?.hint, }); } }) diff --git a/packages/merchant-backoffice-ui/src/paths/instance/accounts/update/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/accounts/update/index.tsx @@ -84,12 +84,12 @@ export default function UpdateValidator({ onUpdate={async (request) => { return lib.instance .updateBankAccount(state.token, bid, request) - .then((updated) => { - if (updated.type === "fail") { + .then((resp) => { + if (resp.type === "fail") { setNotif({ message: i18n.str`Could not update account`, type: "ERROR", - description: updated.detail.hint, + description: resp.detail?.hint, }); return; } @@ -105,15 +105,15 @@ export default function UpdateValidator({ }} onReplace={async (prev, next) => { try { - const created = await lib.instance.addBankAccount( + const resp = await lib.instance.addBankAccount( state.token, next, ); - if (created.type === "fail") { + if (resp.type === "fail") { setNotif({ message: i18n.str`Could not create account`, type: "ERROR", - description: created.detail.hint, + description: resp.detail?.hint, }); return; } @@ -126,15 +126,15 @@ export default function UpdateValidator({ return; } try { - const deleted = await lib.instance.deleteBankAccount( + const resp = await lib.instance.deleteBankAccount( state.token, prev.h_wire, ); - if (deleted.type === "fail") { + if (resp.type === "fail") { setNotif({ message: i18n.str`Could not delete account`, type: "ERROR", - description: deleted.detail.hint, + description: resp.detail?.hint, }); return; } diff --git a/packages/merchant-backoffice-ui/src/paths/instance/categories/create/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/categories/create/index.tsx @@ -58,7 +58,7 @@ export default function CreateCategory({ onConfirm, onBack }: Props): VNode { setNotif({ message: i18n.str`Could not add category`, type: "ERROR", - description: resp.detail.hint, + description: resp.detail?.hint, }); } }) diff --git a/packages/merchant-backoffice-ui/src/paths/instance/categories/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/categories/list/index.tsx @@ -94,7 +94,7 @@ export default function ListCategories({ onCreate, onSelect }: Props): VNode { setNotif({ message: i18n.str`Could not delete the category`, type: "ERROR", - description: resp.detail.hint, + description: resp.detail?.hint, }); } }) diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/create/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/create/index.tsx @@ -99,17 +99,17 @@ export default function OrderCreate({ onConfirm, onBack }: Props): VNode { onCreate={(request: TalerMerchantApi.PostOrderRequest) => { lib.instance .createOrder(state.token, request) - .then((r) => { - if (r.type === "ok") { - return onConfirm(r.body.order_id); + .then((resp) => { + if (resp.type === "ok") { + return onConfirm(resp.body.order_id); } else { setNotif({ message: i18n.str`Could not create order`, type: "ERROR", description: - r.case === HttpStatusCode.Gone - ? i18n.str`No more stock for product with id "${r.body.product_id}".` - : r.detail.hint, + resp.case === HttpStatusCode.Gone + ? i18n.str`No more stock for product with id "${resp.body.product_id}".` + : resp.detail?.hint, }); } }) diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/details/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/details/index.tsx @@ -92,7 +92,7 @@ export default function Update({ oid, onBack }: Props): VNode { setNotif({ message: i18n.str`Could not create the refund`, type: "ERROR", - description: resp.detail.hint, + description: resp.detail?.hint, }); } }) diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/list/index.tsx @@ -167,7 +167,7 @@ export default function OrderList({ onCreate, onSelect }: Props): VNode { setNotif({ message: i18n.str`Could not create the refund`, type: "ERROR", - description: resp.detail.hint, + description: resp.detail?.hint, }); } }) diff --git a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/index.tsx @@ -65,7 +65,7 @@ export default function CreateValidator({ onConfirm, onBack }: Props): VNode { setNotif({ message: i18n.str`Could not add device`, type: "ERROR", - description: resp.detail.hint, + description: resp.detail?.hint, }); } }) diff --git a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/list/index.tsx @@ -94,7 +94,7 @@ export default function ListOtpDevices({ onCreate, onSelect }: Props): VNode { setNotif({ message: i18n.str`Could not delete the device`, type: "ERROR", - description: resp.detail.hint, + description: resp.detail?.hint, }); } }) diff --git a/packages/merchant-backoffice-ui/src/paths/instance/products/create/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/products/create/index.tsx @@ -57,7 +57,7 @@ export default function CreateProduct({ onConfirm, onBack }: Props): VNode { setNotif({ message: i18n.str`Could not create product`, type: "ERROR", - description: resp.detail.hint, + description: resp.detail?.hint, }); } }) diff --git a/packages/merchant-backoffice-ui/src/paths/instance/products/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/products/list/index.tsx @@ -108,7 +108,7 @@ export default function ProductList({ onCreate, onSelect }: Props): VNode { setNotif({ message: i18n.str`Could not update the product`, type: "ERROR", - description: resp.detail.hint, + description: resp.detail?.hint, }); } } catch (error) { @@ -148,7 +148,7 @@ export default function ProductList({ onCreate, onSelect }: Props): VNode { setNotif({ message: i18n.str`Could not delete the product`, type: "ERROR", - description: resp.detail.hint, + description: resp.detail?.hint, }); } } catch (error) { diff --git a/packages/merchant-backoffice-ui/src/paths/instance/products/update/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/products/update/index.tsx @@ -90,7 +90,7 @@ export default function UpdateProduct({ setNotif({ message: i18n.str`Could not update product`, type: "ERROR", - description: resp.detail.hint, + description: resp.detail?.hint, }); } diff --git a/packages/merchant-backoffice-ui/src/paths/instance/templates/create/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/templates/create/index.tsx @@ -57,7 +57,7 @@ export default function CreateTemplate({ onConfirm, onBack }: Props): VNode { setNotif({ message: i18n.str`Could not create template`, type: "ERROR", - description: resp.detail.hint, + description: resp.detail?.hint, }); } }) diff --git a/packages/merchant-backoffice-ui/src/paths/instance/templates/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/templates/list/index.tsx @@ -136,7 +136,7 @@ export default function ListTemplates({ setNotif({ message: i18n.str`Failed to delete template`, type: "ERROR", - description: resp.detail.hint, + description: resp.detail?.hint, }); } } catch (error) { diff --git a/packages/merchant-backoffice-ui/src/paths/instance/templates/update/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/templates/update/index.tsx @@ -95,7 +95,7 @@ export default function UpdateTemplate({ setNotif({ message: i18n.str`Could not update template`, type: "ERROR", - description: resp.detail.hint, + description: resp.detail?.hint, }); } }) diff --git a/packages/merchant-backoffice-ui/src/paths/instance/templates/use/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/templates/use/index.tsx @@ -83,17 +83,17 @@ export default function TemplateUsePage({ request: TalerMerchantApi.UsingTemplateDetails, ) => { return lib.instance.useTemplateCreateOrder(tid, request) - .then((res) => { - if (res.type === "ok") { - onOrderCreated(res.body.order_id) + .then((resp) => { + if (resp.type === "ok") { + onOrderCreated(resp.body.order_id) } else { setNotif({ message: i18n.str`Could not create order from template`, type: "ERROR", description: - res.case === HttpStatusCode.Gone - ? i18n.str`No more stock for product with id "${res.body.product_id}".` - : res.detail.hint, + resp.case === HttpStatusCode.Gone + ? i18n.str`No more stock for product with id "${resp.body.product_id}".` + : resp.detail?.hint, }); } }) diff --git a/packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx @@ -82,7 +82,7 @@ export default function Token({ onChange, onCancel }: Props): VNode { return setNotif({ message: i18n.str`Failed to clear token`, type: "ERROR", - description: resp.detail.hint, + description: resp.detail?.hint, }); } } catch (error) { @@ -108,7 +108,7 @@ export default function Token({ onChange, onCancel }: Props): VNode { return setNotif({ message: i18n.str`Failed to set new token`, type: "ERROR", - description: resp.detail.hint, + description: resp.detail?.hint, }); } } diff --git a/packages/merchant-backoffice-ui/src/paths/instance/tokenfamilies/create/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/tokenfamilies/create/index.tsx @@ -56,7 +56,7 @@ export default function CreateTokenFamily({ onConfirm, onBack }: Props): VNode { setNotif({ message: i18n.str`Could not create token family`, type: "ERROR", - description: resp.detail.hint, + description: resp.detail?.hint, }); } }) diff --git a/packages/merchant-backoffice-ui/src/paths/instance/tokenfamilies/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/tokenfamilies/list/index.tsx @@ -95,7 +95,7 @@ export default function TokenFamilyList({ onCreate, onSelect }: Props): VNode { setNotif({ message: i18n.str`Could not update the token family`, type: "ERROR", - description: resp.detail.hint, + description: resp.detail?.hint, }); } } catch (error) { @@ -133,7 +133,7 @@ export default function TokenFamilyList({ onCreate, onSelect }: Props): VNode { setNotif({ message: i18n.str`Failed to delete token family`, type: "ERROR", - description: resp.detail.hint, + description: resp.detail?.hint, }); } } catch (error) { diff --git a/packages/merchant-backoffice-ui/src/paths/instance/tokenfamilies/update/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/tokenfamilies/update/index.tsx @@ -105,7 +105,7 @@ export default function UpdateTokenFamily({ setNotif({ message: i18n.str`Could not update token family`, type: "ERROR", - description: resp.detail.hint, + description: resp.detail?.hint, }); } }) diff --git a/packages/merchant-backoffice-ui/src/paths/instance/transfers/create/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/transfers/create/index.tsx @@ -67,7 +67,7 @@ export default function CreateTransfer({ onConfirm, onBack }: Props): VNode { setNotif({ message: i18n.str`Could not inform transfer`, type: "ERROR", - description: resp.detail.hint, + description: resp.detail?.hint, }); } }) diff --git a/packages/merchant-backoffice-ui/src/paths/instance/transfers/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/transfers/list/index.tsx @@ -122,7 +122,7 @@ export default function ListTransfer({ onCreate }: Props): VNode { setNotif({ message: i18n.str`Failed to delete transfer`, type: "ERROR", - description: resp.detail.hint, + description: resp.detail?.hint, }); } } catch (error) { diff --git a/packages/merchant-backoffice-ui/src/paths/instance/webhooks/create/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/create/index.tsx @@ -57,7 +57,7 @@ export default function CreateWebhook({ onConfirm, onBack }: Props): VNode { setNotif({ message: i18n.str`Could not create the webhook`, type: "ERROR", - description: resp.detail.hint, + description: resp.detail?.hint, }); } }) diff --git a/packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/index.tsx @@ -92,7 +92,7 @@ export default function ListWebhooks({ onCreate, onSelect }: Props): VNode { setNotif({ message: i18n.str`Could not delete the webhook`, type: "ERROR", - description: resp.detail.hint, + description: resp.detail?.hint, }); } }) diff --git a/packages/merchant-backoffice-ui/src/paths/instance/webhooks/update/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/update/index.tsx @@ -93,7 +93,7 @@ export default function UpdateWebhook({ setNotif({ message: i18n.str`Could not update webhook`, type: "ERROR", - description: resp.detail.hint, + description: resp.detail?.hint, }); } diff --git a/packages/taler-harness/src/index.ts b/packages/taler-harness/src/index.ts @@ -728,7 +728,7 @@ deploymentCli const bc = await bank.getConfig(); if (bc.type === "fail") { - logger.error(`couldn't get bank config. ${bc.detail.hint}`); + logger.error(`couldn't get bank config. ${bc.detail?.hint}`); return; } if (!bank.isCompatible(bc.body.version)) { @@ -739,7 +739,7 @@ deploymentCli } const mc = await merchantManager.getConfig(); if (mc.type === "fail") { - logger.error(`couldn't get merchant config. ${mc.detail.hint}`); + logger.error(`couldn't get merchant config. ${mc.detail?.hint}`); return; } if (!merchantManager.isCompatible(mc.body.version)) { diff --git a/packages/taler-util/src/http-client/challenger.ts b/packages/taler-util/src/http-client/challenger.ts @@ -63,7 +63,7 @@ export enum ChallengerCacheEviction { export class ChallengerHttpClient { httpLib: HttpRequestLibrary; cacheEvictor: CacheEvictor<ChallengerCacheEviction>; - public readonly PROTOCOL_VERSION = "1:0:0"; + public readonly PROTOCOL_VERSION = "2:0:0"; constructor( readonly baseUrl: string, diff --git a/packages/taler-util/src/http-client/exchange.ts b/packages/taler-util/src/http-client/exchange.ts @@ -656,15 +656,17 @@ export class TalerExchangeHttpClient { switch (resp.status) { case HttpStatusCode.Ok: - return opSuccessFromHttp(resp, codecForAccountKycStatus()); + return opSuccessFromHttp( + resp, + codecForAccountKycStatus(), + ); case HttpStatusCode.Accepted: - return opKnownAlternativeFailure( + return opSuccessFromHttp( resp, - resp.status, codecForAccountKycStatus(), ); case HttpStatusCode.NoContent: - return opEmptySuccess(resp); + return opFixedSuccess(undefined); case HttpStatusCode.Forbidden: return opKnownHttpFailure(resp.status, resp); case HttpStatusCode.NotFound: @@ -779,7 +781,24 @@ export class TalerExchangeHttpClient { * https://docs.taler.net/core/api-exchange.html#get--kyc-proof-$PROVIDER_NAME?state=$H_PAYTO * */ - async completeExternalKycProcess(provider: string, state: string) {} + async completeExternalKycProcess(provider: string, state: string, code:string) { + const url = new URL(`kyc-proof/${provider}?state=${state}&code=${code}`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + redirect: "manual" + }); + + switch (resp.status) { + case HttpStatusCode.SeeOther: + return opEmptySuccess(resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + + } // // AML operations @@ -1009,7 +1028,7 @@ export class TalerExchangeHttpClient { } function buildKYCQuerySignature(key: SigningKey): string { - const sigBlob = buildSigPS(TalerSignaturePurpose.AML_QUERY).build(); + const sigBlob = buildSigPS(TalerSignaturePurpose.KYC_AUTH).build(); return encodeCrock(eddsaSign(sigBlob, key)); } diff --git a/packages/taler-util/src/http-client/officer-account.ts b/packages/taler-util/src/http-client/officer-account.ts @@ -17,11 +17,8 @@ import { EncryptionNonce, LockedAccount, - LockedReserve, OfficerAccount, OfficerId, - ReserveAccount, - ReserveId, SigningKey, createEddsaKeyPair, decodeCrock, @@ -31,7 +28,7 @@ import { encryptWithDerivedKey, getRandomBytesF, kdf, - stringToBytes, + stringToBytes } from "@gnu-taler/taler-util"; /** @@ -100,36 +97,6 @@ export async function createNewOfficerAccount( } /** - * Restore previous session and unlock account with password - * - * @param salt string from which crypto params will be derived - * @param key secured private key - * @param password password for the private key - * @returns - */ -export async function unlockWalletKycAccount( - account: LockedReserve, - password: string, -): Promise<ReserveAccount> { - const rawKey = decodeCrock(account); - const rawPassword = stringToBytes(password); - - const signingKey = (await decryptWithDerivedKey( - rawKey, - rawPassword, - password, - ).catch((e) => { - throw new UnwrapKeyError(e instanceof Error ? e.message : String(e)); - })) as SigningKey; - - const publicKey = eddsaGetPublic(signingKey); - - const accountId = encodeCrock(publicKey) as ReserveId; - - return { id: accountId, signingKey }; -} - -/** * Create new account (secured private key) * secured with the given password * diff --git a/packages/taler-util/src/http-common.ts b/packages/taler-util/src/http-common.ts @@ -502,8 +502,8 @@ export function encodeBody(body: unknown): ArrayBuffer { return body.buffer; } else if (body instanceof ArrayBuffer) { return body; - } else if (body instanceof URLSearchParams) { - return body as unknown as ArrayBuffer; + } else if (body instanceof URLSearchParams) { + return textEncoder.encode(body.toString()).buffer } else if (typeof body === "object" && body.constructor.name === "FormData") { return body as ArrayBuffer; } else if (typeof body === "object") { diff --git a/packages/taler-util/src/http-impl.node.ts b/packages/taler-util/src/http-impl.node.ts @@ -138,6 +138,10 @@ export class HttpLibImpl implements HttpRequestLibrary { reqBody = encodeBody(opt.body); } + if (opt?.body instanceof URLSearchParams) { + requestHeadersMap["Content-Type"] = "application/x-www-form-urlencoded" + } + let path = parsedUrl.pathname; if (parsedUrl.search != null) { path += parsedUrl.search; diff --git a/packages/taler-util/src/operation.ts b/packages/taler-util/src/operation.ts @@ -31,14 +31,14 @@ import { TalerErrorDetail, } from "./index.js"; -type OperationFailWithBodyOrNever<ErrorEnum, ErrorMap> = - ErrorEnum extends keyof ErrorMap ? OperationFailWithBody<ErrorMap> : never; +// type OperationFailWithBodyOrNever<ErrorEnum, ErrorMap> = +// ErrorEnum extends keyof ErrorMap ? OperationFailWithBody<ErrorMap> : never; export type OperationResult<Body, ErrorEnum, K = never> = | OperationOk<Body> | OperationAlternative<ErrorEnum, any> | OperationFail<ErrorEnum> - | OperationFailWithBodyOrNever<ErrorEnum, K>; +// | OperationFailWithBodyOrNever<ErrorEnum, K>; export function isOperationOk<T, E>( c: OperationResult<T, E>, @@ -75,7 +75,7 @@ export interface OperationFail<T> { */ case: T; - detail: TalerErrorDetail; + detail?: TalerErrorDetail; } /** @@ -88,12 +88,12 @@ export interface OperationAlternative<T, B> { body: B; } -export interface OperationFailWithBody<B> { - type: "fail"; +// export interface OperationFailWithBody<B> { +// type: "fail"; - case: keyof B; - body: B[OperationFailWithBody<B>["case"]]; -} +// case: keyof B; +// body: B[OperationFailWithBody<B>["case"]]; +// } export async function opSuccessFromHttp<T>( resp: HttpResponse, @@ -115,10 +115,15 @@ export function opEmptySuccess(resp: HttpResponse): OperationOk<void> { return { type: "ok" as const, body: void 0 }; } -export async function opKnownFailureWithBody<B>( - case_: keyof B, - body: B[typeof case_], -): Promise<OperationFailWithBody<B>> { +export async function opKnownFailure<T>( + case_: T): Promise<OperationFail<T>> { + return { type: "fail", case: case_ }; +} + +export async function opKnownFailureWithBody<T,B>( + case_: T, + body: B, +): Promise<OperationAlternative<T, B>> { return { type: "fail", case: case_, body }; } @@ -182,8 +187,8 @@ export function narrowOpSuccessOrThrow<Body, ErrorEnum>( } } -export async function succeedOrThrow<R, E>( - promise: Promise<OperationResult<R, E>>, +export async function succeedOrThrow<R>( + promise: Promise<OperationResult<R, unknown>>, ): Promise<R> { const resp = await promise; if (isOperationOk(resp)) { @@ -196,6 +201,30 @@ export async function succeedOrThrow<R, E>( throw TalerError.fromException(resp); } +export async function alternativeOrThrow<Error,Body, Alt>( + s: Error, + promise: Promise<OperationOk<Body> + | OperationAlternative<Error, Alt> + | OperationFail<Error>>, +): Promise<Alt> { + const resp = await promise; + if (isOperationOk(resp)) { + throw TalerError.fromException( + new Error(`request succeed but failure "${s}" was expected`), + ); + } + if (isOperationFail(resp) && resp.case !== s) { + throw TalerError.fromException( + new Error( + `request failed with "${JSON.stringify( + resp, + )}" but case "${s}" was expected`, + ), + ); + } + return (resp as any).body; +} + export async function failOrThrow<E>( s: E, promise: Promise<OperationResult<unknown, E>>, @@ -223,10 +252,10 @@ export type ResultByMethod< p extends keyof TT, > = TT[p] extends (...args: any[]) => infer Ret ? Ret extends Promise<infer Result> - ? Result extends OperationResult<any, any> - ? Result - : never - : never //api always use Promises + ? 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< diff --git a/packages/taler-util/src/types-taler-common.ts b/packages/taler-util/src/types-taler-common.ts @@ -40,7 +40,7 @@ import { codecForString, codecOptional, } from "./codec.js"; -import { codecForEither } from "./index.js"; +import { codecForEither, ReservePub } from "./index.js"; import { TalerProtocolDuration, TalerProtocolTimestamp, @@ -540,21 +540,8 @@ export interface OfficerAccount { signingKey: SigningKey; } - -declare const opaque_ReserveAccount: unique symbol; -/** - * Sealed private key for AML officer - */ -export type LockedReserve = string & { [opaque_ReserveAccount]: true }; - -declare const opaque_ReserveId: unique symbol; -/** - * Public key for AML officer - */ -export type ReserveId = string & { [opaque_ReserveId]: true }; - export interface ReserveAccount { - id: ReserveId; + id: ReservePub; signingKey: SigningKey; } diff --git a/packages/taler-wallet-core/src/pay-merchant.ts b/packages/taler-wallet-core/src/pay-merchant.ts @@ -891,8 +891,7 @@ async function processDownloadProposal( if (proposal.purchaseStatus != PurchaseStatus.PendingDownloadingProposal) { logger.error( - `unexpected state ${proposal.purchaseStatus}/${ - PurchaseStatus[proposal.purchaseStatus] + `unexpected state ${proposal.purchaseStatus}/${PurchaseStatus[proposal.purchaseStatus] } for ${ctx.transactionId} in processDownloadProposal`, ); return TaskRunResult.finished(); @@ -1152,8 +1151,7 @@ async function createOrReusePurchase( oldProposal.claimToken === claimToken ) { logger.info( - `Found old proposal (status=${ - PurchaseStatus[oldProposal.purchaseStatus] + `Found old proposal (status=${PurchaseStatus[oldProposal.purchaseStatus] }) for order ${orderId} at ${merchantBaseUrl}`, ); if (oldProposal.purchaseStatus === PurchaseStatus.DialogShared) { @@ -1896,7 +1894,11 @@ export async function checkPayForTemplate( const cfg = await merchantApi.getConfig(); if (cfg.type === "fail") { - throw TalerError.fromUncheckedDetail(cfg.detail); + if (cfg.detail) { + throw TalerError.fromUncheckedDetail(cfg.detail); + } else { + throw TalerError.fromException(new Error("failed to get merchant remote config")) + } } // FIXME: Put body.currencies *and* body.currency in the set of diff --git a/packages/taler-wallet-core/src/withdraw.ts b/packages/taler-wallet-core/src/withdraw.ts @@ -1149,7 +1149,11 @@ export async function getBankWithdrawalInfo( ); if (resp.type === "fail") { - throw TalerError.fromUncheckedDetail(resp.detail); + if (resp.detail) { + throw TalerError.fromUncheckedDetail(resp.detail); + } else { + throw TalerError.fromException(new Error("failed to get bank remote config")) + } } const { body: status } = resp; diff --git a/packages/taler-wallet-webextension/src/wallet/AddExchange/index.ts b/packages/taler-wallet-webextension/src/wallet/AddExchange/index.ts @@ -14,7 +14,7 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -import { OperationFailWithBody, OperationOk, TalerExchangeApi } from "@gnu-taler/taler-util"; +import { OperationAlternative, OperationFail, OperationOk, TalerExchangeApi } from "@gnu-taler/taler-util"; import { ErrorAlertView } from "../../components/CurrentAlerts.js"; import { Loading } from "../../components/Loading.js"; import { ErrorAlert } from "../../context/alert.js"; @@ -34,13 +34,6 @@ export type State = State.Loading | State.Confirm | State.Verify; -export type CheckExchangeErrors = { - "invalid-version": string; - "invalid-currency": string; - "not-found": void; - "already-active": void; - "invalid-protocol": void; -} export namespace State { export interface Loading { @@ -73,11 +66,16 @@ export namespace State { url: TextFieldHandler, loading: boolean; knownExchanges: URL[], - result: OperationOk<TalerExchangeApi.ExchangeKeysResponse> | OperationFailWithBody<CheckExchangeErrors> | undefined, + result: OperationOk<TalerExchangeApi.ExchangeKeysResponse> + | OperationAlternative<"invalid-version", string> + | OperationAlternative<"invalid-currency", string> + | OperationFail<"not-found"> + | OperationFail<"already-active"> + | OperationFail<"invalid-protocol"> + | undefined, expectedCurrency: string | undefined, } } - const viewMapping: StateViewMap<State> = { loading: Loading, error: ErrorAlertView, diff --git a/packages/taler-wallet-webextension/src/wallet/AddExchange/state.ts b/packages/taler-wallet-webextension/src/wallet/AddExchange/state.ts @@ -14,7 +14,7 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -import { ExchangeEntryStatus, TalerExchangeHttpClient, canonicalizeBaseUrl, opKnownFailureWithBody } from "@gnu-taler/taler-util"; +import { ExchangeEntryStatus, TalerExchangeHttpClient, canonicalizeBaseUrl, opKnownFailure, opKnownFailureWithBody } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { BrowserFetchHttpLib } from "@gnu-taler/web-util/browser"; import { useCallback, useEffect, useState } from "preact/hooks"; @@ -22,7 +22,7 @@ import { useBackendContext } from "../../context/backend.js"; import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js"; import { withSafe } from "../../mui/handlers.js"; import { RecursiveState } from "../../utils/index.js"; -import { CheckExchangeErrors, Props, State } from "./index.js"; +import { Props, State } from "./index.js"; function urlFromInput(str: string): URL { let result: URL; @@ -59,11 +59,11 @@ export function useComponentState({ onBack, currency, noDebounce }: Props): Recu const checkExchangeBaseUrl_memo = useCallback(async function checkExchangeBaseUrl(str: string) { const baseUrl = urlFromInput(str) if (baseUrl.protocol !== "http:" && baseUrl.protocol !== "https:") { - return opKnownFailureWithBody<CheckExchangeErrors>("invalid-protocol", undefined) + return opKnownFailure("invalid-protocol"as const) } const found = used.findIndex((e) => e.exchangeBaseUrl === baseUrl.href); if (found !== -1) { - return opKnownFailureWithBody<CheckExchangeErrors>("already-active", undefined); + return opKnownFailure("already-active"as const); } /** @@ -84,13 +84,13 @@ export function useComponentState({ onBack, currency, noDebounce }: Props): Recu const api = new TalerExchangeHttpClient(baseUrl.href, new BrowserFetchHttpLib() as any); const config = await api.getConfig() if (config.type === "fail") { - return opKnownFailureWithBody<CheckExchangeErrors>("not-found", undefined) + return opKnownFailure("not-found" as const) } if (!api.isCompatible(config.body.version)) { - return opKnownFailureWithBody<CheckExchangeErrors>("invalid-version", config.body.version) + return opKnownFailureWithBody("invalid-version"as const, config.body.version) } if (currency !== undefined && currency !== config.body.currency) { - return opKnownFailureWithBody<CheckExchangeErrors>("invalid-currency", config.body.currency) + return opKnownFailureWithBody("invalid-currency"as const, config.body.currency) } const keys = await api.getKeys() return keys diff --git a/packages/taler-wallet-webextension/src/wallet/AddExchange/views.tsx b/packages/taler-wallet-webextension/src/wallet/AddExchange/views.tsx @@ -120,8 +120,9 @@ export function VerifyView({ </WarningBox> ); } + default: { - assertUnreachable(result.case); + assertUnreachable(result); } } })()} diff --git a/packages/taler-wallet-webextension/src/wallet/History.tsx b/packages/taler-wallet-webextension/src/wallet/History.tsx @@ -71,8 +71,6 @@ export function HistoryPage({ const state = useAsyncAsHook(async () => { const b = await api.wallet.call(WalletApiOperation.GetBalances, {}); const balances = b.balances; - // const balance = - // b.balances.length > 0 ? b.balances[balanceIndex] : undefined; const tx = await api.wallet.call(WalletApiOperation.GetTransactions, { scopeInfo: showSearch ? undefined : selectedScope, sort: "descending", diff --git a/packages/web-util/src/context/bank-api.ts b/packages/web-util/src/context/bank-api.ts @@ -192,7 +192,11 @@ function buildBankApiClient( async function getRemoteConfig(): Promise<TalerCorebankConfigResponse> { const resp = await bank.getConfig(); if (resp.type === "fail") { - throw TalerError.fromUncheckedDetail(resp.detail); + if (resp.detail) { + throw TalerError.fromUncheckedDetail(resp.detail); + } else { + throw TalerError.fromException(new Error("failed to get bank remote config")) + } } return resp.body; } diff --git a/packages/web-util/src/context/challenger-api.ts b/packages/web-util/src/context/challenger-api.ts @@ -183,7 +183,11 @@ function buildChallengerApiClient( async function getRemoteConfig(): Promise<ChallengerApi.ChallengerTermsOfServiceResponse> { const resp = await challenger.getConfig(); if (resp.type === "fail") { - throw TalerError.fromUncheckedDetail(resp.detail); + if (resp.detail) { + throw TalerError.fromUncheckedDetail(resp.detail); + } else { + throw TalerError.fromException(new Error("failed to get challenger remote config")) + } } return resp.body; } diff --git a/packages/web-util/src/context/exchange-api.ts b/packages/web-util/src/context/exchange-api.ts @@ -187,7 +187,11 @@ function buildExchangeApiClient( async function getRemoteConfig(): Promise<TalerExchangeApi.ExchangeVersionResponse> { const resp = await ex.getConfig(); if (resp.type === "fail") { - throw TalerError.fromUncheckedDetail(resp.detail); + if (resp.detail) { + throw TalerError.fromUncheckedDetail(resp.detail); + } else { + throw TalerError.fromException(new Error("failed to get exchange remote config")) + } } return resp.body; } diff --git a/packages/web-util/src/context/merchant-api.ts b/packages/web-util/src/context/merchant-api.ts @@ -198,7 +198,11 @@ function buildMerchantApiClient( async function getRemoteConfig(): Promise<TalerMerchantApi.TalerMerchantConfigResponse> { const resp = await instance.getConfig(); if (resp.type === "fail") { - throw TalerError.fromUncheckedDetail(resp.detail); + if (resp.detail) { + throw TalerError.fromUncheckedDetail(resp.detail); + } else { + throw TalerError.fromException(new Error("failed to get merchant remote config")) + } } return resp.body; } diff --git a/packages/web-util/src/hooks/useNotifications.ts b/packages/web-util/src/hooks/useNotifications.ts @@ -155,7 +155,7 @@ function errorMap<T extends OperationFail<unknown>>( notify({ type: "error", title: map(resp.case), - description: resp.detail.hint as TranslatedString, + description: (resp.detail?.hint as TranslatedString) ?? "", debug: resp.detail, when: AbsoluteTime.now(), });