taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit 4b414dbd7764d40ffec93acfd466f02a731e9a3a
parent 7dbf5978c37383a5fc8bb65035d6a337d243324c
Author: Florian Dold <florian@dold.me>
Date:   Wed, 19 Feb 2025 14:53:06 +0100

remove usages of deprecated MerchantApiClient (part 2)

Diffstat:
Mpackages/taler-harness/src/harness/harness.ts | 27++++++++++++++++++---------
Mpackages/taler-harness/src/integrationtests/test-merchant-categories.ts | 4++--
Mpackages/taler-harness/src/integrationtests/test-merchant-instances-delete.ts | 48++++++++++++++++++++----------------------------
Mpackages/taler-harness/src/integrationtests/test-merchant-instances-urls.ts | 59+++++++++++++++++++++++++++++++----------------------------
Mpackages/taler-harness/src/integrationtests/test-merchant-instances.ts | 68+++++++++++++++++++++++++++++++-------------------------------------
Mpackages/taler-harness/src/integrationtests/test-merchant-longpolling.ts | 34++++++++++++++++++++--------------
Mpackages/taler-harness/src/integrationtests/test-merchant-refund-api.ts | 117+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Mpackages/taler-harness/src/integrationtests/test-merchant-spec-public-orders.ts | 85+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
Mpackages/taler-harness/src/integrationtests/test-otp.ts | 60++++++++++++++++++++++++++++++++++--------------------------
Mpackages/taler-harness/src/integrationtests/test-pay-paid.ts | 70++++++++++++++++++++++++++++++++++++++++------------------------------
Mpackages/taler-harness/src/integrationtests/test-payment-abort.ts | 32++++++++++++++++++--------------
Mpackages/taler-harness/src/integrationtests/test-payment-claim.ts | 37+++++++++++++++++++++----------------
Mpackages/taler-harness/src/integrationtests/test-payment-deleted.ts | 36++++++++++++++++++++----------------
Mpackages/taler-harness/src/integrationtests/test-payment-expired.ts | 24++++++++++++++----------
Mpackages/taler-harness/src/integrationtests/test-payment-fault.ts | 45+++++++++++++++++++++++++--------------------
Mpackages/taler-harness/src/integrationtests/test-payment-idempotency.ts | 40++++++++++++++++++++++++----------------
Mpackages/taler-harness/src/integrationtests/test-payment-multiple.ts | 45+++++++++++++++++++++++++--------------------
Mpackages/taler-harness/src/integrationtests/test-payment-share.ts | 37+++++++++++++++++--------------------
Mpackages/taler-harness/src/integrationtests/test-payment-template.ts | 55++++++++++++++++++++++++++++++-------------------------
Mpackages/taler-harness/src/integrationtests/test-payment-transient.ts | 32++++++++++++++++++--------------
Dpackages/taler-util/src/MerchantApiClient.ts | 342-------------------------------------------------------------------------------
Mpackages/taler-util/src/http-client/merchant.ts | 9++++++++-
Mpackages/taler-util/src/index.ts | 1-
23 files changed, 526 insertions(+), 781 deletions(-)

