/*
This file is part of GNU Taler
(C) 2022-2024 Taler Systems S.A.
GNU Taler is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
GNU Taler; see the file COPYING. If not, see
*/
import {
HttpStatusCode,
LibtoolVersion,
LongPollParams,
TalerErrorCode,
codecForChallenge,
codecForTalerErrorDetail,
codecForTanTransmission,
opKnownAlternativeFailure,
opKnownHttpFailure,
opKnownTalerFailure,
} from "@gnu-taler/taler-util";
import {
HttpRequestLibrary,
createPlatformHttpLib,
} from "@gnu-taler/taler-util/http";
import {
FailCasesByMethod,
ResultByMethod,
opEmptySuccess,
opFixedSuccess,
opSuccessFromHttp,
opUnknownFailure,
} from "../operation.js";
import { TalerAuthenticationHttpClient } from "./authentication.js";
import { TalerBankConversionHttpClient } from "./bank-conversion.js";
import { TalerBankIntegrationHttpClient } from "./bank-integration.js";
import { TalerRevenueHttpClient } from "./bank-revenue.js";
import { TalerWireGatewayHttpClient } from "./bank-wire.js";
import {
AccessToken,
PaginationParams,
TalerCorebankApi,
UserAndToken,
WithdrawalOperationStatus,
codecForAccountData,
codecForBankAccountCreateWithdrawalResponse,
codecForBankAccountTransactionInfo,
codecForBankAccountTransactionsResponse,
codecForCashoutPending,
codecForCashoutStatusResponse,
codecForCashouts,
codecForCoreBankConfig,
codecForCreateTransactionResponse,
codecForGlobalCashouts,
codecForListBankAccountsResponse,
codecForMonitorResponse,
codecForPublicAccountsResponse,
codecForRegisterAccountResponse,
codecForWithdrawalPublicInfo,
} from "./types.js";
import {
addLongPollingParam,
addPaginationParams,
makeBearerTokenAuthHeader,
} from "./utils.js";
export type TalerCoreBankResultByMethod<
prop extends keyof TalerCoreBankHttpClient,
> = ResultByMethod;
export type TalerCoreBankErrorsByMethod<
prop extends keyof TalerCoreBankHttpClient,
> = FailCasesByMethod;
/**
* Protocol version spoken with the core bank.
*
* Endpoint must be ordered in the same way that in the docs
* Response code (http and taler) must have the same order that in the docs
* That way is easier to see changes
*
* Uses libtool's current:revision:age versioning.
*/
export class TalerCoreBankHttpClient {
public readonly PROTOCOL_VERSION = "4:0:0";
httpLib: HttpRequestLibrary;
constructor(
readonly baseUrl: string,
httpClient?: HttpRequestLibrary,
) {
this.httpLib = httpClient ?? createPlatformHttpLib();
}
isCompatible(version: string): boolean {
const compare = LibtoolVersion.compare(this.PROTOCOL_VERSION, version);
return compare?.compatible ?? false;
}
/**
* https://docs.taler.net/core/api-corebank.html#config
*
*/
async getConfig() {
const url = new URL(`config`, this.baseUrl);
const resp = await this.httpLib.fetch(url.href, {
method: "GET",
});
switch (resp.status) {
case HttpStatusCode.Ok:
return opSuccessFromHttp(resp, codecForCoreBankConfig());
default:
return opUnknownFailure(resp, await resp.text());
}
}
//
// ACCOUNTS
//
/**
* https://docs.taler.net/core/api-corebank.html#post--accounts
*
*/
async createAccount(
auth: AccessToken,
body: TalerCorebankApi.RegisterAccountRequest,
) {
const url = new URL(`accounts`, this.baseUrl);
const resp = await this.httpLib.fetch(url.href, {
method: "POST",
body,
headers: {
Authorization: makeBearerTokenAuthHeader(auth),
},
});
switch (resp.status) {
case HttpStatusCode.Ok:
return opSuccessFromHttp(resp, codecForRegisterAccountResponse());
case HttpStatusCode.BadRequest:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.Unauthorized:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.Conflict: {
const body = await resp.json();
const details = codecForTalerErrorDetail().decode(body);
switch (details.code) {
case TalerErrorCode.BANK_REGISTER_USERNAME_REUSE:
return opKnownTalerFailure(details.code, resp);
case TalerErrorCode.BANK_REGISTER_PAYTO_URI_REUSE:
return opKnownTalerFailure(details.code, resp);
case TalerErrorCode.BANK_UNALLOWED_DEBIT:
return opKnownTalerFailure(details.code, resp);
case TalerErrorCode.BANK_RESERVED_USERNAME_CONFLICT:
return opKnownTalerFailure(details.code, resp);
case TalerErrorCode.BANK_NON_ADMIN_PATCH_DEBT_LIMIT:
return opKnownTalerFailure(details.code, resp);
case TalerErrorCode.BANK_NON_ADMIN_SET_TAN_CHANNEL:
return opKnownTalerFailure(details.code, resp);
case TalerErrorCode.BANK_TAN_CHANNEL_NOT_SUPPORTED:
return opKnownTalerFailure(details.code, resp);
case TalerErrorCode.BANK_MISSING_TAN_INFO:
return opKnownTalerFailure(details.code, resp);
default:
return opUnknownFailure(resp, body);
}
}
default:
return opUnknownFailure(resp, await resp.text());
}
}
/**
* https://docs.taler.net/core/api-corebank.html#delete--accounts-$USERNAME
*
*/
async deleteAccount(auth: UserAndToken, cid?: string) {
const url = new URL(`accounts/${auth.username}`, this.baseUrl);
const resp = await this.httpLib.fetch(url.href, {
method: "DELETE",
headers: {
Authorization: makeBearerTokenAuthHeader(auth.token),
"X-Challenge-Id": cid,
},
});
switch (resp.status) {
case HttpStatusCode.Accepted:
return opKnownAlternativeFailure(
resp,
resp.status,
codecForChallenge(),
);
case HttpStatusCode.NoContent:
return opEmptySuccess(resp);
case HttpStatusCode.Unauthorized:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.NotFound:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.Conflict: {
const body = await resp.json();
const details = codecForTalerErrorDetail().decode(body);
switch (details.code) {
case TalerErrorCode.BANK_RESERVED_USERNAME_CONFLICT:
return opKnownTalerFailure(details.code, resp);
case TalerErrorCode.BANK_ACCOUNT_BALANCE_NOT_ZERO:
return opKnownTalerFailure(details.code, resp);
default:
return opUnknownFailure(resp, body);
}
}
default:
return opUnknownFailure(resp, await resp.text());
}
}
/**
* https://docs.taler.net/core/api-corebank.html#patch--accounts-$USERNAME
*
*/
async updateAccount(
auth: UserAndToken,
body: TalerCorebankApi.AccountReconfiguration,
cid?: string,
) {
const url = new URL(`accounts/${auth.username}`, this.baseUrl);
const resp = await this.httpLib.fetch(url.href, {
method: "PATCH",
body,
headers: {
Authorization: makeBearerTokenAuthHeader(auth.token),
"X-Challenge-Id": cid,
},
});
switch (resp.status) {
case HttpStatusCode.Accepted:
return opKnownAlternativeFailure(
resp,
resp.status,
codecForChallenge(),
);
case HttpStatusCode.NoContent:
return opEmptySuccess(resp);
case HttpStatusCode.Unauthorized:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.NotFound:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.Conflict: {
const body = await resp.json();
const details = codecForTalerErrorDetail().decode(body);
switch (details.code) {
case TalerErrorCode.BANK_NON_ADMIN_PATCH_LEGAL_NAME:
return opKnownTalerFailure(details.code, resp);
case TalerErrorCode.BANK_NON_ADMIN_PATCH_CASHOUT:
return opKnownTalerFailure(details.code, resp);
case TalerErrorCode.BANK_NON_ADMIN_PATCH_DEBT_LIMIT:
return opKnownTalerFailure(details.code, resp);
case TalerErrorCode.BANK_TAN_CHANNEL_NOT_SUPPORTED:
return opKnownTalerFailure(details.code, resp);
case TalerErrorCode.BANK_MISSING_TAN_INFO:
return opKnownTalerFailure(details.code, resp);
default:
return opUnknownFailure(resp, body);
}
}
default:
return opUnknownFailure(resp, await resp.text());
}
}
/**
* https://docs.taler.net/core/api-corebank.html#patch--accounts-$USERNAME-auth
*
*/
async updatePassword(
auth: UserAndToken,
body: TalerCorebankApi.AccountPasswordChange,
cid?: string,
) {
const url = new URL(`accounts/${auth.username}/auth`, this.baseUrl);
const resp = await this.httpLib.fetch(url.href, {
method: "PATCH",
body,
headers: {
Authorization: makeBearerTokenAuthHeader(auth.token),
"X-Challenge-Id": cid,
},
});
switch (resp.status) {
case HttpStatusCode.Accepted:
return opKnownAlternativeFailure(
resp,
resp.status,
codecForChallenge(),
);
case HttpStatusCode.NoContent:
return opEmptySuccess(resp);
case HttpStatusCode.NotFound:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.Unauthorized:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.Conflict: {
const body = await resp.json();
const details = codecForTalerErrorDetail().decode(body);
switch (details.code) {
case TalerErrorCode.BANK_NON_ADMIN_PATCH_MISSING_OLD_PASSWORD:
return opKnownTalerFailure(details.code, resp);
case TalerErrorCode.BANK_PATCH_BAD_OLD_PASSWORD:
return opKnownTalerFailure(details.code, resp);
default:
return opUnknownFailure(resp, body);
}
}
default:
return opUnknownFailure(resp, await resp.text());
}
}
/**
* https://docs.taler.net/core/api-corebank.html#get--public-accounts
*
*/
async getPublicAccounts(
filter: { account?: string } = {},
pagination?: PaginationParams,
) {
const url = new URL(`public-accounts`, this.baseUrl);
addPaginationParams(url, pagination);
if (filter.account !== undefined) {
url.searchParams.set("filter_name", filter.account);
}
const resp = await this.httpLib.fetch(url.href, {
method: "GET",
});
switch (resp.status) {
case HttpStatusCode.Ok:
return opSuccessFromHttp(resp, codecForPublicAccountsResponse());
case HttpStatusCode.NoContent:
return opFixedSuccess({ public_accounts: [] });
case HttpStatusCode.NotFound:
return opFixedSuccess({ public_accounts: [] });
default:
return opUnknownFailure(resp, await resp.text());
}
}
/**
* https://docs.taler.net/core/api-corebank.html#get--accounts
*
*/
async getAccounts(
auth: AccessToken,
filter: { account?: string } = {},
pagination?: PaginationParams,
) {
const url = new URL(`accounts`, this.baseUrl);
addPaginationParams(url, pagination);
if (filter.account !== undefined) {
url.searchParams.set("filter_name", filter.account);
}
const resp = await this.httpLib.fetch(url.href, {
method: "GET",
headers: {
Authorization: makeBearerTokenAuthHeader(auth),
},
});
switch (resp.status) {
case HttpStatusCode.Ok:
return opSuccessFromHttp(resp, codecForListBankAccountsResponse());
case HttpStatusCode.NoContent:
return opFixedSuccess({ accounts: [] });
case HttpStatusCode.Unauthorized:
return opKnownHttpFailure(resp.status, resp);
default:
return opUnknownFailure(resp, await resp.text());
}
}
/**
* https://docs.taler.net/core/api-corebank.html#get--accounts-$USERNAME
*
*/
async getAccount(auth: UserAndToken) {
const url = new URL(`accounts/${auth.username}`, this.baseUrl);
const resp = await this.httpLib.fetch(url.href, {
method: "GET",
headers: {
Authorization: makeBearerTokenAuthHeader(auth.token),
},
});
switch (resp.status) {
case HttpStatusCode.Ok:
return opSuccessFromHttp(resp, codecForAccountData());
case HttpStatusCode.Unauthorized:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.NotFound:
return opKnownHttpFailure(resp.status, resp);
default:
return opUnknownFailure(resp, await resp.text());
}
}
//
// TRANSACTIONS
//
/**
* https://docs.taler.net/core/api-corebank.html#get--accounts-$USERNAME-transactions
*
*/
async getTransactions(
auth: UserAndToken,
params?: PaginationParams & LongPollParams,
) {
const url = new URL(`accounts/${auth.username}/transactions`, this.baseUrl);
addPaginationParams(url, params);
addLongPollingParam(url, params);
const resp = await this.httpLib.fetch(url.href, {
method: "GET",
headers: {
Authorization: makeBearerTokenAuthHeader(auth.token),
},
});
switch (resp.status) {
case HttpStatusCode.Ok:
return opSuccessFromHttp(resp, codecForBankAccountTransactionsResponse());
case HttpStatusCode.NoContent:
return opFixedSuccess({ transactions: [] });
case HttpStatusCode.Unauthorized:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.NotFound:
return opKnownHttpFailure(resp.status, resp);
default:
return opUnknownFailure(resp, await resp.text());
}
}
/**
* https://docs.taler.net/core/api-corebank.html#get--accounts-$USERNAME-transactions-$TRANSACTION_ID
*
*/
async getTransactionById(auth: UserAndToken, txid: number) {
const url = new URL(
`accounts/${auth.username}/transactions/${String(txid)}`,
this.baseUrl,
);
const resp = await this.httpLib.fetch(url.href, {
method: "GET",
headers: {
Authorization: makeBearerTokenAuthHeader(auth.token),
},
});
switch (resp.status) {
case HttpStatusCode.Ok:
return opSuccessFromHttp(resp, codecForBankAccountTransactionInfo());
case HttpStatusCode.NotFound:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.Unauthorized:
return opKnownHttpFailure(resp.status, resp);
default:
return opUnknownFailure(resp, await resp.text());
}
}
/**
* https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-transactions
*
*/
async createTransaction(
auth: UserAndToken,
body: TalerCorebankApi.CreateTransactionRequest,
cid?: string,
) {
const url = new URL(`accounts/${auth.username}/transactions`, this.baseUrl);
const resp = await this.httpLib.fetch(url.href, {
method: "POST",
headers: {
Authorization: makeBearerTokenAuthHeader(auth.token),
"X-Challenge-Id": cid,
},
body,
});
switch (resp.status) {
case HttpStatusCode.Ok:
return opSuccessFromHttp(resp, codecForCreateTransactionResponse());
case HttpStatusCode.Accepted:
return opKnownAlternativeFailure(
resp,
resp.status,
codecForChallenge(),
);
case HttpStatusCode.BadRequest:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.Unauthorized:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.NotFound:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.Conflict: {
const body = await resp.json();
const details = codecForTalerErrorDetail().decode(body);
switch (details.code) {
case TalerErrorCode.BANK_SAME_ACCOUNT:
return opKnownTalerFailure(details.code, resp);
case TalerErrorCode.BANK_UNKNOWN_CREDITOR:
return opKnownTalerFailure(details.code, resp);
case TalerErrorCode.BANK_UNALLOWED_DEBIT:
return opKnownTalerFailure(details.code, resp);
default:
return opUnknownFailure(resp, body);
}
}
default:
return opUnknownFailure(resp, await resp.text());
}
}
//
// WITHDRAWALS
//
/**
* https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-withdrawals
*
*/
async createWithdrawal(
auth: UserAndToken,
body: TalerCorebankApi.BankAccountCreateWithdrawalRequest,
) {
const url = new URL(`accounts/${auth.username}/withdrawals`, this.baseUrl);
const resp = await this.httpLib.fetch(url.href, {
method: "POST",
headers: {
Authorization: makeBearerTokenAuthHeader(auth.token),
},
body,
});
switch (resp.status) {
case HttpStatusCode.Ok:
return opSuccessFromHttp(resp, codecForBankAccountCreateWithdrawalResponse());
case HttpStatusCode.NotFound:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.Conflict:
return opKnownHttpFailure(resp.status, resp);
//FIXME: missing in docs
case HttpStatusCode.Unauthorized:
return opKnownHttpFailure(resp.status, resp);
default:
return opUnknownFailure(resp, await resp.text());
}
}
/**
* https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-withdrawals-$WITHDRAWAL_ID-confirm
*
*/
async confirmWithdrawalById(auth: UserAndToken, wid: string, cid?: string) {
const url = new URL(
`accounts/${auth.username}/withdrawals/${wid}/confirm`,
this.baseUrl,
);
const resp = await this.httpLib.fetch(url.href, {
method: "POST",
headers: {
Authorization: makeBearerTokenAuthHeader(auth.token),
"X-Challenge-Id": cid,
},
});
switch (resp.status) {
case HttpStatusCode.Accepted:
return opKnownAlternativeFailure(
resp,
resp.status,
codecForChallenge(),
);
case HttpStatusCode.NoContent:
return opEmptySuccess(resp);
//FIXME: missing in docs
case HttpStatusCode.BadRequest:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.NotFound:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.Conflict: {
const body = await resp.json();
const details = codecForTalerErrorDetail().decode(body);
switch (details.code) {
case TalerErrorCode.BANK_CONFIRM_ABORT_CONFLICT:
return opKnownTalerFailure(details.code, resp);
case TalerErrorCode.BANK_CONFIRM_INCOMPLETE:
return opKnownTalerFailure(details.code, resp);
case TalerErrorCode.BANK_UNALLOWED_DEBIT:
return opKnownTalerFailure(details.code, resp);
default:
return opUnknownFailure(resp, body);
}
}
default:
return opUnknownFailure(resp, await resp.text());
}
}
/**
* https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-withdrawals-$WITHDRAWAL_ID-abort
*
*/
async abortWithdrawalById(auth: UserAndToken, wid: string) {
const url = new URL(
`accounts/${auth.username}/withdrawals/${wid}/abort`,
this.baseUrl,
);
const resp = await this.httpLib.fetch(url.href, {
method: "POST",
headers: {
Authorization: makeBearerTokenAuthHeader(auth.token),
},
});
switch (resp.status) {
case HttpStatusCode.NoContent:
return opEmptySuccess(resp);
//FIXME: missing in docs
case HttpStatusCode.BadRequest:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.NotFound:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.Conflict:
return opKnownHttpFailure(resp.status, resp);
default:
return opUnknownFailure(resp, await resp.text());
}
}
/**
* https://docs.taler.net/core/api-corebank.html#get--withdrawals-$WITHDRAWAL_ID
*
*/
async getWithdrawalById(
wid: string,
params?: {
old_state?: WithdrawalOperationStatus;
} & LongPollParams,
) {
const url = new URL(`withdrawals/${wid}`, this.baseUrl);
addLongPollingParam(url, params);
if (params) {
url.searchParams.set(
"old_state",
!params.old_state ? "pending" : params.old_state,
);
}
const resp = await this.httpLib.fetch(url.href, {
method: "GET",
});
switch (resp.status) {
case HttpStatusCode.Ok:
return opSuccessFromHttp(resp, codecForWithdrawalPublicInfo());
//FIXME: missing in docs
case HttpStatusCode.BadRequest:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.NotFound:
return opKnownHttpFailure(resp.status, resp);
default:
return opUnknownFailure(resp, await resp.text());
}
}
//
// CASHOUTS
//
/**
* https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-cashouts
*
*/
async createCashout(
auth: UserAndToken,
body: TalerCorebankApi.CashoutRequest,
cid?: string,
) {
const url = new URL(`accounts/${auth.username}/cashouts`, this.baseUrl);
const resp = await this.httpLib.fetch(url.href, {
method: "POST",
headers: {
Authorization: makeBearerTokenAuthHeader(auth.token),
"X-Challenge-Id": cid,
},
body,
});
switch (resp.status) {
case HttpStatusCode.Ok:
return opSuccessFromHttp(resp, codecForCashoutPending());
case HttpStatusCode.Accepted:
return opKnownAlternativeFailure(
resp,
resp.status,
codecForChallenge(),
);
case HttpStatusCode.NotFound:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.Conflict: {
const body = await resp.json();
const details = codecForTalerErrorDetail().decode(body);
switch (details.code) {
case TalerErrorCode.BANK_TRANSFER_REQUEST_UID_REUSED:
return opKnownTalerFailure(details.code, resp);
case TalerErrorCode.BANK_BAD_CONVERSION:
return opKnownTalerFailure(details.code, resp);
case TalerErrorCode.BANK_UNALLOWED_DEBIT:
return opKnownTalerFailure(details.code, resp);
case TalerErrorCode.BANK_CONFIRM_INCOMPLETE:
return opKnownTalerFailure(details.code, resp);
default:
return opUnknownFailure(resp, body);
}
}
case HttpStatusCode.BadGateway: {
const body = await resp.json();
const details = codecForTalerErrorDetail().decode(body);
switch (details.code) {
case TalerErrorCode.BANK_TAN_CHANNEL_SCRIPT_FAILED:
return opKnownTalerFailure(details.code, resp);
default:
return opUnknownFailure(resp, body);
}
}
case HttpStatusCode.NotImplemented:
return opKnownHttpFailure(resp.status, resp);
default:
return opUnknownFailure(resp, await resp.text());
}
}
/**
* https://docs.taler.net/core/api-corebank.html#get--accounts-$USERNAME-cashouts-$CASHOUT_ID
*
*/
async getCashoutById(auth: UserAndToken, cid: number) {
const url = new URL(
`accounts/${auth.username}/cashouts/${cid}`,
this.baseUrl,
);
const resp = await this.httpLib.fetch(url.href, {
method: "GET",
headers: {
Authorization: makeBearerTokenAuthHeader(auth.token),
},
});
switch (resp.status) {
case HttpStatusCode.Ok:
return opSuccessFromHttp(resp, codecForCashoutStatusResponse());
case HttpStatusCode.NotFound:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.NotImplemented:
return opKnownHttpFailure(resp.status, resp);
default:
return opUnknownFailure(resp, await resp.text());
}
}
/**
* https://docs.taler.net/core/api-corebank.html#get--accounts-$USERNAME-cashouts
*
*/
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 opSuccessFromHttp(resp, codecForCashouts());
case HttpStatusCode.NoContent:
return opFixedSuccess({ cashouts: [] });
case HttpStatusCode.NotImplemented:
return opKnownHttpFailure(resp.status, resp);
default:
return opUnknownFailure(resp, await resp.text());
}
}
/**
* https://docs.taler.net/core/api-corebank.html#get--cashouts
*
*/
async getGlobalCashouts(auth: AccessToken, pagination?: PaginationParams) {
const url = new URL(`cashouts`, this.baseUrl);
addPaginationParams(url, pagination);
const resp = await this.httpLib.fetch(url.href, {
method: "GET",
headers: {
Authorization: makeBearerTokenAuthHeader(auth),
},
});
switch (resp.status) {
case HttpStatusCode.Ok:
return opSuccessFromHttp(resp, codecForGlobalCashouts());
case HttpStatusCode.NoContent:
return opFixedSuccess({ cashouts: [] });
case HttpStatusCode.NotImplemented:
return opKnownHttpFailure(resp.status, resp);
default:
return opUnknownFailure(resp, await resp.text());
}
}
//
// 2FA
//
/**
* https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-challenge-$CHALLENGE_ID
*
*/
async sendChallenge(auth: UserAndToken, cid: string) {
const url = new URL(
`accounts/${auth.username}/challenge/${cid}`,
this.baseUrl,
);
const resp = await this.httpLib.fetch(url.href, {
method: "POST",
headers: {
Authorization: makeBearerTokenAuthHeader(auth.token),
},
});
switch (resp.status) {
case HttpStatusCode.Ok:
return opSuccessFromHttp(resp, codecForTanTransmission());
case HttpStatusCode.Unauthorized:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.NotFound:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.BadGateway: {
const body = await resp.json();
const details = codecForTalerErrorDetail().decode(body);
switch (details.code) {
case TalerErrorCode.BANK_TAN_CHANNEL_SCRIPT_FAILED:
return opKnownTalerFailure(details.code, resp);
default:
return opUnknownFailure(resp, body);
}
}
default:
return opUnknownFailure(resp, await resp.text());
}
}
/**
* https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-challenge-$CHALLENGE_ID-confirm
*
*/
async confirmChallenge(
auth: UserAndToken,
cid: string,
body: TalerCorebankApi.ChallengeSolve,
) {
const url = new URL(
`accounts/${auth.username}/challenge/${cid}/confirm`,
this.baseUrl,
);
const resp = await this.httpLib.fetch(url.href, {
method: "POST",
headers: {
Authorization: makeBearerTokenAuthHeader(auth.token),
},
body,
});
switch (resp.status) {
case HttpStatusCode.NoContent:
return opEmptySuccess(resp);
case HttpStatusCode.Unauthorized:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.NotFound:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.Conflict: {
const body = await resp.json();
const details = codecForTalerErrorDetail().decode(body);
switch (details.code) {
case TalerErrorCode.BANK_TAN_CHALLENGE_EXPIRED:
return opKnownTalerFailure(details.code, resp);
case TalerErrorCode.BANK_TAN_CHALLENGE_FAILED:
return opKnownTalerFailure(details.code, resp);
default:
return opUnknownFailure(resp, body);
}
}
case HttpStatusCode.TooManyRequests:
return opKnownHttpFailure(resp.status, resp);
default:
return opUnknownFailure(resp, await resp.text());
}
}
//
// MONITOR
//
/**
* https://docs.taler.net/core/api-corebank.html#get--monitor
*
*/
async getMonitor(
auth: AccessToken,
params: {
timeframe?: TalerCorebankApi.MonitorTimeframeParam;
which?: number;
} = {},
) {
const url = new URL(`monitor`, this.baseUrl);
if (params.timeframe) {
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 opSuccessFromHttp(resp, codecForMonitorResponse());
case HttpStatusCode.BadRequest:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.Unauthorized:
return opKnownHttpFailure(resp.status, resp);
default:
return opUnknownFailure(resp, await resp.text());
}
}
//
// Others API
//
/**
* https://docs.taler.net/core/api-corebank.html#taler-bank-integration-api
*
*/
getIntegrationAPI(): TalerBankIntegrationHttpClient {
const url = new URL(`taler-integration/`, this.baseUrl);
return new TalerBankIntegrationHttpClient(url.href, this.httpLib);
}
/**
* https://docs.taler.net/core/api-corebank.html#taler-bank-integration-api
*
*/
getWireGatewayAPI(username: string): TalerWireGatewayHttpClient {
const url = new URL(
`accounts/${username}/taler-wire-gateway/`,
this.baseUrl,
);
return new TalerWireGatewayHttpClient(url.href, username, this.httpLib);
}
/**
* https://docs.taler.net/core/api-corebank.html#taler-bank-integration-api
*
*/
getRevenueAPI(username: string): TalerRevenueHttpClient {
const url = new URL(`accounts/${username}/taler-revenue/`, this.baseUrl);
return new TalerRevenueHttpClient(url.href, username, this.httpLib);
}
/**
* https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-token
*
*/
getAuthenticationAPI(username: string): TalerAuthenticationHttpClient {
const url = new URL(`accounts/${username}/`, this.baseUrl);
return new TalerAuthenticationHttpClient(url.href, username, this.httpLib);
}
/**
* https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-token
*
*/
getConversionInfoAPI(): TalerBankConversionHttpClient {
const url = new URL(`conversion-info/`, this.baseUrl);
return new TalerBankConversionHttpClient(url.href, this.httpLib);
}
}