summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2024-02-15 16:59:56 -0300
committerSebastian <sebasjm@gmail.com>2024-02-15 16:59:56 -0300
commitfd45d189259cef0a3a51683bb12412cd8c6fb9eb (patch)
tree64091fbe1034a66a0caa6f4a1ef68ccbd3daab05
parent8124d2400e7787020cca549ccc9d021eb5f75a09 (diff)
downloadwallet-core-fd45d189259cef0a3a51683bb12412cd8c6fb9eb.tar.gz
wallet-core-fd45d189259cef0a3a51683bb12412cd8c6fb9eb.tar.bz2
wallet-core-fd45d189259cef0a3a51683bb12412cd8c6fb9eb.zip
add exchange key in the http lib and default toString for taler error
-rw-r--r--packages/taler-util/src/errors.ts17
-rw-r--r--packages/taler-util/src/http-client/exchange.ts20
-rw-r--r--packages/taler-util/src/http-client/types.ts424
-rw-r--r--packages/taler-util/src/http-impl.node.ts7
-rw-r--r--packages/taler-util/src/logging.ts8
-rw-r--r--packages/taler-util/src/operation.ts26
-rw-r--r--packages/taler-util/src/transactions-types.ts5
7 files changed, 488 insertions, 19 deletions
diff --git a/packages/taler-util/src/errors.ts b/packages/taler-util/src/errors.ts
index 69990d41f..3370825f4 100644
--- a/packages/taler-util/src/errors.ts
+++ b/packages/taler-util/src/errors.ts
@@ -222,9 +222,11 @@ export type TalerHttpError =
export class TalerError<T = any> extends Error {
errorDetail: TalerErrorDetail & T;
- private constructor(d: TalerErrorDetail & T) {
+ cause: Error | undefined;
+ private constructor(d: TalerErrorDetail & T, cause?: Error) {
super(d.hint ?? `Error (code ${d.code})`);
this.errorDetail = d;
+ this.cause = cause;
Object.setPrototypeOf(this, TalerError.prototype);
}
@@ -232,21 +234,22 @@ export class TalerError<T = any> extends Error {
code: C,
detail: ErrBody<C>,
hint?: string,
+ cause?: Error,
): TalerError {
if (!hint) {
hint = getDefaultHint(code);
}
const when = AbsoluteTime.now();
- return new TalerError<unknown>({ code, when, hint, ...detail });
+ return new TalerError<unknown>({ code, when, hint, ...detail }, cause);
}
- static fromUncheckedDetail(d: TalerErrorDetail): TalerError {
- return new TalerError<unknown>({ ...d });
+ static fromUncheckedDetail(d: TalerErrorDetail, c?: Error): TalerError {
+ return new TalerError<unknown>({ ...d }, c);
}
static fromException(e: any): TalerError {
const errDetail = getErrorDetailFromException(e);
- return new TalerError(errDetail);
+ return new TalerError(errDetail, e);
}
hasErrorCode<C extends keyof DetailsMap>(
@@ -254,6 +257,10 @@ export class TalerError<T = any> extends Error {
): this is TalerError<DetailsMap[C]> {
return this.errorDetail.code === code;
}
+
+ toString(): string {
+ return `TalerError: ${JSON.stringify(this.errorDetail)}`;
+ }
}
/**
diff --git a/packages/taler-util/src/http-client/exchange.ts b/packages/taler-util/src/http-client/exchange.ts
index 726c28204..003410ddb 100644
--- a/packages/taler-util/src/http-client/exchange.ts
+++ b/packages/taler-util/src/http-client/exchange.ts
@@ -31,6 +31,7 @@ import {
codecForAmlDecisionDetails,
codecForAmlRecords,
codecForExchangeConfig,
+ codecForExchangeKeys,
} from "./types.js";
import { addPaginationParams } from "./utils.js";
@@ -59,7 +60,7 @@ export class TalerExchangeHttpClient {
return compare?.compatible ?? false;
}
/**
- * https://docs.taler.net/core/api-merchant.html#get--config
+ * https://docs.taler.net/core/api-exchange.html#get--config
*
*/
async getConfig() {
@@ -74,6 +75,23 @@ export class TalerExchangeHttpClient {
return opUnknownFailure(resp, await resp.text());
}
}
+ /**
+ * https://docs.taler.net/core/api-merchant.html#get--config
+ *
+ * PARTIALLY IMPLEMENTED!!
+ */
+ async getKeys() {
+ const url = new URL(`keys`, this.baseUrl);
+ const resp = await this.httpLib.fetch(url.href, {
+ method: "GET",
+ });
+ switch (resp.status) {
+ case HttpStatusCode.Ok:
+ return opSuccess(resp, codecForExchangeKeys());
+ default:
+ return opUnknownFailure(resp, await resp.text());
+ }
+ }
// TERMS
diff --git a/packages/taler-util/src/http-client/types.ts b/packages/taler-util/src/http-client/types.ts
index 6c8bf4efd..05fce4a49 100644
--- a/packages/taler-util/src/http-client/types.ts
+++ b/packages/taler-util/src/http-client/types.ts
@@ -243,6 +243,7 @@ export interface CurrencySpecification {
alt_unit_names: { [log10: string]: string };
}
+//FIXME: implement this codec
export const codecForAccessToken = codecForString as () => Codec<AccessToken>;
export const codecForTokenSuccessResponse =
(): Codec<TalerAuthentication.TokenSuccessResponse> =>
@@ -294,6 +295,9 @@ export const codecForCoreBankConfig = (): Codec<TalerCorebankApi.Config> =>
.property("wire_type", codecForString())
.build("TalerCorebankApi.Config");
+//FIXME: implement this codec
+export const codecForURN = codecForString;
+
export const codecForMerchantConfig =
(): Codec<TalerMerchantApi.VersionResponse> =>
buildCodecForObject<TalerMerchantApi.VersionResponse>()
@@ -308,11 +312,20 @@ export const codecForExchangeConfig =
buildCodecForObject<TalerExchangeApi.ExchangeVersionResponse>()
.property("version", codecForString())
.property("name", codecForConstString("taler-exchange"))
+ .property("implementation", codecOptional(codecForURN()))
.property("currency", codecForString())
.property("currency_specification", codecForCurrencySpecificiation())
.property("supported_kyc_requirements", codecForList(codecForString()))
.build("TalerExchangeApi.ExchangeVersionResponse");
+export const codecForExchangeKeys =
+ (): Codec<TalerExchangeApi.ExchangeKeysResponse> =>
+ buildCodecForObject<TalerExchangeApi.ExchangeKeysResponse>()
+ .property("version", codecForString())
+ .property("base_url", codecForString())
+ .property("currency", codecForString())
+ .build("TalerExchangeApi.ExchangeKeysResponse");
+
const codecForBalance = (): Codec<TalerCorebankApi.Balance> =>
buildCodecForObject<TalerCorebankApi.Balance>()
.property("amount", codecForAmountString())
@@ -867,6 +880,8 @@ type Base32 = string;
type DecimalNumber = string;
type RsaSignature = string;
+type Float = number;
+type LibtoolVersion = string;
// The type of a coin's blinded envelope depends on the cipher that is used
// for signing with a denomination key.
type CoinEnvelope = RSACoinEnvelope | CSCoinEnvelope;
@@ -891,9 +906,13 @@ interface CSCoinEnvelope {
// a 256-bit nonce, converted to Crockford Base32.
type DenominationBlindingKeyP = string;
+//FIXME: implement this codec
const codecForURL = codecForString;
+//FIXME: implement this codec
const codecForLibtoolVersion = codecForString;
+//FIXME: implement this codec
const codecForCurrencyName = codecForString;
+//FIXME: implement this codec
const codecForDecimalNumber = codecForString;
export type WithdrawalOperationStatus =
@@ -1892,7 +1911,12 @@ export namespace TalerExchangeApi {
// Name of the protocol.
name: "taler-exchange";
- // Currency supported by this exchange.
+ // URN of the implementation (needed to interpret 'revision' in version).
+ // @since v18, may become mandatory in the future.
+ implementation?: string;
+
+ // Currency supported by this exchange, given
+ // as a currency code ("USD" or "EUR").
currency: string;
// How wallets should render this currency.
@@ -1959,6 +1983,404 @@ export namespace TalerExchangeApi {
// with purpose TALER_SIGNATURE_MASTER_WIRE_DETAILS.
master_sig: EddsaSignature;
}
+
+ export interface ExchangeKeysResponse {
+ // libtool-style representation of the Exchange protocol version, see
+ // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning
+ // The format is "current:revision:age".
+ version: string;
+
+ // The exchange's base URL.
+ base_url: string;
+
+ // The exchange's currency or asset unit.
+ currency: string;
+
+ /**
+ * FIXME: PARTIALLY IMPLEMENTED!!
+ */
+
+ // How wallets should render this currency.
+ // currency_specification: CurrencySpecification;
+
+ // // Absolute cost offset for the STEFAN curve used
+ // // to (over) approximate fees payable by amount.
+ // stefan_abs: AmountString;
+
+ // // Factor to multiply the logarithm of the amount
+ // // with to (over) approximate fees payable by amount.
+ // // Note that the total to be paid is first to be
+ // // divided by the smallest denomination to obtain
+ // // the value that the logarithm is to be taken of.
+ // stefan_log: AmountString;
+
+ // // Linear cost factor for the STEFAN curve used
+ // // to (over) approximate fees payable by amount.
+ // //
+ // // Note that this is a scalar, as it is multiplied
+ // // with the actual amount.
+ // stefan_lin: Float;
+
+ // // Type of the asset. "fiat", "crypto", "regional"
+ // // or "stock". Wallets should adjust their UI/UX
+ // // based on this value.
+ // asset_type: string;
+
+ // // Array of wire accounts operated by the exchange for
+ // // incoming wire transfers.
+ // accounts: WireAccount[];
+
+ // // Object mapping names of wire methods (i.e. "iban" or "x-taler-bank")
+ // // to wire fees.
+ // wire_fees: { method: AggregateTransferFee[] };
+
+ // // List of exchanges that this exchange is partnering
+ // // with to enable wallet-to-wallet transfers.
+ // wads: ExchangePartner[];
+
+ // // Set to true if this exchange allows the use
+ // // of reserves for rewards.
+ // // @deprecated in protocol v18.
+ // rewards_allowed: false;
+
+ // // EdDSA master public key of the exchange, used to sign entries
+ // // in denoms and signkeys.
+ // master_public_key: EddsaPublicKey;
+
+ // // Relative duration until inactive reserves are closed;
+ // // not signed (!), can change without notice.
+ // reserve_closing_delay: RelativeTime;
+
+ // // Threshold amounts beyond which wallet should
+ // // trigger the KYC process of the issuing
+ // // exchange. Optional option, if not given there is no limit.
+ // // Currency must match currency.
+ // wallet_balance_limit_without_kyc?: AmountString[];
+
+ // // Denominations offered by this exchange
+ // denominations: DenomGroup[];
+
+ // // Compact EdDSA signature (binary-only) over the
+ // // contatentation of all of the master_sigs (in reverse
+ // // chronological order by group) in the arrays under
+ // // "denominations". Signature of TALER_ExchangeKeySetPS
+ // exchange_sig: EddsaSignature;
+
+ // // Public EdDSA key of the exchange that was used to generate the signature.
+ // // Should match one of the exchange's signing keys from signkeys. It is given
+ // // explicitly as the client might otherwise be confused by clock skew as to
+ // // which signing key was used for the exchange_sig.
+ // exchange_pub: EddsaPublicKey;
+
+ // // Denominations for which the exchange currently offers/requests recoup.
+ // recoup: Recoup[];
+
+ // // Array of globally applicable fees by time range.
+ // global_fees: GlobalFees[];
+
+ // // The date when the denomination keys were last updated.
+ // list_issue_date: Timestamp;
+
+ // // Auditors of the exchange.
+ // auditors: AuditorKeys[];
+
+ // // The exchange's signing keys.
+ // signkeys: SignKey[];
+
+ // // Optional field with a dictionary of (name, object) pairs defining the
+ // // supported and enabled extensions, such as age_restriction.
+ // extensions?: { name: ExtensionManifest };
+
+ // // Signature by the exchange master key of the SHA-256 hash of the
+ // // normalized JSON-object of field extensions, if it was set.
+ // // The signature has purpose TALER_SIGNATURE_MASTER_EXTENSIONS.
+ // extensions_sig?: EddsaSignature;
+ }
+
+ interface ExtensionManifest {
+ // The criticality of the extension MUST be provided. It has the same
+ // semantics as "critical" has for extensions in X.509:
+ // - if "true", the client must "understand" the extension before
+ // proceeding,
+ // - if "false", clients can safely skip extensions they do not
+ // understand.
+ // (see https://datatracker.ietf.org/doc/html/rfc5280#section-4.2)
+ critical: boolean;
+
+ // The version information MUST be provided in Taler's protocol version
+ // ranges notation, see
+ // https://docs.taler.net/core/api-common.html#protocol-version-ranges
+ version: LibtoolVersion;
+
+ // Optional configuration object, defined by the feature itself
+ config?: object;
+ }
+
+ interface SignKey {
+ // The actual exchange's EdDSA signing public key.
+ key: EddsaPublicKey;
+
+ // Initial validity date for the signing key.
+ stamp_start: Timestamp;
+
+ // Date when the exchange will stop using the signing key, allowed to overlap
+ // slightly with the next signing key's validity to allow for clock skew.
+ stamp_expire: Timestamp;
+
+ // Date when all signatures made by the signing key expire and should
+ // henceforth no longer be considered valid in legal disputes.
+ stamp_end: Timestamp;
+
+ // Signature over key and stamp_expire by the exchange master key.
+ // Signature of TALER_ExchangeSigningKeyValidityPS.
+ // Must have purpose TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY.
+ master_sig: EddsaSignature;
+ }
+
+ interface AuditorKeys {
+ // The auditor's EdDSA signing public key.
+ auditor_pub: EddsaPublicKey;
+
+ // The auditor's URL.
+ auditor_url: string;
+
+ // The auditor's name (for humans).
+ auditor_name: string;
+
+ // An array of denomination keys the auditor affirms with its signature.
+ // Note that the message only includes the hash of the public key, while the
+ // signature is actually over the expanded information including expiration
+ // times and fees. The exact format is described below.
+ denomination_keys: AuditorDenominationKey[];
+ }
+ interface AuditorDenominationKey {
+ // Hash of the public RSA key used to sign coins of the respective
+ // denomination. Note that the auditor's signature covers more than just
+ // the hash, but this other information is already provided in denoms and
+ // thus not repeated here.
+ denom_pub_h: HashCode;
+
+ // Signature of TALER_ExchangeKeyValidityPS.
+ auditor_sig: EddsaSignature;
+ }
+
+ interface GlobalFees {
+ // What date (inclusive) does these fees go into effect?
+ start_date: Timestamp;
+
+ // What date (exclusive) does this fees stop going into effect?
+ end_date: Timestamp;
+
+ // Account history fee, charged when a user wants to
+ // obtain a reserve/account history.
+ history_fee: AmountString;
+
+ // Annual fee charged for having an open account at the
+ // exchange. Charged to the account. If the account
+ // balance is insufficient to cover this fee, the account
+ // is automatically deleted/closed. (Note that the exchange
+ // will keep the account history around for longer for
+ // regulatory reasons.)
+ account_fee: AmountString;
+
+ // Purse fee, charged only if a purse is abandoned
+ // and was not covered by the account limit.
+ purse_fee: AmountString;
+
+ // How long will the exchange preserve the account history?
+ // After an account was deleted/closed, the exchange will
+ // retain the account history for legal reasons until this time.
+ history_expiration: RelativeTime;
+
+ // Non-negative number of concurrent purses that any
+ // account holder is allowed to create without having
+ // to pay the purse_fee.
+ purse_account_limit: Integer;
+
+ // How long does an exchange keep a purse around after a purse
+ // has expired (or been successfully merged)? A 'GET' request
+ // for a purse will succeed until the purse expiration time
+ // plus this value.
+ purse_timeout: RelativeTime;
+
+ // Signature of TALER_GlobalFeesPS.
+ master_sig: EddsaSignature;
+ }
+
+ interface Recoup {
+ // Hash of the public key of the denomination that is being revoked under
+ // emergency protocol (see /recoup).
+ h_denom_pub: HashCode;
+
+ // We do not include any signature here, as the primary use-case for
+ // this emergency involves the exchange having lost its signing keys,
+ // so such a signature here would be pretty worthless. However, the
+ // exchange will not honor /recoup requests unless they are for
+ // denomination keys listed here.
+ }
+
+ interface AggregateTransferFee {
+ // Per transfer wire transfer fee.
+ wire_fee: AmountString;
+
+ // Per transfer closing fee.
+ closing_fee: AmountString;
+
+ // What date (inclusive) does this fee go into effect?
+ // The different fees must cover the full time period in which
+ // any of the denomination keys are valid without overlap.
+ start_date: Timestamp;
+
+ // What date (exclusive) does this fee stop going into effect?
+ // The different fees must cover the full time period in which
+ // any of the denomination keys are valid without overlap.
+ end_date: Timestamp;
+
+ // Signature of TALER_MasterWireFeePS with
+ // purpose TALER_SIGNATURE_MASTER_WIRE_FEES.
+ sig: EddsaSignature;
+ }
+
+ interface ExchangePartner {
+ // Base URL of the partner exchange.
+ partner_base_url: string;
+
+ // Public master key of the partner exchange.
+ partner_master_pub: EddsaPublicKey;
+
+ // Per exchange-to-exchange transfer (wad) fee.
+ wad_fee: AmountString;
+
+ // Exchange-to-exchange wad (wire) transfer frequency.
+ wad_frequency: RelativeTime;
+
+ // When did this partnership begin (under these conditions)?
+ start_date: Timestamp;
+
+ // How long is this partnership expected to last?
+ end_date: Timestamp;
+
+ // Signature using the exchange's offline key over
+ // TALER_WadPartnerSignaturePS
+ // with purpose TALER_SIGNATURE_MASTER_PARTNER_DETAILS.
+ master_sig: EddsaSignature;
+ }
+
+ type DenomGroup =
+ | DenomGroupRsa
+ | DenomGroupCs
+ | DenomGroupRsaAgeRestricted
+ | DenomGroupCsAgeRestricted;
+ interface DenomGroupRsa extends DenomGroupCommon {
+ cipher: "RSA";
+
+ denoms: ({
+ rsa_pub: RsaPublicKey;
+ } & DenomCommon)[];
+ }
+ interface DenomGroupCs extends DenomGroupCommon {
+ cipher: "CS";
+
+ denoms: ({
+ cs_pub: Cs25519Point;
+ } & DenomCommon)[];
+ }
+
+ // Binary representation of the age groups.
+ // The bits set in the mask mark the edges at the beginning of a next age
+ // group. F.e. for the age groups
+ // 0-7, 8-9, 10-11, 12-13, 14-15, 16-17, 18-21, 21-*
+ // the following bits are set:
+ //
+ // 31 24 16 8 0
+ // | | | | |
+ // oooooooo oo1oo1o1 o1o1o1o1 ooooooo1
+ //
+ // A value of 0 means that the exchange does not support the extension for
+ // age-restriction.
+ type AgeMask = Integer;
+
+ interface DenomGroupRsaAgeRestricted extends DenomGroupCommon {
+ cipher: "RSA+age_restricted";
+ age_mask: AgeMask;
+
+ denoms: ({
+ rsa_pub: RsaPublicKey;
+ } & DenomCommon)[];
+ }
+ interface DenomGroupCsAgeRestricted extends DenomGroupCommon {
+ cipher: "CS+age_restricted";
+ age_mask: AgeMask;
+
+ denoms: ({
+ cs_pub: Cs25519Point;
+ } & DenomCommon)[];
+ }
+ // Common attributes for all denomination groups
+ interface DenomGroupCommon {
+ // How much are coins of this denomination worth?
+ value: AmountString;
+
+ // Fee charged by the exchange for withdrawing a coin of this denomination.
+ fee_withdraw: AmountString;
+
+ // Fee charged by the exchange for depositing a coin of this denomination.
+ fee_deposit: AmountString;
+
+ // Fee charged by the exchange for refreshing a coin of this denomination.
+ fee_refresh: AmountString;
+
+ // Fee charged by the exchange for refunding a coin of this denomination.
+ fee_refund: AmountString;
+ }
+ interface DenomCommon {
+ // Signature of TALER_DenominationKeyValidityPS.
+ master_sig: EddsaSignature;
+
+ // When does the denomination key become valid?
+ stamp_start: Timestamp;
+
+ // When is it no longer possible to withdraw coins
+ // of this denomination?
+ stamp_expire_withdraw: Timestamp;
+
+ // When is it no longer possible to deposit coins
+ // of this denomination?
+ stamp_expire_deposit: Timestamp;
+
+ // Timestamp indicating by when legal disputes relating to these coins must
+ // be settled, as the exchange will afterwards destroy its evidence relating to
+ // transactions involving this coin.
+ stamp_expire_legal: Timestamp;
+
+ // Set to 'true' if the exchange somehow "lost"
+ // the private key. The denomination was not
+ // necessarily revoked, but still cannot be used
+ // to withdraw coins at this time (theoretically,
+ // the private key could be recovered in the
+ // future; coins signed with the private key
+ // remain valid).
+ lost?: boolean;
+ }
+ type DenominationKey = RsaDenominationKey | CSDenominationKey;
+ interface RsaDenominationKey {
+ cipher: "RSA";
+
+ // 32-bit age mask.
+ age_mask: Integer;
+
+ // RSA public key
+ rsa_public_key: RsaPublicKey;
+ }
+ interface CSDenominationKey {
+ cipher: "CS";
+
+ // 32-bit age mask.
+ age_mask: Integer;
+
+ // Public key of the denomination.
+ cs_public_key: Cs25519Point;
+ }
}
export namespace TalerMerchantApi {
diff --git a/packages/taler-util/src/http-impl.node.ts b/packages/taler-util/src/http-impl.node.ts
index 8ca2deecd..dec4e3f31 100644
--- a/packages/taler-util/src/http-impl.node.ts
+++ b/packages/taler-util/src/http-impl.node.ts
@@ -21,7 +21,12 @@
*/
import * as net from "node:net";
import type { ClientRequest, IncomingMessage } from "node:http";
-import { FollowOptions, RedirectableRequest, http, https } from "follow-redirects";
+import {
+ FollowOptions,
+ RedirectableRequest,
+ http,
+ https,
+} from "follow-redirects";
import { RequestOptions } from "node:http";
import { TalerError } from "./errors.js";
import { encodeBody, getDefaultHeaders, HttpLibArgs } from "./http-common.js";
diff --git a/packages/taler-util/src/logging.ts b/packages/taler-util/src/logging.ts
index 663bc59c8..17bb184f7 100644
--- a/packages/taler-util/src/logging.ts
+++ b/packages/taler-util/src/logging.ts
@@ -37,7 +37,6 @@ const byTagLogLevel: Record<string, LogLevel> = {};
let nativeLogging: boolean = false;
-
// from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/toString
Error.prototype.toString = function () {
if (
@@ -51,14 +50,13 @@ Error.prototype.toString = function () {
let msg = this.message;
msg = msg === undefined ? "" : `${msg}`;
- let cause = ""
+ let cause = "";
if ("cause" in this) {
- cause = `\n Caused by: ${this.cause}`
+ cause = `\n Caused by: ${this.cause}`;
}
return `${name}: ${msg}${cause}`;
};
-
export function getGlobalLogLevel(): string {
return globalLogLevel;
}
@@ -148,7 +146,7 @@ function writeNodeLog(
* and uses the corresponding console.* method to log in the browser.
*/
export class Logger {
- constructor(private tag: string) { }
+ constructor(private tag: string) {}
shouldLogTrace(): boolean {
const level = byTagLogLevel[this.tag] ?? globalLogLevel;
diff --git a/packages/taler-util/src/operation.ts b/packages/taler-util/src/operation.ts
index a554e1f31..02cf70196 100644
--- a/packages/taler-util/src/operation.ts
+++ b/packages/taler-util/src/operation.ts
@@ -30,10 +30,14 @@ import {
TalerErrorDetail,
} from "./index.js";
-export type OperationResult<Body, ErrorEnum> =
+type OperationFailWithBodyOrNever<ErrorEnum, ErrorMap> =
+ ErrorEnum extends keyof ErrorMap ? OperationFailWithBody<ErrorMap> : never;
+
+export type OperationResult<Body, ErrorEnum, K = never> =
| OperationOk<Body>
- | OperationAlternative<ErrorEnum, Body>
- | OperationFail<ErrorEnum>;
+ | OperationAlternative<ErrorEnum, any>
+ | OperationFail<ErrorEnum>
+ | OperationFailWithBodyOrNever<ErrorEnum, K>;
export function isOperationOk<T, E>(
c: OperationResult<T, E>,
@@ -89,6 +93,15 @@ export interface OperationAlternative<T, B> {
body: B;
}
+export interface OperationFailWithBody<B> {
+ type: "fail";
+
+ httpResp: HttpResponse;
+
+ case: keyof B;
+ body: B[OperationFailWithBody<B>["case"]];
+}
+
export async function opSuccess<T>(
resp: HttpResponse,
codec: Codec<T>,
@@ -109,6 +122,13 @@ export function opEmptySuccess(resp: HttpResponse): OperationOk<void> {
return { type: "ok" as const, body: void 0, httpResp: resp };
}
+export async function opKnownFailureWithBody<B>(
+ case_: keyof B,
+ body: B[typeof case_],
+): Promise<OperationFailWithBody<B>> {
+ return { type: "fail", case: case_, body, httpResp: {} as any };
+}
+
export async function opKnownAlternativeFailure<T extends HttpStatusCode, B>(
resp: HttpResponse,
s: T,
diff --git a/packages/taler-util/src/transactions-types.ts b/packages/taler-util/src/transactions-types.ts
index 3460d2d87..4754603e6 100644
--- a/packages/taler-util/src/transactions-types.ts
+++ b/packages/taler-util/src/transactions-types.ts
@@ -59,9 +59,9 @@ import {
export interface TransactionsRequest {
/**
* return only transactions in the given currency
- *
+ *
* it will be removed in next release
- *
+ *
* @deprecated use scopeInfo
*/
currency?: string;
@@ -88,7 +88,6 @@ export interface TransactionsRequest {
*/
includeRefreshes?: boolean;
-
filterByState?: TransactionStateFilter;
}