summaryrefslogtreecommitdiff
path: root/packages
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2024-03-18 12:12:57 -0300
committerSebastian <sebasjm@gmail.com>2024-03-18 12:12:57 -0300
commitb5312973a6f25ac73c8e29b659bf7ea23d77ac5e (patch)
tree335ede20fa2f69b2495c10a9dc66c28e05a75b90 /packages
parent18f283995378053f7ea42ac5f0aa767d54ee7f1d (diff)
downloadwallet-core-b5312973a6f25ac73c8e29b659bf7ea23d77ac5e.tar.gz
wallet-core-b5312973a6f25ac73c8e29b659bf7ea23d77ac5e.tar.bz2
wallet-core-b5312973a6f25ac73c8e29b659bf7ea23d77ac5e.zip
wip
Diffstat (limited to 'packages')
-rw-r--r--packages/bank-ui/package.json8
-rw-r--r--packages/merchant-backoffice-ui/src/hooks/backend.ts2
-rw-r--r--packages/merchant-backoffice-ui/src/hooks/merchant.ts211
-rw-r--r--packages/taler-util/.eslintrc.cjs28
-rw-r--r--packages/taler-util/package.json4
-rw-r--r--packages/taler-util/src/http-client/README.md24
-rw-r--r--packages/taler-util/src/http-client/merchant.ts679
-rw-r--r--packages/taler-util/src/http-client/types.ts106
8 files changed, 1018 insertions, 44 deletions
diff --git a/packages/bank-ui/package.json b/packages/bank-ui/package.json
index dd5589fe2..c25decf8d 100644
--- a/packages/bank-ui/package.json
+++ b/packages/bank-ui/package.json
@@ -27,6 +27,10 @@
},
"devDependencies": {
"eslint": "^8.56.0",
+ "@typescript-eslint/eslint-plugin": "^6.19.0",
+ "@typescript-eslint/parser": "^6.19.0",
+ "eslint-config-prettier": "^9.1.0",
+ "eslint-plugin-react": "^7.33.2",
"@gnu-taler/pogen": "^0.0.5",
"@tailwindcss/forms": "^0.5.3",
"@tailwindcss/typography": "^0.5.9",
@@ -34,13 +38,9 @@
"@types/history": "^4.7.8",
"@types/mocha": "^10.0.1",
"@types/node": "^18.11.17",
- "@typescript-eslint/eslint-plugin": "^6.19.0",
- "@typescript-eslint/parser": "^6.19.0",
"autoprefixer": "^10.4.14",
"chai": "^4.3.6",
"esbuild": "^0.19.9",
- "eslint-config-prettier": "^9.1.0",
- "eslint-plugin-react": "^7.33.2",
"mocha": "9.2.0",
"po2json": "^0.4.5",
"tailwindcss": "^3.3.2",
diff --git a/packages/merchant-backoffice-ui/src/hooks/backend.ts b/packages/merchant-backoffice-ui/src/hooks/backend.ts
index a3bb43545..292261bc8 100644
--- a/packages/merchant-backoffice-ui/src/hooks/backend.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/backend.ts
@@ -278,7 +278,7 @@ export function useBackendBaseRequest(): useBackendBaseRequestType {
export function useBackendInstanceRequest(): useBackendInstanceRequestType {
const { url: rootBackendUrl, token: rootToken } = useBackendContext();
- const { token: instanceToken, id, admin } = useInstanceContext();
+ const { token: instanceToken, admin } = useInstanceContext();
const { request: requestHandler } = useApiContext();
const { baseUrl, token: loginToken } = !admin
diff --git a/packages/merchant-backoffice-ui/src/hooks/merchant.ts b/packages/merchant-backoffice-ui/src/hooks/merchant.ts
new file mode 100644
index 000000000..5d5785442
--- /dev/null
+++ b/packages/merchant-backoffice-ui/src/hooks/merchant.ts
@@ -0,0 +1,211 @@
+/*
+ This file is part of GNU Taler
+ (C) 2021-2023 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 {
+ HttpResponse,
+ HttpResponseOk,
+ HttpResponsePaginated,
+ RequestError,
+} from "@gnu-taler/web-util/browser";
+import { useEffect, useState } from "preact/hooks";
+import { MerchantBackend } from "../declaration.js";
+import { MAX_RESULT_SIZE, PAGE_SIZE } from "../utils/constants.js";
+import { useBackendInstanceRequest, useMatchMutate } from "./backend.js";
+
+// FIX default import https://github.com/microsoft/TypeScript/issues/49189
+import _useSWR, { SWRHook, mutate } from "swr";
+const useSWR = _useSWR as unknown as SWRHook;
+
+// const MOCKED_ACCOUNTS: Record<string, MerchantBackend.BankAccounts.AccountAddDetails> = {
+// "hwire1": {
+// h_wire: "hwire1",
+// payto_uri: "payto://fake/iban/123",
+// salt: "qwe",
+// },
+// "hwire2": {
+// h_wire: "hwire2",
+// payto_uri: "payto://fake/iban/123",
+// salt: "qwe2",
+// },
+// }
+
+export function useBankAccountAPI(): BankAccountAPI {
+ const mutateAll = useMatchMutate();
+ const { request } = useBackendInstanceRequest();
+
+ const createBankAccount = async (
+ data: MerchantBackend.BankAccounts.AccountAddDetails,
+ ): Promise<HttpResponseOk<void>> => {
+ // MOCKED_ACCOUNTS[data.h_wire] = data
+ // return Promise.resolve({ ok: true, data: undefined });
+ const res = await request<void>(`/private/accounts`, {
+ method: "POST",
+ data,
+ });
+ await mutateAll(/.*private\/accounts.*/);
+ return res;
+ };
+
+ const updateBankAccount = async (
+ h_wire: string,
+ data: MerchantBackend.BankAccounts.AccountPatchDetails,
+ ): Promise<HttpResponseOk<void>> => {
+ // MOCKED_ACCOUNTS[h_wire].credit_facade_credentials = data.credit_facade_credentials
+ // MOCKED_ACCOUNTS[h_wire].credit_facade_url = data.credit_facade_url
+ // return Promise.resolve({ ok: true, data: undefined });
+ const res = await request<void>(`/private/accounts/${h_wire}`, {
+ method: "PATCH",
+ data,
+ });
+ await mutateAll(/.*private\/accounts.*/);
+ return res;
+ };
+
+ const deleteBankAccount = async (
+ h_wire: string,
+ ): Promise<HttpResponseOk<void>> => {
+ // delete MOCKED_ACCOUNTS[h_wire]
+ // return Promise.resolve({ ok: true, data: undefined });
+ const res = await request<void>(`/private/accounts/${h_wire}`, {
+ method: "DELETE",
+ });
+ await mutateAll(/.*private\/accounts.*/);
+ return res;
+ };
+
+ return {
+ createBankAccount,
+ updateBankAccount,
+ deleteBankAccount,
+ };
+}
+
+export interface BankAccountAPI {
+ createBankAccount: (
+ data: MerchantBackend.BankAccounts.AccountAddDetails,
+ ) => Promise<HttpResponseOk<void>>;
+ updateBankAccount: (
+ id: string,
+ data: MerchantBackend.BankAccounts.AccountPatchDetails,
+ ) => Promise<HttpResponseOk<void>>;
+ deleteBankAccount: (id: string) => Promise<HttpResponseOk<void>>;
+}
+
+export interface InstanceBankAccountFilter {
+}
+
+export function revalidateInstanceBankAccounts() {
+ // mutate(key => key instanceof)
+ return mutate((key) => Array.isArray(key) && key[key.length - 1] === "/private/accounts", undefined, { revalidate: true });
+}
+export function useInstanceBankAccounts(
+ args?: InstanceBankAccountFilter,
+ updatePosition?: (id: string) => void,
+): HttpResponsePaginated<
+ MerchantBackend.BankAccounts.AccountsSummaryResponse,
+ MerchantBackend.ErrorDetail
+> {
+
+ const { fetcher } = useBackendInstanceRequest();
+
+ const [pageAfter, setPageAfter] = useState(1);
+
+ const totalAfter = pageAfter * PAGE_SIZE;
+ const {
+ data: afterData,
+ error: afterError,
+ isValidating: loadingAfter,
+ } = useSWR<
+ HttpResponseOk<MerchantBackend.BankAccounts.AccountsSummaryResponse>,
+ RequestError<MerchantBackend.ErrorDetail>
+ >([`/private/accounts`], fetcher);
+
+ const [lastAfter, setLastAfter] = useState<
+ HttpResponse<
+ MerchantBackend.BankAccounts.AccountsSummaryResponse,
+ MerchantBackend.ErrorDetail
+ >
+ >({ loading: true });
+ useEffect(() => {
+ if (afterData) setLastAfter(afterData);
+ }, [afterData /*, beforeData*/]);
+
+ if (afterError) return afterError.cause;
+
+ // if the query returns less that we ask, then we have reach the end or beginning
+ const isReachingEnd =
+ afterData && afterData.data.accounts.length < totalAfter;
+ const isReachingStart = false;
+
+ const pagination = {
+ isReachingEnd,
+ isReachingStart,
+ loadMore: () => {
+ if (!afterData || isReachingEnd) return;
+ if (afterData.data.accounts.length < MAX_RESULT_SIZE) {
+ setPageAfter(pageAfter + 1);
+ } else {
+ const from = `${afterData.data.accounts[afterData.data.accounts.length - 1]
+ .h_wire
+ }`;
+ if (from && updatePosition) updatePosition(from);
+ }
+ },
+ loadMorePrev: () => {
+ },
+ };
+
+ const accounts = !afterData ? [] : (afterData || lastAfter).data.accounts;
+ if (loadingAfter /* || loadingBefore */)
+ return { loading: true, data: { accounts } };
+ if (/*beforeData &&*/ afterData) {
+ return { ok: true, data: { accounts }, ...pagination };
+ }
+ return { loading: true };
+}
+
+export function useBankAccountDetails(
+ h_wire: string,
+): HttpResponse<
+ MerchantBackend.BankAccounts.BankAccountEntry,
+ MerchantBackend.ErrorDetail
+> {
+ // return {
+ // ok: true,
+ // data: {
+ // ...MOCKED_ACCOUNTS[h_wire],
+ // active: true,
+ // }
+ // }
+ const { fetcher } = useBackendInstanceRequest();
+
+ const { data, error, isValidating } = useSWR<
+ HttpResponseOk<MerchantBackend.BankAccounts.BankAccountEntry>,
+ RequestError<MerchantBackend.ErrorDetail>
+ >([`/private/accounts/${h_wire}`], fetcher, {
+ refreshInterval: 0,
+ refreshWhenHidden: false,
+ revalidateOnFocus: false,
+ revalidateOnReconnect: false,
+ refreshWhenOffline: false,
+ });
+
+ if (isValidating) return { loading: true, data: data?.data };
+ if (data) {
+ return data;
+ }
+ if (error) return error.cause;
+ return { loading: true };
+}
diff --git a/packages/taler-util/.eslintrc.cjs b/packages/taler-util/.eslintrc.cjs
new file mode 100644
index 000000000..05618b499
--- /dev/null
+++ b/packages/taler-util/.eslintrc.cjs
@@ -0,0 +1,28 @@
+module.exports = {
+ extends: [
+ 'eslint:recommended',
+ 'plugin:@typescript-eslint/recommended',
+ 'plugin:react/recommended',
+ ],
+ parser: '@typescript-eslint/parser',
+ plugins: ['@typescript-eslint', 'header'],
+ root: true,
+ rules: {
+ "react/no-unknown-property": 0,
+ "react/no-unescaped-entities": 0,
+ "@typescript-eslint/no-namespace": 0,
+ "@typescript-eslint/no-unused-vars": [2,{argsIgnorePattern:"^_"}],
+ "header/header": [2,"copyleft-header.js"]
+ },
+ parserOptions: {
+ ecmaVersion: 6,
+ sourceType: 'module',
+ jsx: true,
+ },
+ settings: {
+ react: {
+ version: "18",
+ pragma: "h",
+ }
+ },
+};
diff --git a/packages/taler-util/package.json b/packages/taler-util/package.json
index 1caf1af9e..c1ff9873f 100644
--- a/packages/taler-util/package.json
+++ b/packages/taler-util/package.json
@@ -64,11 +64,13 @@
"pretty": "prettier --write src"
},
"devDependencies": {
+ "eslint": "^8.56.0",
+ "@typescript-eslint/eslint-plugin": "^6.19.0",
+ "@typescript-eslint/parser": "^6.19.0",
"@types/follow-redirects": "^1.14.4",
"@types/node": "^18.11.17",
"ava": "^6.0.1",
"esbuild": "^0.19.9",
- "prettier": "^3.1.1",
"typescript": "^5.3.3"
},
"dependencies": {
diff --git a/packages/taler-util/src/http-client/README.md b/packages/taler-util/src/http-client/README.md
new file mode 100644
index 000000000..5af5d48a7
--- /dev/null
+++ b/packages/taler-util/src/http-client/README.md
@@ -0,0 +1,24 @@
+HTTP Cclients
+-------------
+
+This folder contain class or function specifically designed to facilitate HTTP client
+interactions with a the core systems.
+
+These API defines:
+
+1. **API Communication**: Handle communication with the component API,
+abstracting away the details of HTTP requests and responses.
+This includes making GET, POST, PUT, and DELETE requests to the servers.
+
+2. **Data Formatting**: Responsible for formatting requests to the API in a
+way that's expected by the servers (JSON) and parsing the responses back
+into formats usable by the client.
+
+3. **Authentication and Security**: Handling authentication with the server API,
+which could involve sending API keys, client credentials, or managing tokens.
+It might also implement security features to ensure data integrity and confidentiality during transit.
+
+4. **Error Handling**: Providing robust error handling and retry mechanisms
+for failed HTTP requests, including logging and potentially user notifications for critical failures.
+
+5. **Data Validation**: Before sending requests, it could validate the data to ensure it meets the API's expected format, types, and value ranges, reducing the likelihood of errors and improving system reliability.
diff --git a/packages/taler-util/src/http-client/merchant.ts b/packages/taler-util/src/http-client/merchant.ts
new file mode 100644
index 000000000..32384f8b4
--- /dev/null
+++ b/packages/taler-util/src/http-client/merchant.ts
@@ -0,0 +1,679 @@
+/*
+ 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 <http://www.gnu.org/licenses/>
+ */
+
+import {
+ HttpStatusCode,
+ LibtoolVersion,
+ MerchantApiClient,
+ TalerMerchantApi,
+ codecForMerchantConfig
+} from "@gnu-taler/taler-util";
+import {
+ HttpRequestLibrary,
+ createPlatformHttpLib,
+} from "@gnu-taler/taler-util/http";
+import {
+ FailCasesByMethod,
+ ResultByMethod,
+ opSuccessFromHttp,
+ opUnknownFailure,
+} from "../operation.js";
+import { CacheEvictor, nullEvictor } from "./utils.js";
+
+export enum TalerMerchantCacheEviction {
+ CREATE_ORDER,
+}
+/**
+ * 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.
+ */
+class TalerMerchantInstanceHttpClient {
+
+ readonly httpLib: HttpRequestLibrary;
+ readonly cacheEvictor: CacheEvictor<TalerMerchantCacheEviction>;
+
+ constructor(
+ readonly baseUrl: string,
+ httpClient?: HttpRequestLibrary,
+ cacheEvictor?: CacheEvictor<TalerMerchantCacheEviction>,
+ ) {
+ this.httpLib = httpClient ?? createPlatformHttpLib();
+ this.cacheEvictor = cacheEvictor ?? nullEvictor;
+ }
+
+ //
+ // Wallet API
+ //
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-orders-$ORDER_ID-claim
+ */
+ async claimOrder(orderId: string, body: TalerMerchantApi.ClaimRequest) {
+ const url = new URL(`orders/${orderId}/claim`, this.baseUrl);
+
+ const resp = await this.httpLib.fetch(url.href, {
+ method: "POST",
+ body,
+ });
+ // switch (resp.status) {
+ // case HttpStatusCode.Ok:
+ // return opSuccessFromHttp(resp, codecForClaimResponse());
+ // case HttpStatusCode.Conflict:
+ // 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-merchant.html#post-[-instances-$INSTANCE]-orders-$ORDER_ID-pay
+ */
+ async makePayment(orderId: string, body: TalerMerchantApi.PayRequest) {
+ const url = new URL(`orders/${orderId}/pay`, this.baseUrl);
+
+ const resp = await this.httpLib.fetch(url.href, {
+ method: "POST",
+ body,
+ });
+
+ ///
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-orders-$ORDER_ID
+ */
+
+ async getPaymentStatus(orderId: string, params: TalerMerchantApi.PaymentStatusRequestParams = {}) {
+ const url = new URL(`orders/${orderId}`, this.baseUrl);
+
+ if (params.allowRefundedForRepurchase !== undefined) {
+ url.searchParams.set("allow_refunded_for_repurchase", params.allowRefundedForRepurchase ? "YES" : "NO")
+ }
+ if (params.awaitRefundObtained !== undefined) {
+ url.searchParams.set("await_refund_obtained", params.allowRefundedForRepurchase ? "YES" : "NO")
+ }
+ if (params.claimToken !== undefined) {
+ url.searchParams.set("token", params.claimToken)
+ }
+ if (params.contractTermHash !== undefined) {
+ url.searchParams.set("h_contract", params.contractTermHash)
+ }
+ if (params.refund !== undefined) {
+ url.searchParams.set("refund", params.refund)
+ }
+ if (params.sessionId !== undefined) {
+ url.searchParams.set("session_id", params.sessionId)
+ }
+ if (params.timeout !== undefined) {
+ url.searchParams.set("timeout_ms", String(params.timeout))
+ }
+
+ const resp = await this.httpLib.fetch(url.href, {
+ method: "GET",
+ // body,
+ });
+
+ ///
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#demonstrating-payment
+ */
+ async demostratePayment(orderId: string, body: TalerMerchantApi.PaidRequest) {
+ const url = new URL(`orders/${orderId}/paid`, this.baseUrl);
+
+ const resp = await this.httpLib.fetch(url.href, {
+ method: "POST",
+ body,
+ });
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#aborting-incomplete-payments
+ */
+ async abortIncompletePayment(orderId: string, body: TalerMerchantApi.AbortRequest) {
+ const url = new URL(`orders/${orderId}/abort`, this.baseUrl);
+
+ const resp = await this.httpLib.fetch(url.href, {
+ method: "POST",
+ body,
+ });
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#obtaining-refunds
+ */
+ async obtainRefund(orderId: string, body: TalerMerchantApi.WalletRefundRequest) {
+ const url = new URL(`orders/${orderId}/refund`, this.baseUrl);
+
+ const resp = await this.httpLib.fetch(url.href, {
+ method: "POST",
+ body,
+ });
+ }
+
+ //
+ // Management
+ //
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-auth
+ */
+ async updateCurrentInstanceAuthentication(body: TalerMerchantApi.InstanceAuthConfigurationMessage) {
+ const url = new URL(`private/auth`, this.baseUrl);
+
+ const resp = await this.httpLib.fetch(url.href, {
+ method: "POST",
+ body,
+ });
+
+ //
+ }
+
+ /**
+ * Get the auth api agaisnt the current instance
+ *
+ * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-token
+ * https://docs.taler.net/core/api-merchant.html#delete-[-instances-$INSTANCE]-private-token
+ */
+ getAuthenticationAPI(): URL {
+ return new URL(`/`, this.baseUrl);
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#patch-[-instances-$INSTANCE]-private
+ */
+ async updateCurrentInstance(body: TalerMerchantApi.InstanceReconfigurationMessage) {
+ const url = new URL(`private`, this.baseUrl);
+
+ const resp = await this.httpLib.fetch(url.href, {
+ method: "PATCH",
+ body,
+ });
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private
+ *
+ */
+ async getCurrentInstance() {
+ const url = new URL(`private`, this.baseUrl);
+
+ const resp = await this.httpLib.fetch(url.href, {
+ method: "GET",
+ });
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#delete-[-instances-$INSTANCE]-private
+ */
+ async deleteCurrentInstance(params: { purge?: boolean }) {
+ const url = new URL(`private`, this.baseUrl);
+
+ if (params.purge) {
+ url.searchParams.set("purge", "YES")
+ }
+
+ const resp = await this.httpLib.fetch(url.href, {
+ method: "DELETE",
+ });
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#get--instances-$INSTANCE-private-kyc
+ */
+ async getCurrentIntanceKycStatus(params: { wireHash?: string, exchangeURL?: string, timeout: number }) {
+ const url = new URL(`private/kyc`, this.baseUrl);
+
+ if (params.wireHash) {
+ url.searchParams.set("h_wire", params.wireHash)
+ }
+ if (params.exchangeURL) {
+ url.searchParams.set("exchange_url", params.exchangeURL)
+ }
+ if (params.timeout) {
+ url.searchParams.set("timeout_ms", String(params.timeout))
+ }
+
+ const resp = await this.httpLib.fetch(url.href, {
+ method: "GET",
+ });
+
+ }
+
+ //
+ // Bank Accounts
+ //
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-accounts
+ */
+ async addAccount(body: TalerMerchantApi.AccountAddDetails) {
+ const url = new URL(`private/accounts`, this.baseUrl);
+
+ const resp = await this.httpLib.fetch(url.href, {
+ method: "POST",
+ body,
+ });
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#patch-[-instances-$INSTANCE]-private-accounts-$H_WIRE
+ */
+ async updateAccount(wireAccount: string, body: TalerMerchantApi.AccountPatchDetails) {
+ const url = new URL(`private/accounts/${wireAccount}`, this.baseUrl);
+
+ const resp = await this.httpLib.fetch(url.href, {
+ method: "PATCH",
+ body,
+ });
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private-accounts
+ */
+ async listAccounts() {
+ const url = new URL(`private/accounts`, this.baseUrl);
+
+ const resp = await this.httpLib.fetch(url.href, {
+ method: "GET",
+ });
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private-accounts-$H_WIRE
+ */
+ async getAccount(wireAccount: string) {
+ const url = new URL(`private/accounts/${wireAccount}`, this.baseUrl);
+
+ const resp = await this.httpLib.fetch(url.href, {
+ method: "GET",
+ });
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#delete-[-instances-$INSTANCE]-private-accounts-$H_WIRE
+ */
+ async deleteAccount(wireAccount: string) {
+ const url = new URL(`private/accounts/${wireAccount}`, this.baseUrl);
+
+ const resp = await this.httpLib.fetch(url.href, {
+ method: "DELETE",
+ });
+ }
+
+ //
+ // Inventory Management
+ //
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-products
+ */
+ async addProduct() {
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#patch-[-instances-$INSTANCE]-private-products-$PRODUCT_ID
+ */
+ async updateProduct() {
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private-products
+ */
+ async listProducts() {
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private-products-$PRODUCT_ID
+ */
+ async getProduct() {
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#reserving-inventory
+ */
+ async lockProduct() {
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#removing-products-from-inventory
+ */
+ async removeProduct() {
+ }
+
+ //
+ // Payment processing
+ //
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-orders
+ */
+ async createOrder() {
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#inspecting-orders
+ */
+ async listOrders() {
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private-orders-$ORDER_ID
+ */
+ async getOrder() {
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#private-order-data-cleanup
+ */
+ async forgetOrder() {
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#delete-[-instances-$INSTANCE]-private-orders-$ORDER_ID
+ */
+ async deleteOrder() {
+ }
+
+ //
+ // Refunds
+ //
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-orders-$ORDER_ID-refund
+ */
+ async addRefund() {
+ }
+
+ //
+ // Wire Transfer
+ //
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-transfers
+ */
+ async informWireTransfer() {
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private-transfers
+ */
+ async listWireTransfers() {
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#delete-[-instances-$INSTANCE]-private-transfers-$TID
+ */
+ async deleteWireTransfer() {
+ }
+
+ //
+ // OTP Devices
+ //
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-otp-devices
+ */
+ async addOtpDevice() {
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#patch-[-instances-$INSTANCE]-private-otp-devices-$DEVICE_ID
+ */
+ async updateOtpDevice() {
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private-otp-devices
+ */
+ async listOtpDevices() {
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private-otp-devices-$DEVICE_ID
+ */
+ async getOtpDevice() {
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#delete-[-instances-$INSTANCE]-private-otp-devices-$DEVICE_ID
+ */
+ async deleteOtpDevice() {
+ }
+
+ //
+ // Templates
+ //
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-templates
+ */
+ async addTemplate() {
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#patch-[-instances-$INSTANCE]-private-templates-$TEMPLATE_ID
+ */
+ async updateTemplate() {
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#inspecting-template
+ */
+ async listTemplates() {
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private-templates-$TEMPLATE_ID
+ */
+ async getTemplate() {
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#delete-[-instances-$INSTANCE]-private-templates-$TEMPLATE_ID
+ */
+ async deleteTemplate() {
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCES]-templates-$TEMPLATE_ID
+ */
+ async useTemplate() {
+ }
+
+ //
+ // Webhooks
+ //
+
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCES]-private-webhooks
+ */
+ async addWebhook() {
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#patch-[-instances-$INSTANCES]-private-webhooks-$WEBHOOK_ID
+ */
+ async updateWebhook() {
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCES]-private-webhooks
+ */
+ async listWebhooks() {
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCES]-private-webhooks-$WEBHOOK_ID
+ */
+ async getWebhook() {
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#delete-[-instances-$INSTANCES]-private-webhooks-$WEBHOOK_ID
+ */
+ async removeWebhook() {
+ }
+
+ //
+ // token families
+ //
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCES]-private-tokenfamilies
+ */
+ async createTokenFamily() {
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#patch-[-instances-$INSTANCES]-private-tokenfamilies-$TOKEN_FAMILY_SLUG
+ */
+ async updateTokenFamily() {
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCES]-private-tokenfamilies
+ */
+ async listTokenFamilies() {
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCES]-private-tokenfamilies-$TOKEN_FAMILY_SLUG
+ */
+ async getTokenFamily() {
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#delete-[-instances-$INSTANCES]-private-tokenfamilies-$TOKEN_FAMILY_SLUG
+ */
+ async deleteTokenFamily() {
+ }
+
+}
+
+export class TalerMerchantManagementHttpClient extends TalerMerchantInstanceHttpClient {
+ public readonly PROTOCOL_VERSION = "10:0:6";
+
+ httpLib: HttpRequestLibrary;
+ cacheEvictor: CacheEvictor<TalerMerchantCacheEviction>;
+ constructor(
+ readonly baseUrl: string,
+ httpClient?: HttpRequestLibrary,
+ cacheEvictor?: CacheEvictor<TalerMerchantCacheEviction>,
+ ) {
+ super(baseUrl, httpClient, cacheEvictor)
+ }
+
+ isCompatible(version: string): boolean {
+ const compare = LibtoolVersion.compare(this.PROTOCOL_VERSION, version);
+ return compare?.compatible ?? false;
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#get--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, codecForMerchantConfig());
+ default:
+ return opUnknownFailure(resp, await resp.text());
+ }
+ }
+
+
+ //
+ // Instance Management
+ //
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#post--management-instances
+ */
+ async createInstance(body: TalerMerchantApi.InstanceConfigurationMessage) {
+ const url = new URL(`management/instances`, this.baseUrl);
+
+ const resp = await this.httpLib.fetch(url.href, {
+ method: "POST",
+ body,
+ });
+
+ //
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#post--management-instances-$INSTANCE-auth
+ */
+ async updateInstanceAuthentication(body: TalerMerchantApi.InstanceAuthConfigurationMessage) {
+ const url = new URL(`management/instances`, this.baseUrl);
+
+ const resp = await this.httpLib.fetch(url.href, {
+ method: "POST",
+ body,
+ });
+
+ //
+ }
+
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#patch--management-instances-$INSTANCE
+ */
+ async updateInstance() {
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#get--management-instances
+ */
+ async listInstances() {
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#get--management-instances-$INSTANCE
+ *
+ */
+ async getInstance() {
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#delete--management-instances-$INSTANCE
+ */
+ async deleteInstance() {
+ }
+
+ /**
+ * https://docs.taler.net/core/api-merchant.html#get--management-instances-$INSTANCE-kyc
+ */
+ async getIntanceKycStatus() {
+ }
+
+
+
+
+}
diff --git a/packages/taler-util/src/http-client/types.ts b/packages/taler-util/src/http-client/types.ts
index 132ca867d..08b29106e 100644
--- a/packages/taler-util/src/http-client/types.ts
+++ b/packages/taler-util/src/http-client/types.ts
@@ -2403,6 +2403,10 @@ export namespace TalerMerchantApi {
// Name of the protocol.
name: "taler-merchant";
+ // URN of the implementation (needed to interpret 'revision' in version).
+ // @since **v8**, may become mandatory in the future.
+ implementation?: string;
+
// Default (!) currency supported by this backend.
// This is the currency that the backend should
// suggest by default to the user when entering
@@ -2417,8 +2421,27 @@ export namespace TalerMerchantApi {
// All currencies in this map are supported by
// the backend.
currencies: { [currency: string]: CurrencySpecification };
+
+ // Array of exchanges trusted by the merchant.
+ // Since protocol **v6**.
+ exchanges: ExchangeConfigInfo[];
}
+ export interface ExchangeConfigInfo {
+ // Base URL of the exchange REST API.
+ base_url: string;
+
+ // Currency for which the merchant is configured
+ // to trust the exchange.
+ // May not be the one the exchange actually uses,
+ // but is the only one we would trust this exchange for.
+ currency: string;
+
+ // Offline master public key of the exchange. The
+ // /keys data must be signed with this public
+ // key for us to trust it.
+ master_pub: EddsaPublicKey;
+ }
export interface ClaimRequest {
// Nonce to identify the wallet that claimed the order.
nonce: string;
@@ -2447,7 +2470,43 @@ export namespace TalerMerchantApi {
pos_confirmation?: string;
}
- interface PayRequest {
+ export interface PaymentStatusRequestParams {
+ // Hash of the order’s contract terms (this is used to
+ // authenticate the wallet/customer in case
+ // $ORDER_ID is guessable).
+ // Required once an order was claimed.
+ contractTermHash?: string;
+ // Authorizes the request via the claim token that
+ // was returned in the PostOrderResponse. Used with
+ // unclaimed orders only. Whether token authorization is
+ // required is determined by the merchant when the
+ // frontend creates the order.
+ claimToken?: string;
+ // Session ID that the payment must be bound to.
+ // If not specified, the payment is not session-bound.
+ sessionId?: string;
+ // If specified, the merchant backend will wait up to
+ // timeout_ms milliseconds for completion of the payment
+ // before sending the HTTP response. A client must never
+ // rely on this behavior, as the merchant backend may return
+ // a response immediately.
+ timeout?: number;
+ // If set to “yes”, poll for the order’s pending refunds
+ // to be picked up. timeout_ms specifies how long we
+ // will wait for the refund.
+ awaitRefundObtained?: boolean;
+ // Indicates that we are polling for a refund above the
+ // given AMOUNT. timeout_ms will specify how long we
+ // will wait for the refund.
+ refund?: AmountString;
+ // Since protocol v9 refunded orders are only returned
+ // under “already_paid_order_id” if this flag is set
+ // explicitly to “YES”.
+ allowRefundedForRepurchase?: boolean;
+
+ }
+
+ export interface PayRequest {
// The coins used to make the payment.
coins: CoinPaySig[];
@@ -2520,7 +2579,7 @@ export namespace TalerMerchantApi {
// refunds. False if it was simply paid.
refunded: boolean;
}
- interface PaidRequest {
+ export interface PaidRequest {
// Signature on TALER_PaymentResponsePS with the public
// key of the merchant instance.
sig: EddsaSignature;
@@ -2537,7 +2596,7 @@ export namespace TalerMerchantApi {
session_id: string;
}
- interface AbortRequest {
+ export interface AbortRequest {
// Hash of the order's contract terms (this is used to authenticate the
// wallet/customer in case $ORDER_ID is guessable).
h_contract: HashCode;
@@ -2603,7 +2662,7 @@ export namespace TalerMerchantApi {
exchange_pub: EddsaPublicKey;
}
- interface WalletRefundRequest {
+ export interface WalletRefundRequest {
// Hash of the order's contract terms (this is used to authenticate the
// wallet/customer).
h_contract: HashCode;
@@ -2723,7 +2782,7 @@ export namespace TalerMerchantApi {
blind_sig: BlindedRsaSignature;
}
- interface InstanceConfigurationMessage {
+ export interface InstanceConfigurationMessage {
// Name of the merchant instance to create (will become $INSTANCE).
// Must match the regex ^[A-Za-z0-9][A-Za-z0-9_.@-]+$.
id: string;
@@ -2771,7 +2830,7 @@ export namespace TalerMerchantApi {
default_pay_delay: RelativeTime;
}
- interface InstanceAuthConfigurationMessage {
+ export interface InstanceAuthConfigurationMessage {
// Type of authentication.
// "external": The mechant backend does not do
// any authentication checks. Instead an API
@@ -2788,37 +2847,8 @@ export namespace TalerMerchantApi {
token?: string;
}
- interface LoginTokenRequest {
- // Scope of the token (which kinds of operations it will allow)
- scope: "readonly" | "write";
-
- // Server may impose its own upper bound
- // on the token validity duration
- duration?: RelativeTime;
-
- // Can this token be refreshed?
- // Defaults to false.
- refreshable?: boolean;
- }
- interface LoginTokenSuccessResponse {
- // The login token that can be used to access resources
- // that are in scope for some time. Must be prefixed
- // with "Bearer " when used in the "Authorization" HTTP header.
- // Will already begin with the RFC 8959 prefix.
- token: string;
-
- // Scope of the token (which kinds of operations it will allow)
- scope: "readonly" | "write";
-
- // Server may impose its own upper bound
- // on the token validity duration
- expiration: Timestamp;
-
- // Can this token be refreshed?
- refreshable: boolean;
- }
- interface InstanceReconfigurationMessage {
+ export interface InstanceReconfigurationMessage {
// Merchant name corresponding to this instance.
name: string;
@@ -2980,7 +3010,7 @@ export namespace TalerMerchantApi {
exchange_http_status: number;
}
- interface AccountAddDetails {
+ export interface AccountAddDetails {
// payto:// URI of the account.
payto_uri: PaytoString;
@@ -3017,7 +3047,7 @@ export namespace TalerMerchantApi {
salt: HashCode;
}
- interface AccountPatchDetails {
+ export interface AccountPatchDetails {
// URL from where the merchant can download information
// about incoming wire transfers to this account.
credit_facade_url?: string;