commit def199019fab39b492b668c668a80877f672196d
parent 9c9b8edabdf8a408da3ee15d280a5f96147c5e8b
Author: Florian Dold <dold@taler.net>
Date: Thu, 23 Jul 2026 02:46:47 +0200
wallet: use typed merchant client for pay-template; wire merchant timeout/cancel
Diffstat:
3 files changed, 30 insertions(+), 15 deletions(-)
diff --git a/packages/taler-util/src/http-client/merchant.ts b/packages/taler-util/src/http-client/merchant.ts
@@ -197,16 +197,19 @@ export class TalerMerchantInstanceHttpClient {
readonly httpLib: HttpRequestLibrary;
readonly cacheEvictor: CacheEvictor<TalerMerchantInstanceCacheEviction>;
readonly cancellationToken: CancellationToken | undefined;
+ readonly timeout: Duration | undefined;
constructor(
readonly baseUrl: string,
httpClient?: HttpRequestLibrary,
cacheEvictor?: CacheEvictor<TalerMerchantInstanceCacheEviction>,
cancellationToken?: CancellationToken,
+ timeout?: Duration,
) {
this.httpLib = httpClient ?? createPlatformHttpLib();
this.cacheEvictor = cacheEvictor ?? nullEvictor;
this.cancellationToken = cancellationToken;
+ this.timeout = timeout;
}
static isCompatible(version: string): boolean {
@@ -453,6 +456,8 @@ export class TalerMerchantInstanceHttpClient {
const resp = await this.httpLib.fetch(url.href, {
method: "POST",
body,
+ cancellationToken: this.cancellationToken,
+ timeout: this.timeout,
});
switch (resp.status) {
@@ -533,7 +538,8 @@ export class TalerMerchantInstanceHttpClient {
const resp = await this.httpLib.fetch(url.href, {
method: "GET",
- // body,
+ cancellationToken: this.cancellationToken,
+ timeout: this.timeout,
});
switch (resp.status) {
@@ -621,6 +627,8 @@ export class TalerMerchantInstanceHttpClient {
const resp = await this.httpLib.fetch(url.href, {
method: "POST",
body,
+ cancellationToken: this.cancellationToken,
+ timeout: this.timeout,
});
switch (resp.status) {
@@ -630,6 +638,11 @@ export class TalerMerchantInstanceHttpClient {
);
return opSuccessFromHttp(resp, codecForPaidRefundStatusResponse());
}
+ case HttpStatusCode.NoContent:
+ this.cacheEvictor.notifySuccess(
+ TalerMerchantInstanceCacheEviction.UPDATE_ORDER,
+ );
+ return opEmptySuccess(resp);
case HttpStatusCode.BadRequest:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.Forbidden:
@@ -653,6 +666,8 @@ export class TalerMerchantInstanceHttpClient {
const resp = await this.httpLib.fetch(url.href, {
method: "POST",
body,
+ cancellationToken: this.cancellationToken,
+ timeout: this.timeout,
});
switch (resp.status) {
@@ -685,6 +700,8 @@ export class TalerMerchantInstanceHttpClient {
const resp = await this.httpLib.fetch(url.href, {
method: "POST",
body,
+ cancellationToken: this.cancellationToken,
+ timeout: this.timeout,
});
switch (resp.status) {
@@ -2598,6 +2615,8 @@ export class TalerMerchantInstanceHttpClient {
const resp = await this.httpLib.fetch(url.href, {
method: "POST",
body,
+ cancellationToken: this.cancellationToken,
+ timeout: this.timeout,
});
return this.procesOrderCreationResponse(resp);
diff --git a/packages/taler-wallet-core/src/pay-template.ts b/packages/taler-wallet-core/src/pay-template.ts
@@ -20,7 +20,6 @@ import {
assertUnreachable,
CheckPayTemplateReponse,
CheckPayTemplateRequest,
- codecForPostOrderResponse,
HostPortPath,
j2s,
Logger,
@@ -38,8 +37,6 @@ import {
TemplateType,
UsingTemplateDetailsRequest,
} from "@gnu-taler/taler-util";
-import { readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http";
-import { cancelableFetch } from "./common.js";
import {
runWithMaybeProgressContext,
runWithProgressRetries,
@@ -299,20 +296,17 @@ export async function instantiateTemplateRaw(
req.templateParams ?? {},
);
- const reqUrl = new URL(
- `templates/${parsedUri.templateId}`,
- parsedUri.merchantBaseUrl,
- );
// Retried under a progress context. Instantiating a template creates a
// fresh order server-side, so a retry after a failure just starts another
// one; the order the wallet ends up paying is the one this call returns.
- const resp = await runWithProgressRetries(wex, async () => {
- const httpReq = await cancelableFetch(wex, reqUrl, {
- method: "POST",
- body: templateDetails,
- });
- return readSuccessResponseJsonOrThrow(httpReq, codecForPostOrderResponse());
- });
+ const resp = await runWithProgressRetries(wex, async () =>
+ succeedOrThrow(
+ await merchantApi.useTemplateCreateOrder(
+ parsedUri.templateId,
+ templateDetails,
+ ),
+ ),
+ );
return {
merchantBaseUrl: parsedUri.merchantBaseUrl,
diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts
@@ -157,12 +157,14 @@ export function walletBankIntegrationClient(
export function walletMerchantClient(
baseUrl: string,
wex: WalletExecutionContext,
+ timeout?: Duration,
): TalerMerchantInstanceHttpClient {
return new TalerMerchantInstanceHttpClient(
baseUrl,
wex.http,
undefined,
wex.cancellationToken,
+ timeout,
);
}