@agent-cards/sdk 0.23.21 → 0.23.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/PREFLIGHT.md +4 -0
- package/README.md +27 -1
- package/dist/amadeus-checkout.generated.d.ts +6 -1
- package/dist/amadeus-checkout.generated.js +26 -2
- package/dist/card-fields.generated.js +1391 -104
- package/dist/cdp.js +53 -18
- package/dist/client.d.ts +73 -6
- package/dist/client.js +164 -24
- package/dist/creditguard.generated.js +4 -2
- package/dist/cse-body.js +11 -0
- package/dist/ebanx.d.ts +1 -1
- package/dist/ebanx.js +1 -1
- package/dist/eximbay.d.ts +46 -0
- package/dist/eximbay.js +69 -0
- package/dist/lifecycle.d.ts +9 -4
- package/dist/lifecycle.js +16 -4
- package/dist/paygent.generated.d.ts +60 -0
- package/dist/paygent.generated.js +425 -0
- package/dist/payrexx.d.ts +91 -0
- package/dist/payrexx.generated.d.ts +91 -0
- package/dist/payrexx.generated.js +536 -0
- package/dist/payrexx.js +141 -0
- package/dist/pre-claim.d.ts +23 -0
- package/dist/pre-claim.js +131 -20
- package/dist/prepared-processor.d.ts +7 -2
- package/dist/prepared-processor.js +16 -2
- package/dist/primer.generated.js +1427 -140
- package/dist/stripe-checkout.generated.js +289 -21
- package/dist/toast-seal.generated.d.ts +37 -0
- package/dist/toast-seal.generated.js +625 -0
- package/dist/toast.generated.d.ts +41 -0
- package/dist/toast.generated.js +113 -0
- package/package.json +2 -2
package/dist/client.js
CHANGED
|
@@ -5,6 +5,7 @@ import { ACI_CAPABILITY, ACI_PSP, aciCardLegAnswer } from './aci.js';
|
|
|
5
5
|
import { PRZELEWY24_CAPABILITY, PRZELEWY24_PSP } from './przelewy24.js';
|
|
6
6
|
import { EPROTECT_CAPABILITY, EPROTECT_PSP, eprotectCheckoutRefusal, eprotectScriptAnswer, isEprotectRegistration } from './eprotect.js';
|
|
7
7
|
import { COMGATE_CAPABILITY, COMGATE_PSP } from './comgate.js';
|
|
8
|
+
import { EXIMBAY_CAPABILITY } from './eximbay.js';
|
|
8
9
|
import { isHostedGetEntry } from './hosted-entry.js';
|
|
9
10
|
import { TRANSBANK_CAPABILITY, TRANSBANK_PSP } from './transbank.js';
|
|
10
11
|
import { isMercadoTokenRequest, parseMercadoCheckoutContext, validateMercadoProcessorContext } from './mercado-checkout.generated.js';
|
|
@@ -19,10 +20,12 @@ import { CONVERGE_CAPABILITY } from './elavon-converge.js';
|
|
|
19
20
|
import { SHIJI_STS_CAPABILITY, SHIJI_STS_PSP, isShijiStsServedCompanion, isShijiStsServedSubstitution } from './shiji-sts.js';
|
|
20
21
|
import { AMADEUS_CHECKOUT_CAPABILITY, AMADEUS_CHECKOUT_PSP } from './amadeus-checkout.generated.js';
|
|
21
22
|
import { PADDLE_VGS_CAPABILITY, PADDLE_VGS_PSP, paddleVgsCardFactsOf } from './paddle-vgs.generated.js';
|
|
23
|
+
import { PAYGENT_CAPABILITY, PAYGENT_PSP, paygentAnswerOutcome } from './paygent.generated.js';
|
|
22
24
|
import { PADDLE_TOKENEX_CAPABILITY, PADDLE_TOKENEX_PSP, isPaddleTokenexServedFacts, isPaddleTokenexServedSubstitution } from './paddle-tokenex.js';
|
|
23
25
|
import { TWOC2P_CAPABILITY, TWOC2P_PSP } from './twoc2p.js';
|
|
24
26
|
import { WIX_PAYMENTS_CAPABILITY, WIX_PAYMENTS_PSP } from './wix-payments.generated.js';
|
|
25
27
|
import { HIPAY_CAPABILITY, HIPAY_PSP } from './hipay.generated.js';
|
|
28
|
+
import { TOAST_CAPABILITY, TOAST_PSP, isToastCiphertext } from './toast.generated.js';
|
|
26
29
|
import { classifyStripeCheckoutRequest, encodeStripeCheckoutContext, hasStripeCheckoutMarker, parseStripeCheckoutContext, parseStripeCheckoutResponse, STRIPE_CHECKOUT_CONTEXT_HEADER, } from './stripe-checkout.generated.js';
|
|
27
30
|
import { VoiceModule } from './voice.js';
|
|
28
31
|
import { BuyModule } from './buy.js';
|
|
@@ -42,6 +45,7 @@ import { PRIMER_CAPABILITY, PRIMER_PSP, primerTokenAnswer } from './primer.js';
|
|
|
42
45
|
import { PAYRAILS_CAPABILITY, isPayrailsPaymentUrl, payrailsAnswer } from './payrails.js';
|
|
43
46
|
import { WSPAY_CAPABILITY, WSPAY_PSP } from './wspay.js';
|
|
44
47
|
import { EbanxFollowUpError } from './ebanx.js';
|
|
48
|
+
import { PAYREXX_CAPABILITY, PAYREXX_PSP, PayrexxFollowUpError } from './payrexx.js';
|
|
45
49
|
import { SECURE_ACCEPTANCE_CAPABILITY, SECURE_ACCEPTANCE_FAST_POLL_MS, SECURE_ACCEPTANCE_PSP, SECURE_ACCEPTANCE_REPLY_WINDOW_MS, secureAcceptanceCheckoutProfile, secureAcceptanceCheckoutRefusal, secureAcceptanceFrameAnswer, } from './cybersource-secure-acceptance.js';
|
|
46
50
|
/**
|
|
47
51
|
* The modes this SDK can finish. Asked for on syncRegistry (the API serves
|
|
@@ -265,6 +269,22 @@ export const SUPPORTED_REGISTRY_FEATURES = ['card_fields', 'checkout_sessions'];
|
|
|
265
269
|
* company until a reviewed change binds GoPay's payee and amount to the approval: the post names
|
|
266
270
|
* neither. The API takes it only at a shop Agentcard reviewed.
|
|
267
271
|
*
|
|
272
|
+
* `paygent_token`: the token request Paygent's own PaygentToken.js sends from a merchant's
|
|
273
|
+
* page (token.paygent.co.jp/n/token/request), only through a prepared checkout: the script
|
|
274
|
+
* abandons the request 35 seconds after the press that sends it, so the cardholder approves
|
|
275
|
+
* before the press. The cardholder's device sends the card itself and the page gets back
|
|
276
|
+
* Paygent's single-use token alone; the SDK refuses a second token request on the same approval.
|
|
277
|
+
* Served on the same terms: only to a build that lists it, for a company Agentcard turned
|
|
278
|
+
* Paygent on for.
|
|
279
|
+
*
|
|
280
|
+
* `payrexx_card_frame`: the card request Payrexx Pay's card frame sends to its own URL
|
|
281
|
+
* (checkout.payrexx.com/?pspId=44&lang=<xx>) on a Payrexx merchant's page. This build pauses only
|
|
282
|
+
* the frame's own one-time card request and answers it with Payrexx's answer as the API recorded
|
|
283
|
+
* it: the token the merchant's page then charges, or the start of 3-D Secure, whose two later sends
|
|
284
|
+
* of the card this build hands to the cardholder's device under the same approval (payrexx.ts,
|
|
285
|
+
* pre-claim.ts payrexxPreClaim). The cardholder's device sends the card through the checkout relay.
|
|
286
|
+
* Served only to a build that lists it, for a company Agentcard turned Payrexx on for.
|
|
287
|
+
*
|
|
268
288
|
* `hipay_vault_token`: the token create HiPay's hosted fields send to HiPay's Secure Vault
|
|
269
289
|
* (secure2-vault.hipay-tpp.com, stage-secure2-vault for a test row), only through a prepared
|
|
270
290
|
* checkout: the merchant's page gives the frame 20 seconds after Pay. The cardholder's device
|
|
@@ -364,11 +384,39 @@ export const SUPPORTED_REGISTRY_FEATURES = ['card_fields', 'checkout_sessions'];
|
|
|
364
384
|
* device sends the card itself, and the API holds the payment to a merchant Agentcard reviewed, at the
|
|
365
385
|
* amount SumUp holds for the checkout. Served on the same terms: only to a build that lists it, for a
|
|
366
386
|
* company Agentcard turned SumUp on for.
|
|
387
|
+
*
|
|
388
|
+
* `clover_card_token`: the card token request Clover's card frame (the hidden frame of
|
|
389
|
+
* checkout.clover.com that Clover's iframe mounts on a merchant's page) sends to
|
|
390
|
+
* token.clover.com/v1/tokens (token-sandbox.dev.clover.com for a test row), with the number
|
|
391
|
+
* encrypted under Clover's key. This build pauses only the frame's own body at that exact URL; the
|
|
392
|
+
* cardholder's device builds the request again with the real card under the key payment-core pins
|
|
393
|
+
* and sends it to Clover itself, and the frame gets the token answer payment-core's judge rebuilt.
|
|
394
|
+
* The request names no amount, so the agent's pair, above zero, is the one the cardholder approves
|
|
395
|
+
* (CLOVER_PSP below). Served on the same terms: only to a build that lists it, for a company
|
|
396
|
+
* Agentcard turned Clover on for.
|
|
397
|
+
*
|
|
398
|
+
* `eximbay_hosted_payment_page`: Eximbay's payment window, whose card-free signed entry
|
|
399
|
+
* (a form post to /Gateway/BasicProcessor.krp on secureapi.eximbay.com, or its test host) this
|
|
400
|
+
* build pauses for the cardholder's device, in the page or in a window it opened once attachToCdp
|
|
401
|
+
* has armed that window (eximbay.ts names the entry that can leave first), and whose
|
|
402
|
+
* step, amount query, card lookup and card post this build never lets the agent's browser send
|
|
403
|
+
* (pre-claim.ts, eximbay.ts). Served on the same terms as NMI's and Redsys's: only to a build
|
|
404
|
+
* that lists it, for a company Agentcard turned Eximbay on for.
|
|
405
|
+
*
|
|
406
|
+
* `toast_pinned_key`: the card request Toast's payments frame sends to
|
|
407
|
+
* payments.toasttab.com/v1/payment-methods on a Toast online-ordering checkout, with
|
|
408
|
+
* the card sealed in card.cardData under one key every Toast restaurant shares. The
|
|
409
|
+
* cardholder's device seals the real card under that key, which payment-core pins, and
|
|
410
|
+
* this build writes it over the agent's placeholder and nothing else before it
|
|
411
|
+
* continues the request. Served on the same terms: only to a build that lists it, for
|
|
412
|
+
* a company Agentcard turned Toast on for.
|
|
367
413
|
*/
|
|
368
414
|
export const SUPPORTED_CAPABILITIES = ['fiserv_card_capture', GMO_CAPABILITY, CYBERSOURCE_FLEX_CAPABILITY, JUSPAY_CAPABILITY, DATATRANS_CAPABILITY, 'authorize_net_dpm_form', PELECARD_CAPABILITY, ACI_CAPABILITY, 'creditguard_pps_process', PRIMER_CAPABILITY, PAYRAILS_CAPABILITY, CONVERGE_CAPABILITY, EPROTECT_CAPABILITY, WSPAY_CAPABILITY, SHIJI_STS_CAPABILITY, AMADEUS_CHECKOUT_CAPABILITY, 'worldline_mycheckout_form', 'verifone_card_capture', 'ekashu_hosted_payment_page', SECURE_ACCEPTANCE_CAPABILITY, 'gravy_session_fields_put', 'moneris_hosted_tokenization', PADDLE_VGS_CAPABILITY, PADDLE_TOKENEX_CAPABILITY,
|
|
369
|
-
'redsys_hosted_payment_page', 'lyra_krypton_payment', 'payfast_card_pay', WIX_PAYMENTS_CAPABILITY, 'paymongo_checkout_pay', 'pay_nl_card_token', HIPAY_CAPABILITY, TWOC2P_CAPABILITY, 'quickpay_hosted_payment_page', 'revolut_card_field', 'paypal_card_fields', 'gopay_card_form', COMGATE_CAPABILITY, PRZELEWY24_CAPABILITY, 'makecommerce_card_frame', 'poynt_collect_nonce',
|
|
415
|
+
'redsys_hosted_payment_page', 'lyra_krypton_payment', 'payfast_card_pay', WIX_PAYMENTS_CAPABILITY, 'paymongo_checkout_pay', PAYGENT_CAPABILITY, 'pay_nl_card_token', HIPAY_CAPABILITY, TWOC2P_CAPABILITY, 'quickpay_hosted_payment_page', 'revolut_card_field', 'paypal_card_fields', 'gopay_card_form', PAYREXX_CAPABILITY, COMGATE_CAPABILITY, PRZELEWY24_CAPABILITY, 'makecommerce_card_frame', 'poynt_collect_nonce',
|
|
370
416
|
TOKENEX_IFRAME_CAPABILITY, TRANSBANK_CAPABILITY,
|
|
371
|
-
'sumup_checkout_process'
|
|
417
|
+
'sumup_checkout_process',
|
|
418
|
+
'clover_card_token',
|
|
419
|
+
EXIMBAY_CAPABILITY, TOAST_CAPABILITY];
|
|
372
420
|
/**
|
|
373
421
|
* Processors whose paused request names no amount at all, so the pair the
|
|
374
422
|
* agent passes is the amount the cardholder approves: authorize() refuses one
|
|
@@ -396,13 +444,21 @@ export const SUPPORTED_CAPABILITIES = ['fiserv_card_capture', GMO_CAPABILITY, CY
|
|
|
396
444
|
* so the agent sends the total Payfast's page shows, above zero (PAYFAST_PSP below),
|
|
397
445
|
* and the API holds it to the payment Payfast itself reports. Wix's tokenize request
|
|
398
446
|
* carries none either: the merchant's page charges Wix's token for its own order, so the
|
|
399
|
-
* agent's pair, which the prepared checkout carries, is the total the cardholder approves.
|
|
447
|
+
* agent's pair, which the prepared checkout carries, is the total the cardholder approves. Toast's
|
|
448
|
+
* card request carries none either: the page's card-free confirm of its payment intent
|
|
449
|
+
* charges whatever the intent says, so the agent's pair, above zero (as Moneris's), is
|
|
450
|
+
* the one figure the approval shows.
|
|
400
451
|
* PayMongo's card attach carries none either: the merchant bound the total, always in
|
|
401
452
|
* Philippine pesos, to the checkout session when it created it, so the agent sends that
|
|
402
453
|
* total, above zero (PAYMONGO_PSP below), and the API holds it to the session PayMongo's
|
|
403
454
|
* own page shows. GoPay's card post carries none either: the shop's server set the amount
|
|
404
455
|
* when it created the payment at GoPay, and GoPay's gateway shows it only inside its own
|
|
405
456
|
* session, so the agent sends the total the gateway shows, above zero (GOPAY_PSP below).
|
|
457
|
+
* Paygent's token request carries none either: the merchant's server charges the token later, so
|
|
458
|
+
* the agent's pair, which the prepared checkout carries, is the total the cardholder approves.
|
|
459
|
+
* Payrexx's card request names the page's total, but it only mints a token: the merchant's page
|
|
460
|
+
* charges its own total later, at its validateForm, so the agent sends the total that page shows,
|
|
461
|
+
* above zero (PAYREXX_PSP), and the API holds it to the frame's figure exactly.
|
|
406
462
|
* 2C2P's Payment carries none either: the merchant bound the total to the
|
|
407
463
|
* payment token when it created it, so the agent sends the total 2C2P's page shows, above
|
|
408
464
|
* zero (TWOC2P_PSP), and the API holds it to the amount 2C2P's own PaymentOption answer names.
|
|
@@ -442,6 +498,9 @@ export const SUPPORTED_CAPABILITIES = ['fiserv_card_capture', GMO_CAPABILITY, CY
|
|
|
442
498
|
* total and its currency to the checkout when it created it, so the agent sends the total the
|
|
443
499
|
* payment page shows, above zero (SUMUP_PSP below), and the API holds it to the checkout SumUp
|
|
444
500
|
* itself reports.
|
|
501
|
+
* Clover's card token request carries none either: the merchant's server charges the token
|
|
502
|
+
* later for its own order, so the agent's pair, above zero (CLOVER_PSP below), is the one figure
|
|
503
|
+
* the approval shows.
|
|
445
504
|
*/
|
|
446
505
|
const MONERIS_PSP = 'moneris';
|
|
447
506
|
const PAYFAST_PSP = 'payfast';
|
|
@@ -453,15 +512,18 @@ const GOPAY_PSP = 'gopay';
|
|
|
453
512
|
const MAKECOMMERCE_PSP = 'makecommerce';
|
|
454
513
|
const POYNT_PSP = 'poynt';
|
|
455
514
|
const SUMUP_PSP = 'sumup';
|
|
456
|
-
const
|
|
457
|
-
|
|
515
|
+
const CLOVER_PSP = 'clover';
|
|
516
|
+
const AGENT_AMOUNT_PROCESSORS = [GMO_PSP, PELECARD_PSP, WSPAY_PSP, SECURE_ACCEPTANCE_PSP, MONERIS_PSP, PADDLE_VGS_PSP, PAYFAST_PSP, WIX_PAYMENTS_PSP, PAYMONGO_PSP, PAYGENT_PSP, PAY_NL_PSP, HIPAY_PSP, TWOC2P_PSP, REVOLUT_PSP, PAYPAL_PSP, GOPAY_PSP, PAYREXX_PSP, COMGATE_PSP,
|
|
517
|
+
PRZELEWY24_PSP, MAKECOMMERCE_PSP, POYNT_PSP, TOKENEX_IFRAME_PSP, TRANSBANK_PSP, SUMUP_PSP,
|
|
518
|
+
CLOVER_PSP, TOAST_PSP];
|
|
458
519
|
/** How AmountRequiredError names a processor. */
|
|
459
520
|
const PROCESSOR_NAMES = { [GMO_PSP]: 'GMO', [PELECARD_PSP]: 'Pelecard', [WSPAY_PSP]: 'WSPay',
|
|
460
|
-
[SECURE_ACCEPTANCE_PSP]: 'CyberSource Secure Acceptance', [MONERIS_PSP]: 'Moneris', [PADDLE_VGS_PSP]: 'Paddle', [PAYFAST_PSP]: 'Payfast', [WIX_PAYMENTS_PSP]: 'Wix', [PAYMONGO_PSP]: 'PayMongo', [PAY_NL_PSP]: 'Pay.', [HIPAY_PSP]: 'HiPay', [TWOC2P_PSP]: '2C2P',
|
|
461
|
-
[REVOLUT_PSP]: 'Revolut', [PAYPAL_PSP]: 'PayPal', [GOPAY_PSP]: 'GoPay',
|
|
521
|
+
[SECURE_ACCEPTANCE_PSP]: 'CyberSource Secure Acceptance', [MONERIS_PSP]: 'Moneris', [PADDLE_VGS_PSP]: 'Paddle', [PAYFAST_PSP]: 'Payfast', [WIX_PAYMENTS_PSP]: 'Wix', [PAYMONGO_PSP]: 'PayMongo', [PAYGENT_PSP]: 'Paygent', [PAY_NL_PSP]: 'Pay.', [HIPAY_PSP]: 'HiPay', [TWOC2P_PSP]: '2C2P',
|
|
522
|
+
[REVOLUT_PSP]: 'Revolut', [PAYPAL_PSP]: 'PayPal', [GOPAY_PSP]: 'GoPay', [PAYREXX_PSP]: 'Payrexx',
|
|
462
523
|
[COMGATE_PSP]: 'ComGate', [PRZELEWY24_PSP]: 'Przelewy24',
|
|
463
524
|
[MAKECOMMERCE_PSP]: 'MakeCommerce', [POYNT_PSP]: 'GoDaddy Payments', [TOKENEX_IFRAME_PSP]: 'TokenEx', [TRANSBANK_PSP]: 'Webpay',
|
|
464
|
-
[SUMUP_PSP]: 'SumUp'
|
|
525
|
+
[SUMUP_PSP]: 'SumUp',
|
|
526
|
+
[CLOVER_PSP]: 'Clover', [TOAST_PSP]: 'Toast' };
|
|
465
527
|
/**
|
|
466
528
|
* Processors whose request and answer name no amount at all, so the total the
|
|
467
529
|
* payment page shows (`pageAmount`) is the one figure that ties the agent's pair
|
|
@@ -741,7 +803,9 @@ export class AmountRequiredError extends Error {
|
|
|
741
803
|
code = 'amount_required';
|
|
742
804
|
constructor(psp) {
|
|
743
805
|
const processor = PROCESSOR_NAMES[psp] ?? psp;
|
|
744
|
-
|
|
806
|
+
// A Payrexx card request names the frame's total, but the merchant's page charges its own total after the token.
|
|
807
|
+
const lacks = psp === REVOLUT_PSP ? 'names its amount but not its currency'
|
|
808
|
+
: psp === PAYREXX_PSP ? "only mints a token the merchant's page charges later" : 'names no amount';
|
|
745
809
|
super(`A ${processor} payment request ${lacks}, so pass amount and currency: that is the amount the cardholder approves. Nothing was created and nothing was charged.`);
|
|
746
810
|
this.psp = psp;
|
|
747
811
|
this.name = 'AmountRequiredError';
|
|
@@ -1086,12 +1150,12 @@ function refusalsOf(v) {
|
|
|
1086
1150
|
return out;
|
|
1087
1151
|
}
|
|
1088
1152
|
/**
|
|
1089
|
-
* How often sendEbanxFollowUp
|
|
1090
|
-
* client's own `pollIntervalMs`. One send is out at a time per approval, so this is 120
|
|
1091
|
-
* API's 240 a minute per caller and authorization (routes/api/v2/checkout-follow-ups.ts).
|
|
1153
|
+
* How often sendEbanxFollowUp and sendPayrexxFollowUp read a send back while the cardholder's device has it: every
|
|
1154
|
+
* half second, whatever the client's own `pollIntervalMs`. One send is out at a time per approval, so this is 120
|
|
1155
|
+
* reads a minute, inside the API's 240 a minute per caller and authorization (routes/api/v2/checkout-follow-ups.ts).
|
|
1092
1156
|
*/
|
|
1093
1157
|
export const EBANX_FOLLOW_UP_READ_MS = 500;
|
|
1094
|
-
/** The longest
|
|
1158
|
+
/** The longest a follow-up send waits after reads the API refused as too many (429): 1, 2, 4, 8, then 15 seconds. */
|
|
1095
1159
|
export const EBANX_FOLLOW_UP_BACKOFF_MAX_MS = 15_000;
|
|
1096
1160
|
export class CheckoutApiError extends Error {
|
|
1097
1161
|
status;
|
|
@@ -1384,6 +1448,18 @@ const SUMUP_CHECKOUT = new RegExp(`(${SLASH}checkouts${SLASH}+)[^/]*`, 'gi');
|
|
|
1384
1448
|
function maskSumupCheckout(path) {
|
|
1385
1449
|
return maskUuids(path.replace(SUMUP_CHECKOUT, '$1{checkout}'), '{checkout}');
|
|
1386
1450
|
}
|
|
1451
|
+
/**
|
|
1452
|
+
* FastSpring's checkout posts its card payment to <store>.onfastspring.com[/popup-<name>]/session/<id>/payment
|
|
1453
|
+
* (payment-core fastspring.js), and the session id in that path is a credential: the session's own document,
|
|
1454
|
+
* which anyone holding the id can read with no cookie, carries the order and the session's token. On every
|
|
1455
|
+
* host under onfastspring.com the segment after /session/, in any case or after an escaped slash, reads
|
|
1456
|
+
* {session}.
|
|
1457
|
+
*/
|
|
1458
|
+
const FASTSPRING_HOST = /(?:^|\.)onfastspring\.com\.?$/i;
|
|
1459
|
+
const FASTSPRING_SESSION = /(\/session(?:\/|%2f))[^/]*/gi;
|
|
1460
|
+
function maskFastspringSession(path) {
|
|
1461
|
+
return path.replace(FASTSPRING_SESSION, '$1{session}');
|
|
1462
|
+
}
|
|
1387
1463
|
/**
|
|
1388
1464
|
* The processors whose card request carries its own credential in the URL path, with the hosts
|
|
1389
1465
|
* that send it, the text that names those hosts anywhere else (a string that is not a URL, or a
|
|
@@ -1558,6 +1634,7 @@ const PATH_CREDENTIALS = [
|
|
|
1558
1634
|
{ host: PAYMENT_HIGHWAY_HOST, named: /(?:paymenthighway\.io|sph-test-solinor\.com)/i, mask: maskPaymentHighwaySession },
|
|
1559
1635
|
{ host: TWOC2P_PAGE_HOST, named: /pgw-ui\.2c2p\.com/i, mask: maskTwoC2pToken, pathMask: maskTwoC2pPath },
|
|
1560
1636
|
{ host: QUICKPAY_HOST, named: /quickpay\.net/i, mask: maskQuickpaySession },
|
|
1637
|
+
{ host: FASTSPRING_HOST, named: /onfastspring\.com/i, mask: maskFastspringSession },
|
|
1561
1638
|
];
|
|
1562
1639
|
/**
|
|
1563
1640
|
* A URL as it may appear in an error message: origin + path only. A paused
|
|
@@ -1595,6 +1672,8 @@ const PATH_CREDENTIALS = [
|
|
|
1595
1672
|
* https://pgw-ui.2c2p.com/payment/4.1/{token}.
|
|
1596
1673
|
* On QuickPay's host the window's session reads `{session}`:
|
|
1597
1674
|
* https://payment.quickpay.net/{session}/3ds_auth.
|
|
1675
|
+
* On FastSpring's store hosts the session id reads `{session}`:
|
|
1676
|
+
* https://daisydisk.onfastspring.com/session/{session}/payment.
|
|
1598
1677
|
* A string that is not a URL keeps the part before any `?` or `#`, with the
|
|
1599
1678
|
* same segments masked for every processor whose host it names.
|
|
1600
1679
|
* A URL is read by its host only when the parser finds one. Text before a URL
|
|
@@ -1703,6 +1782,18 @@ const PADDLE_VGS_PREPARATION_REFUSALS = [
|
|
|
1703
1782
|
* `unsupported_checkout`, which PREPARATION_REFUSALS names for every checkout. Only for a Wix checkout.
|
|
1704
1783
|
*/
|
|
1705
1784
|
const WIX_PAYMENTS_PREPARATION_REFUSALS = ['processor_unavailable', 'live_host_on_sandbox_row', 'merchant_profile_mismatch'];
|
|
1785
|
+
/**
|
|
1786
|
+
* The API's refusals of a Paygent preparation, before any preparation exists, that prepareCheckout passes on
|
|
1787
|
+
* by name: Paygent is off for the company (`processor_unavailable`), the environment is not the client's test
|
|
1788
|
+
* or live mode, a live checkout's currency is not the one the reviewed merchant charges in
|
|
1789
|
+
* (`unsupported_currency`), and the price is zero (`amount_required`): Paygent's token request names no
|
|
1790
|
+
* amount, so the price the agent sends is the one the cardholder approves. A page and name no reviewed pin
|
|
1791
|
+
* lists answers `unsupported_checkout`, which PREPARATION_REFUSALS names for every checkout. The API holds the
|
|
1792
|
+
* pins, not this build, so a merchant a later release reviews needs no new SDK. Only for a Paygent checkout.
|
|
1793
|
+
*/
|
|
1794
|
+
const PAYGENT_PREPARATION_REFUSALS = [
|
|
1795
|
+
'processor_unavailable', 'sandbox_host_on_live_row', 'live_host_on_sandbox_row', 'unsupported_currency', 'amount_required',
|
|
1796
|
+
];
|
|
1706
1797
|
/**
|
|
1707
1798
|
* The API's refusals of a HiPay preparation, before any preparation exists, that prepareCheckout surfaces by name:
|
|
1708
1799
|
* the company is not turned on for HiPay (`processor_unavailable`), the environment is not the caller's key mode's
|
|
@@ -2293,6 +2384,8 @@ export class VaultClient {
|
|
|
2293
2384
|
throw fail(secureAcceptanceRefusal);
|
|
2294
2385
|
const secureAcceptanceProfileId = secureAcceptance ? secureAcceptanceCheckoutProfile({ environment: input.environment,
|
|
2295
2386
|
profileId: input.secureAcceptanceProfileId, merchantOrigin: input.merchantOrigin }) : null;
|
|
2387
|
+
// A live Paygent checkout's merchant is the API's to judge against the reviewed pins it holds, before anyone is
|
|
2388
|
+
// asked to approve (PAYGENT_PREPARATION_REFUSALS); test mode needs no pin.
|
|
2296
2389
|
const timeoutMs = input.timeoutMs ?? 15 * 60_000;
|
|
2297
2390
|
if (!Number.isInteger(timeoutMs) || timeoutMs <= 0 || timeoutMs > 2_147_483_647)
|
|
2298
2391
|
throw fail('timeout_invalid');
|
|
@@ -2412,6 +2505,7 @@ export class VaultClient {
|
|
|
2412
2505
|
|| (input.psp === EPROTECT_PSP && EPROTECT_PREPARATION_REFUSALS.includes(error.code))
|
|
2413
2506
|
|| (input.psp === PADDLE_VGS_PSP && PADDLE_VGS_PREPARATION_REFUSALS.includes(error.code))
|
|
2414
2507
|
|| (input.psp === WIX_PAYMENTS_PSP && WIX_PAYMENTS_PREPARATION_REFUSALS.includes(error.code))
|
|
2508
|
+
|| (input.psp === PAYGENT_PSP && PAYGENT_PREPARATION_REFUSALS.includes(error.code))
|
|
2415
2509
|
|| (input.psp === HIPAY_PSP && HIPAY_PREPARATION_REFUSALS.includes(error.code))
|
|
2416
2510
|
|| (!!flexContext && CYBERSOURCE_FLEX_PREPARATION_REFUSALS.includes(error.code))))
|
|
2417
2511
|
|| (input.psp === 'fiserv' && error.status === 502 && error.code === 'cse_key_unavailable')))
|
|
@@ -2709,17 +2803,21 @@ export class VaultClient {
|
|
|
2709
2803
|
// the total GoPay's payment already holds, so a zero pair would show the cardholder no price at all: it is refused
|
|
2710
2804
|
// like a missing one.
|
|
2711
2805
|
// A ComGate payment charges the total ComGate already holds for it, the same way, and a Webpay transaction the
|
|
2712
|
-
// total the merchant's server bound to it
|
|
2806
|
+
// total the merchant's server bound to it, and a Payrexx page charges its own
|
|
2807
|
+
// total after the frame's token.
|
|
2713
2808
|
// A Moneris token is charged later for whatever the merchant's server decides, and a Payfast pay, a
|
|
2714
2809
|
// PayMongo attach or a MakeCommerce card post charges the total its payment, checkout session or
|
|
2715
2810
|
// transaction already holds, so a zero pair would show the cardholder no price at all: it is refused
|
|
2716
2811
|
// like a missing one. So is a TokenEx iframe token, which the merchant's server charges later for its own order.
|
|
2812
|
+
// A Clover token is charged later for whatever the merchant's server decides, as a Moneris one is.
|
|
2813
|
+
// A Toast payment method is charged by the page's own confirm for whatever its intent says, the same way.
|
|
2717
2814
|
if (hasAmount && rec && rec.psp === PRZELEWY24_PSP && Number(input.amount) <= 0)
|
|
2718
2815
|
throw new AmountRequiredError(rec.psp);
|
|
2719
2816
|
if (hasAmount && rec && (rec.psp === MONERIS_PSP || rec.psp === PAYFAST_PSP || rec.psp === PAYMONGO_PSP || rec.psp === HIPAY_PSP || rec.psp === TWOC2P_PSP
|
|
2720
2817
|
|| rec.psp === REVOLUT_PSP || rec.psp === PAY_NL_PSP || rec.psp === PAYPAL_PSP
|
|
2721
2818
|
|| rec.psp === GOPAY_PSP || rec.psp === COMGATE_PSP || rec.psp === MAKECOMMERCE_PSP
|
|
2722
|
-
|| rec.psp === POYNT_PSP || rec.psp === TOKENEX_IFRAME_PSP || rec.psp === TRANSBANK_PSP || rec.psp === SUMUP_PSP
|
|
2819
|
+
|| rec.psp === POYNT_PSP || rec.psp === TOKENEX_IFRAME_PSP || rec.psp === TRANSBANK_PSP || rec.psp === SUMUP_PSP
|
|
2820
|
+
|| rec.psp === CLOVER_PSP || rec.psp === PAYREXX_PSP || rec.psp === TOAST_PSP) && Number(input.amount) <= 0)
|
|
2723
2821
|
throw new AmountRequiredError(rec.psp);
|
|
2724
2822
|
// Nor is the agent's pair tied to the page by anything but the total the
|
|
2725
2823
|
// page shows: without it the cardholder could approve one figure while the
|
|
@@ -3055,6 +3153,10 @@ export class VaultClient {
|
|
|
3055
3153
|
// source.encryptionData and removes nothing (fiserv.ts); any other shape is not one to act on.
|
|
3056
3154
|
if (rec.psp === 'fiserv' && !isFiservSubstitution(sub))
|
|
3057
3155
|
throw new PaymentOutcomeUnknownError(authorizationId, 'cse_substitutions_malformed');
|
|
3156
|
+
// A Toast approval carries exactly one sealed card, cardData at `card`, and removes nothing
|
|
3157
|
+
// (payment-core toast-seal.js substituteToastCardData checks the rest at the swap).
|
|
3158
|
+
if (rec.psp === TOAST_PSP && !isToastSubstitution(sub))
|
|
3159
|
+
throw new PaymentOutcomeUnknownError(authorizationId, 'cse_substitutions_malformed');
|
|
3058
3160
|
// `remove`: sibling keys the API says to drop with the swap (Adyen's
|
|
3059
3161
|
// `brand`, stamped by adyen-web from the agent's dummy digits). Absent
|
|
3060
3162
|
// on an older API; anything but a list of names is refused, since a
|
|
@@ -3225,6 +3327,18 @@ export class VaultClient {
|
|
|
3225
3327
|
response.headers = answer.headers;
|
|
3226
3328
|
response.body = answer.body;
|
|
3227
3329
|
}
|
|
3330
|
+
if (rec?.psp === PAYGENT_PSP) {
|
|
3331
|
+
// Paygent's answer enters the page only as payment-core rebuilds an approved token from its members
|
|
3332
|
+
// (paygent.js paygentAnswerOutcome: HTTP 200, result 0000 and a token in shape), under a JSON content
|
|
3333
|
+
// type. Anything else, a refusal Paygent answers inside HTTP 200 included, is never handed over as an
|
|
3334
|
+
// approval; the card may have left the device, so the outcome is unknown rather than declined.
|
|
3335
|
+
const judged = paygentAnswerOutcome(response.status, response.body, null);
|
|
3336
|
+
if (judged.outcome !== 'approved' || typeof judged.body !== 'string')
|
|
3337
|
+
throw new PaymentOutcomeUnknownError(authorizationId, 'paygent_token_unconfirmed');
|
|
3338
|
+
response.status = 200;
|
|
3339
|
+
response.headers = { 'content-type': 'application/json' };
|
|
3340
|
+
response.body = judged.body;
|
|
3341
|
+
}
|
|
3228
3342
|
if (rec?.psp === PRIMER_PSP) {
|
|
3229
3343
|
// Primer's answer enters the page only as one single-use card token rebuilt from
|
|
3230
3344
|
// payment-core's allow-list, under a JSON content type (primer.ts primerTokenAnswer).
|
|
@@ -3279,8 +3393,9 @@ export class VaultClient {
|
|
|
3279
3393
|
chargedAmount: typeof s.charged_amount === 'number' ? s.charged_amount : null,
|
|
3280
3394
|
chargedCurrency: typeof s.charged_currency === 'string' ? s.charged_currency : null,
|
|
3281
3395
|
chargedKind: s.charged_kind === 'captured' || s.charged_kind === 'authorized' || s.charged_kind === 'none' ? s.charged_kind : null,
|
|
3282
|
-
// An EBANX token approval
|
|
3283
|
-
|
|
3396
|
+
// An EBANX token approval, or a Payrexx card request whose answer started 3-D Secure, that covers the sends
|
|
3397
|
+
// after it names until when (ebanx.ts EbanxFollowUps, payrexx.ts PayrexxFollowUps).
|
|
3398
|
+
...((rec?.psp === 'ebanx' || rec?.psp === PAYREXX_PSP) && typeof s.follow_ups?.until === 'string' && Number.isFinite(Date.parse(s.follow_ups.until))
|
|
3284
3399
|
? { followUpsUntil: s.follow_ups.until } : {}),
|
|
3285
3400
|
...amountAuthority,
|
|
3286
3401
|
...execution,
|
|
@@ -3493,6 +3608,20 @@ export class VaultClient {
|
|
|
3493
3608
|
* an answer that carried the card, or `options.until` (the approval's window, plus the API's own clocks) passed.
|
|
3494
3609
|
*/
|
|
3495
3610
|
async sendEbanxFollowUp(authorizationId, request, options = {}) {
|
|
3611
|
+
return this.sendFollowUp(authorizationId, request, options, (reason, cardSent) => new EbanxFollowUpError(reason, cardSent, authorizationId));
|
|
3612
|
+
}
|
|
3613
|
+
/**
|
|
3614
|
+
* Send one of Payrexx's 3-D Secure sends an approved Payrexx card request covers (payrexx.ts says which: the card
|
|
3615
|
+
* frame's authentication after the ACS method and its post-authentication after the bank's challenge, bound to that
|
|
3616
|
+
* approval) from the cardholder's device, and resolve with Payrexx's answer for the paused request, exactly as
|
|
3617
|
+
* sendEbanxFollowUp does for EBANX: the same create, reads and clocks, and no prompt. Rejects with a
|
|
3618
|
+
* PayrexxFollowUpError naming why there is no answer and whether the card may have reached Payrexx.
|
|
3619
|
+
*/
|
|
3620
|
+
async sendPayrexxFollowUp(authorizationId, request, options = {}) {
|
|
3621
|
+
return this.sendFollowUp(authorizationId, request, options, (reason, cardSent) => new PayrexxFollowUpError(reason, cardSent, authorizationId));
|
|
3622
|
+
}
|
|
3623
|
+
/** The send behind sendEbanxFollowUp and sendPayrexxFollowUp; `fail` builds the processor's error for a send with no answer. */
|
|
3624
|
+
async sendFollowUp(authorizationId, request, options, fail) {
|
|
3496
3625
|
if (!/^cauth_[A-Za-z0-9_-]{1,128}$/.test(authorizationId))
|
|
3497
3626
|
throw new Error('Invalid authorization ID.');
|
|
3498
3627
|
const base = `/v2/checkout/authorizations/${authorizationId}/follow_ups`;
|
|
@@ -3506,16 +3635,16 @@ export class VaultClient {
|
|
|
3506
3635
|
catch (error) {
|
|
3507
3636
|
// A refusal (a 4xx answer) stored no send, so nothing left. Any other failure (a 5xx, a timeout, a dropped
|
|
3508
3637
|
// connection, an unreadable 201) may have come after the API stored the send, which the device then sends:
|
|
3509
|
-
// the card may reach
|
|
3638
|
+
// the card may reach the processor, and for an EBANX confirm that is a payment whose outcome is unknown.
|
|
3510
3639
|
const refused = error instanceof CheckoutApiError && error.status >= 400 && error.status < 500;
|
|
3511
3640
|
const reason = error instanceof CheckoutApiError
|
|
3512
3641
|
? (typeof error.details.reason === 'string' && /^[a-z_]{1,64}$/.test(error.details.reason) ? error.details.reason : error.code ?? `http_${error.status}`)
|
|
3513
3642
|
: 'follow_up_unavailable';
|
|
3514
|
-
throw
|
|
3643
|
+
throw fail(reason, !refused);
|
|
3515
3644
|
}
|
|
3516
3645
|
const id = created?.id;
|
|
3517
3646
|
if (typeof id !== 'string' || !/^cfu_[0-9a-f]{24}$/.test(id) || created.authorization !== authorizationId) {
|
|
3518
|
-
throw
|
|
3647
|
+
throw fail('follow_up_unrecognized', true);
|
|
3519
3648
|
}
|
|
3520
3649
|
// Reads the API refused in a row as too many (429): each waits twice as long as the last before the next read.
|
|
3521
3650
|
let limited = 0;
|
|
@@ -3527,14 +3656,14 @@ export class VaultClient {
|
|
|
3527
3656
|
}
|
|
3528
3657
|
catch (error) {
|
|
3529
3658
|
if (signal.aborted)
|
|
3530
|
-
throw
|
|
3659
|
+
throw fail('answer_late', true);
|
|
3531
3660
|
if (error instanceof CheckoutApiError && error.status === 429)
|
|
3532
3661
|
limited += 1;
|
|
3533
3662
|
}
|
|
3534
3663
|
if (read?.status === 'answered') {
|
|
3535
3664
|
const r = read.response;
|
|
3536
3665
|
if (!r || !Number.isInteger(r.status) || r.status < 200 || r.status > 599 || typeof r.body !== 'string' || !r.headers || typeof r.headers !== 'object') {
|
|
3537
|
-
throw
|
|
3666
|
+
throw fail('follow_up_unrecognized', true);
|
|
3538
3667
|
}
|
|
3539
3668
|
const headers = {};
|
|
3540
3669
|
for (const [name, value] of Object.entries(r.headers))
|
|
@@ -3544,10 +3673,10 @@ export class VaultClient {
|
|
|
3544
3673
|
}
|
|
3545
3674
|
if (read?.status === 'failed' || read?.status === 'expired') {
|
|
3546
3675
|
const reason = typeof read.failure_reason === 'string' && /^[a-z_]{1,64}$/.test(read.failure_reason) ? read.failure_reason : read.status;
|
|
3547
|
-
throw
|
|
3676
|
+
throw fail(reason, read.card_sent !== false);
|
|
3548
3677
|
}
|
|
3549
3678
|
if (signal.aborted || Date.now() >= deadline)
|
|
3550
|
-
throw
|
|
3679
|
+
throw fail('answer_late', true);
|
|
3551
3680
|
const wait = limited === 0 ? EBANX_FOLLOW_UP_READ_MS : Math.min(EBANX_FOLLOW_UP_BACKOFF_MAX_MS, 1000 * 2 ** (limited - 1));
|
|
3552
3681
|
await interruptibleSleep(Math.max(1, Math.min(wait, deadline - Date.now())), signal);
|
|
3553
3682
|
}
|
|
@@ -4108,3 +4237,14 @@ function interruptibleSleep(ms, signal) {
|
|
|
4108
4237
|
signal?.addEventListener('abort', done, { once: true });
|
|
4109
4238
|
});
|
|
4110
4239
|
}
|
|
4240
|
+
/** A served Toast set: exactly { cardData } at `card`, a 256-byte base64 value, with nothing to remove. */
|
|
4241
|
+
function isToastSubstitution(sub) {
|
|
4242
|
+
if (!sub || typeof sub !== 'object')
|
|
4243
|
+
return false;
|
|
4244
|
+
const { at, fields, remove } = sub;
|
|
4245
|
+
if (at !== 'card' || !fields || typeof fields !== 'object' || Array.isArray(fields))
|
|
4246
|
+
return false;
|
|
4247
|
+
const keys = Object.keys(fields);
|
|
4248
|
+
return keys.length === 1 && keys[0] === 'cardData' && isToastCiphertext(fields.cardData)
|
|
4249
|
+
&& (remove === undefined || (Array.isArray(remove) && remove.length === 0));
|
|
4250
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
2
|
// Generated from @agent-cards/payment-core. Do not edit.
|
|
3
|
-
// artifact-sha256:
|
|
3
|
+
// artifact-sha256: 24cac2580feefe7d273b89de8e5b84e744e561fd258252f98008801750370460
|
|
4
4
|
// src/creditguard.js
|
|
5
5
|
var CREDITGUARD_PPS_HOSTS = Object.freeze(["pps.creditguard.co.il", "pps2.creditguard.co.il", "ppsuat.creditguard.co.il"]);
|
|
6
6
|
var CREDITGUARD_SANDBOX_HOST = "ppsuat.creditguard.co.il";
|
|
@@ -707,6 +707,7 @@ var THREE_DS_INIT_KEYS = Object.freeze([
|
|
|
707
707
|
"cvv",
|
|
708
708
|
"isGooglePayTxn",
|
|
709
709
|
"isPayboxTxn",
|
|
710
|
+
"recaptchaValue",
|
|
710
711
|
"useDcc",
|
|
711
712
|
"acsWindowSize",
|
|
712
713
|
"browserColorDepth",
|
|
@@ -837,6 +838,7 @@ function creditguardDeviceThreeDSInitRequest(processUrl, card, options = {}) {
|
|
|
837
838
|
cvv: parts.cvc,
|
|
838
839
|
isGooglePayTxn: false,
|
|
839
840
|
isPayboxTxn: false,
|
|
841
|
+
recaptchaValue: "",
|
|
840
842
|
useDcc: false,
|
|
841
843
|
acsWindowSize: "4",
|
|
842
844
|
browserColorDepth: browser.colorDepth,
|
|
@@ -887,7 +889,7 @@ function deviceStepBodyRefusal(step, txId, body) {
|
|
|
887
889
|
return "dcc";
|
|
888
890
|
if (value.txId !== txId)
|
|
889
891
|
return "txid_mismatch";
|
|
890
|
-
if (value.acsWindowSize !== "4" || value.browserHeader !== BROWSER_HEADER || value.browserJavascriptEnabled !== true)
|
|
892
|
+
if (value.recaptchaValue !== "" || value.acsWindowSize !== "4" || value.browserHeader !== BROWSER_HEADER || value.browserJavascriptEnabled !== true)
|
|
891
893
|
return "malformed_body";
|
|
892
894
|
try {
|
|
893
895
|
deviceBrowser({
|
package/dist/cse-body.js
CHANGED
|
@@ -4,6 +4,8 @@ import { substituteEncryptedFields } from './substitute.js';
|
|
|
4
4
|
import { substituteMerchantHostedBody } from './merchant-hosted.js';
|
|
5
5
|
import { fiservCapturePinId, isFiservCaptureHost, substituteFiservEnvelope } from './fiserv.js';
|
|
6
6
|
import { substituteVerifoneBody } from './verifone.js';
|
|
7
|
+
import { isToastHost } from './toast.generated.js';
|
|
8
|
+
import { substituteToastCardData } from './toast-seal.generated.js';
|
|
7
9
|
/**
|
|
8
10
|
* The cse continuation: the paused body with the vault's ciphertext in place
|
|
9
11
|
* of the dummy blobs. The adapters send it as postData ALONE. Chromium
|
|
@@ -44,6 +46,15 @@ export function cseBody(body, replay, url, preparation) {
|
|
|
44
46
|
}
|
|
45
47
|
if (isFiservCaptureHost(url))
|
|
46
48
|
throw new Error('Refusing to substitute: a Fiserv capture continues only through a prepared Fiserv approval.');
|
|
49
|
+
// A request on Toast's payments host takes only Toast's own swap: the device's sealed card written over
|
|
50
|
+
// the paused card.cardData and no other byte, refused unless the paused body is still the frame's guest
|
|
51
|
+
// card request and the card is sealed under the key payment-core pins (toast-seal.js substituteToastCardData).
|
|
52
|
+
if (isToastHost(url)) {
|
|
53
|
+
if (replay.kind !== undefined || replay.substitutions.at !== 'card' || (replay.substitutions.remove ?? []).length > 0) {
|
|
54
|
+
throw new Error('Refusing to substitute: the paused request is not the Toast card request the cardholder approved.');
|
|
55
|
+
}
|
|
56
|
+
return substituteToastCardData(url, body, replay.substitutions.fields);
|
|
57
|
+
}
|
|
47
58
|
// A merchant-hosted approval is written into the LIVE paused body, which must
|
|
48
59
|
// still be the body the API checked at create (merchant-hosted.ts).
|
|
49
60
|
if (replay.kind === 'merchant_hosted')
|
package/dist/ebanx.d.ts
CHANGED
|
@@ -75,7 +75,7 @@ export declare class EbanxFollowUps {
|
|
|
75
75
|
stop(): void;
|
|
76
76
|
/**
|
|
77
77
|
* The approval the remembered token request went under, or null when none is remembered. The gate sends nothing
|
|
78
|
-
* unless the checkout's own state names this same approval (pre-claim.ts
|
|
78
|
+
* unless the checkout's own state names this same approval (pre-claim.ts followUpMaySend).
|
|
79
79
|
*/
|
|
80
80
|
get authorizationId(): string | null;
|
|
81
81
|
/**
|
package/dist/ebanx.js
CHANGED
|
@@ -108,7 +108,7 @@ export class EbanxFollowUps {
|
|
|
108
108
|
stop() { this.stopped = true; }
|
|
109
109
|
/**
|
|
110
110
|
* The approval the remembered token request went under, or null when none is remembered. The gate sends nothing
|
|
111
|
-
* unless the checkout's own state names this same approval (pre-claim.ts
|
|
111
|
+
* unless the checkout's own state names this same approval (pre-claim.ts followUpMaySend).
|
|
112
112
|
*/
|
|
113
113
|
get authorizationId() { return this.parent?.authorizationId ?? null; }
|
|
114
114
|
/**
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Eximbay's payment window (secureapi.eximbay.com, the Korean gateway that takes foreign cards for Korean merchants),
|
|
3
|
+
* as this SDK reads it.
|
|
4
|
+
*
|
|
5
|
+
* The merchant's page posts a signed entry form, top-level or into a window it opens, to
|
|
6
|
+
* https://secureapi.eximbay.com/Gateway/BasicProcessor.krp (Eximbay's test host for a test merchant), and Eximbay
|
|
7
|
+
* answers with a page that posts itself, with the session's paramkey, into its window. That entry carries no card,
|
|
8
|
+
* and it is the one request this SDK pauses: the cardholder's device repeats it over the end-to-end TLS relay and
|
|
9
|
+
* fills the card into the window Eximbay returns to it (payment-core processors/eximbay.js). Everything else the
|
|
10
|
+
* agent's browser posts to Eximbay follows the entry and leads to a card: the step that opens the window
|
|
11
|
+
* (/Gateway/BasicProcessor/230/NewGlobalStep1.jsp), the window's amount query and card lookup, which carries the
|
|
12
|
+
* card's first eight digits (controll/checkApprvJson.do, controll/checkCardBin.do), its card post
|
|
13
|
+
* (controll/checkApprv.jsp) and its other posts. This SDK aborts every one of them in a page it watches, so a
|
|
14
|
+
* placeholder card never reaches Eximbay from one. attachToCdp watches a window the merchant's page opens once it has
|
|
15
|
+
* armed that window. Eximbay's popup integration opens the window and posts the entry into it at once, so that entry
|
|
16
|
+
* can leave before the window is armed; the window's next post, the step, is then aborted like any other, and the
|
|
17
|
+
* checkout reads unsupported. attachToPlaywright routes the page alone, never a window it opens.
|
|
18
|
+
*
|
|
19
|
+
* EXIMBAY_HOSTS is payment-core's EXIMBAY_HOSTS, and isEximbayEntry takes the URLs payment-core's isEximbayEntryUrl
|
|
20
|
+
* takes; eximbay.test.mjs pins both to payment-core.
|
|
21
|
+
*/
|
|
22
|
+
export declare const EXIMBAY_PSP = "eximbay";
|
|
23
|
+
/** The dark-launch capability the API serves Eximbay's recognizer behind (payment-core definitions.js). */
|
|
24
|
+
export declare const EXIMBAY_CAPABILITY = "eximbay_hosted_payment_page";
|
|
25
|
+
/** The live host and Eximbay's test host, which serves the same window for a test merchant. */
|
|
26
|
+
export declare const EXIMBAY_HOSTS: readonly string[];
|
|
27
|
+
/** Whether this URL is on one of Eximbay's two hosts. */
|
|
28
|
+
export declare function isEximbayHost(url: string): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* The only request on Eximbay's hosts that is the merchant's entry: a POST to the entry path, written exactly as a
|
|
31
|
+
* browser posts a form to it, with no port, query or fragment (payment-core isEximbayEntryUrl takes those two strings
|
|
32
|
+
* only). The entry the SDK pauses; every other POST there is aborted.
|
|
33
|
+
*/
|
|
34
|
+
export declare function isEximbayEntry(url: string, method: string): boolean;
|
|
35
|
+
/** The entry URL on the same Eximbay host, which the registry recognizes when this build is armed for Eximbay, or null. */
|
|
36
|
+
export declare function eximbayEntryUrl(url: string): string | null;
|
|
37
|
+
/**
|
|
38
|
+
* Whether an adapter must hand this request to the pre-claim gates: it is on an Eximbay host and this build's registry
|
|
39
|
+
* serves Eximbay's entry there. The step, the window's lookups and its card post are not the entry, so the registry's
|
|
40
|
+
* card-request test does not name them; the CDP adapter still pauses them through the recognizer's host pattern, and
|
|
41
|
+
* attachToPlaywright's route predicate asks this, so both adapters show the gates every request to Eximbay once
|
|
42
|
+
* Eximbay is armed.
|
|
43
|
+
*/
|
|
44
|
+
export declare function isArmedEximbayUrl(vault: {
|
|
45
|
+
isCardRequest(url: string, method?: string): boolean;
|
|
46
|
+
}, url: string): boolean;
|
package/dist/eximbay.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Eximbay's payment window (secureapi.eximbay.com, the Korean gateway that takes foreign cards for Korean merchants),
|
|
3
|
+
* as this SDK reads it.
|
|
4
|
+
*
|
|
5
|
+
* The merchant's page posts a signed entry form, top-level or into a window it opens, to
|
|
6
|
+
* https://secureapi.eximbay.com/Gateway/BasicProcessor.krp (Eximbay's test host for a test merchant), and Eximbay
|
|
7
|
+
* answers with a page that posts itself, with the session's paramkey, into its window. That entry carries no card,
|
|
8
|
+
* and it is the one request this SDK pauses: the cardholder's device repeats it over the end-to-end TLS relay and
|
|
9
|
+
* fills the card into the window Eximbay returns to it (payment-core processors/eximbay.js). Everything else the
|
|
10
|
+
* agent's browser posts to Eximbay follows the entry and leads to a card: the step that opens the window
|
|
11
|
+
* (/Gateway/BasicProcessor/230/NewGlobalStep1.jsp), the window's amount query and card lookup, which carries the
|
|
12
|
+
* card's first eight digits (controll/checkApprvJson.do, controll/checkCardBin.do), its card post
|
|
13
|
+
* (controll/checkApprv.jsp) and its other posts. This SDK aborts every one of them in a page it watches, so a
|
|
14
|
+
* placeholder card never reaches Eximbay from one. attachToCdp watches a window the merchant's page opens once it has
|
|
15
|
+
* armed that window. Eximbay's popup integration opens the window and posts the entry into it at once, so that entry
|
|
16
|
+
* can leave before the window is armed; the window's next post, the step, is then aborted like any other, and the
|
|
17
|
+
* checkout reads unsupported. attachToPlaywright routes the page alone, never a window it opens.
|
|
18
|
+
*
|
|
19
|
+
* EXIMBAY_HOSTS is payment-core's EXIMBAY_HOSTS, and isEximbayEntry takes the URLs payment-core's isEximbayEntryUrl
|
|
20
|
+
* takes; eximbay.test.mjs pins both to payment-core.
|
|
21
|
+
*/
|
|
22
|
+
export const EXIMBAY_PSP = 'eximbay';
|
|
23
|
+
/** The dark-launch capability the API serves Eximbay's recognizer behind (payment-core definitions.js). */
|
|
24
|
+
export const EXIMBAY_CAPABILITY = 'eximbay_hosted_payment_page';
|
|
25
|
+
/** The live host and Eximbay's test host, which serves the same window for a test merchant. */
|
|
26
|
+
export const EXIMBAY_HOSTS = Object.freeze(['secureapi.eximbay.com', 'secureapi.test.eximbay.com']);
|
|
27
|
+
const ENTRY_PATH = '/Gateway/BasicProcessor.krp';
|
|
28
|
+
/** The Eximbay host a URL is on (https, no credentials, any port, any letter case, a trailing dot or not), or null. */
|
|
29
|
+
function eximbayHost(raw) {
|
|
30
|
+
let url;
|
|
31
|
+
try {
|
|
32
|
+
url = new URL(raw);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
if (url.protocol !== 'https:' || url.username || url.password)
|
|
38
|
+
return null;
|
|
39
|
+
const host = url.hostname.toLowerCase().replace(/\.$/, '');
|
|
40
|
+
return EXIMBAY_HOSTS.includes(host) ? host : null;
|
|
41
|
+
}
|
|
42
|
+
/** Whether this URL is on one of Eximbay's two hosts. */
|
|
43
|
+
export function isEximbayHost(url) {
|
|
44
|
+
return eximbayHost(url) !== null;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The only request on Eximbay's hosts that is the merchant's entry: a POST to the entry path, written exactly as a
|
|
48
|
+
* browser posts a form to it, with no port, query or fragment (payment-core isEximbayEntryUrl takes those two strings
|
|
49
|
+
* only). The entry the SDK pauses; every other POST there is aborted.
|
|
50
|
+
*/
|
|
51
|
+
export function isEximbayEntry(url, method) {
|
|
52
|
+
return String(method).toUpperCase() === 'POST' && EXIMBAY_HOSTS.some((host) => url === `https://${host}${ENTRY_PATH}`);
|
|
53
|
+
}
|
|
54
|
+
/** The entry URL on the same Eximbay host, which the registry recognizes when this build is armed for Eximbay, or null. */
|
|
55
|
+
export function eximbayEntryUrl(url) {
|
|
56
|
+
const host = eximbayHost(url);
|
|
57
|
+
return host === null ? null : `https://${host}${ENTRY_PATH}`;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Whether an adapter must hand this request to the pre-claim gates: it is on an Eximbay host and this build's registry
|
|
61
|
+
* serves Eximbay's entry there. The step, the window's lookups and its card post are not the entry, so the registry's
|
|
62
|
+
* card-request test does not name them; the CDP adapter still pauses them through the recognizer's host pattern, and
|
|
63
|
+
* attachToPlaywright's route predicate asks this, so both adapters show the gates every request to Eximbay once
|
|
64
|
+
* Eximbay is armed.
|
|
65
|
+
*/
|
|
66
|
+
export function isArmedEximbayUrl(vault, url) {
|
|
67
|
+
const entry = eximbayEntryUrl(url);
|
|
68
|
+
return entry !== null && vault.isCardRequest(entry, 'POST');
|
|
69
|
+
}
|