summaryrefslogtreecommitdiff
path: root/packages
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2024-03-27 01:05:10 -0300
committerSebastian <sebasjm@gmail.com>2024-03-27 01:05:10 -0300
commit237c4e8adae997e84f5fb7a8fe5c03b1148e99dc (patch)
tree26ec2b1a82e730af080aae4625b736aaa77dfec7 /packages
parentecb8c2078ebe94d81a6e03ebfe01ecdde53109e2 (diff)
downloadwallet-core-237c4e8adae997e84f5fb7a8fe5c03b1148e99dc.tar.gz
wallet-core-237c4e8adae997e84f5fb7a8fe5c03b1148e99dc.tar.bz2
wallet-core-237c4e8adae997e84f5fb7a8fe5c03b1148e99dc.zip
wip #8655
Diffstat (limited to 'packages')
-rw-r--r--packages/merchant-backoffice-ui/src/Application.tsx39
-rw-r--r--packages/merchant-backoffice-ui/src/components/form/InputStock.tsx9
-rw-r--r--packages/merchant-backoffice-ui/src/context/instance.ts35
-rw-r--r--packages/merchant-backoffice-ui/src/context/session.ts7
-rw-r--r--packages/merchant-backoffice-ui/src/declaration.d.ts1647
-rw-r--r--packages/merchant-backoffice-ui/src/hooks/backend.ts10
-rw-r--r--packages/merchant-backoffice-ui/src/hooks/instance.test.ts37
-rw-r--r--packages/merchant-backoffice-ui/src/hooks/instance.ts211
-rw-r--r--packages/merchant-backoffice-ui/src/hooks/templates.ts22
-rw-r--r--packages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx2
-rw-r--r--packages/merchant-backoffice-ui/src/paths/admin/create/index.tsx8
-rw-r--r--packages/merchant-backoffice-ui/src/paths/admin/list/index.tsx21
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/details/index.tsx12
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/templates/list/index.tsx2
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/token/DetailPage.tsx7
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx12
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/update/index.tsx30
-rw-r--r--packages/taler-util/src/http-client/merchant.ts4
-rw-r--r--packages/taler-util/src/http-client/types.ts4
-rw-r--r--packages/web-util/src/context/merchant-api.ts25
-rw-r--r--packages/web-util/src/utils/request.ts2
21 files changed, 146 insertions, 2000 deletions
diff --git a/packages/merchant-backoffice-ui/src/Application.tsx b/packages/merchant-backoffice-ui/src/Application.tsx
index d752d612d..497f49c0e 100644
--- a/packages/merchant-backoffice-ui/src/Application.tsx
+++ b/packages/merchant-backoffice-ui/src/Application.tsx
@@ -19,12 +19,14 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
-import { canonicalizeBaseUrl } from "@gnu-taler/taler-util";
+import { TalerMerchantApi, assertUnreachable, canonicalizeBaseUrl } from "@gnu-taler/taler-util";
import {
BrowserHashNavigationProvider,
+ ConfigResultFail,
MerchantApiProvider,
TalerWalletIntegrationBrowserProvider,
- TranslationProvider
+ TranslationProvider,
+ useTranslationContext
} from "@gnu-taler/web-util/browser";
import { VNode, h } from "preact";
import { useEffect, useState } from "preact/hooks";
@@ -34,8 +36,10 @@ import { Loading } from "./components/exception/loading.js";
import { SettingsProvider } from "./context/settings.js";
import { strings } from "./i18n/strings.js";
import { MerchantUiSettings, buildDefaultBackendBaseURL, fetchSettings } from "./settings.js";
+import { NotificationCard } from "./components/menu/index.js";
const WITH_LOCAL_STORAGE_CACHE = false;
+
export function Application(): VNode {
const [settings, setSettings] = useState<MerchantUiSettings>();
useEffect(() => {
@@ -53,7 +57,7 @@ export function Application(): VNode {
de: strings["de"].completeness,
}}
>
- <MerchantApiProvider baseUrl={new URL("/", baseUrl)} frameOnError={({ children }) => <div>{children}</div>}>
+ <MerchantApiProvider baseUrl={new URL("/", baseUrl)} frameOnError={OnConfigError}>
<SWRConfig
value={{
provider: WITH_LOCAL_STORAGE_CACHE
@@ -136,3 +140,32 @@ function localStorageProvider(): Map<unknown, unknown> {
});
return map;
}
+
+function OnConfigError({ state }: { state: ConfigResultFail<TalerMerchantApi.VersionResponse> | undefined }): VNode {
+ const { i18n } = useTranslationContext();
+ if (!state) {
+ return <i18n.Translate>checking compatibility with server...</i18n.Translate>
+ }
+ switch (state.type) {
+ case "error": {
+ return <NotificationCard
+ notification={{
+ message: i18n.str`Contacting the server failed`,
+ description: state.error.message,
+ details: JSON.stringify(state.error.errorDetail, undefined, 2),
+ type: "ERROR",
+ }}
+ />
+ }
+ case "incompatible": {
+ return <NotificationCard
+ notification={{
+ message: i18n.str`The server version is not supported`,
+ description: i18n.str`Supported version "${state.supported}", server version "${state.result.version}".`,
+ type: "WARN",
+ }}
+ />
+ }
+ default: assertUnreachable(state)
+ }
+}
diff --git a/packages/merchant-backoffice-ui/src/components/form/InputStock.tsx b/packages/merchant-backoffice-ui/src/components/form/InputStock.tsx
index e47259732..8104d1f9f 100644
--- a/packages/merchant-backoffice-ui/src/components/form/InputStock.tsx
+++ b/packages/merchant-backoffice-ui/src/components/form/InputStock.tsx
@@ -18,7 +18,8 @@
*
* @author Sebastian Javier Marchano (sebasjm)
*/
-import { Location, useTranslationContext } from "@gnu-taler/web-util/browser";
+import { TalerMerchantApi, TalerProtocolTimestamp } from "@gnu-taler/taler-util";
+import { useTranslationContext } from "@gnu-taler/web-util/browser";
import { Fragment, h } from "preact";
import { useLayoutEffect, useState } from "preact/hooks";
import { FormErrors, FormProvider } from "./FormProvider.js";
@@ -27,7 +28,6 @@ import { InputGroup } from "./InputGroup.js";
import { InputLocation } from "./InputLocation.js";
import { InputNumber } from "./InputNumber.js";
import { InputProps, useField } from "./useField.js";
-import { TalerMerchantApi } from "@gnu-taler/taler-util";
export interface Props<T> extends InputProps<T> {
alreadyExist?: boolean;
@@ -40,7 +40,7 @@ export interface Stock {
lost: number;
sold: number;
address?: TalerMerchantApi.Location;
- nextRestock?: Timestamp;
+ nextRestock?: TalerProtocolTimestamp;
}
interface StockDelta {
@@ -133,8 +133,7 @@ export function InputStock<T>({
const stockAddedErrors: FormErrors<typeof addedStock> = {
lost:
currentStock + addedStock.incoming < addedStock.lost
- ? i18n.str`lost cannot be greater than current and incoming (max ${
- currentStock + addedStock.incoming
+ ? i18n.str`lost cannot be greater than current and incoming (max ${currentStock + addedStock.incoming
})`
: undefined,
};
diff --git a/packages/merchant-backoffice-ui/src/context/instance.ts b/packages/merchant-backoffice-ui/src/context/instance.ts
deleted file mode 100644
index 9b67f7170..000000000
--- a/packages/merchant-backoffice-ui/src/context/instance.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021-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/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import { createContext } from "preact";
-import { useContext } from "preact/hooks";
-
-interface Type {
- id: string;
- token?: LoginToken;
- admin?: boolean;
- changeToken: (t?: LoginToken) => void;
-}
-
-const Context = createContext<Type>({} as any);
-
-const InstanceContextProvider = Context.Provider;
-const useInstanceContext = (): Type => useContext(Context);
diff --git a/packages/merchant-backoffice-ui/src/context/session.ts b/packages/merchant-backoffice-ui/src/context/session.ts
index 83f3f113a..9d63d8e33 100644
--- a/packages/merchant-backoffice-ui/src/context/session.ts
+++ b/packages/merchant-backoffice-ui/src/context/session.ts
@@ -215,7 +215,8 @@ export function useSessionContext(): SessionStateHandler {
.href,
isAdmin: info.instance === DEFAULT_ADMIN_USERNAME,
instance: info.instance,
- token: info.token,
+ // FIXME: bank and merchant should have consistent behavior
+ token: info.token?.substring("secret-token:".length) as AccessToken,
impersonate: {
originalBackendUrl: state.backendUrl,
originalToken: state.token,
@@ -239,7 +240,9 @@ export function useSessionContext(): SessionStateHandler {
impersonate: undefined,
...state,
status: "loggedIn",
- token: info.token,
+ // FIXME: bank and merchant should have consistent behavior
+ token: info.token?.substring("secret-token:".length) as AccessToken,
+ // token: info.token,
};
update(nextState);
cleanAllCache();
diff --git a/packages/merchant-backoffice-ui/src/declaration.d.ts b/packages/merchant-backoffice-ui/src/declaration.d.ts
index 93fecd9c4..1baf80ba6 100644
--- a/packages/merchant-backoffice-ui/src/declaration.d.ts
+++ b/packages/merchant-backoffice-ui/src/declaration.d.ts
@@ -19,1653 +19,6 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
-type HashCode = string;
-type EddsaPublicKey = string;
-type EddsaSignature = string;
-type WireTransferIdentifierRawP = string;
-type RelativeTime = TalerProtocolDuration;
-type ImageDataUrl = string;
-type MerchantUserType = "business" | "individual";
-
-
-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 TalerProtocolDuration {
- d_us: number | "forever";
-}
-interface Duration {
- d_ms: number | "forever";
-}
-
interface WithId {
id: string;
}
-
-type Amount = string;
-type UUID = string;
-type Integer = number;
-
-interface WireAccount {
- // payto:// URI identifying the account and wire method
- payto_uri: string;
-
- // URI to convert amounts from or to the currency used by
- // this wire account of the exchange. Missing if no
- // conversion is applicable.
- conversion_url?: string;
-
- // Restrictions that apply to bank accounts that would send
- // funds to the exchange (crediting this exchange bank account).
- // Optional, empty array for unrestricted.
- credit_restrictions: AccountRestriction[];
-
- // Restrictions that apply to bank accounts that would receive
- // funds from the exchange (debiting this exchange bank account).
- // Optional, empty array for unrestricted.
- debit_restrictions: AccountRestriction[];
-
- // Signature using the exchange's offline key over
- // a TALER_MasterWireDetailsPS
- // with purpose TALER_SIGNATURE_MASTER_WIRE_DETAILS.
- master_sig: EddsaSignature;
-}
-
-type AccountRestriction = RegexAccountRestriction | DenyAllAccountRestriction;
-
-// Account restriction that disables this type of
-// account for the indicated operation categorically.
-interface DenyAllAccountRestriction {
- type: "deny";
-}
-
-// Accounts interacting with this type of account
-// restriction must have a payto://-URI matching
-// the given regex.
-interface RegexAccountRestriction {
- type: "regex";
-
- // Regular expression that the payto://-URI of the
- // partner account must follow. The regular expression
- // should follow posix-egrep, but without support for character
- // classes, GNU extensions, back-references or intervals. See
- // https://www.gnu.org/software/findutils/manual/html_node/find_html/posix_002degrep-regular-expression-syntax.html
- // for a description of the posix-egrep syntax. Applications
- // may support regexes with additional features, but exchanges
- // must not use such regexes.
- payto_regex: string;
-
- // Hint for a human to understand the restriction
- // (that is hopefully easier to comprehend than the regex itself).
- human_hint: string;
-
- // Map from IETF BCP 47 language tags to localized
- // human hints.
- human_hint_i18n?: { [lang_tag: string]: string };
-}
-interface LoginToken {
- token: string,
- expiration: Timestamp,
-}
-// token used to get loginToken
-// must forget after used
-declare const __ac_token: unique symbol;
-
-namespace dead_ExchangeBackend2 {
- interface WireResponse {
- // Master public key of the exchange, must match the key returned in /keys.
- master_public_key: EddsaPublicKey;
-
- // Array of wire accounts operated by the exchange for
- // incoming wire transfers.
- accounts: WireAccount[];
-
- // Object mapping names of wire methods (i.e. "sepa" or "x-taler-bank")
- // to wire fees.
- fees: { method: AggregateTransferFee };
- }
- interface AggregateTransferFee {
- // Per transfer wire transfer fee.
- wire_fee: Amount;
-
- // Per transfer closing fee.
- closing_fee: Amount;
-
- // What date (inclusive) does this fee go into effect?
- // The different fees must cover the full time period in which
- // any of the denomination keys are valid without overlap.
- start_date: Timestamp;
-
- // What date (exclusive) does this fee stop going into effect?
- // The different fees must cover the full time period in which
- // any of the denomination keys are valid without overlap.
- end_date: Timestamp;
-
- // Signature of TALER_MasterWireFeePS with
- // purpose TALER_SIGNATURE_MASTER_WIRE_FEES.
- sig: EddsaSignature;
- }
-}
-namespace dead_MerchantBackend2 {
- interface ErrorDetail {
- // Numeric error code unique to the condition.
- // The other arguments are specific to the error value reported here.
- code: number;
-
- // Human-readable description of the error, i.e. "missing parameter", "commitment violation", ...
- // Should give a human-readable hint about the error's nature. Optional, may change without notice!
- hint?: string;
-
- // Optional detail about the specific input value that failed. May change without notice!
- detail?: string;
-
- // Name of the parameter that was bogus (if applicable).
- parameter?: string;
-
- // Path to the argument that was bogus (if applicable).
- path?: string;
-
- // Offset of the argument that was bogus (if applicable).
- offset?: string;
-
- // Index of the argument that was bogus (if applicable).
- index?: string;
-
- // Name of the object that was bogus (if applicable).
- object?: string;
-
- // Name of the currency than was problematic (if applicable).
- currency?: string;
-
- // Expected type (if applicable).
- type_expected?: string;
-
- // Type that was provided instead (if applicable).
- type_actual?: string;
- }
-
- // Delivery location, loosely modeled as a subset of
- // ISO20022's PostalAddress25.
- interface Tax {
- // the name of the tax
- name: string;
-
- // amount paid in tax
- tax: Amount;
- }
-
- interface Auditor {
- // official name
- name: string;
-
- // Auditor's public key
- auditor_pub: EddsaPublicKey;
-
- // Base URL of the auditor
- url: string;
- }
- interface Exchange {
- // the exchange's base URL
- url: string;
-
- // master public key of the exchange
- master_pub: EddsaPublicKey;
- }
-
- interface Product {
- // merchant-internal identifier for the product.
- product_id?: string;
-
- // Human-readable product description.
- description: string;
-
- // Map from IETF BCP 47 language tags to localized descriptions
- description_i18n?: { [lang_tag: string]: string };
-
- // The number of units of the product to deliver to the customer.
- quantity: Integer;
-
- // The unit in which the product is measured (liters, kilograms, packages, etc.)
- unit: string;
-
- // The price of the product; this is the total price for quantity times unit of this product.
- price?: Amount;
-
- // An optional base64-encoded product image
- image: ImageDataUrl;
-
- // a list of taxes paid by the merchant for this product. Can be empty.
- taxes: Tax[];
-
- // time indicating when this product should be delivered
- delivery_date?: TalerProtocolTimestamp;
-
- // Minimum age buyer must have (in years). Default is 0.
- minimum_age?: Integer;
- }
- interface Merchant {
- // label for a location with the business address of the merchant
- address: Location;
-
- // the merchant's legal name of business
- name: string;
-
- // label for a location that denotes the jurisdiction for disputes.
- // Some of the typical fields for a location (such as a street address) may be absent.
- jurisdiction: Location;
- }
-
- interface VersionResponse {
- // libtool-style representation of the Merchant protocol version, see
- // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning
- // The format is "current:revision:age".
- version: string;
-
- // Name of the protocol.
- name: "taler-merchant";
-
- // Default (!) currency supported by this backend.
- // This is the currency that the backend should
- // suggest by default to the user when entering
- // amounts. See currencies for a list of
- // supported currencies and how to render them.
- currency: string;
-
- // How services should render currencies supported
- // by this backend. Maps
- // currency codes (e.g. "EUR" or "KUDOS") to
- // the respective currency specification.
- // All currencies in this map are supported by
- // the backend. Note that the actual currency
- // specifications are a *hint* for applications
- // that would like *advice* on how to render amounts.
- // Applications *may* ignore the currency specification
- // if they know how to render currencies that they are
- // used with.
- currencies: { currency: CurrencySpecification };
-
- // Array of exchanges trusted by the merchant.
- // Since protocol v6.
- exchanges: ExchangeConfigInfo[];
- }
-
- 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;
- }
- interface Location {
- // Nation with its own government.
- country?: string;
-
- // Identifies a subdivision of a country such as state, region, county.
- country_subdivision?: string;
-
- // Identifies a subdivision within a country sub-division.
- district?: string;
-
- // Name of a built-up area, with defined boundaries, and a local government.
- town?: string;
-
- // Specific location name within the town.
- town_location?: string;
-
- // Identifier consisting of a group of letters and/or numbers that
- // is added to a postal address to assist the sorting of mail.
- post_code?: string;
-
- // Name of a street or thoroughfare.
- street?: string;
-
- // Name of the building or house.
- building_name?: string;
-
- // Number that identifies the position of a building on a street.
- building_number?: string;
-
- // Free-form address lines, should not exceed 7 elements.
- address_lines?: string[];
- }
- namespace dead_Instances2 {
- //POST /private/instances/$INSTANCE/auth
- interface InstanceAuthConfigurationMessage {
- // Type of authentication.
- // "external": The mechant backend does not do
- // any authentication checks. Instead an API
- // gateway must do the authentication.
- // "token": The merchant checks an auth token.
- // See "token" for details.
- method: "external" | "token";
-
- // For method "external", this field is mandatory.
- // The token MUST begin with the string "secret-token:".
- // After the auth token has been set (with method "token"),
- // the value must be provided in a "Authorization: Bearer $token"
- // header.
- token?: string;
- }
- //POST /private/instances
- interface InstanceConfigurationMessage {
- // Name of the merchant instance to create (will become $INSTANCE).
- id: string;
-
- // Merchant name corresponding to this instance.
- name: string;
-
- // Type of the user (business or individual).
- // Defaults to 'business'. Should become mandatory field
- // in the future, left as optional for API compatibility for now.
- user_type?: MerchantUserType;
-
- // Merchant email for customer contact.
- email?: string;
-
- // Merchant public website.
- website?: string;
-
- // Merchant logo.
- logo?: ImageDataUrl;
-
- // "Authentication" header required to authorize management access the instance.
- // Optional, if not given authentication will be disabled for
- // this instance (hopefully authentication checks are still
- // done by some reverse proxy).
- auth: InstanceAuthConfigurationMessage;
-
- // The merchant's physical address (to be put into contracts).
- address: Location;
-
- // The jurisdiction under which the merchant conducts its business
- // (to be put into contracts).
- jurisdiction: Location;
-
- // Use STEFAN curves to determine default fees?
- // If false, no fees are allowed by default.
- // Can always be overridden by the frontend on a per-order basis.
- use_stefan: boolean;
-
- // If the frontend does NOT specify an execution date, how long should
- // we tell the exchange to wait to aggregate transactions before
- // executing the wire transfer? This delay is added to the current
- // time when we generate the advisory execution time for the exchange.
- default_wire_transfer_delay: RelativeTime;
-
- // If the frontend does NOT specify a payment deadline, how long should
- // offers we make be valid by default?
- default_pay_delay: RelativeTime;
- }
-
- // PATCH /private/instances/$INSTANCE
- interface InstanceReconfigurationMessage {
-
- // Merchant name corresponding to this instance.
- name: string;
-
- // Type of the user (business or individual).
- // Defaults to 'business'. Should become mandatory field
- // in the future, left as optional for API compatibility for now.
- user_type?: MerchantUserType;
-
- // Merchant email for customer contact.
- email?: string;
-
- // Merchant public website.
- website?: string;
-
- // Merchant logo.
- logo?: ImageDataUrl;
-
- // The merchant's physical address (to be put into contracts).
- address: Location;
-
- // The jurisdiction under which the merchant conducts its business
- // (to be put into contracts).
- jurisdiction: Location;
-
- // Use STEFAN curves to determine default fees?
- // If false, no fees are allowed by default.
- // Can always be overridden by the frontend on a per-order basis.
- use_stefan: boolean;
-
- // If the frontend does NOT specify an execution date, how long should
- // we tell the exchange to wait to aggregate transactions before
- // executing the wire transfer? This delay is added to the current
- // time when we generate the advisory execution time for the exchange.
- default_wire_transfer_delay: RelativeTime;
-
- // If the frontend does NOT specify a payment deadline, how long should
- // offers we make be valid by default?
- default_pay_delay: RelativeTime;
- }
-
- // GET /private/instances
- interface InstancesResponse {
- // List of instances that are present in the backend (see Instance)
- instances: Instance[];
- }
-
- interface Instance {
- // Merchant name corresponding to this instance.
- name: string;
-
- // Type of the user ("business" or "individual").
- user_type: MerchantUserType;
-
- // Merchant public website.
- website?: string;
-
- // Merchant logo.
- logo?: ImageDataUrl;
-
- // Merchant instance this response is about ($INSTANCE)
- id: string;
-
- // Public key of the merchant/instance, in Crockford Base32 encoding.
- merchant_pub: EddsaPublicKey;
-
- // List of the payment targets supported by this instance. Clients can
- // specify the desired payment target in /order requests. Note that
- // front-ends do not have to support wallets selecting payment targets.
- payment_targets: string[];
-
- // Has this instance been deleted (but not purged)?
- deleted: boolean;
- }
-
- //GET /private/instances/$INSTANCE
- interface QueryInstancesResponse {
-
- // Merchant name corresponding to this instance.
- name: string;
- // Type of the user ("business" or "individual").
- user_type: MerchantUserType;
-
- // Merchant email for customer contact.
- email?: string;
-
- // Merchant public website.
- website?: string;
-
- // Merchant logo.
- logo?: ImageDataUrl;
-
- // Public key of the merchant/instance, in Crockford Base32 encoding.
- merchant_pub: EddsaPublicKey;
-
- // The merchant's physical address (to be put into contracts).
- address: Location;
-
- // The jurisdiction under which the merchant conducts its business
- // (to be put into contracts).
- jurisdiction: Location;
-
- // Use STEFAN curves to determine default fees?
- // If false, no fees are allowed by default.
- // Can always be overridden by the frontend on a per-order basis.
- use_stefan: boolean;
-
- // If the frontend does NOT specify an execution date, how long should
- // we tell the exchange to wait to aggregate transactions before
- // executing the wire transfer? This delay is added to the current
- // time when we generate the advisory execution time for the exchange.
- default_wire_transfer_delay: RelativeTime;
-
- // If the frontend does NOT specify a payment deadline, how long should
- // offers we make be valid by default?
- default_pay_delay: RelativeTime;
-
- // Authentication configuration.
- // Does not contain the token when token auth is configured.
- auth: {
- method: "external" | "token";
- };
- }
- // DELETE /private/instances/$INSTANCE
- 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;
- }
- }
-
- namespace dead_KYC {
- //GET /private/instances/$INSTANCE/kyc
- interface AccountKycRedirects {
- // Array of pending KYCs.
- pending_kycs: MerchantAccountKycRedirect[];
-
- // Array of exchanges with no reply.
- timeout_kycs: ExchangeKycTimeout[];
- }
- interface MerchantAccountKycRedirect {
- // URL that the user should open in a browser to
- // proceed with the KYC process (as returned
- // by the exchange's /kyc-check/ endpoint).
- // Optional, missing if the account is blocked
- // due to AML and not due to KYC.
- kyc_url?: string;
-
- // Base URL of the exchange this is about.
- exchange_url: string;
-
- // AML status of the account.
- aml_status: number;
-
- // Our bank wire account this is about.
- payto_uri: string;
- }
- interface ExchangeKycTimeout {
- // Base URL of the exchange this is about.
- exchange_url: string;
-
- // Numeric error code indicating errors the exchange
- // returned, or TALER_EC_INVALID for none.
- exchange_code: number;
-
- // HTTP status code returned by the exchange when we asked for
- // information about the KYC status.
- // 0 if there was no response at all.
- exchange_http_status: number;
- }
-
- }
-
- namespace dead_BankAccounts {
-
- interface AccountAddDetails {
-
- // payto:// URI of the account.
- payto_uri: string;
-
- // URL from where the merchant can download information
- // about incoming wire transfers to this account.
- credit_facade_url?: string;
-
- // Credentials to use when accessing the credit facade.
- // Never returned on a GET (as this may be somewhat
- // sensitive data). Can be set in POST
- // or PATCH requests to update (or delete) credentials.
- // To really delete credentials, set them to the type: "none".
- credit_facade_credentials?: FacadeCredentials;
-
- }
-
- type FacadeCredentials =
- | NoFacadeCredentials
- | BasicAuthFacadeCredentials;
-
- interface NoFacadeCredentials {
- type: "none";
- }
-
- interface BasicAuthFacadeCredentials {
- type: "basic";
-
- // Username to use to authenticate
- username: string;
-
- // Password to use to authenticate
- password: string;
- }
-
- interface AccountAddResponse {
- // Hash over the wire details (including over the salt).
- h_wire: HashCode;
-
- // Salt used to compute h_wire.
- salt: HashCode;
- }
-
- interface AccountPatchDetails {
-
- // URL from where the merchant can download information
- // about incoming wire transfers to this account.
- credit_facade_url?: string;
-
- // Credentials to use when accessing the credit facade.
- // Never returned on a GET (as this may be somewhat
- // sensitive data). Can be set in POST
- // or PATCH requests to update (or delete) credentials.
- // To really delete credentials, set them to the type: "none".
- credit_facade_credentials?: FacadeCredentials;
- }
-
-
- interface AccountsSummaryResponse {
-
- // List of accounts that are known for the instance.
- accounts: BankAccountEntry[];
- }
-
- interface BankAccountEntry {
- // payto:// URI of the account.
- payto_uri: string;
-
- // Hash over the wire details (including over the salt)
- h_wire: HashCode;
-
- // salt used to compute h_wire
- salt: HashCode;
-
- // URL from where the merchant can download information
- // about incoming wire transfers to this account.
- credit_facade_url?: string;
-
- // Credentials to use when accessing the credit facade.
- // Never returned on a GET (as this may be somewhat
- // sensitive data). Can be set in POST
- // or PATCH requests to update (or delete) credentials.
- credit_facade_credentials?: FacadeCredentials;
-
- // true if this account is active,
- // false if it is historic.
- active: boolean;
- }
-
- }
-
- namespace dead_Products {
- // POST /private/products
- interface ProductAddDetail {
- // product ID to use.
- product_id: string;
-
- // Human-readable product description.
- description: string;
-
- // Map from IETF BCP 47 language tags to localized descriptions
- description_i18n: { [lang_tag: string]: string };
-
- // unit in which the product is measured (liters, kilograms, packages, etc.)
- unit: string;
-
- // The price for one unit of the product. Zero is used
- // to imply that this product is not sold separately, or
- // that the price is not fixed, and must be supplied by the
- // front-end. If non-zero, this price MUST include applicable
- // taxes.
- price: Amount;
-
- // An optional base64-encoded product image
- image: ImageDataUrl;
-
- // a list of taxes paid by the merchant for one unit of this product
- taxes: Tax[];
-
- // Number of units of the product in stock in sum in total,
- // including all existing sales ever. Given in product-specific
- // units.
- // A value of -1 indicates "infinite" (i.e. for "electronic" books).
- total_stock: Integer;
-
- // Identifies where the product is in stock.
- address: Location;
-
- // Identifies when we expect the next restocking to happen.
- next_restock?: Timestamp;
-
- // Minimum age buyer must have (in years). Default is 0.
- minimum_age?: Integer;
- }
- // PATCH /private/products/$PRODUCT_ID
- interface ProductPatchDetail {
- // Human-readable product description.
- description: string;
-
- // Map from IETF BCP 47 language tags to localized descriptions
- description_i18n: { [lang_tag: string]: string };
-
- // unit in which the product is measured (liters, kilograms, packages, etc.)
- unit: string;
-
- // The price for one unit of the product. Zero is used
- // to imply that this product is not sold separately, or
- // that the price is not fixed, and must be supplied by the
- // front-end. If non-zero, this price MUST include applicable
- // taxes.
- price: Amount;
-
- // An optional base64-encoded product image
- image: ImageDataUrl;
-
- // a list of taxes paid by the merchant for one unit of this product
- taxes: Tax[];
-
- // Number of units of the product in stock in sum in total,
- // including all existing sales ever. Given in product-specific
- // units.
- // A value of -1 indicates "infinite" (i.e. for "electronic" books).
- total_stock: Integer;
-
- // Number of units of the product that were lost (spoiled, stolen, etc.)
- total_lost: Integer;
-
- // Identifies where the product is in stock.
- address: Location;
-
- // Identifies when we expect the next restocking to happen.
- next_restock?: Timestamp;
-
- // Minimum age buyer must have (in years). Default is 0.
- minimum_age?: Integer;
- }
-
- // GET /private/products
- interface InventorySummaryResponse {
- // List of products that are present in the inventory
- products: InventoryEntry[];
- }
- interface InventoryEntry {
- // Product identifier, as found in the product.
- product_id: string;
- }
-
- // GET /private/products/$PRODUCT_ID
- interface ProductDetail {
- // Human-readable product description.
- description: string;
-
- // Map from IETF BCP 47 language tags to localized descriptions
- description_i18n: { [lang_tag: string]: string };
-
- // unit in which the product is measured (liters, kilograms, packages, etc.)
- unit: string;
-
- // The price for one unit of the product. Zero is used
- // to imply that this product is not sold separately, or
- // that the price is not fixed, and must be supplied by the
- // front-end. If non-zero, this price MUST include applicable
- // taxes.
- price: Amount;
-
- // An optional base64-encoded product image
- image: ImageDataUrl;
-
- // a list of taxes paid by the merchant for one unit of this product
- taxes: Tax[];
-
- // Number of units of the product in stock in sum in total,
- // including all existing sales ever. Given in product-specific
- // units.
- // A value of -1 indicates "infinite" (i.e. for "electronic" books).
- total_stock: Integer;
-
- // Number of units of the product that have already been sold.
- total_sold: Integer;
-
- // Number of units of the product that were lost (spoiled, stolen, etc.)
- total_lost: Integer;
-
- // Identifies where the product is in stock.
- address: Location;
-
- // Identifies when we expect the next restocking to happen.
- next_restock?: Timestamp;
-
- // Minimum age buyer must have (in years). Default is 0.
- minimum_age?: Integer;
- }
-
- // POST /private/products/$PRODUCT_ID/lock
- interface LockRequest {
- // UUID that identifies the frontend performing the lock
- // It is suggested that clients use a timeflake for this,
- // see https://github.com/anthonynsimon/timeflake
- lock_uuid: UUID;
-
- // How long does the frontend intend to hold the lock
- duration: RelativeTime;
-
- // How many units should be locked?
- quantity: Integer;
- }
-
- // DELETE /private/products/$PRODUCT_ID
- }
-
- namespace dead_Orders {
- type MerchantOrderStatusResponse =
- | CheckPaymentPaidResponse
- | CheckPaymentClaimedResponse
- | CheckPaymentUnpaidResponse;
- interface CheckPaymentPaidResponse {
- // The customer paid for this contract.
- order_status: "paid";
-
- // Was the payment refunded (even partially)?
- refunded: boolean;
-
- // True if there are any approved refunds that the wallet has
- // not yet obtained.
- refund_pending: boolean;
-
- // Did the exchange wire us the funds?
- wired: boolean;
-
- // Total amount the exchange deposited into our bank account
- // for this contract, excluding fees.
- deposit_total: Amount;
-
- // Numeric error code indicating errors the exchange
- // encountered tracking the wire transfer for this purchase (before
- // we even got to specific coin issues).
- // 0 if there were no issues.
- exchange_ec: number;
-
- // HTTP status code returned by the exchange when we asked for
- // information to track the wire transfer for this purchase.
- // 0 if there were no issues.
- exchange_hc: number;
-
- // Total amount that was refunded, 0 if refunded is false.
- refund_amount: Amount;
-
- // Contract terms.
- contract_terms: ContractTerms;
-
- // The wire transfer status from the exchange for this order if
- // available, otherwise empty array.
- wire_details: TransactionWireTransfer[];
-
- // The refund details for this order. One entry per
- // refunded coin; empty array if there are no refunds.
- refund_details: RefundDetails[];
-
- // Status URL, can be used as a redirect target for the browser
- // to show the order QR code / trigger the wallet.
- order_status_url: string;
- }
- interface CheckPaymentClaimedResponse {
- // A wallet claimed the order, but did not yet pay for the contract.
- order_status: "claimed";
-
- // Contract terms.
- contract_terms: ContractTerms;
- }
- interface CheckPaymentUnpaidResponse {
- // The order was neither claimed nor paid.
- order_status: "unpaid";
-
- // when was the order created
- creation_time: Timestamp;
-
- // Order summary text.
- summary: string;
-
- // Total amount of the order (to be paid by the customer).
- total_amount: Amount;
-
- // URI that the wallet must process to complete the payment.
- taler_pay_uri: string;
-
- // Alternative order ID which was paid for already in the same session.
- // Only given if the same product was purchased before in the same session.
- already_paid_order_id?: string;
-
- // Fulfillment URL of an already paid order. Only given if under this
- // session an already paid order with a fulfillment URL exists.
- already_paid_fulfillment_url?: string;
-
- // Status URL, can be used as a redirect target for the browser
- // to show the order QR code / trigger the wallet.
- order_status_url: string;
-
- // We do we NOT return the contract terms here because they may not
- // exist in case the wallet did not yet claim them.
- }
- interface RefundDetails {
- // Reason given for the refund.
- reason: string;
-
- // When was the refund approved.
- timestamp: Timestamp;
-
- // Set to true if a refund is still available for the wallet for this payment.
- pending: boolean;
-
- // Total amount that was refunded (minus a refund fee).
- amount: Amount;
- }
- interface TransactionWireTransfer {
- // Responsible exchange.
- exchange_url: string;
-
- // 32-byte wire transfer identifier.
- wtid: Base32;
-
- // Execution time of the wire transfer.
- execution_time: Timestamp;
-
- // Total amount that has been wire transferred
- // to the merchant.
- amount: Amount;
-
- // Was this transfer confirmed by the merchant via the
- // POST /transfers API, or is it merely claimed by the exchange?
- confirmed: boolean;
- }
- interface TransactionWireReport {
- // Numerical error code.
- code: number;
-
- // Human-readable error description.
- hint: string;
-
- // Numerical error code from the exchange.
- exchange_ec: number;
-
- // HTTP status code received from the exchange.
- exchange_hc: number;
-
- // Public key of the coin for which we got the exchange error.
- coin_pub: CoinPublicKey;
- }
-
- interface OrderHistory {
- // timestamp-sorted array of all orders matching the query.
- // The order of the sorting depends on the sign of delta.
- orders: OrderHistoryEntry[];
- }
- interface OrderHistoryEntry {
- // order ID of the transaction related to this entry.
- order_id: string;
-
- // row ID of the order in the database
- row_id: number;
-
- // when the order was created
- timestamp: Timestamp;
-
- // the amount of money the order is for
- amount: Amount;
-
- // the summary of the order
- summary: string;
-
- // whether some part of the order is refundable,
- // that is the refund deadline has not yet expired
- // and the total amount refunded so far is below
- // the value of the original transaction.
- refundable: boolean;
-
- // whether the order has been paid or not
- paid: boolean;
- }
-
- interface PostOrderRequest {
- // The order must at least contain the minimal
- // order detail, but can override all
- order: Order;
-
- // if set, the backend will then set the refund deadline to the current
- // time plus the specified delay. If it's not set, refunds will not be
- // possible.
- refund_delay?: RelativeTime;
-
- // specifies the payment target preferred by the client. Can be used
- // to select among the various (active) wire methods supported by the instance.
- payment_target?: string;
-
- // specifies that some products are to be included in the
- // order from the inventory. For these inventory management
- // is performed (so the products must be in stock) and
- // details are completed from the product data of the backend.
- inventory_products?: MinimalInventoryProduct[];
-
- // Specifies a lock identifier that was used to
- // lock a product in the inventory. Only useful if
- // manage_inventory is set. Used in case a frontend
- // reserved quantities of the individual products while
- // the shopping card was being built. Multiple UUIDs can
- // be used in case different UUIDs were used for different
- // products (i.e. in case the user started with multiple
- // shopping sessions that were combined during checkout).
- lock_uuids?: UUID[];
-
- // Should a token for claiming the order be generated?
- // False can make sense if the ORDER_ID is sufficiently
- // high entropy to prevent adversarial claims (like it is
- // if the backend auto-generates one). Default is 'true'.
- create_token?: boolean;
-
- // OTP device ID to associate with the order.
- // This parameter is optional.
- otp_id?: string;
- }
- type Order = MinimalOrderDetail | ContractTerms;
-
- interface MinimalOrderDetail {
- // Amount to be paid by the customer
- amount: Amount;
-
- // Short summary of the order
- summary: string;
-
- // URL that will show that the order was successful after
- // it has been paid for. Optional. When POSTing to the
- // merchant, the placeholder "${ORDER_ID}" will be
- // replaced with the actual order ID (useful if the
- // order ID is generated server-side and needs to be
- // in the URL).
- fulfillment_url?: string;
- }
-
- interface MinimalInventoryProduct {
- // Which product is requested (here mandatory!)
- product_id: string;
-
- // How many units of the product are requested
- quantity: Integer;
- }
- interface PostOrderResponse {
- // Order ID of the response that was just created
- order_id: string;
-
- // Token that authorizes the wallet to claim the order.
- // Provided only if "create_token" was set to 'true'
- // in the request.
- token?: ClaimToken;
- }
- interface OutOfStockResponse {
- // Product ID of an out-of-stock item
- product_id: string;
-
- // Requested quantity
- requested_quantity: Integer;
-
- // Available quantity (must be below requested_quanitity)
- available_quantity: Integer;
-
- // When do we expect the product to be again in stock?
- // Optional, not given if unknown.
- restock_expected?: Timestamp;
- }
-
- interface ForgetRequest {
- // Array of valid JSON paths to forgettable fields in the order's
- // contract terms.
- fields: string[];
- }
- interface RefundRequest {
- // Amount to be refunded
- refund: Amount;
-
- // Human-readable refund justification
- reason: string;
- }
- interface MerchantRefundResponse {
- // URL (handled by the backend) that the wallet should access to
- // trigger refund processing.
- // taler://refund/...
- taler_refund_uri: string;
-
- // Contract hash that a client may need to authenticate an
- // HTTP request to obtain the above URI in a wallet-friendly way.
- h_contract: HashCode;
- }
- }
-
- namespace dead_Rewards {
- // GET /private/reserves
- interface RewardReserveStatus {
- // Array of all known reserves (possibly empty!)
- reserves: ReserveStatusEntry[];
- }
- interface ReserveStatusEntry {
- // Public key of the reserve
- reserve_pub: EddsaPublicKey;
-
- // Timestamp when it was established
- creation_time: Timestamp;
-
- // Timestamp when it expires
- expiration_time: Timestamp;
-
- // Initial amount as per reserve creation call
- merchant_initial_amount: Amount;
-
- // Initial amount as per exchange, 0 if exchange did
- // not confirm reserve creation yet.
- exchange_initial_amount: Amount;
-
- // Amount picked up so far.
- pickup_amount: Amount;
-
- // Amount approved for rewards that exceeds the pickup_amount.
- committed_amount: Amount;
-
- // Is this reserve active (false if it was deleted but not purged)
- active: boolean;
- }
-
- interface ReserveCreateRequest {
- // Amount that the merchant promises to put into the reserve
- initial_balance: Amount;
-
- // Exchange the merchant intends to use for reward
- exchange_url: string;
-
- // Desired wire method, for example "iban" or "x-taler-bank"
- wire_method: string;
- }
- interface ReserveCreateConfirmation {
- // Public key identifying the reserve
- reserve_pub: EddsaPublicKey;
-
- // Wire accounts of the exchange where to transfer the funds.
- accounts: WireAccount[];
- }
- interface RewardCreateRequest {
- // Amount that the customer should be reward
- amount: Amount;
-
- // Justification for giving the reward
- justification: string;
-
- // URL that the user should be directed to after rewarding,
- // will be included in the reward_token.
- next_url: string;
- }
- interface RewardCreateConfirmation {
- // Unique reward identifier for the reward that was created.
- reward_id: HashCode;
-
- // taler://reward URI for the reward
- taler_reward_uri: string;
-
- // URL that will directly trigger processing
- // the reward when the browser is redirected to it
- reward_status_url: string;
-
- // when does the reward expire
- reward_expiration: Timestamp;
- }
-
- interface ReserveDetail {
- // Timestamp when it was established.
- creation_time: Timestamp;
-
- // Timestamp when it expires.
- expiration_time: Timestamp;
-
- // Initial amount as per reserve creation call.
- merchant_initial_amount: Amount;
-
- // Initial amount as per exchange, 0 if exchange did
- // not confirm reserve creation yet.
- exchange_initial_amount: Amount;
-
- // Amount picked up so far.
- pickup_amount: Amount;
-
- // Amount approved for rewards that exceeds the pickup_amount.
- committed_amount: Amount;
-
- // Array of all rewards created by this reserves (possibly empty!).
- // Only present if asked for explicitly.
- rewards?: RewardStatusEntry[];
-
- // Is this reserve active (false if it was deleted but not purged)?
- active: boolean;
-
- // Array of wire accounts of the exchange that could
- // be used to fill the reserve, can be NULL
- // if the reserve is inactive or was already filled
- accounts?: WireAccount[];
-
- // URL of the exchange hosting the reserve,
- // NULL if the reserve is inactive
- exchange_url: string;
- }
-
- interface RewardStatusEntry {
- // Unique identifier for the reward.
- reward_id: HashCode;
-
- // Total amount of the reward that can be withdrawn.
- total_amount: Amount;
-
- // Human-readable reason for why the reward was granted.
- reason: string;
- }
-
- interface RewardDetails {
- // Amount that we authorized for this reward.
- total_authorized: Amount;
-
- // Amount that was picked up by the user already.
- total_picked_up: Amount;
-
- // Human-readable reason given when authorizing the reward.
- reason: string;
-
- // Timestamp indicating when the reward is set to expire (may be in the past).
- expiration: Timestamp;
-
- // Reserve public key from which the reward is funded.
- reserve_pub: EddsaPublicKey;
-
- // Array showing the pickup operations of the wallet (possibly empty!).
- // Only present if asked for explicitly.
- pickups?: PickupDetail[];
- }
- interface PickupDetail {
- // Unique identifier for the pickup operation.
- pickup_id: HashCode;
-
- // Number of planchets involved.
- num_planchets: Integer;
-
- // Total amount requested for this pickup_id.
- requested_amount: Amount;
- }
- }
-
- namespace dead_Transfers {
- interface TransferList {
- // list of all the transfers that fit the filter that we know
- transfers: TransferDetails[];
- }
- interface TransferDetails {
- // how much was wired to the merchant (minus fees)
- credit_amount: Amount;
-
- // raw wire transfer identifier identifying the wire transfer (a base32-encoded value)
- wtid: string;
-
- // target account that received the wire transfer
- payto_uri: string;
-
- // base URL of the exchange that made the wire transfer
- exchange_url: string;
-
- // Serial number identifying the transfer in the merchant backend.
- // Used for filgering via offset.
- transfer_serial_id: number;
-
- // Time of the execution of the wire transfer by the exchange, according to the exchange
- // Only provided if we did get an answer from the exchange.
- execution_time?: Timestamp;
-
- // True if we checked the exchange's answer and are happy with it.
- // False if we have an answer and are unhappy, missing if we
- // do not have an answer from the exchange.
- verified?: boolean;
-
- // True if the merchant uses the POST /transfers API to confirm
- // that this wire transfer took place (and it is thus not
- // something merely claimed by the exchange).
- confirmed?: boolean;
- }
-
- interface TransferInformation {
- // how much was wired to the merchant (minus fees)
- credit_amount: Amount;
-
- // raw wire transfer identifier identifying the wire transfer (a base32-encoded value)
- wtid: WireTransferIdentifierRawP;
-
- // target account that received the wire transfer
- payto_uri: string;
-
- // base URL of the exchange that made the wire transfer
- exchange_url: string;
- }
- }
-
- namespace dead_OTP {
- interface OtpDeviceAddDetails {
- // Device ID to use.
- otp_device_id: string;
-
- // Human-readable description for the device.
- otp_device_description: string;
-
- // A base64-encoded key
- otp_key: string;
-
- // Algorithm for computing the POS confirmation.
- otp_algorithm: Integer;
-
- // Counter for counter-based OTP devices.
- otp_ctr?: Integer;
- }
-
- interface OtpDevicePatchDetails {
- // Human-readable description for the device.
- otp_device_description: string;
-
- // A base64-encoded key
- otp_key: string | undefined;
-
- // Algorithm for computing the POS confirmation.
- otp_algorithm: Integer;
-
- // Counter for counter-based OTP devices.
- otp_ctr?: Integer;
- }
-
- interface OtpDeviceSummaryResponse {
- // Array of devices that are present in our backend.
- otp_devices: OtpDeviceEntry[];
- }
- interface OtpDeviceEntry {
- // Device identifier.
- otp_device_id: string;
-
- // Human-readable description for the device.
- device_description: string;
- }
-
- interface OtpDeviceDetails {
- // Human-readable description for the device.
- device_description: string;
-
- // Algorithm for computing the POS confirmation.
- otp_algorithm: Integer;
-
- // Counter for counter-based OTP devices.
- otp_ctr?: Integer;
- }
-
-
- }
- namespace dead_Template {
- interface TemplateAddDetails {
- // Template ID to use.
- template_id: string;
-
- // Human-readable description for the template.
- template_description: string;
-
- // OTP device ID.
- // This parameter is optional.
- otp_id?: string;
-
- // Additional information in a separate template.
- template_contract: TemplateContractDetails;
- }
- interface TemplateContractDetails {
- // Human-readable summary for the template.
- summary?: string;
-
- // The price is imposed by the merchant and cannot be changed by the customer.
- // This parameter is optional.
- amount?: Amount;
-
- // Minimum age buyer must have (in years). Default is 0.
- minimum_age: Integer;
-
- // The time the customer need to pay before his order will be deleted.
- // It is deleted if the customer did not pay and if the duration is over.
- pay_duration: RelativeTime;
- }
- interface TemplatePatchDetails {
- // Human-readable description for the template.
- template_description: string;
-
- // OTP device ID.
- // This parameter is optional.
- otp_id?: string;
-
- // Additional information in a separate template.
- template_contract: TemplateContractDetails;
- }
-
- interface TemplateSummaryResponse {
- // List of templates that are present in our backend.
- templates: TemplateEntry[];
- }
-
- interface TemplateEntry {
- // Template identifier, as found in the template.
- template_id: string;
-
- // Human-readable description for the template.
- template_description: string;
- }
-
- interface TemplateDetails {
- // Human-readable description for the template.
- template_description: string;
-
- // OTP device ID.
- // This parameter is optional.
- otp_id?: string;
-
- // Additional information in a separate template.
- template_contract: TemplateContractDetails;
- }
-
- interface UsingTemplateDetails {
- // Subject of the template
- summary?: string;
-
- // The amount entered by the customer.
- amount?: Amount;
- }
-
- interface UsingTemplateResponse {
- // After enter the request. The user will be pay with a taler URL.
- order_id: string;
- token: string;
- }
- }
-
- namespace dead_Webhooks {
- type MerchantWebhookType = "pay" | "refund";
- interface WebhookAddDetails {
- // Webhook ID to use.
- webhook_id: string;
-
- // The event of the webhook: why the webhook is used.
- event_type: MerchantWebhookType;
-
- // URL of the webhook where the customer will be redirected.
- url: string;
-
- // Method used by the webhook
- http_method: string;
-
- // Header template of the webhook
- header_template?: string;
-
- // Body template by the webhook
- body_template?: string;
- }
- interface WebhookPatchDetails {
- // The event of the webhook: why the webhook is used.
- event_type: string;
-
- // URL of the webhook where the customer will be redirected.
- url: string;
-
- // Method used by the webhook
- http_method: string;
-
- // Header template of the webhook
- header_template?: string;
-
- // Body template by the webhook
- body_template?: string;
- }
- interface WebhookSummaryResponse {
- // List of webhooks that are present in our backend.
- webhooks: WebhookEntry[];
- }
- interface WebhookEntry {
- // Webhook identifier, as found in the webhook.
- webhook_id: string;
-
- // The event of the webhook: why the webhook is used.
- event_type: string;
- }
- interface WebhookDetails {
- // The event of the webhook: why the webhook is used.
- event_type: string;
-
- // URL of the webhook where the customer will be redirected.
- url: string;
-
- // Method used by the webhook
- http_method: string;
-
- // Header template of the webhook
- header_template?: string;
-
- // Body template by the webhook
- body_template?: string;
- }
- }
-
- interface ContractTerms {
- // Human-readable description of the whole purchase
- summary: string;
-
- // Map from IETF BCP 47 language tags to localized summaries
- summary_i18n?: { [lang_tag: string]: string };
-
- // Unique, free-form identifier for the proposal.
- // Must be unique within a merchant instance.
- // For merchants that do not store proposals in their DB
- // before the customer paid for them, the order_id can be used
- // by the frontend to restore a proposal from the information
- // encoded in it (such as a short product identifier and timestamp).
- order_id: string;
-
- // Total price for the transaction.
- // The exchange will subtract deposit fees from that amount
- // before transferring it to the merchant.
- amount: Amount;
-
- // The URL for this purchase. Every time is is visited, the merchant
- // will send back to the customer the same proposal. Clearly, this URL
- // can be bookmarked and shared by users.
- fulfillment_url?: string;
-
- // Maximum total deposit fee accepted by the merchant for this contract
- max_fee: Amount;
-
- // List of products that are part of the purchase (see Product).
- products: Product[];
-
- // Time when this contract was generated
- timestamp: TalerProtocolTimestamp;
-
- // After this deadline has passed, no refunds will be accepted.
- refund_deadline: TalerProtocolTimestamp;
-
- // After this deadline, the merchant won't accept payments for the contact
- pay_deadline: TalerProtocolTimestamp;
-
- // Transfer deadline for the exchange. Must be in the
- // deposit permissions of coins used to pay for this order.
- wire_transfer_deadline: TalerProtocolTimestamp;
-
- // Merchant's public key used to sign this proposal; this information
- // is typically added by the backend Note that this can be an ephemeral key.
- merchant_pub: EddsaPublicKey;
-
- // Base URL of the (public!) merchant backend API.
- // Must be an absolute URL that ends with a slash.
- merchant_base_url: string;
-
- // More info about the merchant, see below
- merchant: Merchant;
-
- // The hash of the merchant instance's wire details.
- h_wire: HashCode;
-
- // Wire transfer method identifier for the wire method associated with h_wire.
- // The wallet may only select exchanges via a matching auditor if the
- // exchange also supports this wire method.
- // The wire transfer fees must be added based on this wire transfer method.
- wire_method: string;
-
- // Any exchanges audited by these auditors are accepted by the merchant.
- auditors: Auditor[];
-
- // Exchanges that the merchant accepts even if it does not accept any auditors that audit them.
- exchanges: Exchange[];
-
- // Delivery location for (all!) products.
- delivery_location?: Location;
-
- // Time indicating when the order should be delivered.
- // May be overwritten by individual products.
- delivery_date?: TalerProtocolTimestamp;
-
- // Nonce generated by the wallet and echoed by the merchant
- // in this field when the proposal is generated.
- nonce: string;
-
- // Specifies for how long the wallet should try to get an
- // automatic refund for the purchase. If this field is
- // present, the wallet should wait for a few seconds after
- // the purchase and then automatically attempt to obtain
- // a refund. The wallet should probe until "delay"
- // after the payment was successful (i.e. via long polling
- // or via explicit requests with exponential back-off).
- //
- // In particular, if the wallet is offline
- // at that time, it MUST repeat the request until it gets
- // one response from the merchant after the delay has expired.
- // If the refund is granted, the wallet MUST automatically
- // recover the payment. This is used in case a merchant
- // knows that it might be unable to satisfy the contract and
- // desires for the wallet to attempt to get the refund without any
- // customer interaction. Note that it is NOT an error if the
- // merchant does not grant a refund.
- auto_refund?: RelativeTime;
-
- // Extra data that is only interpreted by the merchant frontend.
- // Useful when the merchant needs to store extra information on a
- // contract without storing it separately in their database.
- extra?: any;
-
- // Minimum age buyer must have (in years). Default is 0.
- minimum_age?: Integer;
- }
-}
diff --git a/packages/merchant-backoffice-ui/src/hooks/backend.ts b/packages/merchant-backoffice-ui/src/hooks/backend.ts
index 8eb9b4cf2..e4e50c8ad 100644
--- a/packages/merchant-backoffice-ui/src/hooks/backend.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/backend.ts
@@ -177,16 +177,6 @@ interface useBackendBaseRequestType {
}
type YesOrNo = "yes" | "no";
-type LoginResult =
- | {
- valid: true;
- token: string;
- expiration: Timestamp;
- }
- | {
- valid: false;
- cause: HttpError<EmptyObject>;
- };
/**
*
diff --git a/packages/merchant-backoffice-ui/src/hooks/instance.test.ts b/packages/merchant-backoffice-ui/src/hooks/instance.test.ts
index 35147d988..3b02d7758 100644
--- a/packages/merchant-backoffice-ui/src/hooks/instance.test.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/instance.test.ts
@@ -19,15 +19,12 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
-import { AccessToken, TalerMerchantApi } from "@gnu-taler/taler-util";
+import { TalerMerchantApi } from "@gnu-taler/taler-util";
import * as tests from "@gnu-taler/web-util/testing";
import { expect } from "chai";
import {
- useAdminAPI,
useBackendInstances,
- useInstanceAPI,
useInstanceDetails,
- useManagementAPI,
} from "./instance.js";
import { ApiMockEnvironment } from "./testing.js";
import {
@@ -39,6 +36,7 @@ import {
API_UPDATE_CURRENT_INSTANCE_AUTH,
API_UPDATE_INSTANCE_BY_ID,
} from "./urls.js";
+import { useMerchantApiContext } from "@gnu-taler/web-util/browser";
describe("instance api interaction with details", () => {
it("should evict cache when updating an instance", async () => {
@@ -52,7 +50,8 @@ describe("instance api interaction with details", () => {
const hookBehavior = await tests.hookBehaveLikeThis(
() => {
- const api = useInstanceAPI();
+ // const api = useInstanceAPI();
+ const { lib: api } = useMerchantApiContext()
const query = useInstanceDetails();
return { query, api };
},
@@ -82,7 +81,7 @@ describe("instance api interaction with details", () => {
name: "other_name",
} as TalerMerchantApi.QueryInstancesResponse,
});
- api.updateInstance({
+ api.management.updateCurrentInstance(undefined, {
name: "other_name",
} as TalerMerchantApi.InstanceReconfigurationMessage);
},
@@ -120,7 +119,7 @@ describe("instance api interaction with details", () => {
const hookBehavior = await tests.hookBehaveLikeThis(
() => {
- const api = useInstanceAPI();
+ const { lib: api } = useMerchantApiContext()
const query = useInstanceDetails();
return { query, api };
},
@@ -206,7 +205,7 @@ describe("instance api interaction with details", () => {
const hookBehavior = await tests.hookBehaveLikeThis(
() => {
- const api = useInstanceAPI();
+ const { lib: api } = useMerchantApiContext()
const query = useInstanceDetails();
return { query, api };
},
@@ -243,7 +242,9 @@ describe("instance api interaction with details", () => {
} as TalerMerchantApi.QueryInstancesResponse,
});
- api.clearAccessToken(undefined);
+ api.management.updateCurrentInstanceAuthentication(undefined, {
+ method: "external"
+ });
},
({ query, api }) => {
expect(env.assertJustExpectedRequestWereMade()).deep.eq({
@@ -337,7 +338,7 @@ describe("instance admin api interaction with listing", () => {
const hookBehavior = await tests.hookBehaveLikeThis(
() => {
- const api = useAdminAPI();
+ const { lib: api } = useMerchantApiContext()
const query = useBackendInstances();
return { query, api };
},
@@ -379,9 +380,9 @@ describe("instance admin api interaction with listing", () => {
},
});
- api.createInstance({
+ api.management.createInstance(undefined, {
name: "other_name",
- } as TalerMerchantApi.InstanceConfigurationMessage);
+ } as TalerMerchantApi.InstanceConfigurationMessage)
},
({ query, api }) => {
expect(env.assertJustExpectedRequestWereMade()).deep.eq({
@@ -428,7 +429,7 @@ describe("instance admin api interaction with listing", () => {
const hookBehavior = await tests.hookBehaveLikeThis(
() => {
- const api = useAdminAPI();
+ const { lib: api } = useMerchantApiContext()
const query = useBackendInstances();
return { query, api };
},
@@ -469,7 +470,7 @@ describe("instance admin api interaction with listing", () => {
},
});
- api.deleteInstance("the_id");
+ api.management.deleteInstance(undefined, "the_id");
},
({ query, api }) => {
expect(env.assertJustExpectedRequestWereMade()).deep.eq({
@@ -582,7 +583,7 @@ describe("instance admin api interaction with listing", () => {
const hookBehavior = await tests.hookBehaveLikeThis(
() => {
- const api = useAdminAPI();
+ const { lib: api } = useMerchantApiContext()
const query = useBackendInstances();
return { query, api };
},
@@ -627,7 +628,7 @@ describe("instance admin api interaction with listing", () => {
},
});
- api.purgeInstance("the_id");
+ api.management.deleteInstance(undefined, "the_id", { purge: true })
},
({ query, api }) => {
expect(env.assertJustExpectedRequestWereMade()).deep.eq({
@@ -670,7 +671,7 @@ describe("instance management api interaction with listing", () => {
const hookBehavior = await tests.hookBehaveLikeThis(
() => {
- const api = useManagementAPI("managed");
+ const { lib: api } = useMerchantApiContext()
const query = useBackendInstances();
return { query, api };
},
@@ -711,7 +712,7 @@ describe("instance management api interaction with listing", () => {
},
});
- api.updateInstance({
+ api.management.updateCurrentInstance(undefined, {
name: "other_name",
} as TalerMerchantApi.InstanceConfigurationMessage);
},
diff --git a/packages/merchant-backoffice-ui/src/hooks/instance.ts b/packages/merchant-backoffice-ui/src/hooks/instance.ts
index 5f17dbf79..0ba68250a 100644
--- a/packages/merchant-backoffice-ui/src/hooks/instance.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/instance.ts
@@ -20,219 +20,14 @@ import {
} from "@gnu-taler/web-util/browser";
import {
useBackendBaseRequest,
- useBackendInstanceRequest,
- useMatchMutate,
+ useBackendInstanceRequest
} from "./backend.js";
// FIX default import https://github.com/microsoft/TypeScript/issues/49189
-import { AccessToken, TalerErrorDetail, TalerMerchantApi } from "@gnu-taler/taler-util";
-import _useSWR, { SWRHook, useSWRConfig } from "swr";
-import { useSessionContext } from "../context/session.js";
+import { TalerErrorDetail, TalerMerchantApi } from "@gnu-taler/taler-util";
+import _useSWR, { SWRHook } from "swr";
const useSWR = _useSWR as unknown as SWRHook;
-interface InstanceAPI {
- updateInstance: (
- data: TalerMerchantApi.InstanceReconfigurationMessage,
- ) => Promise<void>;
- deleteInstance: () => Promise<void>;
- clearAccessToken: (currentToken: AccessToken | undefined) => Promise<void>;
- // setNewAccessToken: (
- // currentToken: AccessToken | undefined,
- // token: AccessToken,
- // ) => Promise<void>;
-}
-
-export function useAdminAPI(): AdminAPI {
- const { request } = useBackendBaseRequest();
- const mutateAll = useMatchMutate();
-
- const createInstance = async (
- instance: TalerMerchantApi.InstanceConfigurationMessage,
- ): Promise<void> => {
- await request(`/management/instances`, {
- method: "POST",
- data: instance,
- });
-
- mutateAll(/\/management\/instances/);
- };
-
- const deleteInstance = async (id: string): Promise<void> => {
- await request(`/management/instances/${id}`, {
- method: "DELETE",
- });
-
- mutateAll(/\/management\/instances/);
- };
-
- const purgeInstance = async (id: string): Promise<void> => {
- await request(`/management/instances/${id}`, {
- method: "DELETE",
- params: {
- purge: "YES",
- },
- });
-
- mutateAll(/\/management\/instances/);
- };
-
- return { createInstance, deleteInstance, purgeInstance };
-}
-
-export interface AdminAPI {
- createInstance: (
- data: TalerMerchantApi.InstanceConfigurationMessage,
- ) => Promise<void>;
- deleteInstance: (id: string) => Promise<void>;
- purgeInstance: (id: string) => Promise<void>;
-}
-
-export function useManagementAPI(instanceId: string): InstanceAPI {
- const mutateAll = useMatchMutate();
- const {
- state: { backendUrl },
- logIn,
- logOut,
- } = useSessionContext();
- const { request } = useBackendBaseRequest();
-
- const updateInstance = async (
- instance: TalerMerchantApi.InstanceReconfigurationMessage,
- ): Promise<void> => {
- await request(`/management/instances/${instanceId}`, {
- method: "PATCH",
- data: instance,
- });
-
- mutateAll(/\/management\/instances/);
- };
-
- const deleteInstance = async (): Promise<void> => {
- await request(`/management/instances/${instanceId}`, {
- method: "DELETE",
- });
-
- mutateAll(/\/management\/instances/);
- };
-
- const clearAccessToken = async (
- currentToken: AccessToken | undefined,
- ): Promise<void> => {
- await request(`/management/instances/${instanceId}/auth`, {
- method: "POST",
- token: currentToken,
- data: { method: "external" },
- });
-
- mutateAll(/\/management\/instances/);
- };
-
- // const setNewAccessToken = async (
- // currentToken: AccessToken | undefined,
- // newToken: AccessToken,
- // ): Promise<void> => {
-
- // await request(`/management/instances/${instanceId}/auth`, {
- // method: "POST",
- // token: currentToken,
- // data: { method: "token", token: newToken },
- // });
-
- // const resp = await requestNewLoginToken(backendUrl, newToken);
- // if (resp.valid) {
- // logIn({ token: resp.token as AccessToken });
- // } else {
- // logOut();
- // }
-
- // mutateAll(/\/management\/instances/);
- // };
-
- return {
- updateInstance,
- deleteInstance,
- // setNewAccessToken,
- clearAccessToken,
- };
-}
-
-export function useInstanceAPI(): InstanceAPI {
- const { mutate } = useSWRConfig();
- const {
- state: { backendUrl },
- } = useSessionContext();
-
- const { request } = useBackendInstanceRequest();
- const { state, logIn, logOut } = useSessionContext();
-
- const adminToken =
- state.status === "loggedIn" && state.isAdmin ? state.token : undefined;
-
- const updateInstance = async (
- instance: TalerMerchantApi.InstanceReconfigurationMessage,
- ): Promise<void> => {
- await request(`/private/`, {
- method: "PATCH",
- data: instance,
- });
-
- if (adminToken) {
- mutate(["/private/instances", adminToken, backendUrl], null);
- }
- mutate([`/private/`], null);
- };
-
- const deleteInstance = async (): Promise<void> => {
- await request(`/private/`, {
- method: "DELETE",
- // token: adminToken,
- });
-
- if (adminToken) {
- mutate(["/private/instances", adminToken, backendUrl], null);
- }
- mutate([`/private/`], null);
- };
-
- const clearAccessToken = async (
- currentToken: AccessToken | undefined,
- ): Promise<void> => {
- await request(`/private/auth`, {
- method: "POST",
- token: currentToken,
- data: { method: "external" },
- });
-
- mutate([`/private/`], null);
- };
-
- // const setNewAccessToken = async (
- // currentToken: AccessToken | undefined,
- // newToken: AccessToken,
- // ): Promise<void> => {
- // await request(`/private/auth`, {
- // method: "POST",
- // token: currentToken,
- // data: { method: "token", token: newToken },
- // });
-
- // const resp = await requestNewLoginToken(backendUrl, newToken);
- // if (resp.valid) {
- // logIn({ token: resp.token as AccessToken });
- // } else {
- // logOut();
- // }
-
- // mutate([`/private/`], null);
- // };
-
- return {
- updateInstance,
- deleteInstance,
- // setNewAccessToken,
- clearAccessToken,
- };
-}
export function useInstanceDetails(): HttpResponse<
TalerMerchantApi.QueryInstancesResponse,
diff --git a/packages/merchant-backoffice-ui/src/hooks/templates.ts b/packages/merchant-backoffice-ui/src/hooks/templates.ts
index 2e39a0c46..2da02e3c7 100644
--- a/packages/merchant-backoffice-ui/src/hooks/templates.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/templates.ts
@@ -190,20 +190,20 @@ export function useInstanceTemplates(
// if the query returns less that we ask, then we have reach the end or beginning
const isReachingEnd =
- afterData && afterData.data.templates_list.length < totalAfter;
+ afterData && afterData.data.templates.length < totalAfter;
const isReachingStart = args?.position === undefined
||
- (beforeData && beforeData.data.templates_list.length < totalBefore);
+ (beforeData && beforeData.data.templates.length < totalBefore);
const pagination = {
isReachingEnd,
isReachingStart,
loadMore: () => {
if (!afterData || isReachingEnd) return;
- if (afterData.data.templates_list.length < MAX_RESULT_SIZE) {
+ if (afterData.data.templates.length < MAX_RESULT_SIZE) {
setPageAfter(pageAfter + 1);
} else {
- const from = `${afterData.data.templates_list[afterData.data.templates_list.length - 1]
+ const from = `${afterData.data.templates[afterData.data.templates.length - 1]
.template_id
}`;
if (from && updatePosition) updatePosition(from);
@@ -211,10 +211,10 @@ export function useInstanceTemplates(
},
loadMorePrev: () => {
if (!beforeData || isReachingStart) return;
- if (beforeData.data.templates_list.length < MAX_RESULT_SIZE) {
+ if (beforeData.data.templates.length < MAX_RESULT_SIZE) {
setPageBefore(pageBefore + 1);
} else if (beforeData) {
- const from = `${beforeData.data.templates_list[beforeData.data.templates_list.length - 1]
+ const from = `${beforeData.data.templates[beforeData.data.templates.length - 1]
.template_id
}`;
if (from && updatePosition) updatePosition(from);
@@ -223,17 +223,17 @@ export function useInstanceTemplates(
};
// const templates = !afterData ? [] : (afterData || lastAfter).data.templates;
- const templates_list =
+ const templates =
!beforeData || !afterData
? []
- : (beforeData || lastBefore).data.templates_list
+ : (beforeData || lastBefore).data.templates
.slice()
.reverse()
- .concat((afterData || lastAfter).data.templates_list);
+ .concat((afterData || lastAfter).data.templates);
if (loadingAfter || loadingBefore)
- return { loading: true, data: { templates_list } };
+ return { loading: true, data: { templates } };
if (beforeData && afterData) {
- return { ok: true, data: { templates_list }, ...pagination };
+ return { ok: true, data: { templates }, ...pagination };
}
return { loading: true };
}
diff --git a/packages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx b/packages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx
index 731ea8939..d53d93e8b 100644
--- a/packages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx
@@ -123,7 +123,7 @@ export function CreatePage({ onCreate, onBack, forceId }: Props): VNode {
newValue.auth_token = undefined;
newValue.auth = newToken === null || newToken === undefined
? { method: "external" }
- : { method: "token", token: `secret-token:${newToken}` };
+ : { method: "token", token: newToken };
if (!newValue.address) newValue.address = {};
if (!newValue.jurisdiction) newValue.jurisdiction = {};
// remove above use conversion
diff --git a/packages/merchant-backoffice-ui/src/paths/admin/create/index.tsx b/packages/merchant-backoffice-ui/src/paths/admin/create/index.tsx
index 0e8ea1f5b..431015d6f 100644
--- a/packages/merchant-backoffice-ui/src/paths/admin/create/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/admin/create/index.tsx
@@ -26,7 +26,6 @@ import { Fragment, VNode, h } from "preact";
import { useState } from "preact/hooks";
import { NotificationCard } from "../../../components/menu/index.js";
import { useSessionContext } from "../../../context/session.js";
-import { useAdminAPI } from "../../../hooks/instance.js";
import { Notification } from "../../../utils/types.js";
import { CreatePage } from "./CreatePage.js";
@@ -38,11 +37,10 @@ interface Props {
export type Entity = TalerMerchantApi.InstanceConfigurationMessage;
export default function Create({ onBack, onConfirm, forceId }: Props): VNode {
- const { createInstance } = useAdminAPI();
const [notif, setNotif] = useState<Notification | undefined>(undefined);
const { i18n } = useTranslationContext();
const { lib } = useMerchantApiContext();
- const { logIn } = useSessionContext();
+ const { state, logIn } = useSessionContext();
return (
<Fragment>
@@ -54,9 +52,11 @@ export default function Create({ onBack, onConfirm, forceId }: Props): VNode {
onCreate={async (
d: TalerMerchantApi.InstanceConfigurationMessage,
) => {
+ if (state.status !== "loggedIn") return;
try {
- await createInstance(d);
+ await lib.management.createInstance(state.token, d);
if (d.auth.token) {
+ //if auth has been updated, request a new access token
const result = await lib.authenticate.createAccessTokenBearer(
d.auth.token,
{
diff --git a/packages/merchant-backoffice-ui/src/paths/admin/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/admin/list/index.tsx
index d3fa78b65..5b8cf2a5c 100644
--- a/packages/merchant-backoffice-ui/src/paths/admin/list/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/admin/list/index.tsx
@@ -23,6 +23,7 @@ import { HttpStatusCode, TalerErrorDetail, TalerMerchantApi } from "@gnu-taler/t
import {
ErrorType,
HttpError,
+ useMerchantApiContext,
useTranslationContext,
} from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
@@ -30,9 +31,10 @@ import { useState } from "preact/hooks";
import { Loading } from "../../../components/exception/loading.js";
import { NotificationCard } from "../../../components/menu/index.js";
import { DeleteModal, PurgeModal } from "../../../components/modal/index.js";
-import { useAdminAPI, useBackendInstances } from "../../../hooks/instance.js";
+import { useBackendInstances } from "../../../hooks/instance.js";
import { Notification } from "../../../utils/types.js";
import { View } from "./View.js";
+import { useSessionContext } from "../../../context/session.js";
interface Props {
onCreate: () => void;
@@ -55,9 +57,10 @@ export default function Instances({
useState<TalerMerchantApi.Instance | null>(null);
const [purging, setPurging] =
useState<TalerMerchantApi.Instance | null>(null);
- const { deleteInstance, purgeInstance } = useAdminAPI();
const [notif, setNotif] = useState<Notification | undefined>(undefined);
const { i18n } = useTranslationContext();
+ const { lib } = useMerchantApiContext();
+ const { state } = useSessionContext();
if (result.loading) return <Loading />;
if (!result.ok) {
@@ -90,9 +93,12 @@ export default function Instances({
element={deleting}
onCancel={() => setDeleting(null)}
onConfirm={async (): Promise<void> => {
+ if (state.status !== "loggedIn") {
+ return;
+ }
try {
- await deleteInstance(deleting.id);
- // pushNotification({ message: 'delete_success', type: 'SUCCESS' })
+ await lib.management.deleteInstance(state.token, deleting.id);
+ // pushNotification({message: 'delete_success', type: 'SUCCESS' })
setNotif({
message: i18n.str`Instance "${deleting.name}" (ID: ${deleting.id}) has been deleted`,
type: "SUCCESS",
@@ -103,7 +109,7 @@ export default function Instances({
type: "ERROR",
description: error instanceof Error ? error.message : undefined,
});
- // pushNotification({ message: 'delete_error', type: 'ERROR' })
+ // pushNotification({message: 'delete_error', type: 'ERROR' })
}
setDeleting(null);
}}
@@ -114,8 +120,11 @@ export default function Instances({
element={purging}
onCancel={() => setPurging(null)}
onConfirm={async (): Promise<void> => {
+ if (state.status !== "loggedIn") {
+ return;
+ }
try {
- await purgeInstance(purging.id);
+ await lib.management.deleteInstance(state.token, purging.id, { purge: true });
setNotif({
message: i18n.str`Instance '${purging.name}' (ID: ${purging.id}) has been disabled`,
type: "SUCCESS",
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/details/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/details/index.tsx
index b76abee30..2714c8e02 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/details/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/details/index.tsx
@@ -13,12 +13,12 @@
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 { ErrorType, HttpError } from "@gnu-taler/web-util/browser";
+import { ErrorType, HttpError, useMerchantApiContext } from "@gnu-taler/web-util/browser";
import { Fragment, h, VNode } from "preact";
import { useState } from "preact/hooks";
import { Loading } from "../../../components/exception/loading.js";
import { DeleteModal } from "../../../components/modal/index.js";
-import { useInstanceAPI, useInstanceDetails } from "../../../hooks/instance.js";
+import { useInstanceDetails } from "../../../hooks/instance.js";
import { DetailPage } from "./DetailPage.js";
import { HttpStatusCode, TalerErrorDetail } from "@gnu-taler/taler-util";
import { useSessionContext } from "../../../context/session.js";
@@ -42,7 +42,8 @@ export default function Detail({
const result = useInstanceDetails();
const [deleting, setDeleting] = useState<boolean>(false);
- const { deleteInstance } = useInstanceAPI();
+ // const { deleteInstance } = useInstanceAPI();
+ const { lib } = useMerchantApiContext();
if (result.loading) return <Loading />;
if (!result.ok) {
@@ -71,8 +72,11 @@ export default function Detail({
element={{ name: result.data.name, id: state.instance }}
onCancel={() => setDeleting(false)}
onConfirm={async (): Promise<void> => {
+ if (state.status !== "loggedIn") {
+ return
+ }
try {
- await deleteInstance();
+ await lib.management.deleteCurrentInstance(state.token);
onDelete();
} catch (error) {
//FIXME: show message error
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/templates/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/templates/list/index.tsx
index 2138d24a4..40ca6ac98 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/templates/list/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/templates/list/index.tsx
@@ -92,7 +92,7 @@ export default function ListTemplates({
/>
<ListPage
- templates={result.data.templates_list}
+ templates={result.data.templates}
onLoadMoreBefore={
result.isReachingStart ? result.loadMorePrev : undefined
}
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/token/DetailPage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/token/DetailPage.tsx
index f2b1db29b..c833b908c 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/token/DetailPage.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/token/DetailPage.tsx
@@ -77,9 +77,9 @@ export function DetailPage({
async function submitForm() {
if (hasErrors) return;
const oldToken = hasToken
- ? (`secret-token:${form.old_token}` as AccessToken)
+ ? (form.old_token as AccessToken)
: undefined;
- const newToken = `secret-token:${form.new_token}` as AccessToken;
+ const newToken = form.new_token as AccessToken;
onNewToken(oldToken, newToken);
}
@@ -133,8 +133,7 @@ export function DetailPage({
class="button"
onClick={() => {
if (hasToken) {
- const oldToken =
- `secret-token:${form.old_token}` as AccessToken;
+ const oldToken = form.old_token as AccessToken;
onClearToken(oldToken);
} else {
onClearToken(undefined);
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx
index 13b5c45f1..f3c9a52ea 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx
@@ -13,16 +13,16 @@
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 { AccessToken, HttpStatusCode, TalerErrorDetail } from "@gnu-taler/taler-util";
+import { HttpStatusCode, TalerErrorDetail } from "@gnu-taler/taler-util";
import { ErrorType, HttpError, useMerchantApiContext, useTranslationContext } from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
import { useState } from "preact/hooks";
import { Loading } from "../../../components/exception/loading.js";
import { NotificationCard } from "../../../components/menu/index.js";
-import { useInstanceAPI, useInstanceDetails } from "../../../hooks/instance.js";
+import { useSessionContext } from "../../../context/session.js";
+import { useInstanceDetails } from "../../../hooks/instance.js";
import { Notification } from "../../../utils/types.js";
import { DetailPage } from "./DetailPage.js";
-import { useSessionContext } from "../../../context/session.js";
interface Props {
onUnauthorized: () => VNode;
@@ -43,7 +43,7 @@ export default function Token({
const { lib } = useMerchantApiContext();
const { logIn } = useSessionContext();
const [notif, setNotif] = useState<Notification | undefined>(undefined);
- const { clearAccessToken } = useInstanceAPI();
+ // const { clearAccessToken } = useInstanceAPI();
const result = useInstanceDetails()
if (result.loading) return <Loading />;
@@ -71,7 +71,9 @@ export default function Token({
hasToken={hasToken}
onClearToken={async (currentToken): Promise<void> => {
try {
- await clearAccessToken(currentToken);
+ await lib.management.updateCurrentInstanceAuthentication(currentToken, {
+ method: "external",
+ })
onChange();
} catch (error) {
if (error instanceof Error) {
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/update/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/update/index.tsx
index d28ca0555..32e4e149c 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/update/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/update/index.tsx
@@ -13,11 +13,12 @@
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, TalerErrorDetail, TalerMerchantApi } from "@gnu-taler/taler-util";
+import { HttpStatusCode, TalerErrorDetail, TalerMerchantApi, TalerMerchantInstanceHttpClient } from "@gnu-taler/taler-util";
import {
ErrorType,
HttpError,
HttpResponse,
+ useMerchantApiContext,
useTranslationContext,
} from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
@@ -25,13 +26,12 @@ import { useState } from "preact/hooks";
import { Loading } from "../../../components/exception/loading.js";
import { NotificationCard } from "../../../components/menu/index.js";
import {
- useInstanceAPI,
useInstanceDetails,
useManagedInstanceDetails,
- useManagementAPI,
} from "../../../hooks/instance.js";
import { Notification } from "../../../utils/types.js";
import { UpdatePage } from "./UpdatePage.js";
+import { useSessionContext } from "../../../context/session.js";
export interface Props {
onBack: () => void;
@@ -44,19 +44,21 @@ export interface Props {
}
export default function Update(props: Props): VNode {
- const { updateInstance } = useInstanceAPI();
+ const { lib } = useMerchantApiContext();
+ const updateInstance = lib.management.updateCurrentInstance.bind(lib.management)
const result = useInstanceDetails();
- return CommonUpdate(props, result, updateInstance, );
+ return CommonUpdate(props, result, updateInstance,);
}
export function AdminUpdate(props: Props & { instanceId: string }): VNode {
- const { updateInstance } = useManagementAPI(
- props.instanceId,
- );
+ const { lib } = useMerchantApiContext();
+ const t = lib.instance(props.instanceId)
+ const updateInstance = lib.instance(props.instanceId).updateCurrentInstance.bind(t)
const result = useManagedInstanceDetails(props.instanceId);
- return CommonUpdate(props, result, updateInstance, );
+ return CommonUpdate(props, result, updateInstance,);
}
+
function CommonUpdate(
{
onBack,
@@ -69,10 +71,11 @@ function CommonUpdate(
TalerMerchantApi.QueryInstancesResponse,
TalerErrorDetail
>,
- updateInstance: any,
+ updateInstance: typeof TalerMerchantInstanceHttpClient.prototype.updateCurrentInstance,
): VNode {
const [notif, setNotif] = useState<Notification | undefined>(undefined);
const { i18n } = useTranslationContext();
+ const { state } = useSessionContext();
if (result.loading) return <Loading />;
if (!result.ok) {
@@ -99,11 +102,14 @@ function CommonUpdate(
onUpdate={(
d: TalerMerchantApi.InstanceReconfigurationMessage,
): Promise<void> => {
- return updateInstance(d)
+ if (state.status !== "loggedIn") {
+ return Promise.resolve();
+ }
+ return updateInstance(state.token, d)
.then(onConfirm)
.catch((error: Error) =>
setNotif({
- message: i18n.str`Failed to create instance`,
+ message: i18n.str`Failed to update instance`,
type: "ERROR",
description: error.message,
}),
diff --git a/packages/taler-util/src/http-client/merchant.ts b/packages/taler-util/src/http-client/merchant.ts
index 394625e38..fec1e7143 100644
--- a/packages/taler-util/src/http-client/merchant.ts
+++ b/packages/taler-util/src/http-client/merchant.ts
@@ -385,7 +385,7 @@ export class TalerMerchantInstanceHttpClient {
headers,
});
switch (resp.status) {
- case HttpStatusCode.Ok:
+ case HttpStatusCode.NoContent:
return opEmptySuccess(resp);
case HttpStatusCode.NotFound:
return opKnownHttpFailure(resp.status, resp);
@@ -421,7 +421,7 @@ export class TalerMerchantInstanceHttpClient {
/**
* https://docs.taler.net/core/api-merchant.html#delete-[-instances-$INSTANCE]-private
*/
- async deleteCurrentInstance(token: AccessToken | undefined, params: { purge?: boolean }) {
+ async deleteCurrentInstance(token: AccessToken | undefined, params: { purge?: boolean } = {}) {
const url = new URL(`private`, this.baseUrl);
if (params.purge) {
diff --git a/packages/taler-util/src/http-client/types.ts b/packages/taler-util/src/http-client/types.ts
index 8578eecd4..682b08984 100644
--- a/packages/taler-util/src/http-client/types.ts
+++ b/packages/taler-util/src/http-client/types.ts
@@ -801,7 +801,7 @@ export const codecForOtpDeviceDetails =
export const codecForTemplateSummaryResponse =
(): Codec<TalerMerchantApi.TemplateSummaryResponse> =>
buildCodecForObject<TalerMerchantApi.TemplateSummaryResponse>()
- .property("templates_list", codecForList(codecForTemplateEntry()))
+ .property("templates", codecForList(codecForTemplateEntry()))
.build("TalerMerchantApi.TemplateSummaryResponse");
export const codecForTemplateEntry =
@@ -4606,7 +4606,7 @@ export namespace TalerMerchantApi {
export interface TemplateSummaryResponse {
// List of templates that are present in our backend.
- templates_list: TemplateEntry[];
+ templates: TemplateEntry[];
}
export interface TemplateEntry {
diff --git a/packages/web-util/src/context/merchant-api.ts b/packages/web-util/src/context/merchant-api.ts
index a531a5958..23ea05cd2 100644
--- a/packages/web-util/src/context/merchant-api.ts
+++ b/packages/web-util/src/context/merchant-api.ts
@@ -79,6 +79,9 @@ type Evictors = {
type ConfigResult<T> =
| undefined
| { type: "ok"; config: T; hints: VersionHint[] }
+ | ConfigResultFail<T>;
+
+export type ConfigResultFail<T> =
| { type: "incompatible"; result: T; supported: string }
| { type: "error"; error: TalerError };
@@ -91,7 +94,7 @@ export const MerchantApiProvider = ({
baseUrl: URL;
evictors?: Evictors;
children: ComponentChildren;
- frameOnError: FunctionComponent<{ children: ComponentChildren }>;
+ frameOnError: FunctionComponent<{ state: ConfigResultFail<TalerMerchantApi.VersionResponse> | undefined }>;
}): VNode => {
const [checked, setChecked] =
useState<ConfigResult<TalerMerchantApi.VersionResponse>>();
@@ -120,24 +123,8 @@ export const MerchantApiProvider = ({
});
}, []);
- if (checked === undefined) {
- return h(frameOnError, {
- children: h("div", {}, "checking compatibility with server..."),
- });
- }
- if (checked.type === "error") {
- return h(frameOnError, {
- children: h(ErrorLoading, { error: checked.error, showDetail: true }),
- });
- }
- if (checked.type === "incompatible") {
- return h(frameOnError, {
- children: h(
- "div",
- {},
- i18n.str`The server version is not supported. Supported version "${checked.supported}", server version "${checked.result.version}"`,
- ),
- });
+ if (!checked || checked.type !== "ok") {
+ return h(frameOnError, { state: checked }, []);
}
const value: MerchantContextType = {
diff --git a/packages/web-util/src/utils/request.ts b/packages/web-util/src/utils/request.ts
index f8a892d99..70f943540 100644
--- a/packages/web-util/src/utils/request.ts
+++ b/packages/web-util/src/utils/request.ts
@@ -41,7 +41,7 @@ export async function defaultRequestHandler<T>(
): Promise<HttpResponseOk<T>> {
const requestHeaders: Record<string, string> = {};
if (options.token) {
- requestHeaders.Authorization = `Bearer ${options.token}`;
+ requestHeaders.Authorization = `Bearer secret-token:${options.token}`;
} else if (options.basicAuth) {
requestHeaders.Authorization = `Basic ${base64encode(
`${options.basicAuth.username}:${options.basicAuth.password}`,