taler-typescript-core

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

commit 9fab59bfda03a8c32bcaef131cd84c8c6cb634f6
parent da2a8b0bafacedae5a925d2ddb4ab541910386cd
Author: Florian Dold <dold@taler.net>
Date:   Tue, 21 Jul 2026 11:41:47 +0200

util: give the corebank token listing its own type

One TokenInfo served two endpoints with incompatible bodies; it matched the
merchant shape, so every conforming corebank response failed to decode.

Diffstat:
Mpackages/taler-util/src/http-client/bank-core.ts | 8++++----
Mpackages/taler-util/src/types-taler-common.ts | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 69 insertions(+), 4 deletions(-)

diff --git a/packages/taler-util/src/http-client/bank-core.ts b/packages/taler-util/src/http-client/bank-core.ts @@ -28,11 +28,11 @@ import { OperationOk, PaginationParams, TalerErrorCode, - TokenInfos, + BankTokenInfos, TokenRequest, UserAndToken, carefullyParseConfig, - codecForTokenInfoList, + codecForBankTokenInfoList, codecForTokenSuccessResponse, opKnownAlternativeHttpFailure, opKnownHttpFailure, @@ -248,7 +248,7 @@ export class TalerCoreBankHttpClient { token: AccessToken, pagination?: PaginationParams, ): Promise< - | OperationOk<TokenInfos> + | OperationOk<BankTokenInfos> | OperationFail< | HttpStatusCode.Unauthorized | HttpStatusCode.Forbidden @@ -265,7 +265,7 @@ export class TalerCoreBankHttpClient { }); switch (resp.status) { case HttpStatusCode.Ok: - return opSuccessFromHttp(resp, codecForTokenInfoList()); + return opSuccessFromHttp(resp, codecForBankTokenInfoList()); case HttpStatusCode.NoContent: return opFixedSuccess(resp, { tokens: [] }); case HttpStatusCode.Unauthorized: diff --git a/packages/taler-util/src/types-taler-common.ts b/packages/taler-util/src/types-taler-common.ts @@ -392,6 +392,71 @@ export interface TokenSuccessResponse { access_token: AccessToken; } +/** + * Response of the corebank `GET /accounts/$USERNAME/tokens`. + * + * The merchant backend answers its own token listing with a different object; + * see {@link TokenInfos}. + */ +export interface BankTokenInfos { + tokens: BankTokenInfo[]; +} + +export interface BankTokenInfo { + // Time when the token was created. + creation_time: Timestamp; + + // Expiration determined by the server. + expiration: Timestamp; + + // Scope for the token. Deliberately not narrowed to BankTokenScope: a + // listing must not fail to decode because the server knows a scope this + // client does not. Requests are narrowed, see TokenRequest. + scope: string; + + // Is the token refreshable into a new token during its + // validity? + // Refreshable tokens effectively provide indefinite + // access if they are refreshed in time. + refreshable: boolean; + + // Optional token description + description?: string; + + // Time when the token was last used. + last_access: Timestamp; + + // ID identifying the token. + token_id: Integer; + + /** + * @deprecated since corebank protocol v9, use token_id + */ + row_id?: Integer; +} + +export const codecForBankTokenInfo = (): Codec<BankTokenInfo> => + buildCodecForObject<BankTokenInfo>() + .property("creation_time", codecForTimestamp) + .property("expiration", codecForTimestamp) + .property("scope", codecForString()) + .property("refreshable", codecForBoolean()) + .property("description", codecOptional(codecForString())) + .property("last_access", codecForTimestamp) + .property("token_id", codecForNumber()) + .property("row_id", codecOptional(codecForNumber())) + .build("BankTokenInfo"); + +export const codecForBankTokenInfoList = (): Codec<BankTokenInfos> => + buildCodecForObject<BankTokenInfos>() + .property("tokens", codecForList(codecForBankTokenInfo())) + .build("BankTokenInfoList"); + +/** + * Response of the merchant `GET [/instances/$INSTANCE]/private/tokens`. + * + * The corebank listing has a different shape; see {@link BankTokenInfos}. + */ export interface TokenInfos { tokens: TokenInfo[]; }