taler-typescript-core

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

commit 482c6cfddf2f8c2a074efa653dba06c266d64ad0
parent 86a836eebeb95f230925185b794b2e0ad988af74
Author: Florian Dold <dold@taler.net>
Date:   Wed, 19 Aug 2026 18:16:21 +0200

taler-util: preserve merchant token metadata

Diffstat:
Mpackages/taler-util/src/types-taler-merchant.test.ts | 26++++++++++++++++++++++++++
Mpackages/taler-util/src/types-taler-merchant.ts | 12++++++++++++
2 files changed, 38 insertions(+), 0 deletions(-)

diff --git a/packages/taler-util/src/types-taler-merchant.test.ts b/packages/taler-util/src/types-taler-merchant.test.ts @@ -19,6 +19,7 @@ import { test } from "node:test"; import { codecForLoginTokenSuccessResponse, codecForQueryInstancesResponse, + codecForTokenFamilyDetails, } from "./types-taler-merchant.js"; function instancesResponse(method: string): any { @@ -91,3 +92,28 @@ test("every login token scope the SPA can request decodes", (t) => { ); } }); + +test("token family details retain arbitrary extra_data", () => { + const extra_data = { + discount: { + type: "percentage", + percentage: "20", + rounding: { mode: "nearest", precision: "0.01" }, + product_categories: [1, 2], + }, + future_field: { keep: true }, + }; + const decoded = codecForTokenFamilyDetails().decode({ + slug: "coffee20", + name: "Coffee club", + description: "Twenty percent off coffee", + extra_data, + valid_after: { t_s: 1 }, + valid_before: { t_s: 2 }, + duration: { d_us: 1_000_000 }, + kind: "discount", + issued: 3, + used: 1, + }); + assert.deepStrictEqual(decoded.extra_data, extra_data); +}); diff --git a/packages/taler-util/src/types-taler-merchant.ts b/packages/taler-util/src/types-taler-merchant.ts @@ -3854,6 +3854,11 @@ export interface TokenFamilyCreateRequest { // Optional map from IETF BCP 47 language tags to localized descriptions. description_i18n?: { [lang_tag: string]: string }; + // Additional kind-specific metadata. Parts of this object can become + // wallet-visible when the family is referenced by an order, so callers + // must not use it for secrets. + extra_data?: Record<string, unknown>; + // Start time of the token family's validity period. // If not specified, merchant backend will use the current time. valid_after?: Timestamp; @@ -3899,6 +3904,9 @@ export interface TokenFamilyUpdateRequest { // Optional map from IETF BCP 47 language tags to localized descriptions. description_i18n: { [lang_tag: string]: string }; + // Additional kind-specific metadata. + extra_data?: Record<string, unknown>; + // Start time of the token family's validity period. valid_after: Timestamp; @@ -3956,6 +3964,9 @@ export interface TokenFamilyDetails { // Optional map from IETF BCP 47 language tags to localized descriptions. description_i18n?: { [lang_tag: string]: string }; + // Additional kind-specific metadata. + extra_data?: Record<string, unknown>; + // Start time of the token family's validity period. valid_after: Timestamp; @@ -5550,6 +5561,7 @@ export const codecForTokenFamilyDetails = (): Codec<TokenFamilyDetails> => "description_i18n", codecOptional(codecForInternationalizedString()), ) + .property("extra_data", codecOptional(codecForAny())) .property("valid_after", codecForTimestamp) .property("valid_before", codecForTimestamp) .property("duration", codecForDuration)