@agent-cards/sdk 0.23.13 → 0.23.15
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 +39 -0
- package/PREFLIGHT.md +3 -1
- package/README.md +54 -13
- package/dist/adyen-merchant-hosted.generated.js +2 -2
- package/dist/amadeus.d.ts +5 -2
- package/dist/amadeus.js +17 -3
- package/dist/card-fields.generated.js +924 -3
- package/dist/cdp.js +83 -19
- package/dist/client.d.ts +97 -1
- package/dist/client.js +235 -16
- package/dist/creditguard.generated.d.ts +100 -2
- package/dist/creditguard.generated.js +333 -3
- package/dist/datatrans.generated.d.ts +19 -4
- package/dist/datatrans.generated.js +15 -3
- package/dist/ebanx.d.ts +107 -0
- package/dist/ebanx.generated.d.ts +78 -0
- package/dist/ebanx.generated.js +577 -0
- package/dist/ebanx.js +159 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/lifecycle.d.ts +32 -5
- package/dist/lifecycle.js +40 -5
- package/dist/paddle-tokenex.d.ts +56 -0
- package/dist/paddle-tokenex.generated.d.ts +67 -0
- package/dist/paddle-tokenex.generated.js +951 -0
- package/dist/paddle-tokenex.js +95 -0
- package/dist/paypal-card-forms.d.ts +73 -0
- package/dist/paypal-card-forms.js +126 -0
- package/dist/pre-claim.d.ts +39 -1
- package/dist/pre-claim.js +348 -18
- package/dist/preparation.d.ts +13 -0
- package/dist/preparation.js +22 -0
- package/dist/prepared-processor.d.ts +5 -1
- package/dist/prepared-processor.js +17 -2
- package/dist/primer.generated.js +960 -39
- package/dist/redsys.d.ts +42 -0
- package/dist/redsys.js +68 -0
- package/dist/stripe-checkout.generated.js +494 -9
- package/dist/wix-payments.generated.d.ts +42 -0
- package/dist/wix-payments.generated.js +241 -0
- package/package.json +8 -5
package/dist/cdp.js
CHANGED
|
@@ -8,14 +8,18 @@ import { MERCADO_CHECKOUT_PATTERN } from './mercado-checkout.generated.js';
|
|
|
8
8
|
import { JuspayCheckoutGate } from './juspay-gate.js';
|
|
9
9
|
import { ACI_CHECKOUT_REUSED, AciGate, playwrightReplacesNavigationBody } from './aci.js';
|
|
10
10
|
import { EprotectGate } from './eprotect.js';
|
|
11
|
-
import { dispatchPreClaim, eventUrl } from './pre-claim.js';
|
|
11
|
+
import { dispatchPreClaim, eventUrl, isArmedCreditguardCall } from './pre-claim.js';
|
|
12
12
|
import { GMO_TOKEN_V1_PATTERNS, gmoRequestShop, isGmoTokenV1Request, recognizesGmo } from './gmo.js';
|
|
13
13
|
import { isPaddleVgsCardsUrl } from './paddle-vgs.generated.js';
|
|
14
14
|
import { PADDLE_VGS_PAY_PATTERNS, PaddleVgsPayGate, isPaddleCheckoutService, recognizesPaddleVgs } from './paddle-vgs-pay.js';
|
|
15
15
|
import { DatatransRepeats } from './datatrans.js';
|
|
16
16
|
import { SHIJI_STS_COMPANION_WINDOW_MS, ShijiStsCompanions, ShijiStsError, isShijiStsHost, shijiStsTokenContinuation, } from './shiji-sts.js';
|
|
17
|
+
import { paddleTokenexTokenContinuation } from './paddle-tokenex.js';
|
|
17
18
|
import { isArmedEkashuUrl } from './ekashu.js';
|
|
19
|
+
import { isArmedRedsysUrl } from './redsys.js';
|
|
18
20
|
import { PAYPAL_HOSTED_FIELDS_PATTERNS, isPaypalHostedFieldsConfirm } from './paypal-hosted-fields.js';
|
|
21
|
+
import { EBANX_RESEND_PATTERNS, EbanxFollowUps, isEbanxResendUrl } from './ebanx.js';
|
|
22
|
+
import { PAYPAL_CARD_FORM_PATTERNS, isPaypalCardFormUrl } from './paypal-card-forms.js';
|
|
19
23
|
import { CYBERSOURCE_SECURE_ACCEPTANCE_PATTERNS, CYBERSOURCE_SECURE_ACCEPTANCE_RECIPIENT, SecureAcceptanceFollowUpWatch, isCybersourceSecureAcceptanceUrl, secureAcceptanceFollowUp, secureAcceptanceFrameAnswer, secureAcceptanceReplyLast4, } from './cybersource-secure-acceptance.js';
|
|
20
24
|
import { CheckoutAttachmentError, attachmentDeadline, attachmentFailure, withinAttachmentDeadline } from './attachment.js';
|
|
21
25
|
import { cseBody } from './cse-body.js';
|
|
@@ -339,8 +343,14 @@ function cseAuthorizedDetail(replay, url, shijiCvv = null) {
|
|
|
339
343
|
*/
|
|
340
344
|
function cseContinuation(opts, url, body, replay, approved, preparation) {
|
|
341
345
|
const shiji = shijiStsTokenContinuation(url, body, replay.substitutions, approved, replay.kind === 'merchant_hosted' || replay.kind === 'verifone' ? undefined : replay.shijiStsCompanion);
|
|
342
|
-
|
|
343
|
-
|
|
346
|
+
if (shiji)
|
|
347
|
+
return { body: shiji.body, shijiCvv: shiji.cvv, shijiCvvKeySequenceSha256: shiji.cvvKeySequenceSha256 };
|
|
348
|
+
// Paddle TokenEx writes two ciphertexts and five metadata facts under the pinned key, which the generic
|
|
349
|
+
// Adyen swap cannot, so it is dispatched by the /pay URL to substitutePaddleTokenex (paddle-tokenex.ts).
|
|
350
|
+
const paddleTokenex = replay.kind === undefined ? paddleTokenexTokenContinuation(url, body, replay.substitutions, replay.paddleTokenexFacts, approved) : null;
|
|
351
|
+
if (paddleTokenex)
|
|
352
|
+
return { body: paddleTokenex.body, shijiCvv: null, shijiCvvKeySequenceSha256: null };
|
|
353
|
+
return { body: cseContinuationBody(opts, body, replay, url, preparation), shijiCvv: null, shijiCvvKeySequenceSha256: null };
|
|
344
354
|
}
|
|
345
355
|
/**
|
|
346
356
|
* The opaque page id a Shiji STS companion is bound to: the CDP session and
|
|
@@ -1373,11 +1383,12 @@ function merchantAttempt(lifecycle, survives) {
|
|
|
1373
1383
|
let rebound = false;
|
|
1374
1384
|
let delivering = false;
|
|
1375
1385
|
let bound = null;
|
|
1376
|
-
// A send window (an Amadeus SDK add's, a Secure Acceptance token create's
|
|
1377
|
-
// confirms the card never left the device and never can (amadeus.ts): a
|
|
1378
|
-
// prepared checkout ends failed with that reason, and a fresh attachment can
|
|
1379
|
-
// other stop leaves the outcome unknown.
|
|
1386
|
+
// A send window (an Amadeus SDK add's, a Secure Acceptance token create's, a Wix tokenize request's)
|
|
1387
|
+
// closes only once the API confirms the card never left the device and never can (amadeus.ts): a
|
|
1388
|
+
// known non-payment, so the prepared checkout ends failed with that reason, and a fresh attachment can
|
|
1389
|
+
// prepare again. Every other stop leaves the outcome unknown.
|
|
1380
1390
|
const error = () => reason === 'amadeus_send_window_closed' || reason === 'secure_acceptance_send_window_closed'
|
|
1391
|
+
|| reason === 'wix_payments_send_window_closed'
|
|
1381
1392
|
? new CheckoutPreparationError(lifecycle.getState().preparationId ?? null, reason)
|
|
1382
1393
|
: new PaymentOutcomeUnknownError(lifecycle.getState().authorizationId, reason);
|
|
1383
1394
|
const attempt = {
|
|
@@ -1607,8 +1618,8 @@ function pauseForBusiness(opts, lifecycle, attemptSignal, request, pageOrigin) {
|
|
|
1607
1618
|
}
|
|
1608
1619
|
/**
|
|
1609
1620
|
* Arm the send window of a request paused under a preparation, when its processor sets one: a
|
|
1610
|
-
* prepared Amadeus SDK add
|
|
1611
|
-
* preparedSendWindowMs). Returns the disarm function, or null with no window. lifecycle.begin()
|
|
1621
|
+
* prepared Amadeus SDK add, a prepared Secure Acceptance token create and a prepared Wix tokenize
|
|
1622
|
+
* request do (amadeus.ts preparedSendWindowMs). Returns the disarm function, or null with no window. lifecycle.begin()
|
|
1612
1623
|
* cleared the authorization ID, so the one the window reads is this attempt's.
|
|
1613
1624
|
*/
|
|
1614
1625
|
function armWindowFor(opts, lifecycle, attempt, preparation, url, delivering) {
|
|
@@ -1758,6 +1769,8 @@ export async function attachToCdp(cdp, pageSessionId, opts) {
|
|
|
1758
1769
|
};
|
|
1759
1770
|
// Juspay's tokenize answer and the synthetic tokens it issued (juspay-gate.ts).
|
|
1760
1771
|
const juspayCheckout = new JuspayCheckoutGate(opts.vault);
|
|
1772
|
+
// The approved EBANX token request on this attachment and the sends claimed under it (ebanx.ts).
|
|
1773
|
+
const ebanxFollowUps = new EbanxFollowUps();
|
|
1761
1774
|
const aci = new AciGate(opts.vault);
|
|
1762
1775
|
const eprotect = new EprotectGate(opts.vault);
|
|
1763
1776
|
// The merchant's follow-up request after a delivered Secure Acceptance reply (cybersource-secure-acceptance.ts).
|
|
@@ -2049,13 +2062,20 @@ export async function attachToCdp(cdp, pageSessionId, opts) {
|
|
|
2049
2062
|
// PayPal's legacy Hosted Fields confirm is armed for every org, whatever the
|
|
2050
2063
|
// registry serves: one that carries the typed card is paused only to be
|
|
2051
2064
|
// refused, and one with no card continues (see paypal-hosted-fields.ts).
|
|
2065
|
+
// PayPal's Card Fields confirm and GraphQL on www.paypal.com are armed the
|
|
2066
|
+
// same way: a card the guard refuses is paused only to be refused, a
|
|
2067
|
+
// confirm the registry recognizes pauses for its recognizer, and a request
|
|
2068
|
+
// with no card continues (see paypal-card-forms.ts).
|
|
2052
2069
|
// CyberSource Secure Acceptance's /silent/ paths are armed the same way, form
|
|
2053
|
-
// navigations included (see cybersource-secure-acceptance.ts)
|
|
2070
|
+
// navigations included (see cybersource-secure-acceptance.ts), and so are
|
|
2071
|
+
// EBANX's 3-D Secure calls and hosted confirm, which send the typed card again
|
|
2072
|
+
// after its token: the cardholder's device sends one the approved token request
|
|
2073
|
+
// covers, and any other is refused (see ebanx.ts).
|
|
2054
2074
|
const urlPatterns = [...new Set([...(derived.length > 0 ? derived : FALLBACK_CARD_PATTERNS), ...guards.patterns,
|
|
2055
2075
|
...(stripeCheckout.isEnabled() ? ['https://api.stripe.com/*'] : []), MERCADO_CHECKOUT_PATTERN, ...merchantPatterns,
|
|
2056
2076
|
...(recognizesGmo(opts.vault) ? GMO_TOKEN_V1_PATTERNS : []), ...juspayCheckout.urlPatterns(), ...cardEndpointPatterns(),
|
|
2057
|
-
...(payrails ? PAYRAILS_GUARD_PATTERNS : []), ...PAYPAL_HOSTED_FIELDS_PATTERNS, ...
|
|
2058
|
-
...(recognizesPaddleVgs(opts.vault) ? PADDLE_VGS_PAY_PATTERNS : [])])];
|
|
2077
|
+
...(payrails ? PAYRAILS_GUARD_PATTERNS : []), ...PAYPAL_HOSTED_FIELDS_PATTERNS, ...PAYPAL_CARD_FORM_PATTERNS,
|
|
2078
|
+
...CYBERSOURCE_SECURE_ACCEPTANCE_PATTERNS, ...(recognizesPaddleVgs(opts.vault) ? PADDLE_VGS_PAY_PATTERNS : []), ...EBANX_RESEND_PATTERNS])];
|
|
2059
2079
|
const arm = async (sessionId, resume = false, worker = false) => {
|
|
2060
2080
|
const key = sessionId ?? '__root__';
|
|
2061
2081
|
if (armed.has(key))
|
|
@@ -2485,6 +2505,7 @@ export async function attachToCdp(cdp, pageSessionId, opts) {
|
|
|
2485
2505
|
cybersourceFlex: { judge: (flexRequest) => microforms.judge(flexRequest, frameId, () => rereadMicroforms(sessionId, frameId)) },
|
|
2486
2506
|
juspay: juspayCheckout,
|
|
2487
2507
|
datatrans: datatransRepeats,
|
|
2508
|
+
ebanx: ebanxFollowUps,
|
|
2488
2509
|
frame: typeof frameId === 'string' && frameId ? frameId : undefined,
|
|
2489
2510
|
payrails,
|
|
2490
2511
|
shijiSts: { companions: shijiCompanions, page: () => cdpShijiPage(sessionId, frameId) },
|
|
@@ -2598,7 +2619,10 @@ export async function attachToCdp(cdp, pageSessionId, opts) {
|
|
|
2598
2619
|
// A request that skipped the spent preparation's claim and was not bound as
|
|
2599
2620
|
// its retry (the approval ended while it was judged) is refused as that
|
|
2600
2621
|
// claim would refuse it, never asked as a new approval.
|
|
2601
|
-
|
|
2622
|
+
// An EBANX send still out (a confirm that may pay) holds the attachment too: a new card request the page sends
|
|
2623
|
+
// meanwhile, a second tap on the hosted page's Pay among them, would start another payment over it.
|
|
2624
|
+
const followUpOut = lifecycle.followUpsInFlight();
|
|
2625
|
+
if (terminal || lifecycle.isBlocked() || awaitingApproval || followUpOut || preparedRetry || Date.now() < quietUntil) {
|
|
2602
2626
|
let repeatedAuthorizationId = null;
|
|
2603
2627
|
if (lastSubmitted) {
|
|
2604
2628
|
const body = pausedBody(request);
|
|
@@ -2607,12 +2631,12 @@ export async function attachToCdp(cdp, pageSessionId, opts) {
|
|
|
2607
2631
|
}
|
|
2608
2632
|
}
|
|
2609
2633
|
const why = terminal ?? (lifecycle.isBlocked() ? lifecycle.getState().status : awaitingApproval ? 'an approval is already outstanding'
|
|
2610
|
-
: preparedRetry ? 'CheckoutPreparationError' : 'awaiting approval cooldown');
|
|
2634
|
+
: followUpOut ? 'an EBANX send is in flight' : preparedRetry ? 'CheckoutPreparationError' : 'awaiting approval cooldown');
|
|
2611
2635
|
opts.onEvent?.({ type: 'blocked', detail: why instanceof Error ? failureSummary(why) : String(why) });
|
|
2612
2636
|
if (preparation)
|
|
2613
2637
|
preparationGate.retireUnboundClaim();
|
|
2614
2638
|
// A card form navigation never reads that nothing was sent while a payment for this checkout may exist.
|
|
2615
|
-
await refusePaused(requestId, sessionId, request.url, cardEndpoint, heldNavigationRefusal(terminal, awaitingApproval, lifecycle), secureAcceptance);
|
|
2639
|
+
await refusePaused(requestId, sessionId, request.url, cardEndpoint, heldNavigationRefusal(terminal, awaitingApproval || followUpOut, lifecycle), secureAcceptance);
|
|
2616
2640
|
if (repeatedAuthorizationId)
|
|
2617
2641
|
void opts.vault.reportDuplicateGuard?.(repeatedAuthorizationId);
|
|
2618
2642
|
return;
|
|
@@ -2641,6 +2665,8 @@ export async function attachToCdp(cdp, pageSessionId, opts) {
|
|
|
2641
2665
|
// The approval the device gave, and whether it reached a browser request.
|
|
2642
2666
|
let approvedId = null;
|
|
2643
2667
|
let deliveryBegun = false;
|
|
2668
|
+
// Whether this handoff kept an EBANX approval's follow-ups (ebanxFollowUps.remember), which a failed handoff stops.
|
|
2669
|
+
let ebanxRemembered = false;
|
|
2644
2670
|
// The business's pause, so resume resolves once the page has its answer.
|
|
2645
2671
|
let businessPause = null;
|
|
2646
2672
|
// A prepared Amadeus SDK add must be sent within its window (see amadeus.ts).
|
|
@@ -2920,6 +2946,14 @@ export async function attachToCdp(cdp, pageSessionId, opts) {
|
|
|
2920
2946
|
catch {
|
|
2921
2947
|
throw new PaymentOutcomeUnknownError(replay.authorizationId, 'paddle_vgs_card_facts_unavailable');
|
|
2922
2948
|
}
|
|
2949
|
+
// An approved EBANX token request whose read names a window covers the 3-D Secure calls and the confirm the
|
|
2950
|
+
// page sends next (ebanx.ts): kept as the API stored it, the request that raised the approval. Kept before the
|
|
2951
|
+
// page has the answer, since the page may send its first 3-D Secure call the moment the answer lands; a
|
|
2952
|
+
// handoff that then fails stops them (the catch below).
|
|
2953
|
+
if (replay.mode !== 'device_encrypt') {
|
|
2954
|
+
ebanxFollowUps.remember({ url: request.url, body }, replay);
|
|
2955
|
+
ebanxRemembered = true;
|
|
2956
|
+
}
|
|
2923
2957
|
await cdp.send('Fetch.fulfillRequest', {
|
|
2924
2958
|
requestId: deliverTo,
|
|
2925
2959
|
responseCode: replay.status,
|
|
@@ -2945,6 +2979,10 @@ export async function attachToCdp(cdp, pageSessionId, opts) {
|
|
|
2945
2979
|
catch (err) {
|
|
2946
2980
|
// Ignore the failure event caused by our own safe decline/error abort.
|
|
2947
2981
|
const dead = attempt.target ?? { requestId, sessionId };
|
|
2982
|
+
// An EBANX token answer this handoff kept follow-ups for and did not finish handing over: nothing after it is
|
|
2983
|
+
// claimed (ebanx.ts EbanxFollowUps.stop).
|
|
2984
|
+
if (ebanxRemembered)
|
|
2985
|
+
ebanxFollowUps.stop();
|
|
2948
2986
|
// The business's resume settles once the request is answered: a terminal read is an answer (failed, nothing charged), a lost handoff is not.
|
|
2949
2987
|
const settlePause = () => { if (businessPause) {
|
|
2950
2988
|
if (isApprovalOutcome(err))
|
|
@@ -3089,6 +3127,8 @@ export async function attachToPlaywright(page, opts) {
|
|
|
3089
3127
|
};
|
|
3090
3128
|
// Juspay's tokenize answer and the synthetic tokens it issued (juspay-gate.ts).
|
|
3091
3129
|
const juspayCheckout = new JuspayCheckoutGate(opts.vault);
|
|
3130
|
+
// The approved EBANX token request on this attachment and the sends claimed under it (ebanx.ts).
|
|
3131
|
+
const ebanxFollowUps = new EbanxFollowUps();
|
|
3092
3132
|
const aci = new AciGate(opts.vault);
|
|
3093
3133
|
let navigationBodyReplaced;
|
|
3094
3134
|
const eprotect = new EprotectGate(opts.vault);
|
|
@@ -3407,12 +3447,23 @@ export async function attachToPlaywright(page, opts) {
|
|
|
3407
3447
|
// Every request to an NMI host whose entry is served (ekashu.ts), as attachToCdp arms the
|
|
3408
3448
|
// host: the card page's post and its 3-D Secure calls reach the NMI gate and fail.
|
|
3409
3449
|
|| isArmedEkashuUrl(opts.vault, url.toString())
|
|
3450
|
+
// A CreditGuard page's own calls beside its submit (its card lookup and its 3-D Secure calls), for an
|
|
3451
|
+
// org the API served CreditGuard to, as attachToCdp arms its hosts: the CreditGuard gate answers them
|
|
3452
|
+
// under a ready preparation and lets them go on with none (pre-claim.ts isArmedCreditguardCall).
|
|
3453
|
+
|| isArmedCreditguardCall(opts.vault, url.toString())
|
|
3454
|
+
// Every request to a Redsys host once its entry is served (redsys.ts), as attachToCdp arms the
|
|
3455
|
+
// hosts: the card page's post and Redsys's other card requests reach the Redsys gate and fail.
|
|
3456
|
+
|| isArmedRedsysUrl(opts.vault, url.toString())
|
|
3410
3457
|
// PayPal's legacy Hosted Fields confirm, for every org, as attachToCdp arms it (paypal-hosted-fields.ts).
|
|
3411
3458
|
|| isPaypalHostedFieldsConfirm(url.toString())
|
|
3459
|
+
// PayPal's Card Fields confirm and GraphQL on www.paypal.com, for every org, as attachToCdp arms them (paypal-card-forms.ts).
|
|
3460
|
+
|| isPaypalCardFormUrl(url.toString())
|
|
3412
3461
|
// CyberSource Secure Acceptance's /silent/ paths, for every org, as attachToCdp arms them (cybersource-secure-acceptance.ts).
|
|
3413
3462
|
|| isCybersourceSecureAcceptanceUrl(url.toString())
|
|
3414
3463
|
// Paddle's checkout services, routed only for an org the API served Paddle VGS to (see attachToCdp).
|
|
3415
|
-
|| (isPaddleCheckoutService(url.toString()) && recognizesPaddleVgs(opts.vault))
|
|
3464
|
+
|| (isPaddleCheckoutService(url.toString()) && recognizesPaddleVgs(opts.vault))
|
|
3465
|
+
// EBANX's 3-D Secure calls and hosted confirm, for every org, as attachToCdp arms them (ebanx.ts).
|
|
3466
|
+
|| isEbanxResendUrl(url.toString()), async (route) => {
|
|
3416
3467
|
const request = route.request();
|
|
3417
3468
|
// When this request paused, and the page it came from: the merchant's total is read as of now.
|
|
3418
3469
|
const pausedAt = Date.now();
|
|
@@ -3505,6 +3556,7 @@ export async function attachToPlaywright(page, opts) {
|
|
|
3505
3556
|
} },
|
|
3506
3557
|
juspay: juspayCheckout,
|
|
3507
3558
|
datatrans: datatransRepeats,
|
|
3559
|
+
ebanx: ebanxFollowUps,
|
|
3508
3560
|
frame: frameOf(request),
|
|
3509
3561
|
payrails,
|
|
3510
3562
|
shijiSts: { companions: shijiCompanions, page: async () => (await playwrightShijiDocumentPage(request)) ?? `pw:none:${++playwrightShijiSeq}` },
|
|
@@ -3599,7 +3651,9 @@ export async function attachToPlaywright(page, opts) {
|
|
|
3599
3651
|
// identically whichever adapter is attached. An Amadeus card request is
|
|
3600
3652
|
// 'failed' (ERR_FAILED) in both too, see failsAsNetworkError (refusalFailure).
|
|
3601
3653
|
// As in attachToCdp: an unbound request that skipped the spent preparation's claim is refused.
|
|
3602
|
-
|
|
3654
|
+
// As in attachToCdp: an EBANX send still out holds the attachment too.
|
|
3655
|
+
const followUpOut = lifecycle.followUpsInFlight();
|
|
3656
|
+
if (terminal || lifecycle.isBlocked() || awaitingApproval || followUpOut || preparedRetry || Date.now() < quietUntil) {
|
|
3603
3657
|
let repeatedAuthorizationId = null;
|
|
3604
3658
|
if (lastSubmitted) {
|
|
3605
3659
|
let body = null;
|
|
@@ -3612,12 +3666,12 @@ export async function attachToPlaywright(page, opts) {
|
|
|
3612
3666
|
}
|
|
3613
3667
|
}
|
|
3614
3668
|
const why = terminal ?? (lifecycle.isBlocked() ? lifecycle.getState().status : awaitingApproval ? 'an approval is already outstanding'
|
|
3615
|
-
: preparedRetry ? 'CheckoutPreparationError' : 'awaiting approval cooldown');
|
|
3669
|
+
: followUpOut ? 'an EBANX send is in flight' : preparedRetry ? 'CheckoutPreparationError' : 'awaiting approval cooldown');
|
|
3616
3670
|
opts.onEvent?.({ type: 'blocked', detail: why instanceof Error ? failureSummary(why) : String(why) });
|
|
3617
3671
|
if (preparation)
|
|
3618
3672
|
preparationGate.retireUnboundClaim();
|
|
3619
3673
|
// As in attachToCdp: never that nothing was sent while a payment for this checkout may exist.
|
|
3620
|
-
const refused = await refuseRoute(route, heldNavigationRefusal(terminal, awaitingApproval, lifecycle));
|
|
3674
|
+
const refused = await refuseRoute(route, heldNavigationRefusal(terminal, awaitingApproval || followUpOut, lifecycle));
|
|
3621
3675
|
if (repeatedAuthorizationId)
|
|
3622
3676
|
void opts.vault.reportDuplicateGuard?.(repeatedAuthorizationId);
|
|
3623
3677
|
return refused;
|
|
@@ -3665,6 +3719,8 @@ export async function attachToPlaywright(page, opts) {
|
|
|
3665
3719
|
// The approval the device gave, and whether it reached a browser request.
|
|
3666
3720
|
let approvedId = null;
|
|
3667
3721
|
let deliveryBegun = false;
|
|
3722
|
+
// See the same flag in attachToCdp.
|
|
3723
|
+
let ebanxRemembered = false;
|
|
3668
3724
|
// A prepared Amadeus SDK add must be sent within its window (see amadeus.ts).
|
|
3669
3725
|
let disarmSendWindow = null;
|
|
3670
3726
|
try {
|
|
@@ -3879,6 +3935,11 @@ export async function attachToPlaywright(page, opts) {
|
|
|
3879
3935
|
catch {
|
|
3880
3936
|
throw new PaymentOutcomeUnknownError(replay.authorizationId, 'paddle_vgs_card_facts_unavailable');
|
|
3881
3937
|
}
|
|
3938
|
+
// See the same step in attachToCdp: kept before the page has the answer.
|
|
3939
|
+
if (replay.mode !== 'device_encrypt') {
|
|
3940
|
+
ebanxFollowUps.remember({ url: request.url(), body }, replay);
|
|
3941
|
+
ebanxRemembered = true;
|
|
3942
|
+
}
|
|
3882
3943
|
await deliverTo.fulfill({ status: replay.status, headers: withCorsHeaders(replay.headers, cors.headers), body: replay.body });
|
|
3883
3944
|
datatransRepeats.remember(frameOf(deliverRequest), deliverRequest.url(), deliverBody, replay);
|
|
3884
3945
|
assertRequestLive();
|
|
@@ -3894,6 +3955,9 @@ export async function attachToPlaywright(page, opts) {
|
|
|
3894
3955
|
}
|
|
3895
3956
|
catch (err) {
|
|
3896
3957
|
const dead = attempt.target?.route ?? route;
|
|
3958
|
+
// See the same step in attachToCdp.
|
|
3959
|
+
if (ebanxRemembered)
|
|
3960
|
+
ebanxFollowUps.stop();
|
|
3897
3961
|
if (activeRequest?.attempt === attempt)
|
|
3898
3962
|
activeRequest = null;
|
|
3899
3963
|
try {
|
package/dist/client.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { type MerchantTotalApproved, type MerchantTotalCapture } from './merchan
|
|
|
5
5
|
import { type PreparationMode, type PreparationProcessor } from './prepared-processor.js';
|
|
6
6
|
import { type VerifoneProfile, type VerifoneSubstitutions } from './verifone.js';
|
|
7
7
|
import { type MerchantSessionCapture } from './merchant-session-probe.js';
|
|
8
|
+
import { type PaddleTokenexServedFacts } from './paddle-tokenex.js';
|
|
8
9
|
import { VoiceModule, type VoiceOptions } from './voice.js';
|
|
9
10
|
import { BuyModule } from './buy.js';
|
|
10
11
|
import { RequestRegistry } from './requests.js';
|
|
@@ -205,6 +206,11 @@ export declare const SUPPORTED_REGISTRY_FEATURES: readonly string[];
|
|
|
205
206
|
* Moneris on for. A gated recognizer never sits in BUILTIN_REGISTRY, so it is paused
|
|
206
207
|
* only after a sync.
|
|
207
208
|
*
|
|
209
|
+
* `redsys_hosted_payment_page`: Redsys's hosted payment page (the TPV Virtual redirect), whose
|
|
210
|
+
* card-free signed entry this build pauses for the cardholder's device and whose card page this build
|
|
211
|
+
* never lets the agent's browser post to (pre-claim.ts, redsys.ts). Served on the same terms as NMI's: only
|
|
212
|
+
* to a build that lists it, for a company Agentcard turned Redsys on for.
|
|
213
|
+
*
|
|
208
214
|
* `paddle_vgs_cards`: the card request Paddle's checkout frame sends to its VGS card
|
|
209
215
|
* vault (vault.paddle.com/cards) on a checkout that names VGS, only through a prepared
|
|
210
216
|
* checkout: the frame aborts the request 10 seconds after Pay and sends it once more,
|
|
@@ -212,6 +218,37 @@ export declare const SUPPORTED_REGISTRY_FEATURES: readonly string[];
|
|
|
212
218
|
* device sends the card itself and the frame gets back the stored card's id alone.
|
|
213
219
|
* Served on the same terms: only to a build that lists it, for a company Agentcard
|
|
214
220
|
* turned Paddle on for.
|
|
221
|
+
*
|
|
222
|
+
* `paddle_tokenex_pay`: the /pay Paddle's checkout frame sends to its checkout service
|
|
223
|
+
* (checkout-service.paddle.com) on a checkout that names TokenEx. The frame encrypts the
|
|
224
|
+
* card in the page under the account's TokenEx key, so /pay carries the placeholder's two
|
|
225
|
+
* ciphertexts and facts; this build pauses it and writes over them the device's own, under
|
|
226
|
+
* the key payment-core pins (paddle-tokenex.ts). Served on the same terms: only to a build
|
|
227
|
+
* that lists it, for a company Agentcard turned Paddle on for.
|
|
228
|
+
*
|
|
229
|
+
* `lyra_krypton_payment`: the card payment Lyra's Krypton form (PayZen, Systempay,
|
|
230
|
+
* Sogecommerce) sends from its hidden checkout frame to ProcessPayment/2 on the brand's API
|
|
231
|
+
* host. This build pauses only the frame's card body under a form token that pays once; the
|
|
232
|
+
* cardholder's device sends the card through the checkout relay, and the frame gets Lyra's
|
|
233
|
+
* answer byte for byte with Lyra's payment id, so it runs any 3-D Secure step itself and its
|
|
234
|
+
* card-free follow-up passes untouched. Served on the same terms: only to a build that lists
|
|
235
|
+
* it, for a company Agentcard turned Lyra on for.
|
|
236
|
+
*
|
|
237
|
+
* `payfast_card_pay`: the card tab's pay on Payfast's hosted payment page (POST
|
|
238
|
+
* /eng/method/CreditCard/<uuid>/pay on payment.payfast.io, www.payfast.co.za or the sandbox),
|
|
239
|
+
* which this build pauses only as the card tab's own form body and answers with Payfast's own
|
|
240
|
+
* answer as the API recorded it: `[true]` once the payment is done, or the 3-D Secure step the
|
|
241
|
+
* card tab then runs in the agent's browser. The cardholder's device sends the card through the
|
|
242
|
+
* checkout relay. Served on the same terms: only to a build that lists it, for a company
|
|
243
|
+
* Agentcard turned Payfast on for.
|
|
244
|
+
*
|
|
245
|
+
* `wix_payments_tokenize`: the card request Wix Cashier's card frame sends to Wix's
|
|
246
|
+
* tokenizer (cashier-pci.wixapps.net), only through a prepared checkout: Wix's payment
|
|
247
|
+
* widget fails the payment 30 seconds after it asks the frame for a token. The
|
|
248
|
+
* cardholder's device sends the card through the checkout relay and the frame gets back
|
|
249
|
+
* Wix's token. A second card request from the frame, which Wix's frame sends after a 401
|
|
250
|
+
* or 403 under a fresh instance, is never answered from the same approval. Served on the
|
|
251
|
+
* same terms: only to a build that lists it, for a company Agentcard turned Wix on for.
|
|
215
252
|
*/
|
|
216
253
|
export declare const SUPPORTED_CAPABILITIES: readonly string[];
|
|
217
254
|
/**
|
|
@@ -289,6 +326,12 @@ export interface TokenReplay extends ExecutionMetadata {
|
|
|
289
326
|
chargedKind?: 'captured' | 'authorized' | 'none' | null;
|
|
290
327
|
/** Who named the amount the person approved. */
|
|
291
328
|
amountAuthority?: AmountAuthority;
|
|
329
|
+
/**
|
|
330
|
+
* An EBANX token approval that covers the sends EBANX's page makes after it (its 3-D Secure calls and the hosted
|
|
331
|
+
* page's confirm), for a company Agentcard turned that on for: until when (ISO 8601) the adapters may ask the
|
|
332
|
+
* cardholder's device to send them (sendEbanxFollowUp). Absent on every other approval.
|
|
333
|
+
*/
|
|
334
|
+
followUpsUntil?: string;
|
|
292
335
|
}
|
|
293
336
|
/**
|
|
294
337
|
* The cse flow (Adyen): the cardholder's device encrypted the card under the
|
|
@@ -316,6 +359,13 @@ export interface CseReplay extends ExecutionMetadata {
|
|
|
316
359
|
shijiStsCompanion?: Readonly<{
|
|
317
360
|
keySequenceSha256: readonly string[];
|
|
318
361
|
}>;
|
|
362
|
+
/**
|
|
363
|
+
* Paddle TokenEx only: the five metadata facts the device read from the real card, served beside the two
|
|
364
|
+
* ciphertexts in `substitutions.fields` (`paddle_tokenex_facts`). The adapters write them over the
|
|
365
|
+
* placeholder's at metadata while the ciphertexts go into tokenex_card (paddle-tokenex.ts), because the
|
|
366
|
+
* expiry parts are numbers and cannot ride the string-only `fields`.
|
|
367
|
+
*/
|
|
368
|
+
paddleTokenexFacts?: Readonly<PaddleTokenexServedFacts>;
|
|
319
369
|
amountAuthority?: AmountAuthority;
|
|
320
370
|
}
|
|
321
371
|
/**
|
|
@@ -488,7 +538,12 @@ export interface PrepareCheckoutOptions {
|
|
|
488
538
|
* it to the merchant (https://pps.creditguard.co.il/?txId=<transaction id>;
|
|
489
539
|
* pps2 is production too, ppsuat is the sandbox). Agentcard reads that
|
|
490
540
|
* transaction from CreditGuard before the cardholder is asked, and only that
|
|
491
|
-
* transaction's card submit can use the preparation.
|
|
541
|
+
* transaction's card submit can use the preparation. On a transaction that runs
|
|
542
|
+
* 3-D Secure through Cardinal, this SDK answers the page's own 3-D Secure calls
|
|
543
|
+
* and card lookup itself, so the placeholder never reaches CreditGuard, and the
|
|
544
|
+
* cardholder's device runs 3-D Secure with the real card before it sends the
|
|
545
|
+
* submit: prepare() tells Agentcard so (`three_d_secure: 'device'`), and
|
|
546
|
+
* Agentcard admits such a transaction only for a build that says it.
|
|
492
547
|
*/
|
|
493
548
|
paymentPageUrl?: string;
|
|
494
549
|
/**
|
|
@@ -1045,6 +1100,14 @@ export interface PresetRefusal {
|
|
|
1045
1100
|
}
|
|
1046
1101
|
/** A decline reason only the company presets stamp (see PresetRefusedError). */
|
|
1047
1102
|
export declare const PRESET_REFUSAL_REASONS: ReadonlySet<string>;
|
|
1103
|
+
/**
|
|
1104
|
+
* How often sendEbanxFollowUp reads a send back while the cardholder's device has it: every half second, whatever the
|
|
1105
|
+
* client's own `pollIntervalMs`. One send is out at a time per approval, so this is 120 reads a minute, inside the
|
|
1106
|
+
* API's 240 a minute per caller and authorization (routes/api/v2/checkout-follow-ups.ts).
|
|
1107
|
+
*/
|
|
1108
|
+
export declare const EBANX_FOLLOW_UP_READ_MS = 500;
|
|
1109
|
+
/** The longest sendEbanxFollowUp waits after reads the API refused as too many (429): 1, 2, 4, 8, then 15 seconds. */
|
|
1110
|
+
export declare const EBANX_FOLLOW_UP_BACKOFF_MAX_MS = 15000;
|
|
1048
1111
|
export declare class CheckoutApiError extends Error {
|
|
1049
1112
|
status: number;
|
|
1050
1113
|
path: string;
|
|
@@ -1104,6 +1167,13 @@ export declare class CheckoutAuthError extends Error {
|
|
|
1104
1167
|
* On Rapyd's hosts the hosted page's id reads `{token}`: https://api.rapyd.net/v1/checkout/{token}.
|
|
1105
1168
|
* On api.stripe.com a Checkout Session id reads `{session}`:
|
|
1106
1169
|
* https://api.stripe.com/v1/payment_pages/{session}/confirm.
|
|
1170
|
+
* On Payfast's hosts the payment's uuid reads `{uuid}`:
|
|
1171
|
+
* https://payment.payfast.io/eng/method/CreditCard/{uuid}/pay.
|
|
1172
|
+
* On Redsys's hosts the session id after `;jsessionid=` reads `{session}`:
|
|
1173
|
+
* https://sis.redsys.es/sis/pagoTarjeta;jsessionid={session}.
|
|
1174
|
+
* On Lyra's API hosts the form token's session id reads `{session}`.
|
|
1175
|
+
* On PayPal's hosts an order id reads `{order}`:
|
|
1176
|
+
* https://www.paypal.com/v2/checkout/orders/{order}/confirm-payment-source.
|
|
1107
1177
|
* A string that is not a URL keeps the part before any `?` or `#`, with the
|
|
1108
1178
|
* same segments masked.
|
|
1109
1179
|
*/
|
|
@@ -1460,6 +1530,32 @@ export declare class VaultClient {
|
|
|
1460
1530
|
}): Promise<{
|
|
1461
1531
|
setupIntentId: string;
|
|
1462
1532
|
}>;
|
|
1533
|
+
/**
|
|
1534
|
+
* Send one request an approved EBANX token request covers (ebanx.ts says which: EBANX's 3-D Secure calls and the
|
|
1535
|
+
* hosted page's confirm, bound to that approval) from the cardholder's device, and resolve with EBANX's answer for
|
|
1536
|
+
* the paused request: POST /v2/checkout/authorizations/:id/follow_ups with the request as the page sent it, the
|
|
1537
|
+
* agent's placeholder card in it, then the send read back every half second until the device answered
|
|
1538
|
+
* (EBANX_FOLLOW_UP_READ_MS, whatever `pollIntervalMs` says, so the reads stay inside the API's per-approval budget).
|
|
1539
|
+
* A read the API refuses as too many (429) waits longer each time, doubling from a second up to
|
|
1540
|
+
* EBANX_FOLLOW_UP_BACKOFF_MAX_MS, inside the same deadline, and the next answered read goes back to the half second.
|
|
1541
|
+
* No prompt: the cardholder approved the token request, and the Vault page that sent it sends these while it stays
|
|
1542
|
+
* open. Rejects with an EbanxFollowUpError naming why there is no answer and whether the card may have reached
|
|
1543
|
+
* EBANX: the API refused the send (nothing sent), no device started it in time, the device refused it or withheld
|
|
1544
|
+
* an answer that carried the card, or `options.until` (the approval's window, plus the API's own clocks) passed.
|
|
1545
|
+
*/
|
|
1546
|
+
sendEbanxFollowUp(authorizationId: string, request: {
|
|
1547
|
+
url: string;
|
|
1548
|
+
method: 'POST';
|
|
1549
|
+
headers: Record<string, string>;
|
|
1550
|
+
body: string;
|
|
1551
|
+
}, options?: {
|
|
1552
|
+
signal?: AbortSignal;
|
|
1553
|
+
until?: number;
|
|
1554
|
+
}): Promise<{
|
|
1555
|
+
status: number;
|
|
1556
|
+
headers: Record<string, string>;
|
|
1557
|
+
body: string;
|
|
1558
|
+
}>;
|
|
1463
1559
|
/**
|
|
1464
1560
|
* Create a merchant-session probe, the phase-0 read of the deterministic merchant total:
|
|
1465
1561
|
* `user` is the org's connected user, who opens the returned Vault link and reads the
|