diff --git a/packages/taler-harness/src/harness/harness.ts b/packages/taler-harness/src/harness/harness.ts @@ -27,25 +27,24 @@ import { AmountJson, Amounts, - CheckPaymentUnpaidResponse, ConfigSources, Configuration, CoreApiResponse, Duration, EddsaKeyPair, + InstanceAuthConfigurationMessage, + InstanceConfigurationMessage, Logger, MerchantAccountKycRedirectsResponse, - MerchantInstanceConfig, - PartialMerchantInstanceConfig, + MerchantAuthMethod, PaytoString, - PostOrderRequest, TalerCoreBankHttpClient, TalerCorebankApiClient, TalerError, TalerExchangeHttpClient, TalerMerchantApi, - TalerMerchantInstanceHttpClient, TalerMerchantManagementHttpClient, + TalerProtocolDuration, WalletNotification, WireGatewayApiClient, codecForAccountKycRedirects, @@ -58,7 +57,6 @@ import { openPromise, parsePaytoUri, stringToBytes, - succeedOrThrow, } from "@gnu-taler/taler-util"; import { HttpRequestLibrary, @@ -1778,6 +1776,17 @@ export const harnessHttpLib = createPlatformHttpLib({ enableThrottling: false, }); +export interface PartialMerchantInstanceConfig { + auth?: InstanceAuthConfigurationMessage; + id: string; + name: string; + paytoUris: string[]; + address?: unknown; + jurisdiction?: unknown; + defaultWireTransferDelay?: TalerProtocolDuration; + defaultPayDelay?: TalerProtocolDuration; +} + export class MerchantService implements MerchantServiceInterface { static fromExistingConfig( gc: GlobalTestState, @@ -1996,7 +2005,7 @@ export class MerchantService implements MerchantServiceInterface { name: "Default Instance", paytoUris: [getTestHarnessPaytoForLabel("merchant-default")], auth: { - method: "external", + method: MerchantAuthMethod.EXTERNAL, }, }); } @@ -2012,9 +2021,9 @@ export class MerchantService implements MerchantServiceInterface { } logger.info(`adding instance '${instanceConfig.id}'`); const url = `http://localhost:${this.merchantConfig.httpPort}/management/instances`; - const auth = instanceConfig.auth ?? { method: "external" }; + const auth = instanceConfig.auth ?? { method: MerchantAuthMethod.EXTERNAL }; - const body: MerchantInstanceConfig = { + const body: InstanceConfigurationMessage = { auth, id: instanceConfig.id, name: instanceConfig.name, diff --git a/packages/taler-harness/src/integrationtests/test-merchant-categories.ts b/packages/taler-harness/src/integrationtests/test-merchant-categories.ts @@ -17,7 +17,7 @@ /** * Imports. */ -import { URL, j2s } from "@gnu-taler/taler-util"; +import { MerchantAuthMethod, URL, j2s } from "@gnu-taler/taler-util"; import { ExchangeService, GlobalTestState, @@ -79,7 +79,7 @@ export async function runMerchantCategoriesTest(t: GlobalTestState) { name: "Default Instance", paytoUris: [getTestHarnessPaytoForLabel("merchant-default")], auth: { - method: "external", + method: MerchantAuthMethod.EXTERNAL, }, }); diff --git a/packages/taler-harness/src/integrationtests/test-merchant-instances-delete.ts b/packages/taler-harness/src/integrationtests/test-merchant-instances-delete.ts @@ -17,7 +17,13 @@ /** * Imports. */ -import { MerchantApiClient, TalerError, URL } from "@gnu-taler/taler-util"; +import { + AccessToken, + MerchantAuthMethod, + TalerError, + TalerMerchantManagementHttpClient, + URL, +} from "@gnu-taler/taler-util"; import { ExchangeService, GlobalTestState, @@ -79,7 +85,7 @@ export async function runMerchantInstancesDeleteTest(t: GlobalTestState) { name: "Default Instance", paytoUris: [getTestHarnessPaytoForLabel("merchant-default")], auth: { - method: "external", + method: MerchantAuthMethod.EXTERNAL, }, }); @@ -89,43 +95,29 @@ export async function runMerchantInstancesDeleteTest(t: GlobalTestState) { name: "Second Instance", paytoUris: [getTestHarnessPaytoForLabel("merchant-default")], auth: { - method: "external", + method: MerchantAuthMethod.EXTERNAL, }, }); - let merchantClient = new MerchantApiClient(merchant.makeInstanceBaseUrl(), { - auth: { - method: "external", - }, - }); + let auth = undefined; - await merchantClient.changeAuth({ - method: "token", - token: "secret-token:foobar", - }); + let merchantManagementClient = new TalerMerchantManagementHttpClient( + merchant.makeInstanceBaseUrl(), + ); - merchantClient = new MerchantApiClient(merchant.makeInstanceBaseUrl(), { - auth: { - method: "token", - token: "secret-token:foobar", - }, + await merchantManagementClient.updateCurrentInstanceAuthentication(auth, { + method: MerchantAuthMethod.TOKEN, + token: "secret-token:foobar" as AccessToken, }); // Check that deleting an instance checks the auth // of the default instance. { - const unauthMerchantClient = new MerchantApiClient( - merchant.makeInstanceBaseUrl(), - { - auth: { - method: "token", - token: "secret-token:invalid", - }, - }, - ); - const exc = await t.assertThrowsAsync(async () => { - await unauthMerchantClient.deleteInstance("myinst"); + await merchantManagementClient.deleteInstance( + "secret-token:bla" as AccessToken, + "myinst", + ); }); console.log("Got expected exception", exc); t.assertTrue(exc instanceof TalerError); diff --git a/packages/taler-harness/src/integrationtests/test-merchant-instances-urls.ts b/packages/taler-harness/src/integrationtests/test-merchant-instances-urls.ts @@ -17,12 +17,18 @@ /** * Imports. */ -import { Duration, MerchantApiClient } from "@gnu-taler/taler-util"; +import { + AccessToken, + Duration, + MerchantAuthMethod, + succeedOrThrow, + TalerMerchantManagementHttpClient, +} from "@gnu-taler/taler-util"; import { ExchangeService, GlobalTestState, - MerchantService, harnessHttpLib, + MerchantService, setupDb, } from "../harness/harness.js"; @@ -50,35 +56,32 @@ export async function runMerchantInstancesUrlsTest(t: GlobalTestState) { await merchant.start(); await merchant.pingUntilAvailable(); - const clientForDefault = new MerchantApiClient( + const tok = "secret-token:i-am-default" as AccessToken; + const clientForDefault = new TalerMerchantManagementHttpClient( merchant.makeInstanceBaseUrl(), - { + ); + + succeedOrThrow( + await clientForDefault.createInstance(tok, { + id: "default", + address: {}, + use_stefan: true, + default_pay_delay: Duration.toTalerProtocolDuration( + Duration.fromSpec({ seconds: 60 }), + ), + default_wire_transfer_delay: Duration.toTalerProtocolDuration( + Duration.fromSpec({ seconds: 60 }), + ), + jurisdiction: {}, + name: "My Default Instance", auth: { - method: "token", - token: "secret-token:i-am-default", + method: MerchantAuthMethod.TOKEN, + token: "secret-token:i-am-default" as AccessToken, }, - }, + }), ); - await clientForDefault.createInstance({ - id: "default", - address: {}, - use_stefan: true, - default_pay_delay: Duration.toTalerProtocolDuration( - Duration.fromSpec({ seconds: 60 }), - ), - default_wire_transfer_delay: Duration.toTalerProtocolDuration( - Duration.fromSpec({ seconds: 60 }), - ), - jurisdiction: {}, - name: "My Default Instance", - auth: { - method: "token", - token: "secret-token:i-am-default", - }, - }); - - await clientForDefault.createInstance({ + await clientForDefault.createInstance(undefined, { id: "myinst", address: {}, default_pay_delay: Duration.toTalerProtocolDuration( @@ -91,8 +94,8 @@ export async function runMerchantInstancesUrlsTest(t: GlobalTestState) { jurisdiction: {}, name: "My Second Instance", auth: { - method: "token", - token: "secret-token:i-am-myinst", + method: MerchantAuthMethod.TOKEN, + token: "secret-token:i-am-myinst" as AccessToken, }, }); diff --git a/packages/taler-harness/src/integrationtests/test-merchant-instances.ts b/packages/taler-harness/src/integrationtests/test-merchant-instances.ts @@ -17,13 +17,19 @@ /** * Imports. */ -import { MerchantApiClient, URL } from "@gnu-taler/taler-util"; +import { + AccessToken, + MerchantAuthMethod, + succeedOrThrow, + TalerMerchantManagementHttpClient, + URL, +} from "@gnu-taler/taler-util"; import { ExchangeService, - GlobalTestState, - MerchantService, getTestHarnessPaytoForLabel, + GlobalTestState, harnessHttpLib, + MerchantService, setupDb, } from "../harness/harness.js"; @@ -79,7 +85,7 @@ export async function runMerchantInstancesTest(t: GlobalTestState) { name: "Default Instance", paytoUris: [getTestHarnessPaytoForLabel("merchant-default")], auth: { - method: "external", + method: MerchantAuthMethod.EXTERNAL, }, }); @@ -89,7 +95,7 @@ export async function runMerchantInstancesTest(t: GlobalTestState) { name: "Default Instance", paytoUris: [getTestHarnessPaytoForLabel("merchant-default")], auth: { - method: "external", + method: MerchantAuthMethod.EXTERNAL, }, }); @@ -99,18 +105,16 @@ export async function runMerchantInstancesTest(t: GlobalTestState) { name: "Second Instance", paytoUris: [getTestHarnessPaytoForLabel("merchant-default")], auth: { - method: "external", + method: MerchantAuthMethod.EXTERNAL, }, }); - let merchantClient = new MerchantApiClient(merchant.makeInstanceBaseUrl(), { - auth: { - method: "external", - }, - }); + let merchantClient = new TalerMerchantManagementHttpClient( + merchant.makeInstanceBaseUrl(), + ); { - const r = await merchantClient.getInstances(); + const r = succeedOrThrow(await merchantClient.listInstances(undefined)); t.assertDeepEqual(r.instances.length, 2); } @@ -129,34 +133,31 @@ export async function runMerchantInstancesTest(t: GlobalTestState) { } { - const fullDetails = await merchantClient.getInstanceFullDetails("default"); + const fullDetails = succeedOrThrow( + await merchantClient.getInstanceDetails(undefined, "default"), + ); t.assertDeepEqual(fullDetails.auth.method, "external"); } - await merchantClient.changeAuth({ - method: "token", - token: "secret-token:foobar", + await merchantClient.updateCurrentInstanceAuthentication(undefined, { + method: MerchantAuthMethod.TOKEN, + token: "secret-token:foobar" as AccessToken, }); // Now this should fail, as we didn't change the auth of the client yet. const exc = await t.assertThrowsAsync(async () => { - console.log("requesting instances with auth", merchantClient.auth); - const resp = await merchantClient.getInstances(); + console.log("requesting instances with no auth"); + const resp = await merchantClient.listInstances(undefined); console.log("instances result:", resp); }); console.log(exc); t.assertTrue(exc.errorDetail.httpStatusCode === 401); - merchantClient = new MerchantApiClient(merchant.makeInstanceBaseUrl(), { - auth: { - method: "token", - token: "secret-token:foobar", - }, - }); + const auth = "secret-token:foobar" as AccessToken; // With the new client auth settings, request should work again. - await merchantClient.getInstances(); + succeedOrThrow(await merchantClient.listInstances(auth)); // Now, try some variations. { @@ -175,26 +176,19 @@ export async function runMerchantInstancesTest(t: GlobalTestState) { // Check that auth is reported properly { - const fullDetails = await merchantClient.getInstanceFullDetails("default"); + const fullDetails = succeedOrThrow( + await merchantClient.getInstanceDetails(auth, "default"), + ); t.assertDeepEqual(fullDetails.auth.method, "token"); // Token should *not* be reported back. - t.assertDeepEqual(fullDetails.auth.token, undefined); + t.assertDeepEqual((fullDetails.auth as any).token, undefined); } // Check that deleting an instance checks the auth // of the default instance. { - const unauthMerchantClient = new MerchantApiClient( - merchant.makeInstanceBaseUrl(), - { - auth: { - method: "external", - }, - }, - ); - const exc = await t.assertThrowsAsync(async () => { - await unauthMerchantClient.deleteInstance("myinst"); + await merchantClient.deleteInstance(undefined, "myinst"); }); console.log(exc); t.assertTrue(exc.errorDetail.httpStatusCode === 401); diff --git a/packages/taler-harness/src/integrationtests/test-merchant-longpolling.ts b/packages/taler-harness/src/integrationtests/test-merchant-longpolling.ts @@ -19,10 +19,11 @@ */ import { ConfirmPayResultType, - MerchantApiClient, PreparePayResultType, + TalerMerchantInstanceHttpClient, URL, codecForMerchantOrderStatusUnpaid, + succeedOrThrow, } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { @@ -50,7 +51,9 @@ export async function runMerchantLongpollingTest(t: GlobalTestState) { await wres.withdrawalFinishedCond; - const merchantClient = new MerchantApiClient(merchant.makeInstanceBaseUrl()); + const merchantClient = new TalerMerchantInstanceHttpClient( + merchant.makeInstanceBaseUrl(), + ); /** * ========================================================================= @@ -61,19 +64,22 @@ export async function runMerchantLongpollingTest(t: GlobalTestState) { * ========================================================================= */ - let orderResp = await merchantClient.createOrder({ - order: { - summary: "Buy me!", - amount: "TESTKUDOS:5", - fulfillment_url: "https://example.com/article42", - }, - create_token: false, - }); + let orderResp = succeedOrThrow( + await merchantClient.createOrder(undefined, { + order: { + summary: "Buy me!", + amount: "TESTKUDOS:5", + fulfillment_url: "https://example.com/article42", + }, + create_token: false, + }), + ); - let orderStatus = await merchantClient.queryPrivateOrderStatus({ - orderId: orderResp.order_id, - sessionId: "mysession-one", - }); + let orderStatus = succeedOrThrow( + await merchantClient.getOrderDetails(undefined, orderResp.order_id, { + sessionId: "mysession-one", + }), + ); t.assertTrue(orderStatus.order_status === "unpaid"); diff --git a/packages/taler-harness/src/integrationtests/test-merchant-refund-api.ts b/packages/taler-harness/src/integrationtests/test-merchant-refund-api.ts @@ -19,22 +19,23 @@ */ import { Duration, - MerchantApiClient, PreparePayResultType, + succeedOrThrow, + TalerMerchantInstanceHttpClient, URL, } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { + createSimpleTestkudosEnvironmentV3, + withdrawViaBankV3, +} from "../harness/environments.js"; +import { ExchangeServiceInterface, GlobalTestState, + harnessHttpLib, MerchantServiceInterface, WalletClient, - harnessHttpLib, } from "../harness/harness.js"; -import { - createSimpleTestkudosEnvironmentV3, - withdrawViaBankV3, -} from "../harness/environments.js"; async function testRefundApiWithFulfillmentUrl( t: GlobalTestState, @@ -46,23 +47,27 @@ async function testRefundApiWithFulfillmentUrl( ): Promise<void> { const { walletClient, merchant } = env; - const merchantClient = new MerchantApiClient(merchant.makeInstanceBaseUrl()); + const merchantClient = new TalerMerchantInstanceHttpClient( + merchant.makeInstanceBaseUrl(), + ); // Set up order. - const orderResp = await merchantClient.createOrder({ - order: { - summary: "Buy me!", - amount: "TESTKUDOS:5", - fulfillment_url: "https://example.com/fulfillment", - }, - refund_delay: Duration.toTalerProtocolDuration( - Duration.fromSpec({ minutes: 5 }), - ), - }); + const orderResp = succeedOrThrow( + await merchantClient.createOrder(undefined, { + order: { + summary: "Buy me!", + amount: "TESTKUDOS:5", + fulfillment_url: "https://example.com/fulfillment", + }, + refund_delay: Duration.toTalerProtocolDuration( + Duration.fromSpec({ minutes: 5 }), + ), + }), + ); - let orderStatus = await merchantClient.queryPrivateOrderStatus({ - orderId: orderResp.order_id, - }); + let orderStatus = succeedOrThrow( + await merchantClient.getOrderDetails(undefined, orderResp.order_id), + ); t.assertTrue(orderStatus.order_status === "unpaid"); @@ -88,9 +93,9 @@ async function testRefundApiWithFulfillmentUrl( // Check if payment was successful. - orderStatus = await merchantClient.queryPrivateOrderStatus({ - orderId: orderResp.order_id, - }); + orderStatus = succeedOrThrow( + await merchantClient.getOrderDetails(undefined, orderResp.order_id), + ); t.assertTrue(orderStatus.order_status === "paid"); @@ -105,16 +110,14 @@ async function testRefundApiWithFulfillmentUrl( preparePayResult.status === PreparePayResultType.AlreadyConfirmed, ); - await merchantClient.giveRefund({ - amount: "TESTKUDOS:5", - instance: "default", - justification: "foo", - orderId: orderResp.order_id, + await merchantClient.addRefund(undefined, orderResp.order_id, { + refund: "TESTKUDOS:5", + reason: "foo", }); - orderStatus = await merchantClient.queryPrivateOrderStatus({ - orderId: orderResp.order_id, - }); + orderStatus = succeedOrThrow( + await merchantClient.getOrderDetails(undefined, orderResp.order_id), + ); t.assertTrue(orderStatus.order_status === "paid"); @@ -161,23 +164,27 @@ async function testRefundApiWithFulfillmentMessage( ): Promise<void> { const { walletClient, merchant } = env; - const merchantClient = new MerchantApiClient(merchant.makeInstanceBaseUrl()); + const merchantClient = new TalerMerchantInstanceHttpClient( + merchant.makeInstanceBaseUrl(), + ); // Set up order. - const orderResp = await merchantClient.createOrder({ - order: { - summary: "Buy me!", - amount: "TESTKUDOS:5", - fulfillment_message: "Thank you for buying foobar", - }, - refund_delay: Duration.toTalerProtocolDuration( - Duration.fromSpec({ minutes: 5 }), - ), - }); + const orderResp = succeedOrThrow( + await merchantClient.createOrder(undefined, { + order: { + summary: "Buy me!", + amount: "TESTKUDOS:5", + fulfillment_message: "Thank you for buying foobar", + }, + refund_delay: Duration.toTalerProtocolDuration( + Duration.fromSpec({ minutes: 5 }), + ), + }), + ); - let orderStatus = await merchantClient.queryPrivateOrderStatus({ - orderId: orderResp.order_id, - }); + let orderStatus = succeedOrThrow( + await merchantClient.getOrderDetails(undefined, orderResp.order_id), + ); t.assertTrue(orderStatus.order_status === "unpaid"); @@ -203,9 +210,9 @@ async function testRefundApiWithFulfillmentMessage( // Check if payment was successful. - orderStatus = await merchantClient.queryPrivateOrderStatus({ - orderId: orderResp.order_id, - }); + orderStatus = succeedOrThrow( + await merchantClient.getOrderDetails(undefined, orderResp.order_id), + ); t.assertTrue(orderStatus.order_status === "paid"); @@ -220,16 +227,14 @@ async function testRefundApiWithFulfillmentMessage( preparePayResult.status === PreparePayResultType.AlreadyConfirmed, ); - await merchantClient.giveRefund({ - amount: "TESTKUDOS:5", - instance: "default", - justification: "foo", - orderId: orderResp.order_id, + await merchantClient.addRefund(undefined, orderId, { + refund: "TESTKUDOS:5", + reason: "foo", }); - orderStatus = await merchantClient.queryPrivateOrderStatus({ - orderId: orderResp.order_id, - }); + orderStatus = succeedOrThrow( + await merchantClient.getOrderDetails(undefined, orderId), + ); t.assertTrue(orderStatus.order_status === "paid"); diff --git a/packages/taler-harness/src/integrationtests/test-merchant-spec-public-orders.ts b/packages/taler-harness/src/integrationtests/test-merchant-spec-public-orders.ts @@ -19,12 +19,13 @@ */ import { ConfirmPayResultType, - MerchantApiClient, PreparePayResultType, TalerCorebankApiClient, + TalerMerchantInstanceHttpClient, URL, encodeCrock, getRandomBytes, + succeedOrThrow, } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { @@ -65,15 +66,19 @@ async function testWithClaimToken( }); await wres.withdrawalFinishedCond; const sessionId = "mysession"; - const merchantClient = new MerchantApiClient(merchant.makeInstanceBaseUrl()); - const orderResp = await merchantClient.createOrder({ - order: { - summary: "Buy me!", - amount: "TESTKUDOS:5", - fulfillment_url: "https://example.com/article42", - public_reorder_url: "https://example.com/article42-share", - }, - }); + const merchantClient = new TalerMerchantInstanceHttpClient( + merchant.makeInstanceBaseUrl(), + ); + const orderResp = succeedOrThrow( + await merchantClient.createOrder(undefined, { + order: { + summary: "Buy me!", + amount: "TESTKUDOS:5", + fulfillment_url: "https://example.com/article42", + public_reorder_url: "https://example.com/article42-share", + }, + }), + ); const claimToken = orderResp.token; const orderId = orderResp.order_id; @@ -255,14 +260,16 @@ async function testWithClaimToken( t.assertTrue(confirmPayRes2.type === ConfirmPayResultType.Done); // Create another order with identical fulfillment URL to test the "already paid" flow - const alreadyPaidOrderResp = await merchantClient.createOrder({ - order: { - summary: "Buy me!", - amount: "TESTKUDOS:5", - fulfillment_url: "https://example.com/article42", - public_reorder_url: "https://example.com/article42-share", - }, - }); + const alreadyPaidOrderResp = succeedOrThrow( + await merchantClient.createOrder(undefined, { + order: { + summary: "Buy me!", + amount: "TESTKUDOS:5", + fulfillment_url: "https://example.com/article42", + public_reorder_url: "https://example.com/article42-share", + }, + }), + ); const apOrderId = alreadyPaidOrderResp.order_id; const apToken = alreadyPaidOrderResp.token; @@ -319,7 +326,9 @@ async function testWithoutClaimToken( const sessionId = "mysession2"; const { bankClient, exchange } = c; const { merchant, merchantBaseUrl } = c; - const merchantClient = new MerchantApiClient(merchant.makeInstanceBaseUrl()); + const merchantClient = new TalerMerchantInstanceHttpClient( + merchant.makeInstanceBaseUrl(), + ); const wres = await withdrawViaBankV3(t, { walletClient, bankClient, @@ -327,15 +336,17 @@ async function testWithoutClaimToken( amount: "TESTKUDOS:20", }); await wres.withdrawalFinishedCond; - const orderResp = await merchantClient.createOrder({ - order: { - summary: "Buy me!", - amount: "TESTKUDOS:5", - fulfillment_url: "https://example.com/article42", - public_reorder_url: "https://example.com/article42-share", - }, - create_token: false, - }); + const orderResp = succeedOrThrow( + await merchantClient.createOrder(undefined, { + order: { + summary: "Buy me!", + amount: "TESTKUDOS:5", + fulfillment_url: "https://example.com/article42", + public_reorder_url: "https://example.com/article42-share", + }, + create_token: false, + }), + ); const orderId = orderResp.order_id; let talerPayUri: string; @@ -515,14 +526,16 @@ async function testWithoutClaimToken( t.assertTrue(confirmPayRes2.type === ConfirmPayResultType.Done); // Create another order with identical fulfillment URL to test the "already paid" flow - const alreadyPaidOrderResp = await merchantClient.createOrder({ - order: { - summary: "Buy me!", - amount: "TESTKUDOS:5", - fulfillment_url: "https://example.com/article42", - public_reorder_url: "https://example.com/article42-share", - }, - }); + const alreadyPaidOrderResp = succeedOrThrow( + await merchantClient.createOrder(undefined, { + order: { + summary: "Buy me!", + amount: "TESTKUDOS:5", + fulfillment_url: "https://example.com/article42", + public_reorder_url: "https://example.com/article42-share", + }, + }), + ); const apOrderId = alreadyPaidOrderResp.order_id; const apToken = alreadyPaidOrderResp.token; diff --git a/packages/taler-harness/src/integrationtests/test-otp.ts b/packages/taler-harness/src/integrationtests/test-otp.ts @@ -20,19 +20,20 @@ import { ConfirmPayResultType, Duration, - MerchantApiClient, PreparePayResultType, + TalerMerchantInstanceHttpClient, TransactionType, j2s, narrowOpSuccessOrThrow, randomRfc3548Base32Key, + succeedOrThrow, } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; -import { GlobalTestState } from "../harness/harness.js"; import { createSimpleTestkudosEnvironmentV3, withdrawViaBankV3, } from "../harness/environments.js"; +import { GlobalTestState } from "../harness/harness.js"; /** * Run test for basic, bank-integrated withdrawal and payment. @@ -43,31 +44,38 @@ export async function runOtpTest(t: GlobalTestState) { const { walletClient, bankClient, exchange, merchant } = await createSimpleTestkudosEnvironmentV3(t); - const merchantClient = new MerchantApiClient(merchant.makeInstanceBaseUrl()); - const createOtpRes = await merchantClient.createOtpDevice({ - otp_algorithm: 1, - otp_device_description: "Hello", - otp_device_id: "mydevice", - otp_key: randomRfc3548Base32Key(), - }); - narrowOpSuccessOrThrow("createOtpDevice", createOtpRes); - - const createTemplateRes = await merchantClient.createTemplate({ - template_description: "my template", - template_id: "tpl1", - otp_id: "mydevice", - template_contract: { - summary: "test", - amount: "TESTKUDOS:1", - minimum_age: 0, - pay_duration: Duration.toTalerProtocolDuration( - Duration.fromSpec({ hours: 1 }), - ), - }, - }); - narrowOpSuccessOrThrow("createTemplate", createTemplateRes); + const merchantClient = new TalerMerchantInstanceHttpClient( + merchant.makeInstanceBaseUrl(), + ); + succeedOrThrow( + await merchantClient.addOtpDevice(undefined, { + otp_algorithm: 1, + otp_device_description: "Hello", + otp_device_id: "mydevice", + otp_key: randomRfc3548Base32Key(), + }), + ); - const getTemplateResp = await merchantClient.getTemplate("tpl1"); + succeedOrThrow( + await merchantClient.addTemplate(undefined, { + template_description: "my template", + template_id: "tpl1", + otp_id: "mydevice", + template_contract: { + summary: "test", + amount: "TESTKUDOS:1", + minimum_age: 0, + pay_duration: Duration.toTalerProtocolDuration( + Duration.fromSpec({ hours: 1 }), + ), + }, + }), + ); + + const getTemplateResp = await merchantClient.getTemplateDetails( + undefined, + "tpl1", + ); narrowOpSuccessOrThrow("getTemplate", getTemplateResp); console.log(`template: ${j2s(getTemplateResp.body)}`); diff --git a/packages/taler-harness/src/integrationtests/test-pay-paid.ts b/packages/taler-harness/src/integrationtests/test-pay-paid.ts @@ -19,11 +19,12 @@ */ import { ConfirmPayResultType, - MerchantApiClient, PreparePayResultType, TalerCorebankApiClient, + TalerMerchantInstanceHttpClient, URL, codecForMerchantOrderStatusUnpaid, + succeedOrThrow, } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { @@ -71,21 +72,26 @@ export async function runPayPaidTest(t: GlobalTestState) { const merchant = faultyMerchant; - const merchantClient = new MerchantApiClient(merchant.makeInstanceBaseUrl()); + const merchantClient = new TalerMerchantInstanceHttpClient( + merchant.makeInstanceBaseUrl(), + ); - let orderResp = await merchantClient.createOrder({ - order: { - summary: "Buy me!", - amount: "TESTKUDOS:5", - fulfillment_url: "https://example.com/article42", - public_reorder_url: "https://example.com/article42-share", - }, - }); + let orderResp = succeedOrThrow( + await merchantClient.createOrder(undefined, { + order: { + summary: "Buy me!", + amount: "TESTKUDOS:5", + fulfillment_url: "https://example.com/article42", + public_reorder_url: "https://example.com/article42-share", + }, + }), + ); - let orderStatus = await merchantClient.queryPrivateOrderStatus({ - orderId: orderResp.order_id, - sessionId: "mysession-one", - }); + let orderStatus = succeedOrThrow( + await merchantClient.getOrderDetails(undefined, orderResp.order_id, { + sessionId: "mysession-one", + }), + ); t.assertTrue(orderStatus.order_status === "unpaid"); @@ -152,10 +158,11 @@ export async function runPayPaidTest(t: GlobalTestState) { * ========================================================================= */ - orderStatus = await merchantClient.queryPrivateOrderStatus({ - orderId: orderResp.order_id, - sessionId: "mysession-two", - }); + orderStatus = succeedOrThrow( + await merchantClient.getOrderDetails(undefined, orderResp.order_id, { + sessionId: "mysession-two", + }), + ); console.log( "order status under mysession-two:", @@ -179,19 +186,22 @@ export async function runPayPaidTest(t: GlobalTestState) { }, }); - let orderRespTwo = await merchantClient.createOrder({ - order: { - summary: "Buy me!", - amount: "TESTKUDOS:5", - fulfillment_url: "https://example.com/article42", - public_reorder_url: "https://example.com/article42-share", - }, - }); + let orderRespTwo = succeedOrThrow( + await merchantClient.createOrder(undefined, { + order: { + summary: "Buy me!", + amount: "TESTKUDOS:5", + fulfillment_url: "https://example.com/article42", + public_reorder_url: "https://example.com/article42-share", + }, + }), + ); - let orderStatusTwo = await merchantClient.queryPrivateOrderStatus({ - orderId: orderRespTwo.order_id, - sessionId: "mysession-two", - }); + let orderStatusTwo = succeedOrThrow( + await merchantClient.getOrderDetails(undefined, orderRespTwo.order_id, { + sessionId: "mysession-two", + }), + ); t.assertTrue(orderStatusTwo.order_status === "unpaid"); diff --git a/packages/taler-harness/src/integrationtests/test-payment-abort.ts b/packages/taler-harness/src/integrationtests/test-payment-abort.ts @@ -19,14 +19,15 @@ */ import { ConfirmPayResultType, - MerchantApiClient, PreparePayResultType, TalerCorebankApiClient, TalerErrorCode, TalerErrorDetail, + TalerMerchantInstanceHttpClient, URL, codecForMerchantOrderStatusUnpaid, j2s, + succeedOrThrow, } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { @@ -55,23 +56,26 @@ export async function runPaymentAbortTest(t: GlobalTestState) { await wres.withdrawalFinishedCond; - const merchantClient = new MerchantApiClient( + const merchantClient = new TalerMerchantInstanceHttpClient( faultyMerchant.makeInstanceBaseUrl(), ); - let orderResp = await merchantClient.createOrder({ - order: { - summary: "Buy me!", - amount: "TESTKUDOS:5", - fulfillment_url: "https://example.com/article42", - public_reorder_url: "https://example.com/article42-share", - }, - }); + let orderResp = succeedOrThrow( + await merchantClient.createOrder(undefined, { + order: { + summary: "Buy me!", + amount: "TESTKUDOS:5", + fulfillment_url: "https://example.com/article42", + public_reorder_url: "https://example.com/article42-share", + }, + }), + ); - let orderStatus = await merchantClient.queryPrivateOrderStatus({ - orderId: orderResp.order_id, - sessionId: "mysession-one", - }); + let orderStatus = succeedOrThrow( + await merchantClient.getOrderDetails(undefined, orderResp.order_id, { + sessionId: "mysession-one", + }), + ); t.assertTrue(orderStatus.order_status === "unpaid"); diff --git a/packages/taler-harness/src/integrationtests/test-payment-claim.ts b/packages/taler-harness/src/integrationtests/test-payment-claim.ts @@ -18,17 +18,18 @@ * Imports. */ import { - MerchantApiClient, PreparePayResultType, + succeedOrThrow, TalerErrorCode, + TalerMerchantInstanceHttpClient, } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; -import { GlobalTestState } from "../harness/harness.js"; import { createSimpleTestkudosEnvironmentV3, createWalletDaemonWithClient, withdrawViaBankV3, } from "../harness/environments.js"; +import { GlobalTestState } from "../harness/harness.js"; /** * Run test where a wallet tries to claim an already claimed order. @@ -39,7 +40,9 @@ export async function runPaymentClaimTest(t: GlobalTestState) { const { walletClient, bankClient, exchange, merchant } = await createSimpleTestkudosEnvironmentV3(t); - const merchantClient = new MerchantApiClient(merchant.makeInstanceBaseUrl()); + const merchantClient = new TalerMerchantInstanceHttpClient( + merchant.makeInstanceBaseUrl(), + ); const w2 = await createWalletDaemonWithClient(t, { name: "w2" }); @@ -56,17 +59,19 @@ export async function runPaymentClaimTest(t: GlobalTestState) { // Set up order. - const orderResp = await merchantClient.createOrder({ - order: { - summary: "Buy me!", - amount: "TESTKUDOS:5", - fulfillment_url: "taler://fulfillment-success/thx", - }, - }); + const orderResp = succeedOrThrow( + await merchantClient.createOrder(undefined, { + order: { + summary: "Buy me!", + amount: "TESTKUDOS:5", + fulfillment_url: "taler://fulfillment-success/thx", + }, + }), + ); - let orderStatus = await merchantClient.queryPrivateOrderStatus({ - orderId: orderResp.order_id, - }); + let orderStatus = succeedOrThrow( + await merchantClient.getOrderDetails(undefined, orderResp.order_id), + ); t.assertTrue(orderStatus.order_status === "unpaid"); @@ -99,9 +104,9 @@ export async function runPaymentClaimTest(t: GlobalTestState) { // Check if payment was successful. - orderStatus = await merchantClient.queryPrivateOrderStatus({ - orderId: orderResp.order_id, - }); + orderStatus = succeedOrThrow( + await merchantClient.getOrderDetails(undefined, orderResp.order_id), + ); t.assertTrue(orderStatus.order_status === "paid"); diff --git a/packages/taler-harness/src/integrationtests/test-payment-deleted.ts b/packages/taler-harness/src/integrationtests/test-payment-deleted.ts @@ -19,16 +19,17 @@ */ import { ConfirmPayResultType, - MerchantApiClient, PreparePayResultType, + TalerMerchantInstanceHttpClient, j2s, + succeedOrThrow, } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; -import { GlobalTestState } from "../harness/harness.js"; import { createSimpleTestkudosEnvironmentV3, withdrawViaBankV3, } from "../harness/environments.js"; +import { GlobalTestState } from "../harness/harness.js"; /** * Test behavior when an order is deleted while the wallet is paying for it. @@ -52,18 +53,22 @@ export async function runPaymentDeletedTest(t: GlobalTestState) { await walletClient.call(WalletApiOperation.TestingWaitTransactionsFinal, {}); - const merchantClient = new MerchantApiClient(merchant.makeInstanceBaseUrl()); + const merchantClient = new TalerMerchantInstanceHttpClient( + merchant.makeInstanceBaseUrl(), + ); - const orderResp = await merchantClient.createOrder({ - order: { - summary: "Hello", - amount: "TESTKUDOS:2", - }, - }); + const orderResp = succeedOrThrow( + await merchantClient.createOrder(undefined, { + order: { + summary: "Hello", + amount: "TESTKUDOS:2", + }, + }), + ); - let orderStatus = await merchantClient.queryPrivateOrderStatus({ - orderId: orderResp.order_id, - }); + let orderStatus = succeedOrThrow( + await merchantClient.getOrderDetails(undefined, orderResp.order_id), + ); t.assertTrue(orderStatus.order_status === "unpaid"); @@ -80,10 +85,9 @@ export async function runPaymentDeletedTest(t: GlobalTestState) { preparePayResult.status === PreparePayResultType.PaymentPossible, ); - await merchantClient.deleteOrder({ - orderId: orderResp.order_id, - force: true, - }); + succeedOrThrow( + await merchantClient.deleteOrder(undefined, orderResp.order_id, true), + ); const r2 = await walletClient.call(WalletApiOperation.ConfirmPay, { transactionId: preparePayResult.transactionId, diff --git a/packages/taler-harness/src/integrationtests/test-payment-expired.ts b/packages/taler-harness/src/integrationtests/test-payment-expired.ts @@ -19,20 +19,20 @@ */ import { AbsoluteTime, - ConfirmPayResultType, Duration, - MerchantApiClient, PreparePayResultType, TalerMerchantApi, + TalerMerchantInstanceHttpClient, j2s, + succeedOrThrow, } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; -import { GlobalTestState } from "../harness/harness.js"; import { applyTimeTravelV2, createSimpleTestkudosEnvironmentV3, withdrawViaBankV3, } from "../harness/environments.js"; +import { GlobalTestState } from "../harness/harness.js"; /** * Run a test for the following scenario: @@ -76,15 +76,19 @@ export async function runPaymentExpiredTest(t: GlobalTestState) { ), }; - const merchantClient = new MerchantApiClient(merchant.makeInstanceBaseUrl()); + const merchantClient = new TalerMerchantInstanceHttpClient( + merchant.makeInstanceBaseUrl(), + ); - const orderResp = await merchantClient.createOrder({ - order, - }); + const orderResp = succeedOrThrow( + await merchantClient.createOrder(undefined, { + order, + }), + ); - let orderStatus = await merchantClient.queryPrivateOrderStatus({ - orderId: orderResp.order_id, - }); + let orderStatus = succeedOrThrow( + await merchantClient.getOrderDetails(undefined, orderResp.order_id), + ); t.assertTrue(orderStatus.order_status === "unpaid"); diff --git a/packages/taler-harness/src/integrationtests/test-payment-fault.ts b/packages/taler-harness/src/integrationtests/test-payment-fault.ts @@ -23,12 +23,17 @@ */ import { ConfirmPayResultType, - MerchantApiClient, + succeedOrThrow, TalerCorebankApiClient, + TalerMerchantInstanceHttpClient, } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { defaultCoinConfig } from "../harness/denomStructures.js"; import { + createWalletDaemonWithClient, + withdrawViaBankV3, +} from "../harness/environments.js"; +import { FaultInjectedExchangeService, FaultInjectionRequestContext, FaultInjectionResponseContext, @@ -36,15 +41,11 @@ import { import { BankService, ExchangeService, + getTestHarnessPaytoForLabel, GlobalTestState, MerchantService, - getTestHarnessPaytoForLabel, setupDb, } from "../harness/harness.js"; -import { - createWalletDaemonWithClient, - withdrawViaBankV3, -} from "../harness/environments.js"; /** * Run test for basic, bank-integrated withdrawal. @@ -142,7 +143,9 @@ export async function runPaymentFaultTest(t: GlobalTestState) { paytoUris: [getTestHarnessPaytoForLabel("merchant-default")], }); - const merchantClient = new MerchantApiClient(merchant.makeInstanceBaseUrl()); + const merchantClient = new TalerMerchantInstanceHttpClient( + merchant.makeInstanceBaseUrl(), + ); console.log("setup done!"); @@ -163,17 +166,19 @@ export async function runPaymentFaultTest(t: GlobalTestState) { // Set up order. - const orderResp = await merchantClient.createOrder({ - order: { - summary: "Buy me!", - amount: "TESTKUDOS:5", - fulfillment_url: "taler://fulfillment-success/thx", - }, - }); + const orderResp = succeedOrThrow( + await merchantClient.createOrder(undefined, { + order: { + summary: "Buy me!", + amount: "TESTKUDOS:5", + fulfillment_url: "taler://fulfillment-success/thx", + }, + }), + ); - let orderStatus = await merchantClient.queryPrivateOrderStatus({ - orderId: orderResp.order_id, - }); + let orderStatus = succeedOrThrow( + await merchantClient.getOrderDetails(undefined, orderResp.order_id), + ); t.assertTrue(orderStatus.order_status === "unpaid"); @@ -222,9 +227,9 @@ export async function runPaymentFaultTest(t: GlobalTestState) { // Check if payment was successful. - orderStatus = await merchantClient.queryPrivateOrderStatus({ - orderId: orderResp.order_id, - }); + orderStatus = succeedOrThrow( + await merchantClient.getOrderDetails(undefined, orderResp.order_id), + ); t.assertTrue(orderStatus.order_status === "paid"); } diff --git a/packages/taler-harness/src/integrationtests/test-payment-idempotency.ts b/packages/taler-harness/src/integrationtests/test-payment-idempotency.ts @@ -17,13 +17,17 @@ /** * Imports. */ -import { MerchantApiClient, PreparePayResultType } from "@gnu-taler/taler-util"; +import { + PreparePayResultType, + succeedOrThrow, + TalerMerchantInstanceHttpClient, +} from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; -import { GlobalTestState } from "../harness/harness.js"; import { createSimpleTestkudosEnvironmentV3, withdrawViaBankV3, } from "../harness/environments.js"; +import { GlobalTestState } from "../harness/harness.js"; /** * Test the wallet-core payment API, especially that repeated operations @@ -46,21 +50,25 @@ export async function runPaymentIdempotencyTest(t: GlobalTestState) { await wres.withdrawalFinishedCond; - const merchantClient = new MerchantApiClient(merchant.makeInstanceBaseUrl()); + const merchantClient = new TalerMerchantInstanceHttpClient( + merchant.makeInstanceBaseUrl(), + ); // Set up order. - const orderResp = await merchantClient.createOrder({ - order: { - summary: "Buy me!", - amount: "TESTKUDOS:5", - fulfillment_url: "taler://fulfillment-success/thx", - }, - }); + const orderResp = succeedOrThrow( + await merchantClient.createOrder(undefined, { + order: { + summary: "Buy me!", + amount: "TESTKUDOS:5", + fulfillment_url: "taler://fulfillment-success/thx", + }, + }), + ); - let orderStatus = await merchantClient.queryPrivateOrderStatus({ - orderId: orderResp.order_id, - }); + let orderStatus = succeedOrThrow( + await merchantClient.getOrderDetails(undefined, orderResp.order_id), + ); t.assertTrue(orderStatus.order_status === "unpaid"); @@ -104,9 +112,9 @@ export async function runPaymentIdempotencyTest(t: GlobalTestState) { // Check if payment was successful. - orderStatus = await merchantClient.queryPrivateOrderStatus({ - orderId: orderResp.order_id, - }); + orderStatus = succeedOrThrow( + await merchantClient.getOrderDetails(undefined, orderResp.order_id), + ); t.assertTrue(orderStatus.order_status === "paid"); diff --git a/packages/taler-harness/src/integrationtests/test-payment-multiple.ts b/packages/taler-harness/src/integrationtests/test-payment-multiple.ts @@ -18,23 +18,24 @@ * Imports. */ import { - MerchantApiClient, + succeedOrThrow, TalerCorebankApiClient, + TalerMerchantInstanceHttpClient, } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { coin_ct10, coin_u1 } from "../harness/denomStructures.js"; import { + createWalletDaemonWithClient, + withdrawViaBankV3, +} from "../harness/environments.js"; +import { BankService, ExchangeService, + getTestHarnessPaytoForLabel, GlobalTestState, MerchantService, - getTestHarnessPaytoForLabel, setupDb, } from "../harness/harness.js"; -import { - createWalletDaemonWithClient, - withdrawViaBankV3, -} from "../harness/environments.js"; async function setupTest(t: GlobalTestState): Promise<{ merchant: MerchantService; @@ -144,7 +145,9 @@ export async function runPaymentMultipleTest(t: GlobalTestState) { name: "default", }); - const merchantClient = new MerchantApiClient(merchant.makeInstanceBaseUrl()); + const merchantClient = new TalerMerchantInstanceHttpClient( + merchant.makeInstanceBaseUrl(), + ); // Withdraw digital cash into the wallet. @@ -159,17 +162,19 @@ export async function runPaymentMultipleTest(t: GlobalTestState) { // Set up order. - const orderResp = await merchantClient.createOrder({ - order: { - summary: "Buy me!", - amount: "TESTKUDOS:80", - fulfillment_url: "taler://fulfillment-success/thx", - }, - }); + const orderResp = succeedOrThrow( + await merchantClient.createOrder(undefined, { + order: { + summary: "Buy me!", + amount: "TESTKUDOS:80", + fulfillment_url: "taler://fulfillment-success/thx", + }, + }), + ); - let orderStatus = await merchantClient.queryPrivateOrderStatus({ - orderId: orderResp.order_id, - }); + let orderStatus = succeedOrThrow( + await merchantClient.getOrderDetails(undefined, orderResp.order_id), + ); t.assertTrue(orderStatus.order_status === "unpaid"); @@ -185,9 +190,9 @@ export async function runPaymentMultipleTest(t: GlobalTestState) { // Check if payment was successful. - orderStatus = await merchantClient.queryPrivateOrderStatus({ - orderId: orderResp.order_id, - }); + orderStatus = succeedOrThrow( + await merchantClient.getOrderDetails(undefined, orderResp.order_id), + ); t.assertTrue(orderStatus.order_status === "paid"); diff --git a/packages/taler-harness/src/integrationtests/test-payment-share.ts b/packages/taler-harness/src/integrationtests/test-payment-share.ts @@ -20,18 +20,17 @@ import { AmountString, ConfirmPayResultType, - MerchantApiClient, - NotificationType, PreparePayResultType, - j2s, + succeedOrThrow, + TalerMerchantInstanceHttpClient, } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; -import { GlobalTestState } from "../harness/harness.js"; import { createSimpleTestkudosEnvironmentV3, createWalletDaemonWithClient, withdrawViaBankV3, } from "../harness/environments.js"; +import { GlobalTestState } from "../harness/harness.js"; /** * Run test for basic, bank-integrated withdrawal and payment. @@ -45,7 +44,9 @@ export async function runPaymentShareTest(t: GlobalTestState) { merchant, } = await createSimpleTestkudosEnvironmentV3(t); - const merchantClient = new MerchantApiClient(merchant.makeInstanceBaseUrl()); + const merchantClient = new TalerMerchantInstanceHttpClient( + merchant.makeInstanceBaseUrl(), + ); // Withdraw digital cash into the wallet. await withdrawViaBankV3(t, { @@ -87,13 +88,15 @@ export async function runPaymentShareTest(t: GlobalTestState) { const args = { order }; - const orderResp = await merchantClient.createOrder({ - order: args.order, - }); + const orderResp = succeedOrThrow( + await merchantClient.createOrder(undefined, { + order: args.order, + }), + ); - const orderStatus = await merchantClient.queryPrivateOrderStatus({ - orderId: orderResp.order_id, - }); + const orderStatus = succeedOrThrow( + await merchantClient.getOrderDetails(undefined, orderResp.order_id), + ); t.assertTrue(orderStatus.order_status === "unpaid"); return { id: orderResp.order_id, uri: orderStatus.taler_pay_uri }; @@ -184,7 +187,7 @@ export async function runPaymentShareTest(t: GlobalTestState) { t.assertTrue( claimFirstWalletAgain.status === PreparePayResultType.AlreadyConfirmed, ); - t.assertTrue( claimFirstWalletAgain.paid ); + t.assertTrue(claimFirstWalletAgain.paid); t.logStep("w1-prepared-again"); @@ -196,10 +199,7 @@ export async function runPaymentShareTest(t: GlobalTestState) { t.logStep("w1-confirmed-shared"); - await firstWallet.call( - WalletApiOperation.TestingWaitTransactionsFinal, - {}, - ); + await firstWallet.call(WalletApiOperation.TestingWaitTransactionsFinal, {}); await secondWallet.call( WalletApiOperation.TestingWaitTransactionsFinal, @@ -297,10 +297,7 @@ export async function runPaymentShareTest(t: GlobalTestState) { t.assertTrue( claimSecondWalletAgain.status === PreparePayResultType.AlreadyConfirmed, ); - t.assertTrue( - claimSecondWalletAgain.paid, - ); - + t.assertTrue(claimSecondWalletAgain.paid); } t.logStep("second-case-done"); diff --git a/packages/taler-harness/src/integrationtests/test-payment-template.ts b/packages/taler-harness/src/integrationtests/test-payment-template.ts @@ -21,16 +21,16 @@ import { AmountString, ConfirmPayResultType, Duration, - MerchantApiClient, PreparePayResultType, - narrowOpSuccessOrThrow, + TalerMerchantInstanceHttpClient, + succeedOrThrow, } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; -import { GlobalTestState } from "../harness/harness.js"; import { createSimpleTestkudosEnvironmentV3, withdrawViaBankV3, } from "../harness/environments.js"; +import { GlobalTestState } from "../harness/harness.js"; /** * Test for taler://payment-template/ URIs @@ -41,27 +41,30 @@ export async function runPaymentTemplateTest(t: GlobalTestState) { const { walletClient, bankClient, exchange, merchant } = await createSimpleTestkudosEnvironmentV3(t); - const merchantClient = new MerchantApiClient(merchant.makeInstanceBaseUrl()); + const merchantClient = new TalerMerchantInstanceHttpClient( + merchant.makeInstanceBaseUrl(), + ); const mySummary = "hello, I'm a summary"; - const createTemplateRes = await merchantClient.createTemplate({ - template_id: "template1", - template_description: "my test template", - template_contract: { - minimum_age: 0, - pay_duration: Duration.toTalerProtocolDuration( - Duration.fromSpec({ - minutes: 2, - }), - ), - summary: mySummary, - }, - editable_defaults: { - amount: "TESTKUDOS:1" as AmountString, - }, - }); - narrowOpSuccessOrThrow("createTemplate", createTemplateRes); + succeedOrThrow( + await merchantClient.addTemplate(undefined, { + template_id: "template1", + template_description: "my test template", + template_contract: { + minimum_age: 0, + pay_duration: Duration.toTalerProtocolDuration( + Duration.fromSpec({ + minutes: 2, + }), + ), + summary: mySummary, + }, + editable_defaults: { + amount: "TESTKUDOS:1" as AmountString, + }, + }), + ); // Withdraw digital cash into the wallet. @@ -115,10 +118,12 @@ export async function runPaymentTemplateTest(t: GlobalTestState) { // Check if payment was successful. - const orderStatus = await merchantClient.queryPrivateOrderStatus({ - orderId: preparePayResult.contractTerms.order_id, - instance: "default", - }); + const orderStatus = succeedOrThrow( + await merchantClient.getOrderDetails( + undefined, + preparePayResult.contractTerms.order_id, + ), + ); t.assertTrue(orderStatus.order_status === "paid"); await walletClient.call(WalletApiOperation.TestingWaitTransactionsFinal, {}); diff --git a/packages/taler-harness/src/integrationtests/test-payment-transient.ts b/packages/taler-harness/src/integrationtests/test-payment-transient.ts @@ -19,13 +19,14 @@ */ import { ConfirmPayResultType, - MerchantApiClient, PreparePayResultType, TalerCorebankApiClient, TalerErrorCode, TalerErrorDetail, + TalerMerchantInstanceHttpClient, URL, codecForMerchantOrderStatusUnpaid, + succeedOrThrow, } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { @@ -45,7 +46,7 @@ export async function runPaymentTransientTest(t: GlobalTestState) { const { walletClient, bank, faultyMerchant, faultyExchange } = await createFaultInjectedMerchantTestkudosEnvironment(t); - const merchantClient = new MerchantApiClient( + const merchantClient = new TalerMerchantInstanceHttpClient( faultyMerchant.makeInstanceBaseUrl(), ); @@ -62,19 +63,22 @@ export async function runPaymentTransientTest(t: GlobalTestState) { await wres.withdrawalFinishedCond; - let orderResp = await merchantClient.createOrder({ - order: { - summary: "Buy me!", - amount: "TESTKUDOS:5", - fulfillment_url: "https://example.com/article42", - public_reorder_url: "https://example.com/article42-share", - }, - }); + let orderResp = succeedOrThrow( + await merchantClient.createOrder(undefined, { + order: { + summary: "Buy me!", + amount: "TESTKUDOS:5", + fulfillment_url: "https://example.com/article42", + public_reorder_url: "https://example.com/article42-share", + }, + }), + ); - let orderStatus = await merchantClient.queryPrivateOrderStatus({ - orderId: orderResp.order_id, - sessionId: "mysession-one", - }); + let orderStatus = succeedOrThrow( + await merchantClient.getOrderDetails(undefined, orderResp.order_id, { + sessionId: "mysession-one", + }), + ); t.assertTrue(orderStatus.order_status === "unpaid"); diff --git a/packages/taler-util/src/MerchantApiClient.ts b/packages/taler-util/src/MerchantApiClient.ts @@ -1,342 +0,0 @@ -/* - This file is part of GNU Taler - (C) 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 { codecForAny } from "./codec.js"; -import { HttpStatusCode } from "./http-status-codes.js"; -import { - createPlatformHttpLib, - expectSuccessResponseOrThrow, - readSuccessResponseJsonOrThrow, - readTalerErrorResponse, -} from "./http.js"; -import { LibtoolVersion } from "./libtool-version.js"; -import { Logger } from "./logging.js"; -import { - FailCasesByMethod, - OperationFail, - OperationOk, - ResultByMethod, - opEmptySuccess, - opKnownHttpFailure, - opSuccessFromHttp, - opUnknownFailure, -} from "./operation.js"; -import { TalerProtocolDuration } from "./time.js"; -import { AmountString } from "./types-taler-common.js"; -import { - OtpDeviceAddDetails, - codecForTalerMerchantConfigResponse, - codecForMerchantOrderPrivateStatusResponse, - codecForPostOrderResponse, -} from "./types-taler-merchant.js"; - -import * as TalerMerchantApi from "./types-taler-merchant.js"; - -const logger = new Logger("MerchantApiClient.ts"); - -// FIXME: Explain! -export type TalerMerchantResultByMethod<prop extends keyof MerchantApiClient> = - ResultByMethod<MerchantApiClient, prop>; - -// FIXME: Explain! -export type TalerMerchantErrorsByMethod<prop extends keyof MerchantApiClient> = - FailCasesByMethod<MerchantApiClient, prop>; - -export interface MerchantAuthConfiguration { - method: "external" | "token"; - token?: string; -} - -// FIXME: Why do we need this? Describe / fix! -export interface PartialMerchantInstanceConfig { - auth?: MerchantAuthConfiguration; - id: string; - name: string; - paytoUris: string[]; - address?: unknown; - jurisdiction?: unknown; - defaultWireTransferDelay?: TalerProtocolDuration; - defaultPayDelay?: TalerProtocolDuration; -} - -export interface CreateMerchantTippingReserveRequest { - // Amount that the merchant promises to put into the reserve - initial_balance: AmountString; - - // Exchange the merchant intends to use for tipping - exchange_url: string; - - // Desired wire method, for example "iban" or "x-taler-bank" - wire_method: string; -} - -export interface DeleteTippingReserveArgs { - reservePub: string; - purge?: boolean; -} - -export interface MerchantInstanceConfig { - auth: MerchantAuthConfiguration; - id: string; - name: string; - address: unknown; - jurisdiction: unknown; - use_stefan: boolean; - default_wire_transfer_delay: TalerProtocolDuration; - default_pay_delay: TalerProtocolDuration; -} - -export interface PrivateOrderStatusQuery { - instance?: string; - orderId: string; - sessionId?: string; -} - -/** - * Client for the GNU Taler merchant backend. - * - * @deprecated in favor of TalerMerchantInstanceHttpClient - */ -export class MerchantApiClient { - /** - * Base URL for the particular instance that this merchant API client - * is for. - */ - private baseUrl: string; - - readonly auth: MerchantAuthConfiguration; - - public readonly PROTOCOL_VERSION = "6:0:2"; - - constructor( - baseUrl: string, - options: { auth?: MerchantAuthConfiguration } = {}, - ) { - this.baseUrl = baseUrl; - - this.auth = options?.auth ?? { - method: "external", - }; - } - - httpClient = createPlatformHttpLib(); - - async changeAuth(auth: MerchantAuthConfiguration): Promise<void> { - const url = new URL("private/auth", this.baseUrl); - const res = await this.httpClient.fetch(url.href, { - method: "POST", - body: auth, - headers: this.makeAuthHeader(), - }); - await expectSuccessResponseOrThrow(res); - } - - async getPrivateInstanceInfo(): Promise<any> { - const url = new URL("private", this.baseUrl); - const resp = await this.httpClient.fetch(url.href, { - method: "GET", - headers: this.makeAuthHeader(), - }); - return await resp.json(); - } - - async deleteInstance(instanceId: string) { - const url = new URL(`management/instances/${instanceId}`, this.baseUrl); - const resp = await this.httpClient.fetch(url.href, { - method: "DELETE", - headers: this.makeAuthHeader(), - }); - await expectSuccessResponseOrThrow(resp); - } - - async createInstance(req: MerchantInstanceConfig): Promise<void> { - const url = new URL("management/instances", this.baseUrl); - await this.httpClient.fetch(url.href, { - method: "POST", - body: req, - headers: this.makeAuthHeader(), - }); - } - - async getInstances(): Promise<TalerMerchantApi.InstancesResponse> { - const url = new URL("management/instances", this.baseUrl); - const resp = await this.httpClient.fetch(url.href, { - headers: this.makeAuthHeader(), - }); - return readSuccessResponseJsonOrThrow(resp, codecForAny()); - } - - async getInstanceFullDetails(instanceId: string): Promise<any> { - const url = new URL(`management/instances/${instanceId}`, this.baseUrl); - try { - const resp = await this.httpClient.fetch(url.href, { - headers: this.makeAuthHeader(), - }); - return resp.json(); - } catch (e) { - throw e; - } - } - - async createOrder( - req: TalerMerchantApi.PostOrderRequest, - ): Promise<TalerMerchantApi.PostOrderResponse> { - let url = new URL("private/orders", this.baseUrl); - const resp = await this.httpClient.fetch(url.href, { - method: "POST", - body: req, - headers: this.makeAuthHeader(), - }); - return readSuccessResponseJsonOrThrow(resp, codecForPostOrderResponse()); - } - - async deleteOrder(req: { orderId: string; force?: boolean }): Promise<void> { - let url = new URL(`private/orders/${req.orderId}`, this.baseUrl); - if (req.force) { - url.searchParams.set("force", "yes"); - } - const resp = await this.httpClient.fetch(url.href, { - method: "DELETE", - body: req, - headers: this.makeAuthHeader(), - }); - if (resp.status !== 204) { - throw Error(`failed to delete order (status ${resp.status})`); - } - } - - async queryPrivateOrderStatus( - query: PrivateOrderStatusQuery, - ): Promise<TalerMerchantApi.MerchantOrderStatusResponse> { - const reqUrl = new URL(`private/orders/${query.orderId}`, this.baseUrl); - if (query.sessionId) { - reqUrl.searchParams.set("session_id", query.sessionId); - } - const resp = await this.httpClient.fetch(reqUrl.href, { - headers: this.makeAuthHeader(), - }); - return readSuccessResponseJsonOrThrow( - resp, - codecForMerchantOrderPrivateStatusResponse(), - ); - } - - async giveRefund(r: { - instance: string; - orderId: string; - amount: string; - justification: string; - }): Promise<{ talerRefundUri: string }> { - const reqUrl = new URL(`private/orders/${r.orderId}/refund`, this.baseUrl); - const resp = await this.httpClient.fetch(reqUrl.href, { - method: "POST", - body: { - refund: r.amount, - reason: r.justification, - }, - }); - const respBody = await resp.json(); - return { - talerRefundUri: respBody.taler_refund_uri, - }; - } - - async createTemplate(req: TalerMerchantApi.MerchantTemplateAddDetails) { - let url = new URL("private/templates", this.baseUrl); - const resp = await this.httpClient.fetch(url.href, { - method: "POST", - body: req, - headers: this.makeAuthHeader(), - }); - switch (resp.status) { - case HttpStatusCode.Ok: - case HttpStatusCode.NoContent: - return opEmptySuccess(resp); - case HttpStatusCode.NotFound: - return opKnownHttpFailure(resp.status, resp); - default: - return opUnknownFailure(resp, await readTalerErrorResponse(resp)); - } - } - - async getTemplate(templateId: string) { - let url = new URL(`private/templates/${templateId}`, this.baseUrl); - const resp = await this.httpClient.fetch(url.href, { - method: "GET", - headers: this.makeAuthHeader(), - }); - switch (resp.status) { - case HttpStatusCode.Ok: - return opSuccessFromHttp(resp, codecForAny()); - case HttpStatusCode.NotFound: - return opKnownHttpFailure(resp.status, resp); - default: - return opUnknownFailure(resp, await readTalerErrorResponse(resp)); - } - } - - 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(): Promise<OperationOk<TalerMerchantApi.TalerMerchantConfigResponse>> { - const url = new URL(`config`, this.baseUrl); - const resp = await this.httpClient.fetch(url.href, { - method: "GET", - }); - switch (resp.status) { - case HttpStatusCode.Ok: - return opSuccessFromHttp(resp, codecForTalerMerchantConfigResponse()); - default: - return opUnknownFailure(resp, await readTalerErrorResponse(resp)); - } - } - - async createOtpDevice( - req: OtpDeviceAddDetails, - ): Promise<OperationOk<void> | OperationFail<HttpStatusCode.NotFound>> { - let url = new URL("private/otp-devices", this.baseUrl); - const resp = await this.httpClient.fetch(url.href, { - method: "POST", - body: req, - headers: this.makeAuthHeader(), - }); - switch (resp.status) { - case HttpStatusCode.Ok: - case HttpStatusCode.NoContent: - return opEmptySuccess(resp); - case HttpStatusCode.NotFound: - return opKnownHttpFailure(resp.status, resp); - default: - return opUnknownFailure(resp, await readTalerErrorResponse(resp)); - } - } - - private makeAuthHeader(): Record<string, string> { - switch (this.auth.method) { - case "external": - return {}; - case "token": - return { - Authorization: `Bearer ${this.auth.token}`, - }; - } - } -} diff --git a/packages/taler-util/src/http-client/merchant.ts b/packages/taler-util/src/http-client/merchant.ts @@ -1482,8 +1482,15 @@ export class TalerMerchantInstanceHttpClient { /** * https://docs.taler.net/core/api-merchant.html#delete-[-instances-$INSTANCE]-private-orders-$ORDER_ID */ - async deleteOrder(token: AccessToken | undefined, orderId: string) { + async deleteOrder( + token: AccessToken | undefined, + orderId: string, + force: boolean = false, + ) { const url = new URL(`private/orders/${orderId}`, this.baseUrl); + if (force) { + url.searchParams.set("force", "yes"); + } const headers: Record<string, string> = {}; if (token) { diff --git a/packages/taler-util/src/index.ts b/packages/taler-util/src/index.ts @@ -35,7 +35,6 @@ export * from "./invariants.js"; export * from "./kdf.js"; export * from "./libtool-version.js"; export * from "./logging.js"; -export * from "./MerchantApiClient.js"; export { crypto_sign_keyPair_fromSeed, randomBytes,