taler-typescript-core

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

commit 9d77dc861f88b0e47caaddd21fd1023f7d499912
parent 85a355cfdd7fcab7cac2d16a142633575d584173
Author: Florian Dold <florian@dold.me>
Date:   Wed,  3 Jun 2026 19:13:49 +0200

harness: new playground command for testing short expiration payments

Diffstat:
Mpackages/taler-harness/src/index.ts | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mpackages/taler-util/src/http-client/merchant.ts | 16++++++++++++++++
Mpackages/taler-util/src/types-taler-merchant.ts | 5+++--
3 files changed, 122 insertions(+), 2 deletions(-)

diff --git a/packages/taler-harness/src/index.ts b/packages/taler-harness/src/index.ts @@ -18,6 +18,7 @@ * Imports. */ import { + AbsoluteTime, AccessToken, AmountJson, AmountString, @@ -32,6 +33,9 @@ import { Logger, LoginTokenScope, MerchantAuthMethod, + OrderInputType, + OrderOutputType, + OrderVersion, PaytoString, TalerBankConversionHttpClient, TalerCoreBankHttpClient, @@ -1767,6 +1771,105 @@ talerHarnessCli.subcommand("tvgcheck", "tvgcheck").action(async (args) => { console.log("check passed!"); }); +export const playgroundCli = talerHarnessCli.subcommand( + "playground", + "playground", + { + help: "Helpers for testing various scenarios.", + }, +); + +playgroundCli + .subcommand("exp", "blog", {}) + .requiredOption("merchantUrl", ["--merchant-url"], clk.STRING) + .requiredOption("merchantPw", ["--merchant-pw"], clk.STRING) + .maybeOption("payDelay", ["--pay-delay"], clk.STRING) + .action(async (args) => { + const merchantClient = new TalerMerchantInstanceHttpClient( + args.exp.merchantUrl, + ); + const config = succeedOrThrow(await merchantClient.getConfig()); + const tok = succeedOrThrow( + await merchantClient.createAccessToken( + merchantClient.guessInstanceName(), + args.exp.merchantPw, + { + scope: LoginTokenScope.All, + duration: Duration.toTalerProtocolDuration( + Duration.fromSpec({ hours: 1 }), + ), + }, + ), + ); + + const subscriptionAmount = `${config.currency}:5` as AmountString; + const articleAmount = `${config.currency}:1` as AmountString; + + const payDeadline = + args.exp.payDelay == null + ? undefined + : AbsoluteTime.toProtocolTimestamp( + AbsoluteTime.addDuration( + AbsoluteTime.now(), + Duration.fromPrettyString(args.exp.payDelay), + ), + ); + + const createResp = succeedOrThrow( + await merchantClient.createOrder(tok.access_token, { + order: { + pay_deadline: payDeadline, + version: OrderVersion.V1, + summary: "Test Blog Payment", + choices: [ + { + amount: articleAmount, + description: "Buy an individual article", + }, + { + amount: subscriptionAmount as AmountString, + description: "Buy one month of unlimited access", + outputs: [ + { + type: OrderOutputType.Token, + token_family_slug: "blog_abo_en", + }, + ], + }, + { + amount: Amounts.stringify( + Amounts.zeroOfCurrency(config.currency), + ), + inputs: [ + { + type: OrderInputType.Token, + token_family_slug: "blog_abo_en", + }, + ], + outputs: [ + { + type: OrderOutputType.Token, + token_family_slug: "blog_abo_en", + }, + ], + }, + ], + }, + }), + ); + + const st = succeedOrThrow( + await merchantClient.getOrderDetails( + tok.access_token, + createResp.order_id, + ), + ); + + if (st.order_status === "unpaid") { + console.log(st.taler_pay_uri); + } + }); + export const helpersCli = talerHarnessCli.subcommand( "helperProgram", "helper-program", diff --git a/packages/taler-util/src/http-client/merchant.ts b/packages/taler-util/src/http-client/merchant.ts @@ -216,6 +216,22 @@ export class TalerMerchantInstanceHttpClient { } /** + * Derive the instance name from the base URL. + */ + guessInstanceName(): string { + const inst = "/instances/"; + const instIndex = this.baseUrl.lastIndexOf(inst); + if (instIndex < 0) { + return "admin"; + } else { + return this.baseUrl.substring( + instIndex + inst.length, + this.baseUrl.length - 1, + ); + } + } + + /** * https://docs.taler.net/core/api-merchant.html#get--config */ async getConfig() { diff --git a/packages/taler-util/src/types-taler-merchant.ts b/packages/taler-util/src/types-taler-merchant.ts @@ -3088,8 +3088,7 @@ export interface CheckPaymentUnpaidResponse { // 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. + proto_contract_terms?: any; } export interface RefundDetails { // Reason given for the refund. @@ -4841,6 +4840,7 @@ export const codecForLoginTokenSuccessResponse = .property("access_token", codecForAccessToken()) .property("expiration", codecForTimestamp) .property("refreshable", codecForBoolean()) + .deprecatedProperty("token") .build("TalerMerchantApi.LoginTokenSuccessResponse"); export const codecForExchangeKycTimeout = (): Codec<ExchangeKycTimeout> => @@ -5172,6 +5172,7 @@ export const codecForCheckPaymentUnpaidResponse = .property("already_paid_order_id", codecOptional(codecForString())) .property("already_paid_fulfillment_url", codecOptional(codecForString())) .property("order_status_url", codecForString()) + .property("proto_contract_terms", codecOptional(codecForAny())) .build("TalerMerchantApi.CheckPaymentUnpaidResponse"); export const codecForCheckPaymentClaimedResponse =