aboutsummaryrefslogtreecommitdiff
path: root/packages
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2023-11-03 18:59:27 -0300
committerSebastian <sebasjm@gmail.com>2023-11-03 18:59:27 -0300
commit08898c7aa32b5a4dbc40c2fecd82a5a652126705 (patch)
tree9a82a960784e025caf0f2eb7f32e9b8292d46403 /packages
parent368a87a361e845dd748036f10a66b7f202f84df8 (diff)
downloadwallet-core-08898c7aa32b5a4dbc40c2fecd82a5a652126705.tar.xz
update to the new bank api breaking changes
Diffstat (limited to 'packages')
-rw-r--r--packages/taler-util/src/http-client/bank-core.ts207
-rw-r--r--packages/taler-util/src/http-client/types.ts86
-rw-r--r--packages/taler-util/src/operation.ts23
-rw-r--r--packages/taler-util/src/wallet-types.ts2
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");