taler-typescript-core

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

commit afde176e9b70e721190bc2564b966c83432d7270
parent 17eb4673564ac5abe3cd150d722502e784be1669
Author: Sebastian <sebasjm@gmail.com>
Date:   Tue, 11 Feb 2025 12:03:36 -0300

fix #9513

Diffstat:
Mpackages/merchant-backoffice-ui/src/paths/instance/accounts/create/CreatePage.tsx | 25+++++++++++++++++++++----
Mpackages/merchant-backoffice-ui/src/paths/instance/accounts/update/UpdatePage.tsx | 7++++---
Mpackages/taler-util/src/types-taler-merchant.ts | 397++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
3 files changed, 269 insertions(+), 160 deletions(-)

diff --git a/packages/merchant-backoffice-ui/src/paths/instance/accounts/create/CreatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/accounts/create/CreatePage.tsx @@ -59,13 +59,19 @@ interface Props { onBack?: () => void; } -const accountAuthType = ["none", "basic"]; +const accountAuthType = ["none", "basic", "bearer"]; export function CreatePage({ onCreate, onBack }: Props): VNode { const { i18n } = useTranslationContext(); const [importing, setImporting] = useState(false); - const [state, setState] = useState<Partial<Entity>>({}); + const [state, setState] = useState<Partial<Entity>>({ + credit_facade_credentials: { + type: "basic", + password: "", + username: "", + }, + }); const facadeURL = safeConvertURL(state.credit_facade_url); const [revenuePayto, setRevenuePayto] = useState<PaytoUri | undefined>( @@ -246,8 +252,9 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { tooltip={i18n.str`Choose the authentication type for the account info URL`} values={accountAuthType} toStr={(str) => { - if (str === "none") return "Without authentication"; - return "Username and password"; + if (str === "none") return i18n.str`Without authentication`; + if (str === "bearer") return i18n.str`With token`; + return "With username and password"; }} /> {state.credit_facade_credentials?.type === "basic" ? ( @@ -265,6 +272,16 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { /> </Fragment> ) : undefined} + {state.credit_facade_credentials?.type === "bearer" ? ( + <Fragment> + <Input + name="credit_facade_credentials.token" + label={i18n.str`Token`} + inputType="password" + tooltip={i18n.str`Access token to access the account information.`} + /> + </Fragment> + ) : undefined} <InputToggle<Entity> label={i18n.str`Match`} tooltip={i18n.str`Check where the information match against the server info.`} diff --git a/packages/merchant-backoffice-ui/src/paths/instance/accounts/update/UpdatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/accounts/update/UpdatePage.tsx @@ -111,7 +111,7 @@ export function UpdatePage({ : undefined, credit_facade_credentials: !state.credit_facade_credentials ? undefined - : undefinedIfEmpty({ + : (undefinedIfEmpty({ type: replacingAccountId && // @ts-expect-error unedit is not in facade creds @@ -138,7 +138,7 @@ export function UpdatePage({ : !state.credit_facade_credentials.password ? i18n.str`Required` : undefined, - }) as any, + }) as any), }); const hasErrors = errors !== undefined; @@ -312,7 +312,8 @@ export function UpdatePage({ values={accountAuthType} toStr={(str) => { if (str === "none") return i18n.str`Without authentication`; - if (str === "basic") return i18n.str`With password`; + if (str === "basic") + return i18n.str`With username and password`; if (str === "bearer") return i18n.str`With token`; return i18n.str`Do not change`; }} diff --git a/packages/taler-util/src/types-taler-merchant.ts b/packages/taler-util/src/types-taler-merchant.ts @@ -34,6 +34,7 @@ import { ExchangeWireAccount, ObjectCodec, PaytoString, + assertUnreachable, buildCodecForUnion, codecForAccountLimit, codecForAmountJson, @@ -689,7 +690,6 @@ export interface MerchantContractOutputTaxReceipt { // Total amount that will be on the tax receipt. // Optional, if missing the full amount will be on the receipt. amount?: AmountString; - } export interface MerchantContractTokenFamily { @@ -742,7 +742,6 @@ export interface TokenIssueCsPublicKey { // End time of this key's signatures validity period. signature_validity_end: Timestamp; - } export type MerchantContractTokenDetails = @@ -864,51 +863,60 @@ export const codecForMerchantInfo = (): Codec<MerchantInfo> => .property("jurisdiction", codecOptional(codecForLocation())) .build("MerchantInfo"); -const codecForMerchantContractTermsCommon = (): ObjectCodec<MerchantContractTermsCommon> => - buildCodecForObject<MerchantContractTermsCommon>() - .property("order_id", codecForString()) - .property("fulfillment_url", codecOptional(codecForString())) - .property("fulfillment_message", codecOptional(codecForString())) - .property( - "fulfillment_message_i18n", - codecOptional(codecForInternationalizedString()), - ) - .property("merchant_base_url", codecForString()) - .property("h_wire", codecForString()) - .property("auto_refund", codecOptional(codecForDuration)) - .property("wire_method", codecForString()) - .property("summary", codecForString()) - .property("summary_i18n", codecOptional(codecForInternationalizedString())) - .property("nonce", codecForString()) - .property("pay_deadline", codecForTimestamp) - .property("refund_deadline", codecForTimestamp) - .property("wire_transfer_deadline", codecForTimestamp) - .property("timestamp", codecForTimestamp) - .property("delivery_location", codecOptional(codecForLocation())) - .property("delivery_date", codecOptional(codecForTimestamp)) - .property("merchant", codecForMerchantInfo()) - .property("merchant_pub", codecForString()) - .property("exchanges", codecForList(codecForExchange())) - .property("products", codecOptional(codecForList(codecForProduct()))) - .property("extra", codecForAny()) - .property("minimum_age", codecOptional(codecForNumber())) - .build("TalerMerchantApi.ContractTermsCommon"); - -export const codecForMerchantContractTermsV0 = (): Codec<MerchantContractTermsV0> => - buildCodecForObject<MerchantContractTermsV0>() - .property("version", codecOptional(codecForConstNumber(0))) - .property("amount", codecForAmountString()) - .property("max_fee", codecForAmountString()) - .mixin(codecForMerchantContractTermsCommon()) - .build("TalerMerchantApi.ContractTermsV0"); +const codecForMerchantContractTermsCommon = + (): ObjectCodec<MerchantContractTermsCommon> => + buildCodecForObject<MerchantContractTermsCommon>() + .property("order_id", codecForString()) + .property("fulfillment_url", codecOptional(codecForString())) + .property("fulfillment_message", codecOptional(codecForString())) + .property( + "fulfillment_message_i18n", + codecOptional(codecForInternationalizedString()), + ) + .property("merchant_base_url", codecForString()) + .property("h_wire", codecForString()) + .property("auto_refund", codecOptional(codecForDuration)) + .property("wire_method", codecForString()) + .property("summary", codecForString()) + .property( + "summary_i18n", + codecOptional(codecForInternationalizedString()), + ) + .property("nonce", codecForString()) + .property("pay_deadline", codecForTimestamp) + .property("refund_deadline", codecForTimestamp) + .property("wire_transfer_deadline", codecForTimestamp) + .property("timestamp", codecForTimestamp) + .property("delivery_location", codecOptional(codecForLocation())) + .property("delivery_date", codecOptional(codecForTimestamp)) + .property("merchant", codecForMerchantInfo()) + .property("merchant_pub", codecForString()) + .property("exchanges", codecForList(codecForExchange())) + .property("products", codecOptional(codecForList(codecForProduct()))) + .property("extra", codecForAny()) + .property("minimum_age", codecOptional(codecForNumber())) + .build("TalerMerchantApi.ContractTermsCommon"); -export const codecForMerchantContractTermsV1 = (): Codec<MerchantContractTermsV1> => - buildCodecForObject<MerchantContractTermsV1>() - .property("version", codecForConstNumber(1)) - .property("choices", codecForList(codecForMerchantContractChoice())) - .property("token_families", codecForMap(codecForMerchantContractTokenFamily())) - .mixin(codecForMerchantContractTermsCommon()) - .build("TalerMerchantApi.ContractTermsV1"); +export const codecForMerchantContractTermsV0 = + (): Codec<MerchantContractTermsV0> => + buildCodecForObject<MerchantContractTermsV0>() + .property("version", codecOptional(codecForConstNumber(0))) + .property("amount", codecForAmountString()) + .property("max_fee", codecForAmountString()) + .mixin(codecForMerchantContractTermsCommon()) + .build("TalerMerchantApi.ContractTermsV0"); + +export const codecForMerchantContractTermsV1 = + (): Codec<MerchantContractTermsV1> => + buildCodecForObject<MerchantContractTermsV1>() + .property("version", codecForConstNumber(1)) + .property("choices", codecForList(codecForMerchantContractChoice())) + .property( + "token_families", + codecForMap(codecForMerchantContractTokenFamily()), + ) + .mixin(codecForMerchantContractTermsCommon()) + .build("TalerMerchantApi.ContractTermsV1"); export const codecForMerchantContractTerms = (): Codec<MerchantContractTerms> => buildCodecForUnion<MerchantContractTerms>() @@ -918,58 +926,67 @@ export const codecForMerchantContractTerms = (): Codec<MerchantContractTerms> => .alternative(1, codecForMerchantContractTermsV1()) .build("TalerMerchantApi.ContractTerms"); -export const codecForMerchantContractChoice = (): Codec<MerchantContractChoice> => - buildCodecForObject<MerchantContractChoice>() - .property("amount", codecForAmountString()) - .property("inputs", codecForList(codecForMerchantContractInput())) - .property("outputs", codecForList(codecForMerchantContractOutput())) - .property("max_fee", codecForAmountString()) - .build("TalerMerchantApi.ContractChoice"); +export const codecForMerchantContractChoice = + (): Codec<MerchantContractChoice> => + buildCodecForObject<MerchantContractChoice>() + .property("amount", codecForAmountString()) + .property("inputs", codecForList(codecForMerchantContractInput())) + .property("outputs", codecForList(codecForMerchantContractOutput())) + .property("max_fee", codecForAmountString()) + .build("TalerMerchantApi.ContractChoice"); export const codecForMerchantContractInput = (): Codec<MerchantContractInput> => buildCodecForUnion<MerchantContractInput>() - .discriminateOn("type") - .alternative("token", codecForMerchantContractInputToken()) - .build("TalerMerchantApi.ContractInput"); - -export const codecForMerchantContractInputToken = (): Codec<MerchantContractInputToken> => - buildCodecForObject<MerchantContractInputToken>() - .property("type", codecForConstString("token")) - .property("token_family_slug", codecForString()) - .property("count", codecOptional(codecForNumber())) - .build("TalerMerchantApi.ContractInputToken"); - -export const codecForMerchantContractOutput = (): Codec<MerchantContractOutput> => - buildCodecForUnion<MerchantContractOutput>() .discriminateOn("type") - .alternative("token", codecForMerchantContractOutputToken()) - .alternative("tax-receipt", codecForMerchantContractOutputTaxReceipt()) - .build("TalerMerchantApi.ContractOutput"); - -export const codecForMerchantContractOutputToken = (): Codec<MerchantContractOutputToken> => - buildCodecForObject<MerchantContractOutputToken>() - .property("type", codecForConstString("token")) - .property("token_family_slug", codecForString()) - .property("count", codecOptional(codecForNumber())) - .property("key_index", codecForNumber()) - .build("TalerMerchantApi.ContractOutputToken"); - -export const codecForMerchantContractOutputTaxReceipt = (): Codec<MerchantContractOutputTaxReceipt> => - buildCodecForObject<MerchantContractOutputTaxReceipt>() - .property("type", codecForConstString("tax-receipt")) - .property("donau_urls", codecForList(codecForString())) - .property("amount", codecOptional(codecForAmountString())) - .build("TalerMerchantApi.ContractOutputTaxReceipt"); - -export const codecForMerchantContractTokenFamily = (): Codec<MerchantContractTokenFamily> => - buildCodecForObject<MerchantContractTokenFamily>() - .property("name", codecForString()) - .property("description", codecForString()) - .property("description_i18n", codecOptional(codecForInternationalizedString())) - .property("keys", codecForList(codecForTokenIssuePublicKey())) - .property("details", codecForMerchantContractTokenDetails()) - .property("critical", codecForBoolean()) - .build("TalerMerchantApi.ContractTokenFamily"); + .alternative("token", codecForMerchantContractInputToken()) + .build("TalerMerchantApi.ContractInput"); + +export const codecForMerchantContractInputToken = + (): Codec<MerchantContractInputToken> => + buildCodecForObject<MerchantContractInputToken>() + .property("type", codecForConstString("token")) + .property("token_family_slug", codecForString()) + .property("count", codecOptional(codecForNumber())) + .build("TalerMerchantApi.ContractInputToken"); + +export const codecForMerchantContractOutput = + (): Codec<MerchantContractOutput> => + buildCodecForUnion<MerchantContractOutput>() + .discriminateOn("type") + .alternative("token", codecForMerchantContractOutputToken()) + .alternative("tax-receipt", codecForMerchantContractOutputTaxReceipt()) + .build("TalerMerchantApi.ContractOutput"); + +export const codecForMerchantContractOutputToken = + (): Codec<MerchantContractOutputToken> => + buildCodecForObject<MerchantContractOutputToken>() + .property("type", codecForConstString("token")) + .property("token_family_slug", codecForString()) + .property("count", codecOptional(codecForNumber())) + .property("key_index", codecForNumber()) + .build("TalerMerchantApi.ContractOutputToken"); + +export const codecForMerchantContractOutputTaxReceipt = + (): Codec<MerchantContractOutputTaxReceipt> => + buildCodecForObject<MerchantContractOutputTaxReceipt>() + .property("type", codecForConstString("tax-receipt")) + .property("donau_urls", codecForList(codecForString())) + .property("amount", codecOptional(codecForAmountString())) + .build("TalerMerchantApi.ContractOutputTaxReceipt"); + +export const codecForMerchantContractTokenFamily = + (): Codec<MerchantContractTokenFamily> => + buildCodecForObject<MerchantContractTokenFamily>() + .property("name", codecForString()) + .property("description", codecForString()) + .property( + "description_i18n", + codecOptional(codecForInternationalizedString()), + ) + .property("keys", codecForList(codecForTokenIssuePublicKey())) + .property("details", codecForMerchantContractTokenDetails()) + .property("critical", codecForBoolean()) + .build("TalerMerchantApi.ContractTokenFamily"); export const codecForTokenIssuePublicKey = (): Codec<TokenIssuePublicKey> => buildCodecForUnion<TokenIssuePublicKey>() @@ -978,13 +995,14 @@ export const codecForTokenIssuePublicKey = (): Codec<TokenIssuePublicKey> => .alternative("CS", codecForTokenIssueCsPublicKey()) .build("TalerMerchantApi.TokenIssuePublicKey"); -export const codecForTokenIssueRsaPublicKey = (): Codec<TokenIssueRsaPublicKey> => - buildCodecForObject<TokenIssueRsaPublicKey>() - .property("cipher", codecForConstString("RSA")) - .property("rsa_pub", codecForString()) - .property("signature_validity_start", codecForTimestamp) - .property("signature_validity_end", codecForTimestamp) - .build("TalerMerchantApi.TokenIssueRsaPublicKey"); +export const codecForTokenIssueRsaPublicKey = + (): Codec<TokenIssueRsaPublicKey> => + buildCodecForObject<TokenIssueRsaPublicKey>() + .property("cipher", codecForConstString("RSA")) + .property("rsa_pub", codecForString()) + .property("signature_validity_start", codecForTimestamp) + .property("signature_validity_end", codecForTimestamp) + .build("TalerMerchantApi.TokenIssueRsaPublicKey"); export const codecForTokenIssueCsPublicKey = (): Codec<TokenIssueCsPublicKey> => buildCodecForObject<TokenIssueCsPublicKey>() @@ -994,12 +1012,16 @@ export const codecForTokenIssueCsPublicKey = (): Codec<TokenIssueCsPublicKey> => .property("signature_validity_end", codecForTimestamp) .build("TalerMerchantApi.TokenIssueRsaPublicKey"); -export const codecForMerchantContractTokenDetails = (): Codec<MerchantContractTokenDetails> => - buildCodecForUnion<MerchantContractTokenDetails>() - .discriminateOn("class") - .alternative("subscription", codecForMerchantContractSubscriptionTokenDetails()) - .alternative("discount", codecForMerchantContractDiscountTokenDetails()) - .build("TalerMerchantApi.ContractTokenDetails"); +export const codecForMerchantContractTokenDetails = + (): Codec<MerchantContractTokenDetails> => + buildCodecForUnion<MerchantContractTokenDetails>() + .discriminateOn("class") + .alternative( + "subscription", + codecForMerchantContractSubscriptionTokenDetails(), + ) + .alternative("discount", codecForMerchantContractDiscountTokenDetails()) + .build("TalerMerchantApi.ContractTokenDetails"); export const codecForMerchantContractSubscriptionTokenDetails = (): Codec<MerchantContractSubscriptionTokenDetails> => @@ -1396,36 +1418,6 @@ export interface MerchantCoinRefundSuccessStatus { execution_time: Timestamp; } -interface RewardInformation { - // Exchange from which the reward will be withdrawn. Needed by the - // wallet to determine denominations, fees, etc. - exchange_url: string; - - // URL where to go after obtaining the reward. - next_url: string; - - // (Remaining) amount of the reward (including fees). - reward_amount: AmountString; - - // Timestamp indicating when the reward is set to expire (may be in the past). - // Note that rewards that have expired MAY also result in a 404 response. - expiration: Timestamp; -} - -interface PlanchetDetail { - // Hash of the denomination's public key (hashed to reduce - // bandwidth consumption). - denom_pub_hash: HashCodeString; - - // Coin's blinded public key. - coin_ev: CoinEnvelope; -} - -interface BlindSignature { - // The (blind) RSA signature. Still needs to be unblinded. - blind_sig: BlindedRsaSignature; -} - export interface InstanceConfigurationMessage { // Name of the merchant instance to create (will become $INSTANCE). // Must match the regex ^[A-Za-z0-9][A-Za-z0-9_.@-]+$. @@ -1481,7 +1473,7 @@ export interface InstanceAuthConfigurationMessage { // gateway must do the authentication. // "token": The merchant checks an auth token. // See "token" for details. - method: "external" | "token"; + method: MerchantAuthMethod; // For method "token", this field is mandatory. // The token MUST begin with the string "secret-token:". @@ -1609,9 +1601,21 @@ export interface QueryInstancesResponse { // Authentication configuration. // Does not contain the token when token auth is configured. auth: { - method: "external" | "token"; + method: MerchantAuthMethod; }; } + +// Type of authentication. +// "external": The mechant backend does not do +// any authentication checks. Instead an API +// gateway must do the authentication. +// "token": The merchant checks an auth token. +// See "token" for details. +export enum MerchantAuthMethod { + EXTERNAL = "external", + TOKEN = "token", +} + export interface MerchantAccountKycRedirectsResponse { // Array of KYC status information for // the exchanges and bank accounts selected @@ -1619,10 +1623,82 @@ export interface MerchantAccountKycRedirectsResponse { kyc_data: MerchantAccountKycRedirect[]; } +export enum MerchantAccountKycStatus { + NO_EXCHANGE_KEY = "no-exchange-keys", + KYC_WIRE_IMPOSSIBLE = "kyc-wire-impossible", + KYC_WIRE_REQUIRED = "kyc-wire-required", + KYC_REQUIRED = "kyc-required", + AWAITING_AML_REVIEW = "awaiting-aml-review", + READY = "ready", + LOGIC_BUG = "logic-bug", + EXCHANGE_INTERNAL_ERROR = "exchange-internal-error", + EXCHANGE_GATEWAY_TIMEOUT = "exchange-gateway-timeout", + EXCHANGE_UNREACHABLE = "exchange-unreachable", + EXCHANGE_STATUS_INVALID = "exchange-status-invalid", +} + +export enum MerchantAccountKycStatusSimplified { + OK = 0, + ACTION_REQUIRED = 100, + WARNING = 200, + ERROR = 300, +} + +export function getMerchantAccountKycStatusSimplified( + st: MerchantAccountKycStatus, +): MerchantAccountKycStatusSimplified { + switch (st) { + case MerchantAccountKycStatus.AWAITING_AML_REVIEW: + case MerchantAccountKycStatus.READY: + return MerchantAccountKycStatusSimplified.OK; + case MerchantAccountKycStatus.KYC_WIRE_REQUIRED: + case MerchantAccountKycStatus.KYC_REQUIRED: + return MerchantAccountKycStatusSimplified.ACTION_REQUIRED; + case MerchantAccountKycStatus.NO_EXCHANGE_KEY: + case MerchantAccountKycStatus.EXCHANGE_INTERNAL_ERROR: + case MerchantAccountKycStatus.EXCHANGE_GATEWAY_TIMEOUT: + case MerchantAccountKycStatus.EXCHANGE_UNREACHABLE: + return MerchantAccountKycStatusSimplified.WARNING; + case MerchantAccountKycStatus.KYC_WIRE_IMPOSSIBLE: + case MerchantAccountKycStatus.LOGIC_BUG: + case MerchantAccountKycStatus.EXCHANGE_STATUS_INVALID: + return MerchantAccountKycStatusSimplified.ERROR; + default: + assertUnreachable(st); + } +} + export interface MerchantAccountKycRedirect { + // Summary of the status of the KYC process. Possible values are: + // + // o "no-exchange-keys": we do not (yet) have the /keys of the exchange + // - "kyc-wire-impossible": KYC auth transfer needed but not possible + // @ "kyc-wire-required": KYC auth transfer still needed and possible + // @ "kyc-required": merchant must supply KYC data to proceed + // + "awaiting-aml-review": account under review by payment provider + // + "ready": everything is fine, account can be fully used + // - "logic-bug": merchant backend logic bug + // o "exchange-internal-error": exchange had an internal error + // o "exchange-gateway-timeout": network timeout at gateway + // o "exchange-unreachable": exchange did not respond at all + // - "exchange-status-invalid": exchange violated protocol in reply + // + // "+" are perfectly normal states, "@" are states where the user + // must performn an action (show link!); "o" are reasonable transient + // states that could happen and are we are expected to likely recover + // from automatically but that we should inform the user about + // (show in yellow?), "-" are hard error states from which + // there is likely no good automatic recovery from (show in red?). + status: MerchantAccountKycStatus; + // Our bank wire account this is about. payto_uri: string; + // Hash of the salted payto://-URI of our + // bank wire account this is about. + // Since protocol **v17**. + h_wire: string; + // Base URL of the exchange this is about. exchange_url: string; @@ -3274,6 +3350,11 @@ export const codecForMerchantCoinRefundStatus = .alternative("failure", codecForMerchantCoinRefundFailureStatus()) .build("TalerMerchantApi.MerchantCoinRefundStatus"); +export const codecForMerchantAuthMethod = codecForEither( + codecForConstString(MerchantAuthMethod.EXTERNAL), + codecForConstString(MerchantAuthMethod.TOKEN), +); + export const codecForQueryInstancesResponse = (): Codec<QueryInstancesResponse> => buildCodecForObject<QueryInstancesResponse>() @@ -3293,13 +3374,7 @@ export const codecForQueryInstancesResponse = buildCodecForObject<{ method: "external" | "token"; }>() - .property( - "method", - codecForEither( - codecForConstString("token"), - codecForConstString("external"), - ), - ) + .property("method", codecForMerchantAuthMethod) .build("TalerMerchantApi.QueryInstancesResponse.auth"), ) .build("TalerMerchantApi.QueryInstancesResponse"); @@ -3311,9 +3386,25 @@ export const codecForAccountKycRedirects = .build("TalerMerchantApi.MerchantAccountKycRedirectsResponse"); +export const codecForMerchantAccountKycStatus = codecForEither( + codecForConstString(MerchantAccountKycStatus.AWAITING_AML_REVIEW), + codecForConstString(MerchantAccountKycStatus.EXCHANGE_GATEWAY_TIMEOUT), + codecForConstString(MerchantAccountKycStatus.EXCHANGE_INTERNAL_ERROR), + codecForConstString(MerchantAccountKycStatus.EXCHANGE_STATUS_INVALID), + codecForConstString(MerchantAccountKycStatus.EXCHANGE_UNREACHABLE), + codecForConstString(MerchantAccountKycStatus.KYC_REQUIRED), + codecForConstString(MerchantAccountKycStatus.KYC_WIRE_IMPOSSIBLE), + codecForConstString(MerchantAccountKycStatus.KYC_WIRE_REQUIRED), + codecForConstString(MerchantAccountKycStatus.LOGIC_BUG), + codecForConstString(MerchantAccountKycStatus.NO_EXCHANGE_KEY), + codecForConstString(MerchantAccountKycStatus.READY), +); + export const codecForMerchantAccountKycRedirect = (): Codec<MerchantAccountKycRedirect> => buildCodecForObject<MerchantAccountKycRedirect>() + .property("status", codecForMerchantAccountKycStatus) + .property("h_wire", codecForString()) .property("payto_uri", codecForPaytoString()) .property("exchange_url", codecForURLString()) .property("exchange_http_status", codecForNumber()) @@ -3736,11 +3827,11 @@ export const codecForWebhookDetails = (): Codec<WebhookDetails> => .property("body_template", codecOptional(codecForString())) .build("TalerMerchantApi.WebhookDetails"); -export const codecForTokenFamilyKind = (): Codec<TokenFamilyKind> => - codecForEither( - codecForConstString("discount"), - codecForConstString("subscription"), - ) as any; //FIXME: create a codecForEnum +export const codecForTokenFamilyKind = codecForEither( + codecForConstString(TokenFamilyKind.Discount), + codecForConstString(TokenFamilyKind.Subscription), +); + export const codecForTokenFamilyDetails = (): Codec<TokenFamilyDetails> => buildCodecForObject<TokenFamilyDetails>() .property("slug", codecForString()) @@ -3753,7 +3844,7 @@ export const codecForTokenFamilyDetails = (): Codec<TokenFamilyDetails> => .property("valid_after", codecForTimestamp) .property("valid_before", codecForTimestamp) .property("duration", codecForDuration) - .property("kind", codecForTokenFamilyKind()) + .property("kind", codecForTokenFamilyKind) .property("issued", codecForNumber()) .property("redeemed", codecForNumber()) .build("TalerMerchantApi.TokenFamilyDetails"); @@ -3769,7 +3860,7 @@ export const codecForTokenFamilySummary = (): Codec<TokenFamilySummary> => .property("name", codecForString()) .property("valid_after", codecForTimestamp) .property("valid_before", codecForTimestamp) - .property("kind", codecForTokenFamilyKind()) + .property("kind", codecForTokenFamilyKind) .build("TalerMerchantApi.TokenFamilySummary"); export const codecForInstancesResponse = (): Codec<InstancesResponse> =>