wip: http-client
This commit is contained in:
parent
8ae4ad9342
commit
36b7918a79
523
packages/taler-util/src/http-client/core-bank.ts
Normal file
523
packages/taler-util/src/http-client/core-bank.ts
Normal file
@ -0,0 +1,523 @@
|
|||||||
|
/*
|
||||||
|
This file is part of GNU Taler
|
||||||
|
(C) 2022 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 <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
AmountJson,
|
||||||
|
Amounts,
|
||||||
|
Logger
|
||||||
|
} from "@gnu-taler/taler-util";
|
||||||
|
import {
|
||||||
|
createPlatformHttpLib,
|
||||||
|
expectSuccessResponseOrThrow,
|
||||||
|
HttpRequestLibrary,
|
||||||
|
readSuccessResponseJsonOrThrow
|
||||||
|
} from "@gnu-taler/taler-util/http";
|
||||||
|
import { AccessToken, codecForAccountData, codecForBankAccountCreateWithdrawalResponse, codecForBankAccountGetWithdrawalResponse, codecForBankAccountTransactionInfo, codecForBankAccountTransactionsResponse, codecForCashoutConversionResponse, codecForCashoutPending, codecForCashouts, codecForCashoutStatusResponse, codecForConversionRatesResponse, codecForCoreBankConfig, codecForGlobalCashouts, codecForListBankAccountsResponse, codecForMonitorResponse, codecForPublicAccountsResponse, codecForTokenSuccessResponse, TalerAuthentication, TalerCorebankApi } from "./types.js";
|
||||||
|
import { addPaginationParams, makeBasicAuthHeader, makeBearerTokenAuthHeader, PaginationParams, UserAndPassword, UserAndToken } from "./utils.js";
|
||||||
|
|
||||||
|
const logger = new Logger("http-client/core-bank.ts");
|
||||||
|
|
||||||
|
export class TalerCoreBankHttpClient {
|
||||||
|
httpLib: HttpRequestLibrary;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private baseUrl: string,
|
||||||
|
httpClient?: HttpRequestLibrary,
|
||||||
|
) {
|
||||||
|
this.httpLib = httpClient ?? createPlatformHttpLib();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-token
|
||||||
|
*
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async createAccessToken(
|
||||||
|
auth: UserAndPassword,
|
||||||
|
body: TalerAuthentication.TokenRequest,
|
||||||
|
): Promise<TalerAuthentication.TokenSuccessResponse> {
|
||||||
|
const url = new URL(`accounts/${auth.username}/token`, this.baseUrl);
|
||||||
|
const resp = await this.httpLib.fetch(url.href, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
Authorization: makeBasicAuthHeader(auth.username, auth.password),
|
||||||
|
},
|
||||||
|
body
|
||||||
|
});
|
||||||
|
return readSuccessResponseJsonOrThrow(resp, codecForTokenSuccessResponse());
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteAccessToken(
|
||||||
|
auth: UserAndToken,
|
||||||
|
): Promise<void> {
|
||||||
|
const url = new URL(`accounts/${auth.username}/token`, this.baseUrl);
|
||||||
|
const resp = await this.httpLib.fetch(url.href, {
|
||||||
|
method: "DELETE",
|
||||||
|
headers: {
|
||||||
|
Authorization: makeBearerTokenAuthHeader(auth.token),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return expectSuccessResponseOrThrow(resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://docs.taler.net/core/api-corebank.html#get--accounts-$USERNAME
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async getConfig(): Promise<TalerCorebankApi.Config> {
|
||||||
|
const url = new URL(`config`, this.baseUrl);
|
||||||
|
const resp = await this.httpLib.fetch(url.href, {
|
||||||
|
method: "GET"
|
||||||
|
});
|
||||||
|
return readSuccessResponseJsonOrThrow(resp, codecForCoreBankConfig());
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// ACCOUNTS
|
||||||
|
//
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://docs.taler.net/core/api-corebank.html#post--accounts
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async createAccount(auth: AccessToken, body: TalerCorebankApi.RegisterAccountRequest): Promise<void> {
|
||||||
|
const url = new URL(`accounts`, this.baseUrl);
|
||||||
|
const resp = await this.httpLib.fetch(url.href, {
|
||||||
|
method: "POST",
|
||||||
|
body,
|
||||||
|
headers: {
|
||||||
|
Authorization: makeBearerTokenAuthHeader(auth)
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return expectSuccessResponseOrThrow(resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://docs.taler.net/core/api-corebank.html#delete--accounts-$USERNAME
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async deleteAccount(auth: UserAndToken): Promise<void> {
|
||||||
|
const url = new URL(`accounts/${auth.username}`, this.baseUrl);
|
||||||
|
const resp = await this.httpLib.fetch(url.href, {
|
||||||
|
method: "DELETE",
|
||||||
|
headers: {
|
||||||
|
Authorization: makeBearerTokenAuthHeader(auth.token)
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return expectSuccessResponseOrThrow(resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://docs.taler.net/core/api-corebank.html#patch--accounts-$USERNAME
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async updateAccount(auth: UserAndToken, body: TalerCorebankApi.AccountReconfiguration): Promise<void> {
|
||||||
|
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)
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return expectSuccessResponseOrThrow(resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://docs.taler.net/core/api-corebank.html#patch--accounts-$USERNAME-auth
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async updatePassword(auth: UserAndToken, body: TalerCorebankApi.AccountPasswordChange): Promise<void> {
|
||||||
|
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)
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return expectSuccessResponseOrThrow(resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://docs.taler.net/core/get-$BANK_API_BASE_URL-public-accounts
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async getPublicAccounts(): Promise<TalerCorebankApi.PublicAccountsResponse> {
|
||||||
|
const url = new URL(`public-accounts`, this.baseUrl);
|
||||||
|
const resp = await this.httpLib.fetch(url.href, {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return readSuccessResponseJsonOrThrow(resp, codecForPublicAccountsResponse());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://docs.taler.net/core/api-corebank.html#get--accounts
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async getAccounts(auth: AccessToken): Promise<TalerCorebankApi.ListBankAccountsResponse> {
|
||||||
|
const url = new URL(`accounts`, this.baseUrl);
|
||||||
|
const resp = await this.httpLib.fetch(url.href, {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
Authorization: makeBearerTokenAuthHeader(auth)
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return readSuccessResponseJsonOrThrow(resp, codecForListBankAccountsResponse());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://docs.taler.net/core/api-corebank.html#get--accounts-$USERNAME
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async getAccount(auth: UserAndToken): Promise<TalerCorebankApi.AccountData> {
|
||||||
|
const url = new URL(`accounts/${auth.username}`, this.baseUrl);
|
||||||
|
const resp = await this.httpLib.fetch(url.href, {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
Authorization: makeBearerTokenAuthHeader(auth.token)
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return readSuccessResponseJsonOrThrow(resp, codecForAccountData());
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// TRANSACTIONS
|
||||||
|
//
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://docs.taler.net/core/api-corebank.html#get-$BANK_API_BASE_URL-accounts-$account_name-transactions
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async getTransactions(auth: UserAndToken, pagination?: PaginationParams): Promise<TalerCorebankApi.BankAccountTransactionsResponse> {
|
||||||
|
const url = new URL(`accounts/${auth.username}/transactions`, this.baseUrl);
|
||||||
|
addPaginationParams(url, pagination)
|
||||||
|
const resp = await this.httpLib.fetch(url.href, {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
Authorization: makeBearerTokenAuthHeader(auth.token)
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return readSuccessResponseJsonOrThrow(resp, codecForBankAccountTransactionsResponse());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://docs.taler.net/core/api-corebank.html#get-$BANK_API_BASE_URL-accounts-$account_name-transactions-$transaction_id
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async getTransactionById(auth: UserAndToken, txid: number): Promise<TalerCorebankApi.BankAccountTransactionInfo> {
|
||||||
|
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)
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return readSuccessResponseJsonOrThrow(resp, codecForBankAccountTransactionInfo());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://docs.taler.net/core/api-corebank.html#post-$BANK_API_BASE_URL-accounts-$account_name-transactions
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async createTransaction(auth: UserAndToken, body: TalerCorebankApi.CreateBankAccountTransactionCreate): Promise<void> {
|
||||||
|
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)
|
||||||
|
},
|
||||||
|
body,
|
||||||
|
});
|
||||||
|
return expectSuccessResponseOrThrow(resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// WITHDRAWALS
|
||||||
|
//
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://docs.taler.net/core/api-corebank.html#post-$BANK_API_BASE_URL-accounts-$account_name-withdrawals
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async createWithdrawal(auth: UserAndToken, body: TalerCorebankApi.BankAccountCreateWithdrawalRequest): Promise<TalerCorebankApi.BankAccountCreateWithdrawalResponse> {
|
||||||
|
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,
|
||||||
|
});
|
||||||
|
return readSuccessResponseJsonOrThrow(resp, codecForBankAccountCreateWithdrawalResponse());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://docs.taler.net/core/api-corebank.html#post-$BANK_API_BASE_URL-accounts-$account_name-withdrawals
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async getWithdrawalById(wid: string): Promise<TalerCorebankApi.BankAccountGetWithdrawalResponse> {
|
||||||
|
const url = new URL(`withdrawals/${wid}`, this.baseUrl);
|
||||||
|
const resp = await this.httpLib.fetch(url.href, {
|
||||||
|
method: "GET",
|
||||||
|
});
|
||||||
|
return readSuccessResponseJsonOrThrow(resp, codecForBankAccountGetWithdrawalResponse());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://docs.taler.net/core/api-corebank.html#post-$BANK_API_BASE_URL-withdrawals-$withdrawal_id-abort
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async abortWithdrawalById(wid: string): Promise<void> {
|
||||||
|
const url = new URL(`withdrawals/${wid}/abort`, this.baseUrl);
|
||||||
|
const resp = await this.httpLib.fetch(url.href, {
|
||||||
|
method: "POST",
|
||||||
|
});
|
||||||
|
return expectSuccessResponseOrThrow(resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://docs.taler.net/core/api-corebank.html#post-$BANK_API_BASE_URL-withdrawals-$withdrawal_id-confirm
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async confirmWithdrawalById(wid: string): Promise<void> {
|
||||||
|
const url = new URL(`withdrawals/${wid}/confirm`, this.baseUrl);
|
||||||
|
const resp = await this.httpLib.fetch(url.href, {
|
||||||
|
method: "POST",
|
||||||
|
});
|
||||||
|
return expectSuccessResponseOrThrow(resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// CASHOUTS
|
||||||
|
//
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-cashouts
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async createCashout(auth: UserAndToken, body: TalerCorebankApi.CashoutRequest): Promise<TalerCorebankApi.CashoutPending> {
|
||||||
|
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)
|
||||||
|
},
|
||||||
|
body,
|
||||||
|
});
|
||||||
|
return readSuccessResponseJsonOrThrow(resp, codecForCashoutPending());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-cashouts-$CASHOUT_ID-abort
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async abortCashoutById(auth: UserAndToken, cid: string): Promise<void> {
|
||||||
|
const url = new URL(`accounts/${auth.username}/cashouts/${cid}/abort`, this.baseUrl);
|
||||||
|
const resp = await this.httpLib.fetch(url.href, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
Authorization: makeBearerTokenAuthHeader(auth.token)
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return expectSuccessResponseOrThrow(resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-cashouts-$CASHOUT_ID-confirm
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async confirmCashoutById(auth: UserAndToken, cid: string, body: TalerCorebankApi.CashoutConfirmRequest): Promise<void> {
|
||||||
|
const url = new URL(`accounts/${auth.username}/cashouts/${cid}/confirm`, this.baseUrl);
|
||||||
|
const resp = await this.httpLib.fetch(url.href, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
Authorization: makeBearerTokenAuthHeader(auth.token)
|
||||||
|
},
|
||||||
|
body,
|
||||||
|
});
|
||||||
|
return expectSuccessResponseOrThrow(resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-cashouts-$CASHOUT_ID-confirm
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async getCashoutRate(conversion: { debit?: AmountJson, credit?: AmountJson }): Promise<TalerCorebankApi.CashoutConversionResponse> {
|
||||||
|
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",
|
||||||
|
});
|
||||||
|
return readSuccessResponseJsonOrThrow(resp, codecForCashoutConversionResponse());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://docs.taler.net/core/api-corebank.html#get--accounts-$USERNAME-cashouts
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async getAccountCashouts(auth: UserAndToken): Promise<TalerCorebankApi.Cashouts> {
|
||||||
|
const url = new URL(`accounts/${auth.username}/cashouts`, this.baseUrl);
|
||||||
|
const resp = await this.httpLib.fetch(url.href, {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
Authorization: makeBearerTokenAuthHeader(auth.token)
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return readSuccessResponseJsonOrThrow(resp, codecForCashouts());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://docs.taler.net/core/api-corebank.html#get--cashouts
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async getGlobalCashouts(auth: AccessToken): Promise<TalerCorebankApi.GlobalCashouts> {
|
||||||
|
const url = new URL(`cashouts`, this.baseUrl);
|
||||||
|
const resp = await this.httpLib.fetch(url.href, {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
Authorization: makeBearerTokenAuthHeader(auth)
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return readSuccessResponseJsonOrThrow(resp, codecForGlobalCashouts());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://docs.taler.net/core/api-corebank.html#get--accounts-$USERNAME-cashouts-$CASHOUT_ID
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async getCashoutById(auth: UserAndToken, cid: string): Promise<TalerCorebankApi.CashoutStatusResponse> {
|
||||||
|
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)
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return readSuccessResponseJsonOrThrow(resp, codecForCashoutStatusResponse());
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// CONVERSION RATE
|
||||||
|
//
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://docs.taler.net/core/api-corebank.html#get--conversion-rates
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async getConversionRates(): Promise<TalerCorebankApi.ConversionRatesResponse> {
|
||||||
|
const url = new URL(`conversion-rates`, this.baseUrl);
|
||||||
|
const resp = await this.httpLib.fetch(url.href, {
|
||||||
|
method: "GET",
|
||||||
|
});
|
||||||
|
return readSuccessResponseJsonOrThrow(resp, codecForConversionRatesResponse());
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// MONITOR
|
||||||
|
//
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://docs.taler.net/core/api-corebank.html#get--monitor
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async getMonitor(params: { timeframe: TalerCorebankApi.MonitorTimeframeParam, which: number }): Promise<TalerCorebankApi.MonitorResponse> {
|
||||||
|
const url = new URL(`monitor`, this.baseUrl);
|
||||||
|
url.searchParams.set("timeframe", params.timeframe.toString())
|
||||||
|
url.searchParams.set("which", String(params.which))
|
||||||
|
const resp = await this.httpLib.fetch(url.href, {
|
||||||
|
method: "GET",
|
||||||
|
});
|
||||||
|
return readSuccessResponseJsonOrThrow(resp, codecForMonitorResponse());
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// 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,)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TalerBankIntegrationHttpClient {
|
||||||
|
httpLib: HttpRequestLibrary;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private baseUrl: string,
|
||||||
|
httpClient?: HttpRequestLibrary,
|
||||||
|
) {
|
||||||
|
this.httpLib = httpClient ?? createPlatformHttpLib();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TalerWireGatewayHttpClient {
|
||||||
|
httpLib: HttpRequestLibrary;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private baseUrl: string,
|
||||||
|
private username: string,
|
||||||
|
httpClient?: HttpRequestLibrary,
|
||||||
|
) {
|
||||||
|
this.httpLib = httpClient ?? createPlatformHttpLib();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TalerRevenueHttpClient {
|
||||||
|
httpLib: HttpRequestLibrary;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private baseUrl: string,
|
||||||
|
private username: string,
|
||||||
|
httpClient?: HttpRequestLibrary,
|
||||||
|
) {
|
||||||
|
this.httpLib = httpClient ?? createPlatformHttpLib();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
703
packages/taler-util/src/http-client/types.ts
Normal file
703
packages/taler-util/src/http-client/types.ts
Normal file
@ -0,0 +1,703 @@
|
|||||||
|
import { codecForAmountJson, codecForAmountString } from "../amounts.js";
|
||||||
|
import { TalerCorebankApiClient } from "../bank-api-client.js";
|
||||||
|
import { Codec, buildCodecForObject, codecForAny, codecForBoolean, codecForConstString, codecForEither, codecForList, codecForMap, codecForNumber, codecForString, codecOptional } from "../codec.js";
|
||||||
|
import { codecForTimestamp } from "../time.js";
|
||||||
|
|
||||||
|
|
||||||
|
type HashCode = string;
|
||||||
|
type EddsaPublicKey = string;
|
||||||
|
type EddsaSignature = string;
|
||||||
|
type WireTransferIdentifierRawP = string;
|
||||||
|
type RelativeTime = {
|
||||||
|
d_us: number | "forever"
|
||||||
|
};
|
||||||
|
type ImageDataUrl = string;
|
||||||
|
|
||||||
|
interface WithId {
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Timestamp {
|
||||||
|
// Milliseconds since epoch, or the special
|
||||||
|
// value "forever" to represent an event that will
|
||||||
|
// never happen.
|
||||||
|
t_s: number | "never";
|
||||||
|
}
|
||||||
|
interface Duration {
|
||||||
|
d_us: number | "forever";
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WithId {
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type UUID = string;
|
||||||
|
type Integer = number;
|
||||||
|
|
||||||
|
type Amount = string;
|
||||||
|
|
||||||
|
|
||||||
|
export interface LoginToken {
|
||||||
|
token: AccessToken,
|
||||||
|
expiration: Timestamp,
|
||||||
|
}
|
||||||
|
// token used to get loginToken
|
||||||
|
// must forget after used
|
||||||
|
declare const __ac_token: unique symbol;
|
||||||
|
export type AccessToken = string & {
|
||||||
|
[__ac_token]: true;
|
||||||
|
};
|
||||||
|
|
||||||
|
export namespace TalerAuthentication {
|
||||||
|
|
||||||
|
export interface TokenRequest {
|
||||||
|
// Service-defined scope for the token.
|
||||||
|
// Typical scopes would be "readonly" or "readwrite".
|
||||||
|
scope: string;
|
||||||
|
|
||||||
|
// Server may impose its own upper bound
|
||||||
|
// on the token validity duration
|
||||||
|
duration?: RelativeTime;
|
||||||
|
|
||||||
|
// Is the token refreshable into a new token during its
|
||||||
|
// validity?
|
||||||
|
// Refreshable tokens effectively provide indefinite
|
||||||
|
// access if they are refreshed in time.
|
||||||
|
refreshable?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TokenSuccessResponse {
|
||||||
|
// Expiration determined by the server.
|
||||||
|
// Can be based on the token_duration
|
||||||
|
// from the request, but ultimately the
|
||||||
|
// server decides the expiration.
|
||||||
|
expiration: Timestamp;
|
||||||
|
|
||||||
|
// Opque access token.
|
||||||
|
access_token: AccessToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
// Number of fractional digits to render in normal font and size.
|
||||||
|
num_fractional_normal_digits: Integer;
|
||||||
|
|
||||||
|
// Number of fractional digits to render always, if needed by
|
||||||
|
// 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".
|
||||||
|
// Communicates the currency symbol to be used.
|
||||||
|
alt_unit_names: { [log10: string]: string };
|
||||||
|
}
|
||||||
|
|
||||||
|
export const codecForAccessToken = codecForString as () => Codec<AccessToken>;
|
||||||
|
export const codecForTokenSuccessResponse =
|
||||||
|
(): Codec<TalerAuthentication.TokenSuccessResponse> =>
|
||||||
|
buildCodecForObject<TalerAuthentication.TokenSuccessResponse>()
|
||||||
|
.property("access_token", codecForAccessToken())
|
||||||
|
.property("expiration", codecForTimestamp)
|
||||||
|
.build("TalerAuthentication.TokenSuccessResponse")
|
||||||
|
|
||||||
|
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")
|
||||||
|
|
||||||
|
export const codecForCoreBankConfig =
|
||||||
|
(): Codec<TalerCorebankApi.Config> =>
|
||||||
|
buildCodecForObject<TalerCorebankApi.Config>()
|
||||||
|
.property("name", codecForString())
|
||||||
|
.property("version", codecForString())
|
||||||
|
.property("have_cashout", codecOptional(codecForBoolean()))
|
||||||
|
.property("currency", codecForCurrencySpecificiation())
|
||||||
|
.property("fiat_currency", codecOptional(codecForCurrencySpecificiation()))
|
||||||
|
.build("TalerCorebankApi.Config")
|
||||||
|
|
||||||
|
const codecForBalance = (): Codec<TalerCorebankApi.Balance> =>
|
||||||
|
buildCodecForObject<TalerCorebankApi.Balance>()
|
||||||
|
.property("amount", codecForAmountString())
|
||||||
|
.property("credit_debit_indicator", codecForEither(codecForConstString("credit"), codecForConstString("debit")))
|
||||||
|
.build("TalerCorebankApi.Balance")
|
||||||
|
|
||||||
|
const codecForPublicAccount = (): Codec<TalerCorebankApi.PublicAccount> =>
|
||||||
|
buildCodecForObject<TalerCorebankApi.PublicAccount>()
|
||||||
|
.property("account_name", codecForString())
|
||||||
|
.property("balance", codecForBalance())
|
||||||
|
.property("payto_uri", codecForPaytoURI())
|
||||||
|
.build("TalerCorebankApi.PublicAccount")
|
||||||
|
|
||||||
|
export const codecForPublicAccountsResponse =
|
||||||
|
(): Codec<TalerCorebankApi.PublicAccountsResponse> =>
|
||||||
|
buildCodecForObject<TalerCorebankApi.PublicAccountsResponse>()
|
||||||
|
.property("public_accounts", codecForList(codecForPublicAccount()))
|
||||||
|
.build("TalerCorebankApi.PublicAccountsResponse")
|
||||||
|
|
||||||
|
|
||||||
|
export const codecForAccountMinimalData =
|
||||||
|
(): Codec<TalerCorebankApi.AccountMinimalData> =>
|
||||||
|
buildCodecForObject<TalerCorebankApi.AccountMinimalData>()
|
||||||
|
.property("balance", codecForBalance())
|
||||||
|
.property("debit_threshold", codecForAmountString())
|
||||||
|
.property("name", codecForString())
|
||||||
|
.property("username", codecForString())
|
||||||
|
.build("TalerCorebankApi.AccountMinimalData")
|
||||||
|
|
||||||
|
export const codecForListBankAccountsResponse =
|
||||||
|
(): Codec<TalerCorebankApi.ListBankAccountsResponse> =>
|
||||||
|
buildCodecForObject<TalerCorebankApi.ListBankAccountsResponse>()
|
||||||
|
.property("accounts", codecForList(codecForAccountMinimalData()))
|
||||||
|
.build("TalerCorebankApi.ListBankAccountsResponse")
|
||||||
|
|
||||||
|
export const codecForAccountData =
|
||||||
|
(): Codec<TalerCorebankApi.AccountData> =>
|
||||||
|
buildCodecForObject<TalerCorebankApi.AccountData>()
|
||||||
|
.property("name", codecForString())
|
||||||
|
.property("balance", codecForBalance())
|
||||||
|
.property("payto_uri", codecForPaytoURI())
|
||||||
|
.property("debit_threshold", codecForAmountString())
|
||||||
|
.property("contact_data", codecOptional(codecForChallengeContactData()))
|
||||||
|
.property("cashout_payto_uri", codecOptional(codecForPaytoURI()))
|
||||||
|
.build("TalerCorebankApi.AccountData")
|
||||||
|
|
||||||
|
|
||||||
|
export const codecForChallengeContactData =
|
||||||
|
(): Codec<TalerCorebankApi.ChallengeContactData> =>
|
||||||
|
buildCodecForObject<TalerCorebankApi.ChallengeContactData>()
|
||||||
|
.property("email", codecOptional(codecForString()))
|
||||||
|
.property("phone", codecOptional(codecForString()))
|
||||||
|
.build("TalerCorebankApi.ChallengeContactData")
|
||||||
|
|
||||||
|
export const codecForBankAccountTransactionsResponse =
|
||||||
|
(): Codec<TalerCorebankApi.BankAccountTransactionsResponse> =>
|
||||||
|
buildCodecForObject<TalerCorebankApi.BankAccountTransactionsResponse>()
|
||||||
|
.property("transactions", codecForList(codecForBankAccountTransactionInfo()))
|
||||||
|
.build("TalerCorebankApi.BankAccountTransactionsResponse");
|
||||||
|
|
||||||
|
export const codecForBankAccountTransactionInfo =
|
||||||
|
(): Codec<TalerCorebankApi.BankAccountTransactionInfo> =>
|
||||||
|
buildCodecForObject<TalerCorebankApi.BankAccountTransactionInfo>()
|
||||||
|
.property("amount", codecForAmountString())
|
||||||
|
.property("creditor_payto_uri", codecForPaytoURI())
|
||||||
|
.property("date", codecForTimestamp)
|
||||||
|
.property("debtor_payto_uri", codecForPaytoURI())
|
||||||
|
.property("direction", codecForEither(codecForConstString("debit"), codecForConstString("credit")))
|
||||||
|
.property("row_id", codecForNumber())
|
||||||
|
.property("subject", codecForString())
|
||||||
|
.build("TalerCorebankApi.BankAccountTransactionInfo");
|
||||||
|
|
||||||
|
export const codecForBankAccountCreateWithdrawalResponse =
|
||||||
|
(): Codec<TalerCorebankApi.BankAccountCreateWithdrawalResponse> =>
|
||||||
|
buildCodecForObject<TalerCorebankApi.BankAccountCreateWithdrawalResponse>()
|
||||||
|
.property("taler_withdraw_uri", codecForTalerWithdrawalURI())
|
||||||
|
.property("withdrawal_id", codecForString())
|
||||||
|
.build("TalerCorebankApi.BankAccountCreateWithdrawalResponse");
|
||||||
|
|
||||||
|
export const codecForBankAccountGetWithdrawalResponse =
|
||||||
|
(): Codec<TalerCorebankApi.BankAccountGetWithdrawalResponse> =>
|
||||||
|
buildCodecForObject<TalerCorebankApi.BankAccountGetWithdrawalResponse>()
|
||||||
|
.property("aborted", codecForBoolean())
|
||||||
|
.property("amount", codecForAmountString())
|
||||||
|
.property("confirmation_done", codecForBoolean())
|
||||||
|
.property("selected_exchange_account", codecOptional(codecForString()))
|
||||||
|
.property("selected_reserve_pub", codecOptional(codecForString()))
|
||||||
|
.property("selection_done", (codecForBoolean()))
|
||||||
|
.build("TalerCorebankApi.BankAccountGetWithdrawalResponse");
|
||||||
|
|
||||||
|
export const codecForCashoutPending =
|
||||||
|
(): Codec<TalerCorebankApi.CashoutPending> =>
|
||||||
|
buildCodecForObject<TalerCorebankApi.CashoutPending>()
|
||||||
|
.property("cashout_id", codecForString())
|
||||||
|
.build("TalerCorebankApi.CashoutPending");
|
||||||
|
|
||||||
|
export const codecForCashoutConversionResponse =
|
||||||
|
(): Codec<TalerCorebankApi.CashoutConversionResponse> =>
|
||||||
|
buildCodecForObject<TalerCorebankApi.CashoutConversionResponse>()
|
||||||
|
.property("amount_credit", codecForAmountString())
|
||||||
|
.property("amount_debit", codecForAmountString())
|
||||||
|
.build("TalerCorebankApi.CashoutConversionResponse");
|
||||||
|
|
||||||
|
export const codecForCashouts =
|
||||||
|
(): Codec<TalerCorebankApi.Cashouts> =>
|
||||||
|
buildCodecForObject<TalerCorebankApi.Cashouts>()
|
||||||
|
.property("cashouts", codecForList(codecForCashoutInfo()))
|
||||||
|
.build("TalerCorebankApi.Cashouts");
|
||||||
|
|
||||||
|
export const codecForCashoutInfo =
|
||||||
|
(): Codec<TalerCorebankApi.CashoutInfo> =>
|
||||||
|
buildCodecForObject<TalerCorebankApi.CashoutInfo>()
|
||||||
|
.property("cashout_id", codecForString())
|
||||||
|
.property("status", codecForEither(codecForConstString("pending"), codecForConstString("confirmed"),))
|
||||||
|
.build("TalerCorebankApi.CashoutInfo");
|
||||||
|
|
||||||
|
export const codecForGlobalCashouts =
|
||||||
|
(): Codec<TalerCorebankApi.GlobalCashouts> =>
|
||||||
|
buildCodecForObject<TalerCorebankApi.GlobalCashouts>()
|
||||||
|
.property("cashouts", codecForList(codecForGlobalCashoutInfo()))
|
||||||
|
.build("TalerCorebankApi.GlobalCashouts");
|
||||||
|
|
||||||
|
export const codecForGlobalCashoutInfo =
|
||||||
|
(): Codec<TalerCorebankApi.GlobalCashoutInfo> =>
|
||||||
|
buildCodecForObject<TalerCorebankApi.GlobalCashoutInfo>()
|
||||||
|
.property("cashout_id", codecForString())
|
||||||
|
.property("username", codecForString())
|
||||||
|
.property("status", codecForEither(codecForConstString("pending"), codecForConstString("confirmed"),))
|
||||||
|
.build("TalerCorebankApi.GlobalCashoutInfo");
|
||||||
|
|
||||||
|
export const codecForCashoutStatusResponse =
|
||||||
|
(): Codec<TalerCorebankApi.CashoutStatusResponse> =>
|
||||||
|
buildCodecForObject<TalerCorebankApi.CashoutStatusResponse>()
|
||||||
|
.property("amount_credit", codecForAmountString())
|
||||||
|
.property("amount_debit", codecForAmountString())
|
||||||
|
.property("confirmation_time", codecForTimestamp)
|
||||||
|
.property("creation_time", codecForTimestamp)
|
||||||
|
.property("credit_payto_uri", codecForPaytoURI())
|
||||||
|
.property("status", codecForEither(codecForConstString("pending"), codecForConstString("confirmed")))
|
||||||
|
.property("subject", codecForString())
|
||||||
|
.build("TalerCorebankApi.CashoutStatusResponse");
|
||||||
|
|
||||||
|
export const codecForConversionRatesResponse =
|
||||||
|
(): Codec<TalerCorebankApi.ConversionRatesResponse> =>
|
||||||
|
buildCodecForObject<TalerCorebankApi.ConversionRatesResponse>()
|
||||||
|
.property("buy_at_ratio", codecForDecimalNumber())
|
||||||
|
.property("buy_in_fee", codecForDecimalNumber())
|
||||||
|
.property("sell_at_ratio", codecForDecimalNumber())
|
||||||
|
.property("sell_out_fee", codecForDecimalNumber())
|
||||||
|
.build("TalerCorebankApi.ConversionRatesResponse");
|
||||||
|
|
||||||
|
export const codecForMonitorResponse =
|
||||||
|
(): Codec<TalerCorebankApi.MonitorResponse> =>
|
||||||
|
buildCodecForObject<TalerCorebankApi.MonitorResponse>()
|
||||||
|
.property("cashinCount", codecForNumber())
|
||||||
|
.property("cashinExternalVolume", codecForAmountString())
|
||||||
|
.property("cashoutCount", codecForNumber())
|
||||||
|
.property("cashoutExternalVolume", codecForAmountString())
|
||||||
|
.property("talerPayoutCount", codecForNumber())
|
||||||
|
.property("talerPayoutInternalVolume", codecForAmountString())
|
||||||
|
.build("TalerCorebankApi.MonitorResponse");
|
||||||
|
|
||||||
|
// export const codecFor =
|
||||||
|
// (): Codec<TalerCorebankApi.PublicAccountsResponse> =>
|
||||||
|
// buildCodecForObject<TalerCorebankApi.PublicAccountsResponse>()
|
||||||
|
// .property("", codecForString())
|
||||||
|
// .build("TalerCorebankApi.PublicAccountsResponse");
|
||||||
|
|
||||||
|
type EmailAddress = string;
|
||||||
|
type PhoneNumber = string;
|
||||||
|
type DecimalNumber = string;
|
||||||
|
|
||||||
|
const codecForPaytoURI = codecForString
|
||||||
|
const codecForTalerWithdrawalURI = codecForString
|
||||||
|
const codecForDecimalNumber = codecForString
|
||||||
|
|
||||||
|
enum TanChannel {
|
||||||
|
SMS = "sms",
|
||||||
|
EMAIL = "email",
|
||||||
|
FILE = "file"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export namespace TalerCorebankApi {
|
||||||
|
|
||||||
|
export interface Config {
|
||||||
|
// Name of this API, always "circuit".
|
||||||
|
name: string;
|
||||||
|
// API version in the form $n:$n:$n
|
||||||
|
version: string;
|
||||||
|
|
||||||
|
// If 'true', the server provides local currency
|
||||||
|
// conversion support.
|
||||||
|
// If missing or false, some parts of the API
|
||||||
|
// are not supported and return 404.
|
||||||
|
have_cashout?: boolean;
|
||||||
|
|
||||||
|
// How the bank SPA should render the currency.
|
||||||
|
currency: CurrencySpecification;
|
||||||
|
|
||||||
|
// Fiat currency. That is the currency in which
|
||||||
|
// cash-out operations ultimately wire money.
|
||||||
|
// Only applicable if have_cashout=true.
|
||||||
|
fiat_currency?: CurrencySpecification;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BankAccountCreateWithdrawalRequest {
|
||||||
|
// Amount to withdraw.
|
||||||
|
amount: Amount;
|
||||||
|
}
|
||||||
|
export interface BankAccountCreateWithdrawalResponse {
|
||||||
|
// ID of the withdrawal, can be used to view/modify the withdrawal operation.
|
||||||
|
withdrawal_id: string;
|
||||||
|
|
||||||
|
// URI that can be passed to the wallet to initiate the withdrawal.
|
||||||
|
taler_withdraw_uri: string;
|
||||||
|
}
|
||||||
|
export interface BankAccountGetWithdrawalResponse {
|
||||||
|
// Amount that will be withdrawn with this withdrawal operation.
|
||||||
|
amount: Amount;
|
||||||
|
|
||||||
|
// Was the withdrawal aborted?
|
||||||
|
aborted: boolean;
|
||||||
|
|
||||||
|
// Has the withdrawal been confirmed by the bank?
|
||||||
|
// The wire transfer for a withdrawal is only executed once
|
||||||
|
// both confirmation_done is true and selection_done is true.
|
||||||
|
confirmation_done: boolean;
|
||||||
|
|
||||||
|
// Did the wallet select reserve details?
|
||||||
|
selection_done: boolean;
|
||||||
|
|
||||||
|
// Reserve public key selected by the exchange,
|
||||||
|
// only non-null if selection_done is true.
|
||||||
|
selected_reserve_pub: string | undefined;
|
||||||
|
|
||||||
|
// Exchange account selected by the wallet, or by the bank
|
||||||
|
// (with the default exchange) in case the wallet did not provide one
|
||||||
|
// through the Integration API.
|
||||||
|
selected_exchange_account: string | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BankAccountTransactionsResponse {
|
||||||
|
transactions: BankAccountTransactionInfo[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BankAccountTransactionInfo {
|
||||||
|
creditor_payto_uri: string;
|
||||||
|
debtor_payto_uri: string;
|
||||||
|
|
||||||
|
amount: Amount;
|
||||||
|
direction: "debit" | "credit";
|
||||||
|
|
||||||
|
subject: string;
|
||||||
|
|
||||||
|
// Transaction unique ID. Matches
|
||||||
|
// $transaction_id from the URI.
|
||||||
|
row_id: number;
|
||||||
|
date: Timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreateBankAccountTransactionCreate {
|
||||||
|
// Address in the Payto format of the wire transfer receiver.
|
||||||
|
// It needs at least the 'message' query string parameter.
|
||||||
|
payto_uri: string;
|
||||||
|
|
||||||
|
// Transaction amount (in the $currency:x.y format), optional.
|
||||||
|
// However, when not given, its value must occupy the 'amount'
|
||||||
|
// query string parameter of the 'payto' field. In case it
|
||||||
|
// is given in both places, the paytoUri's takes the precedence.
|
||||||
|
amount?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RegisterAccountRequest {
|
||||||
|
// Username
|
||||||
|
username: string;
|
||||||
|
|
||||||
|
// Password.
|
||||||
|
password: string;
|
||||||
|
|
||||||
|
// Legal name of the account owner
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
// Defaults to false.
|
||||||
|
is_public?: boolean;
|
||||||
|
|
||||||
|
// Is this a taler exchange account?
|
||||||
|
// If true:
|
||||||
|
// - incoming transactions to the account that do not
|
||||||
|
// have a valid reserve public key are automatically
|
||||||
|
// - the account provides the taler-wire-gateway-api endpoints
|
||||||
|
// Defaults to false.
|
||||||
|
is_taler_exchange?: boolean;
|
||||||
|
|
||||||
|
// Addresses where to send the TAN for transactions.
|
||||||
|
// Currently only used for cashouts.
|
||||||
|
// If missing, cashouts will fail.
|
||||||
|
// In the future, might be used for other transactions
|
||||||
|
// as well.
|
||||||
|
challenge_contact_data?: ChallengeContactData;
|
||||||
|
|
||||||
|
// 'payto' address pointing a bank account
|
||||||
|
// external to the libeufin-bank.
|
||||||
|
// Payments will be sent to this bank account
|
||||||
|
// when the user wants to convert the local currency
|
||||||
|
// back to fiat currency outside libeufin-bank.
|
||||||
|
cashout_payto_uri?: string;
|
||||||
|
|
||||||
|
// Internal payto URI of this bank account.
|
||||||
|
// Used mostly for testing.
|
||||||
|
internal_payto_uri?: string;
|
||||||
|
}
|
||||||
|
export interface ChallengeContactData {
|
||||||
|
|
||||||
|
// E-Mail address
|
||||||
|
email?: EmailAddress;
|
||||||
|
|
||||||
|
// Phone number.
|
||||||
|
phone?: PhoneNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AccountReconfiguration {
|
||||||
|
|
||||||
|
// Addresses where to send the TAN for transactions.
|
||||||
|
// Currently only used for cashouts.
|
||||||
|
// If missing, cashouts will fail.
|
||||||
|
// In the future, might be used for other transactions
|
||||||
|
// as well.
|
||||||
|
challenge_contact_data?: ChallengeContactData;
|
||||||
|
|
||||||
|
// 'payto' address pointing a bank account
|
||||||
|
// external to the libeufin-bank.
|
||||||
|
// Payments will be sent to this bank account
|
||||||
|
// when the user wants to convert the local currency
|
||||||
|
// back to fiat currency outside libeufin-bank.
|
||||||
|
cashout_address?: string;
|
||||||
|
|
||||||
|
// Legal name associated with $username.
|
||||||
|
// When missing, the old name is kept.
|
||||||
|
name?: string;
|
||||||
|
|
||||||
|
// If present, change the is_exchange configuration.
|
||||||
|
// See RegisterAccountRequest
|
||||||
|
is_exchange?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface AccountPasswordChange {
|
||||||
|
|
||||||
|
// New password.
|
||||||
|
new_password: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PublicAccountsResponse {
|
||||||
|
public_accounts: PublicAccount[];
|
||||||
|
}
|
||||||
|
export interface PublicAccount {
|
||||||
|
payto_uri: string;
|
||||||
|
|
||||||
|
balance: Balance;
|
||||||
|
|
||||||
|
// The account name (=username) of the
|
||||||
|
// libeufin-bank account.
|
||||||
|
account_name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ListBankAccountsResponse {
|
||||||
|
accounts: AccountMinimalData[];
|
||||||
|
}
|
||||||
|
export interface Balance {
|
||||||
|
amount: Amount;
|
||||||
|
credit_debit_indicator: "credit" | "debit";
|
||||||
|
}
|
||||||
|
export interface AccountMinimalData {
|
||||||
|
// Username
|
||||||
|
username: string;
|
||||||
|
|
||||||
|
// Legal name of the account owner.
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
// current balance of the account
|
||||||
|
balance: Balance;
|
||||||
|
|
||||||
|
// Number indicating the max debit allowed for the requesting user.
|
||||||
|
debit_threshold: Amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AccountData {
|
||||||
|
// Legal name of the account owner.
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
// Available balance on the account.
|
||||||
|
balance: Balance;
|
||||||
|
|
||||||
|
// payto://-URI of the account.
|
||||||
|
payto_uri: string;
|
||||||
|
|
||||||
|
// Number indicating the max debit allowed for the requesting user.
|
||||||
|
debit_threshold: Amount;
|
||||||
|
|
||||||
|
contact_data?: ChallengeContactData;
|
||||||
|
|
||||||
|
// 'payto' address pointing the bank account
|
||||||
|
// where to send cashouts. This field is optional
|
||||||
|
// because not all the accounts are required to participate
|
||||||
|
// in the merchants' circuit. One example is the exchange:
|
||||||
|
// that never cashouts. Registering these accounts can
|
||||||
|
// be done via the access API.
|
||||||
|
cashout_payto_uri?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface CashoutRequest {
|
||||||
|
|
||||||
|
// Optional subject to associate to the
|
||||||
|
// cashout operation. This data will appear
|
||||||
|
// as the incoming wire transfer subject in
|
||||||
|
// the user's external bank account.
|
||||||
|
subject?: string;
|
||||||
|
|
||||||
|
// That is the plain amount that the user specified
|
||||||
|
// to cashout. Its $currency is the (regional) currency of the
|
||||||
|
// bank instance.
|
||||||
|
amount_debit: Amount;
|
||||||
|
|
||||||
|
// That is the amount that will effectively be
|
||||||
|
// transferred by the bank to the user's bank
|
||||||
|
// account, that is external to the regional currency.
|
||||||
|
// It is expressed in the fiat currency and
|
||||||
|
// is calculated after the cashout fee and the
|
||||||
|
// exchange rate. See the /cashout-rates call.
|
||||||
|
// The client needs to calculate this amount
|
||||||
|
// correctly based on the amount_debit and the cashout rate,
|
||||||
|
// otherwise the request will fail.
|
||||||
|
amount_credit: Amount;
|
||||||
|
|
||||||
|
// Which channel the TAN should be sent to. If
|
||||||
|
// this field is missing, it defaults to SMS.
|
||||||
|
// The default choice prefers to change the communication
|
||||||
|
// channel respect to the one used to issue this request.
|
||||||
|
tan_channel?: TanChannel;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CashoutPending {
|
||||||
|
// ID identifying the operation being created
|
||||||
|
// and now waiting for the TAN confirmation.
|
||||||
|
cashout_id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CashoutConfirmRequest {
|
||||||
|
// the TAN that confirms $CASHOUT_ID.
|
||||||
|
tan: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CashoutConversionResponse {
|
||||||
|
// Amount that the user will get deducted from their regional
|
||||||
|
// bank account, according to the 'amount_credit' value.
|
||||||
|
amount_debit: Amount;
|
||||||
|
// Amount that the user will receive in their fiat
|
||||||
|
// bank account, according to 'amount_debit'.
|
||||||
|
amount_credit: Amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Cashouts {
|
||||||
|
// Every string represents a cash-out operation ID.
|
||||||
|
cashouts: CashoutInfo[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CashoutInfo {
|
||||||
|
cashout_id: string;
|
||||||
|
status: "pending" | "confirmed";
|
||||||
|
}
|
||||||
|
export interface GlobalCashouts {
|
||||||
|
// Every string represents a cash-out operation ID.
|
||||||
|
cashouts: GlobalCashoutInfo[];
|
||||||
|
}
|
||||||
|
export interface GlobalCashoutInfo {
|
||||||
|
cashout_id: string;
|
||||||
|
username: string;
|
||||||
|
status: "pending" | "confirmed";
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CashoutStatusResponse {
|
||||||
|
status: "pending" | "confirmed";
|
||||||
|
|
||||||
|
// Amount debited to the internal
|
||||||
|
// regional currency bank account.
|
||||||
|
amount_debit: Amount;
|
||||||
|
|
||||||
|
// Amount credited to the external bank account.
|
||||||
|
amount_credit: Amount;
|
||||||
|
|
||||||
|
// Transaction subject.
|
||||||
|
subject: string;
|
||||||
|
|
||||||
|
// Fiat bank account that will receive the cashed out amount.
|
||||||
|
// Specified as a payto URI.
|
||||||
|
credit_payto_uri: string;
|
||||||
|
|
||||||
|
// Time when the cashout was created.
|
||||||
|
creation_time: Timestamp;
|
||||||
|
|
||||||
|
// Time when the cashout was confirmed via its TAN.
|
||||||
|
// Missing when the operation wasn't confirmed yet.
|
||||||
|
confirmation_time?: Timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ConversionRatesResponse {
|
||||||
|
|
||||||
|
// Exchange rate to buy the local currency from the external one
|
||||||
|
buy_at_ratio: DecimalNumber;
|
||||||
|
|
||||||
|
// Exchange rate to sell the local currency for the external one
|
||||||
|
sell_at_ratio: DecimalNumber;
|
||||||
|
|
||||||
|
// Fee to subtract after applying the buy ratio.
|
||||||
|
buy_in_fee: DecimalNumber;
|
||||||
|
|
||||||
|
// Fee to subtract after applying the sell ratio.
|
||||||
|
sell_out_fee: DecimalNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum MonitorTimeframeParam{
|
||||||
|
hour, day, month, year, decade,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MonitorResponse {
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// 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: Amount;
|
||||||
|
|
||||||
|
// This number identifies how many cashout operations were
|
||||||
|
// confirmed in the timeframe speficied in the request.
|
||||||
|
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: Amount;
|
||||||
|
|
||||||
|
// 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: Amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
62
packages/taler-util/src/http-client/utils.ts
Normal file
62
packages/taler-util/src/http-client/utils.ts
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import { base64FromArrayBuffer } from "../base64.js";
|
||||||
|
import { stringToBytes } from "../taler-crypto.js";
|
||||||
|
import { AccessToken, TalerAuthentication } from "./types.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to generate the "Authorization" HTTP header.
|
||||||
|
*/
|
||||||
|
export function makeBasicAuthHeader(username: string, password: string): string {
|
||||||
|
const auth = `${username}:${password}`;
|
||||||
|
const authEncoded: string = base64FromArrayBuffer(stringToBytes(auth));
|
||||||
|
return `Basic ${authEncoded}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rfc8959
|
||||||
|
* @param token
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function makeBearerTokenAuthHeader(token: AccessToken): string {
|
||||||
|
return `Bearer secret-token:${token}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://bugs.gnunet.org/view.php?id=7949
|
||||||
|
*/
|
||||||
|
export function addPaginationParams(url: URL, pagination?: PaginationParams) {
|
||||||
|
if (!pagination) return;
|
||||||
|
if (pagination.timoutMs) {
|
||||||
|
url.searchParams.set("long_poll_ms", String(pagination.timoutMs))
|
||||||
|
}
|
||||||
|
if (pagination.offset) {
|
||||||
|
url.searchParams.set("start", pagination.offset)
|
||||||
|
}
|
||||||
|
if (pagination.limit) {
|
||||||
|
url.searchParams.set("delta", String(pagination.limit))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UserAndPassword = {
|
||||||
|
username: string,
|
||||||
|
password: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UserAndToken = {
|
||||||
|
username: string,
|
||||||
|
token: AccessToken,
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PaginationParams = {
|
||||||
|
/**
|
||||||
|
* row identifier as the starting point of the query
|
||||||
|
*/
|
||||||
|
offset?: string,
|
||||||
|
/**
|
||||||
|
* max number of element in the result response
|
||||||
|
*/
|
||||||
|
limit?: number,
|
||||||
|
/**
|
||||||
|
* milliseconds the server should wait for at least one result to be shown
|
||||||
|
*/
|
||||||
|
timoutMs?: number,
|
||||||
|
}
|
@ -50,7 +50,7 @@ export interface HttpResponse {
|
|||||||
export const DEFAULT_REQUEST_TIMEOUT_MS = 60000;
|
export const DEFAULT_REQUEST_TIMEOUT_MS = 60000;
|
||||||
|
|
||||||
export interface HttpRequestOptions {
|
export interface HttpRequestOptions {
|
||||||
method?: "POST" | "PUT" | "GET" | "DELETE";
|
method?: "POST" | "PATCH" | "PUT" | "GET" | "DELETE";
|
||||||
headers?: { [name: string]: string };
|
headers?: { [name: string]: string };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user