@agent-cards/sdk 0.23.21 → 0.23.23
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 +36 -0
- package/PREFLIGHT.md +4 -0
- package/README.md +53 -4
- package/dist/aci.generated.js +3 -3
- package/dist/agent-amount.generated.d.ts +7 -0
- package/dist/agent-amount.generated.js +3 -0
- package/dist/amadeus-checkout.generated.d.ts +6 -1
- package/dist/amadeus-checkout.generated.js +26 -2
- package/dist/capabilities.generated.d.ts +2 -0
- package/dist/capabilities.generated.js +3 -0
- package/dist/card-fields.generated.js +2574 -186
- package/dist/cdp.js +103 -29
- package/dist/client.d.ts +130 -9
- package/dist/client.js +304 -115
- 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/hosted-entry.js +2 -1
- package/dist/hosted-form.d.ts +5 -0
- package/dist/hosted-form.js +5 -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/paytrail.d.ts +58 -0
- package/dist/paytrail.js +98 -0
- package/dist/pre-claim.d.ts +27 -0
- package/dist/pre-claim.js +175 -20
- package/dist/prepared-processor.d.ts +7 -2
- package/dist/prepared-processor.js +16 -2
- package/dist/primer.generated.js +2709 -321
- package/dist/registry.d.ts +4 -3
- package/dist/registry.js +12 -4
- package/dist/sbps.d.ts +57 -0
- package/dist/sbps.generated.d.ts +96 -0
- package/dist/sbps.generated.js +427 -0
- package/dist/sbps.js +90 -0
- package/dist/stripe-checkout.generated.js +744 -27
- 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/dist/transbank.d.ts +33 -0
- package/dist/transbank.js +62 -0
- package/dist/url-mask-parts.d.ts +24 -0
- package/dist/url-mask-parts.js +22 -0
- package/dist/url-masks.generated.d.ts +3 -0
- package/dist/url-masks.generated.js +2 -0
- package/package.json +4 -4
package/dist/pre-claim.js
CHANGED
|
@@ -80,12 +80,14 @@ import { cardEndpointCarriesCard, cardEndpointDetail, cardEndpointFor, cardEndpo
|
|
|
80
80
|
import { cardEndpointStoppedPage, refusedNavigationOutcome } from './card-endpoint-page.js';
|
|
81
81
|
import { PAYRAILS_HOLDING_REASONS, PAYRAILS_SESSION_MESSAGE, isPayrailsHost, isPayrailsPaymentUrl, isPayrailsStaticHost, payrailsKeyRefusal, payrailsPaymentRefusal, payrailsRequestKind, payrailsSaveRefusal, } from './payrails.js';
|
|
82
82
|
import { classifyVerifoneProfileRequest, verifoneTemplatedUrl } from './verifone.js';
|
|
83
|
+
import { isPaymentHighwayCardLookup, isPaymentHighwayHost, isPaytrailCardMethodUrl, isPaytrailEntry, isPaytrailServed } from './paytrail.js';
|
|
83
84
|
import { ekashuEntryUrl, isEkashuEntry, isEkashuHost } from './ekashu.js';
|
|
84
85
|
import { isArmedTransbankUrl } from './transbank.js';
|
|
85
86
|
import { isRedsysEntry, isRedsysHost, redsysEntryUrl } from './redsys.js';
|
|
86
87
|
import { isArmedPrzelewy24Url, isPrzelewy24PayStep } from './przelewy24.js';
|
|
87
88
|
import { isQuickpayCardLookup, isQuickpayEntry, quickpayEntryUrl } from './quickpay.js';
|
|
88
89
|
import { isArmedComgateUrl } from './comgate.js';
|
|
90
|
+
import { isArmedEximbayUrl, isEximbayEntry } from './eximbay.js';
|
|
89
91
|
import { PAYPAL_HOSTED_FIELDS_REASON, isPaypalHostedFieldsConfirm, paypalHostedFieldsBody } from './paypal-hosted-fields.js';
|
|
90
92
|
import { PAYPAL_CARD_FIELDS_REASON, PAYPAL_GUEST_CHECKOUT_REASON, isPaypalCardFieldsConfirm, isPaypalGraphql, paypalCardFieldsBody, paypalGraphqlCard, paypalGraphqlNamesCardOperation, } from './paypal-card-forms.js';
|
|
91
93
|
import { CYBERSOURCE_SECURE_ACCEPTANCE_REASON, CYBERSOURCE_SECURE_ACCEPTANCE_RECIPIENT, cybersourceSecureAcceptanceRequest, isCybersourceSecureAcceptanceUrl, isSecureAcceptanceFramePost, } from './cybersource-secure-acceptance.js';
|
|
@@ -93,6 +95,7 @@ import { isWorldlineMyCheckoutEndpoint } from './worldline-mycheckout.js';
|
|
|
93
95
|
import { paddleVgsPayEventUrl } from './paddle-vgs-pay.js';
|
|
94
96
|
import { HIPAY_PSP, HIPAY_TOKEN_URLS, HIPAY_UPDATE_PATH, HIPAY_VAULT_HOSTS, hipayNumberOnlyRequest } from './hipay.generated.js';
|
|
95
97
|
import { EBANX_RESEND_REASON, EbanxFollowUpError, ebanxResendRefusalOf, isEbanxResendUrl, } from './ebanx.js';
|
|
98
|
+
import { PAYREXX_RESEND_REASON, PayrexxFollowUpError, isPayrexxResend, } from './payrexx.js';
|
|
96
99
|
/**
|
|
97
100
|
* The URL an event may name for a request. For an armed merchant profile's
|
|
98
101
|
* endpoint or a sibling of it: the endpoint origin, the path TEMPLATE and the
|
|
@@ -1507,6 +1510,23 @@ const eprotectPreClaim = (ctx) => {
|
|
|
1507
1510
|
return eprotectFailoverAbort(ctx);
|
|
1508
1511
|
return unsupportedAbort(ctx);
|
|
1509
1512
|
};
|
|
1513
|
+
// SB Payment Service, once the registry serves it (a synced build that declares its capability, for
|
|
1514
|
+
// an org the API enabled); for every other client the gate defers on everything, so nothing changes.
|
|
1515
|
+
// On SBPS's token hosts:
|
|
1516
|
+
// - the token request GET the recognizer admits defers to the arbiter, which pauses it for the vault
|
|
1517
|
+
// claim flow; one the registry does not cover aborts as unsupported instead of reaching SBPS;
|
|
1518
|
+
// - any other request on /token/generateToken (another method, query or spelling) aborts as an
|
|
1519
|
+
// unsupported checkout, so the placeholder's ciphertext never leaves;
|
|
1520
|
+
// - everything else there (the scripts, the 3-D Secure info request) continues.
|
|
1521
|
+
// Synchronous for a token request, so it pauses in the microtask it paused in.
|
|
1522
|
+
const sbpsPreClaim = (ctx) => {
|
|
1523
|
+
const request = ctx.sbps?.classify(ctx.request.url, ctx.request.method);
|
|
1524
|
+
if (!request || request.kind === 'sibling')
|
|
1525
|
+
return undefined;
|
|
1526
|
+
if (request.kind === 'token_request')
|
|
1527
|
+
return ctx.vault.isCardRequest(ctx.request.url, ctx.request.method) ? undefined : unsupportedAbort(ctx);
|
|
1528
|
+
return unsupportedAbort(ctx);
|
|
1529
|
+
};
|
|
1510
1530
|
async function eprotectFailoverAbort(ctx) {
|
|
1511
1531
|
ctx.onEvent?.({ type: 'blocked', detail: 'eprotect_failover_aborted' });
|
|
1512
1532
|
await ctx.effects.abort();
|
|
@@ -1667,7 +1687,7 @@ export const ekashuPreClaim = (ctx) => {
|
|
|
1667
1687
|
return processorPageAbort(ctx);
|
|
1668
1688
|
};
|
|
1669
1689
|
// The stop for a card post into a processor's own page that only the cardholder's device may pay (NMI's, Redsys's,
|
|
1670
|
-
// QuickPay's).
|
|
1690
|
+
// QuickPay's, Eximbay's).
|
|
1671
1691
|
async function processorPageAbort(ctx) {
|
|
1672
1692
|
const { url, method } = ctx.request;
|
|
1673
1693
|
ctx.preparationGate.invalidate('unsupported_checkout');
|
|
@@ -1697,6 +1717,32 @@ export const transbankPreClaim = (ctx) => {
|
|
|
1697
1717
|
return undefined;
|
|
1698
1718
|
return processorPageAbort(ctx);
|
|
1699
1719
|
};
|
|
1720
|
+
// Paytrail's card method (paytrail.ts). Once this build's registry serves Paytrail's entry (a capability the API serves
|
|
1721
|
+
// only to a company Agentcard turned Paytrail on for), every request to Paytrail's entry host and to Payment Highway's
|
|
1722
|
+
// card page host pauses, and this gate judges the card method's posts and the card page's card lookup:
|
|
1723
|
+
// - the merchant's entry (the card method's loading-and-redirect route for one transaction, exactly) defers, and the
|
|
1724
|
+
// terminal arbiter pauses it for the claim flow like any card request: the cardholder's device pays it;
|
|
1725
|
+
// - every other post of the card method on Paytrail's host (the loading page's post to initialize-payment, which
|
|
1726
|
+
// opens Payment Highway's card page, or the entry in another spelling) aborts as an unsupported checkout, and so do
|
|
1727
|
+
// every POST to Payment Highway (the card post, the Click to Pay posts, the 3-D Secure step, the older card form's
|
|
1728
|
+
// post) and the card page's GET that looks up the typed card's first digits, so Payment Highway never sees the card
|
|
1729
|
+
// the agent typed. The agent's browser reaches Payment Highway only when the entry was not paused (an attachment
|
|
1730
|
+
// made too late, say), and then only the cardholder's device can pay.
|
|
1731
|
+
// Any other request (another payment method's form, the card page itself, its scripts and images) is not this gate's
|
|
1732
|
+
// and continues. With Paytrail not served, the entry is no card request, the gate defers, and every request continues
|
|
1733
|
+
// as before. Synchronous until it must abort, like every gate. Exported for the gate registry's tests.
|
|
1734
|
+
export const paytrailPreClaim = (ctx) => {
|
|
1735
|
+
const { url, method } = ctx.request;
|
|
1736
|
+
const post = String(method).toUpperCase() === 'POST';
|
|
1737
|
+
const paymentHighway = isPaymentHighwayHost(url) && (post || isPaymentHighwayCardLookup(url, method));
|
|
1738
|
+
if (!paymentHighway && !(post && isPaytrailCardMethodUrl(url)))
|
|
1739
|
+
return undefined;
|
|
1740
|
+
if (!isPaytrailServed(ctx.vault))
|
|
1741
|
+
return undefined;
|
|
1742
|
+
if (isPaytrailEntry(url, method))
|
|
1743
|
+
return undefined;
|
|
1744
|
+
return processorPageAbort(ctx);
|
|
1745
|
+
};
|
|
1700
1746
|
// Redsys's hosted payment page (redsys.ts). Once this build's registry serves Redsys's entry (a
|
|
1701
1747
|
// capability the API serves only to a company Agentcard turned Redsys on for), every request to
|
|
1702
1748
|
// Redsys's hosts pauses, and this gate judges the POSTs:
|
|
@@ -1762,6 +1808,25 @@ export const comgatePreClaim = (ctx) => {
|
|
|
1762
1808
|
return undefined;
|
|
1763
1809
|
return processorPageAbort(ctx);
|
|
1764
1810
|
};
|
|
1811
|
+
// Eximbay's payment window (eximbay.ts). Once this build's registry serves Eximbay's entry on a host (a capability the
|
|
1812
|
+
// API serves only to a company Agentcard turned Eximbay on for), every request to that host pauses, and this gate
|
|
1813
|
+
// judges the POSTs:
|
|
1814
|
+
// - the merchant's entry (the entry path exactly, no query) defers, and the terminal arbiter pauses it for the claim
|
|
1815
|
+
// flow like any card request: the cardholder's device pays it;
|
|
1816
|
+
// - every other POST to Eximbay (the step that opens the window, the window's amount query and its card lookup,
|
|
1817
|
+
// which carries the typed card's first eight digits, its card post, and its close and method posts) aborts as an
|
|
1818
|
+
// unsupported checkout, so Eximbay never sees the card the agent typed. The agent's browser only reaches Eximbay's
|
|
1819
|
+
// window when the entry was not paused (an attachment made too late, say), and then only the cardholder's device
|
|
1820
|
+
// can pay.
|
|
1821
|
+
// A GET (the window's scripts and images) is not this gate's and continues. With Eximbay not served, the entry is no
|
|
1822
|
+
// card request, the gate defers, and every request continues as before. Synchronous until it must abort, like every
|
|
1823
|
+
// gate. Exported for the gate registry's tests.
|
|
1824
|
+
export const eximbayPreClaim = (ctx) => {
|
|
1825
|
+
const { url, method } = ctx.request;
|
|
1826
|
+
if (String(method).toUpperCase() !== 'POST' || !isArmedEximbayUrl(ctx.vault, url) || isEximbayEntry(url, method))
|
|
1827
|
+
return undefined;
|
|
1828
|
+
return processorPageAbort(ctx);
|
|
1829
|
+
};
|
|
1765
1830
|
// PayPal's legacy Hosted Fields (paypal-hosted-fields.ts). Its tokenization frame posts the card the
|
|
1766
1831
|
// agent typed to the Orders v2 confirm-payment-source on cors.api.paypal.com (or its sandbox), which
|
|
1767
1832
|
// no Vault mode takes over, so every company's adapters hand each POST there to this gate:
|
|
@@ -2144,7 +2209,7 @@ async function hipayRefused(ctx, reason) {
|
|
|
2144
2209
|
// again. A checkout whose token request was already approved keeps that approval's state (lifecycle.unsupported),
|
|
2145
2210
|
// and its follow-ups stop (EbanxFollowUps.stop): a later request the approval would cover is refused too, so the
|
|
2146
2211
|
// page cannot finish 3-D Secure and pay through the confirm after a refusal. A failed send stops them the same way.
|
|
2147
|
-
// A send goes on only while the checkout itself names the remembered approval (
|
|
2212
|
+
// A send goes on only while the checkout itself names the remembered approval (followUpMaySend): it awaits the
|
|
2148
2213
|
// merchant, reports the bank's challenge, or holds that approval's answer for the page (awaiting_approval while
|
|
2149
2214
|
// the token's answer is on its way, since the adapters remember the approval before they hand the answer over, or
|
|
2150
2215
|
// ready_to_submit while the approval waits for the page's retry). A new token request awaiting the person, a new
|
|
@@ -2173,38 +2238,39 @@ export const ebanxPreClaim = (ctx) => {
|
|
|
2173
2238
|
catch {
|
|
2174
2239
|
body = null;
|
|
2175
2240
|
}
|
|
2176
|
-
const claim = ctx.ebanx && typeof ctx.vault.sendEbanxFollowUp === 'function' &&
|
|
2241
|
+
const claim = ctx.ebanx && typeof ctx.vault.sendEbanxFollowUp === 'function' && followUpMaySend(ctx, ctx.ebanx)
|
|
2177
2242
|
? ctx.ebanx.claim({ url, method: 'POST', headers: ctx.request.headers ?? {}, body }) : null;
|
|
2178
2243
|
return claim ? ebanxFollowUp(ctx, claim) : ebanxResendRefused(ctx, refusal);
|
|
2179
2244
|
};
|
|
2180
2245
|
/**
|
|
2181
2246
|
* The checkout states in which a send may go on under the remembered approval, an allowlist: the checkout awaits the
|
|
2182
|
-
* merchant, the application reported the bank's challenge (requestUserAction), the
|
|
2247
|
+
* merchant, the application reported the bank's challenge (requestUserAction), the approved answer is still on its way
|
|
2183
2248
|
* to the page (awaiting_approval: the page may send its first 3-D Secure call the moment the answer lands), or the
|
|
2184
2249
|
* approval waits for the page's retry (ready_to_submit). Every other state refuses, idle and the final ones among them.
|
|
2250
|
+
* The same for EBANX's sends and Payrexx's.
|
|
2185
2251
|
*/
|
|
2186
|
-
const
|
|
2252
|
+
const FOLLOW_UP_SENDING_STATES = new Set(['awaiting_merchant', 'requires_user_action', 'awaiting_approval', 'ready_to_submit']);
|
|
2187
2253
|
/**
|
|
2188
2254
|
* Whether a send may go on: nothing aborted the checkout, no reconciliation of the merchant's order is running (one
|
|
2189
2255
|
* that resolves failed while a confirm is out would let the application start another attempt), it is in one of
|
|
2190
|
-
*
|
|
2191
|
-
* person (awaiting_approval with no approval, or another one), a new
|
|
2192
|
-
* checkout and another approval's state all refuse.
|
|
2256
|
+
* FOLLOW_UP_SENDING_STATES, and its state names the approval the attachment remembered (`followUps`, EBANX's or
|
|
2257
|
+
* Payrexx's). A new card request awaiting the person (awaiting_approval with no approval, or another one), a new
|
|
2258
|
+
* attempt after a merchant failure, a prepared checkout and another approval's state all refuse.
|
|
2193
2259
|
*/
|
|
2194
|
-
function
|
|
2195
|
-
if (ctx.lifecycleAborted() || ctx.terminal() || !
|
|
2260
|
+
function followUpMaySend(ctx, followUps) {
|
|
2261
|
+
if (ctx.lifecycleAborted() || ctx.terminal() || !followUps || ctx.lifecycle.isReconciling())
|
|
2196
2262
|
return false;
|
|
2197
|
-
const approval =
|
|
2263
|
+
const approval = followUps.authorizationId;
|
|
2198
2264
|
const state = ctx.lifecycle.getState();
|
|
2199
|
-
return approval !== null &&
|
|
2265
|
+
return approval !== null && FOLLOW_UP_SENDING_STATES.has(state.status) && state.authorizationId === approval;
|
|
2200
2266
|
}
|
|
2201
2267
|
/**
|
|
2202
2268
|
* The checkout's final merchant results: completed, failed, declined, timed out, cancelled, an unknown outcome, or an
|
|
2203
2269
|
* unsupported request. A 3-D Secure call, which charges nothing, that fails in one of them leaves that outcome alone.
|
|
2204
2270
|
*/
|
|
2205
|
-
const
|
|
2206
|
-
/** Whether the checkout already ended (
|
|
2207
|
-
const
|
|
2271
|
+
const FOLLOW_UP_FINAL_STATES = new Set(['completed', 'failed', 'declined', 'timed_out', 'cancelled', 'outcome_unknown', 'unsupported']);
|
|
2272
|
+
/** Whether the checkout already ended (FOLLOW_UP_FINAL_STATES): its state and reason stand, whatever a later 3-D Secure call does. */
|
|
2273
|
+
const followUpCheckoutEnded = (ctx) => FOLLOW_UP_FINAL_STATES.has(ctx.lifecycle.getState().status);
|
|
2208
2274
|
/**
|
|
2209
2275
|
* A confirm whose card may have reached EBANX and whose answer the page never got: only a payment the merchant
|
|
2210
2276
|
* already confirmed (completed) stands, and every other state of this approval turns unknown, since EBANX may have
|
|
@@ -2245,7 +2311,7 @@ async function ebanxUnreadable(ctx) {
|
|
|
2245
2311
|
* (CheckoutLifecycle.followUpStarted): meanwhile reconcile() and retryAfterMerchantFailure() throw, so the application
|
|
2246
2312
|
* starts no other attempt while a confirm may pay. A confirm that may have left keeps only a payment the merchant
|
|
2247
2313
|
* confirmed (completed); any other state of its approval turns unknown (ebanxConfirmUnconfirmed). Any other send keeps
|
|
2248
|
-
* a final outcome (
|
|
2314
|
+
* a final outcome (FOLLOW_UP_FINAL_STATES) with its reason.
|
|
2249
2315
|
*/
|
|
2250
2316
|
async function ebanxFollowUp(ctx, claim) {
|
|
2251
2317
|
const settle = ctx.lifecycle.followUpStarted();
|
|
@@ -2271,7 +2337,7 @@ async function sendEbanxFollowUp(ctx, claim) {
|
|
|
2271
2337
|
ctx.onEvent?.({ type: 'ebanx_follow_up_failed', detail: { ...detail, reason, cardSent } });
|
|
2272
2338
|
if (cardSent && claim.kind === 'confirm')
|
|
2273
2339
|
ebanxConfirmUnconfirmed(ctx, claim.authorizationId, 'ebanx_confirm_unconfirmed');
|
|
2274
|
-
else if (!
|
|
2340
|
+
else if (!followUpCheckoutEnded(ctx))
|
|
2275
2341
|
ctx.lifecycle.unsupported(EBANX_RESEND_REASON);
|
|
2276
2342
|
await ctx.effects.abort();
|
|
2277
2343
|
return { kind: 'abort' };
|
|
@@ -2286,7 +2352,7 @@ async function sendEbanxFollowUp(ctx, claim) {
|
|
|
2286
2352
|
ctx.onEvent?.({ type: 'ebanx_follow_up_failed', detail: { ...detail, reason: 'handoff_failed', cardSent: true } });
|
|
2287
2353
|
if (claim.kind === 'confirm')
|
|
2288
2354
|
ebanxConfirmUnconfirmed(ctx, claim.authorizationId, 'ebanx_follow_up_handoff_failed');
|
|
2289
|
-
else if (!
|
|
2355
|
+
else if (!followUpCheckoutEnded(ctx))
|
|
2290
2356
|
ctx.lifecycle.unsupported(EBANX_RESEND_REASON);
|
|
2291
2357
|
await ctx.effects.abort();
|
|
2292
2358
|
return { kind: 'abort' };
|
|
@@ -2294,6 +2360,95 @@ async function sendEbanxFollowUp(ctx, claim) {
|
|
|
2294
2360
|
ctx.onEvent?.({ type: 'ebanx_follow_up_answered', detail: { ...detail, status: answer.status } });
|
|
2295
2361
|
return { kind: 'answer' };
|
|
2296
2362
|
}
|
|
2363
|
+
// Payrexx Pay's card frame after its card request (payrexx.ts, payment-core payrexx.js). When Payrexx answers the card
|
|
2364
|
+
// request by starting 3-D Secure, the frame posts the card again to its own URL for the authentication after the ACS
|
|
2365
|
+
// method and the post-authentication after the bank's challenge. On a page this SDK is attached to that card is the
|
|
2366
|
+
// agent's placeholder, and the frame's URL is the card request's, so this gate judges each such post before the
|
|
2367
|
+
// card-request arbiter would pause it as a new card request:
|
|
2368
|
+
// - one the approved card request on this attachment covers (PayrexxFollowUps.claim) goes to the cardholder's device
|
|
2369
|
+
// under that approval (payrexxFollowUp below), and the frame receives Payrexx's answer to the real card;
|
|
2370
|
+
// - any other aborts as an unsupported checkout, reason `unsupported_payrexx_card_resend`, with no claim, create or
|
|
2371
|
+
// prompt, so Payrexx never receives the placeholder as a card, and the attachment holds. A checkout whose card
|
|
2372
|
+
// request was already approved keeps that approval's state, and its sends stop (PayrexxFollowUps.stop), as
|
|
2373
|
+
// EBANX's do. A send goes on only while the checkout itself names the remembered approval (followUpMaySend).
|
|
2374
|
+
// The card request itself, a wallet's body with no card value, a body the adapter could not read and every other
|
|
2375
|
+
// request defer: the arbiter pauses the card request for its recognizer and judges the rest (card-fields.js).
|
|
2376
|
+
// Synchronous until it must abort or send, like every gate. Exported for the gate registry's tests.
|
|
2377
|
+
export const payrexxPreClaim = (ctx) => {
|
|
2378
|
+
const { url, method } = ctx.request;
|
|
2379
|
+
if (!isPayrexxResend(url, method, () => ctx.request.body))
|
|
2380
|
+
return undefined;
|
|
2381
|
+
let body;
|
|
2382
|
+
try {
|
|
2383
|
+
body = ctx.request.body;
|
|
2384
|
+
}
|
|
2385
|
+
catch {
|
|
2386
|
+
body = null;
|
|
2387
|
+
}
|
|
2388
|
+
const claim = ctx.payrexx && typeof ctx.vault.sendPayrexxFollowUp === 'function' && followUpMaySend(ctx, ctx.payrexx)
|
|
2389
|
+
? ctx.payrexx.claim({ url, method: 'POST', headers: ctx.request.headers ?? {}, body }) : null;
|
|
2390
|
+
return claim ? payrexxFollowUp(ctx, claim) : payrexxResendRefused(ctx);
|
|
2391
|
+
};
|
|
2392
|
+
async function payrexxResendRefused(ctx) {
|
|
2393
|
+
const { url, method } = ctx.request;
|
|
2394
|
+
ctx.preparationGate.invalidate('unsupported_checkout');
|
|
2395
|
+
ctx.payrexx?.stop();
|
|
2396
|
+
ctx.lifecycle.unsupported(PAYREXX_RESEND_REASON);
|
|
2397
|
+
ctx.onEvent?.({ type: 'unsupported_checkout', detail: { url: eventUrl(ctx.vault, url), method, reason: PAYREXX_RESEND_REASON, step: 'three_d_secure' } });
|
|
2398
|
+
await ctx.effects.abort();
|
|
2399
|
+
return { kind: 'abort' };
|
|
2400
|
+
}
|
|
2401
|
+
/**
|
|
2402
|
+
* A 3-D Secure send the approved card request covers: the cardholder's device sends it with the real card
|
|
2403
|
+
* (VaultClient.sendPayrexxFollowUp), and the frame receives Payrexx's answer, with no second prompt. The events name the
|
|
2404
|
+
* approval and the step, never the request, the card or Payrexx's answer. A send charges nothing: the merchant's page
|
|
2405
|
+
* charges only the token a later answer names, at its own validateForm. So a send that gets no answer, or whose answer
|
|
2406
|
+
* the frame never receives, leaves no payment behind it: the frame's request fails, the attachment holds as the
|
|
2407
|
+
* refusal above does (a final outcome keeps its state and reason), and nothing more is sent. While a send is out it
|
|
2408
|
+
* counts as work in flight (CheckoutLifecycle.followUpStarted), so the application starts no other attempt over it.
|
|
2409
|
+
*/
|
|
2410
|
+
async function payrexxFollowUp(ctx, claim) {
|
|
2411
|
+
const settle = ctx.lifecycle.followUpStarted();
|
|
2412
|
+
try {
|
|
2413
|
+
return await sendPayrexxFollowUp(ctx, claim);
|
|
2414
|
+
}
|
|
2415
|
+
finally {
|
|
2416
|
+
settle();
|
|
2417
|
+
}
|
|
2418
|
+
}
|
|
2419
|
+
async function sendPayrexxFollowUp(ctx, claim) {
|
|
2420
|
+
const detail = { authorizationId: claim.authorizationId, step: claim.kind };
|
|
2421
|
+
ctx.onEvent?.({ type: 'payrexx_follow_up_requested', detail });
|
|
2422
|
+
let answer;
|
|
2423
|
+
try {
|
|
2424
|
+
answer = await ctx.vault.sendPayrexxFollowUp(claim.authorizationId, claim.request, { signal: ctx.lifecycle.abort.signal, until: claim.until });
|
|
2425
|
+
}
|
|
2426
|
+
catch (error) {
|
|
2427
|
+
claim.settle(null);
|
|
2428
|
+
ctx.payrexx?.stop();
|
|
2429
|
+
const reason = error instanceof PayrexxFollowUpError ? error.reason : 'follow_up_unavailable';
|
|
2430
|
+
const cardSent = error instanceof PayrexxFollowUpError ? error.cardSent : true;
|
|
2431
|
+
ctx.onEvent?.({ type: 'payrexx_follow_up_failed', detail: { ...detail, reason, cardSent } });
|
|
2432
|
+
if (!followUpCheckoutEnded(ctx))
|
|
2433
|
+
ctx.lifecycle.unsupported(PAYREXX_RESEND_REASON);
|
|
2434
|
+
await ctx.effects.abort();
|
|
2435
|
+
return { kind: 'abort' };
|
|
2436
|
+
}
|
|
2437
|
+
claim.settle({ status: answer.status, text: answer.body });
|
|
2438
|
+
try {
|
|
2439
|
+
await ctx.effects.answer({ status: answer.status, headers: answer.headers, body: answer.body });
|
|
2440
|
+
}
|
|
2441
|
+
catch {
|
|
2442
|
+
ctx.payrexx?.stop();
|
|
2443
|
+
ctx.onEvent?.({ type: 'payrexx_follow_up_failed', detail: { ...detail, reason: 'handoff_failed', cardSent: true } });
|
|
2444
|
+
if (!followUpCheckoutEnded(ctx))
|
|
2445
|
+
ctx.lifecycle.unsupported(PAYREXX_RESEND_REASON);
|
|
2446
|
+
await ctx.effects.abort();
|
|
2447
|
+
return { kind: 'abort' };
|
|
2448
|
+
}
|
|
2449
|
+
ctx.onEvent?.({ type: 'payrexx_follow_up_answered', detail: { ...detail, status: answer.status } });
|
|
2450
|
+
return { kind: 'answer' };
|
|
2451
|
+
}
|
|
2297
2452
|
// The terminal arbiter, always last. A request that no gate claimed and that is
|
|
2298
2453
|
// neither a native Stripe step nor a recognized card request continues, unless
|
|
2299
2454
|
// it matches a declared payment endpoint we do not support (then it aborts as an
|
|
@@ -2327,8 +2482,8 @@ async function unsupportedContinue(ctx) {
|
|
|
2327
2482
|
* arbiter runs after all of them and is not part of this list. A gate appended
|
|
2328
2483
|
* after Stripe is never offered a step Stripe claimed: Stripe answers, aborts or
|
|
2329
2484
|
* pauses each one itself. */
|
|
2330
|
-
export const PSP_PRE_CLAIM_GATES = [cardEndpointResendPreClaim, cardEndpointPreClaim, mercadoPreClaim, juspayPreClaim, braintreePreClaim, stripePreClaim, merchantHostedPreClaim, verifonePreClaim, fiservPreClaim, gmoPreClaim, cybersourceFlexPreClaim, datatransPreClaim, tokenexIframePreClaim, pelecardPreClaim, aciPreClaim, creditguardPreClaim, primerPreClaim, payrailsPreClaim, convergePreClaim, eprotectPreClaim, wspayPreClaim, shijiStsPreClaim, ekashuPreClaim, redsysPreClaim, quickpayPreClaim, comgatePreClaim, przelewy24PreClaim, transbankPreClaim, paypalHostedFieldsPreClaim,
|
|
2331
|
-
paypalCardFormsPreClaim, cybersourceSecureAcceptancePreClaim, worldlineMyCheckoutPreClaim, paddleVgsPayPreClaim, ebanxPreClaim, hipayPreClaim];
|
|
2485
|
+
export const PSP_PRE_CLAIM_GATES = [cardEndpointResendPreClaim, cardEndpointPreClaim, mercadoPreClaim, juspayPreClaim, braintreePreClaim, stripePreClaim, merchantHostedPreClaim, verifonePreClaim, fiservPreClaim, gmoPreClaim, cybersourceFlexPreClaim, datatransPreClaim, tokenexIframePreClaim, pelecardPreClaim, aciPreClaim, creditguardPreClaim, primerPreClaim, payrailsPreClaim, convergePreClaim, eprotectPreClaim, sbpsPreClaim, wspayPreClaim, shijiStsPreClaim, ekashuPreClaim, redsysPreClaim, quickpayPreClaim, comgatePreClaim, przelewy24PreClaim, transbankPreClaim, eximbayPreClaim, paypalHostedFieldsPreClaim,
|
|
2486
|
+
paypalCardFormsPreClaim, cybersourceSecureAcceptancePreClaim, worldlineMyCheckoutPreClaim, paddleVgsPayPreClaim, ebanxPreClaim, payrexxPreClaim, hipayPreClaim, paytrailPreClaim];
|
|
2332
2487
|
/** Run each gate in order; the first to return a decision wins. If none does,
|
|
2333
2488
|
* the terminal arbiter decides between continue, abort (unsupported) and pause.
|
|
2334
2489
|
* Returns synchronously while every gate defers synchronously (an ordinary card
|
|
@@ -25,11 +25,15 @@
|
|
|
25
25
|
* Cashier's card frame for a token, too soon for an approval after Pay. Its one environment is
|
|
26
26
|
* production: Wix's tokenizer has no test host.
|
|
27
27
|
*
|
|
28
|
+
* paygent: prepared only. Paygent's PaygentToken.js abandons its token request 35 seconds after the
|
|
29
|
+
* merchant's press sends it, too soon for an approval after the press. Its environments are its two token
|
|
30
|
+
* hosts: token.paygent.co.jp (production) and sandbox.paygent.co.jp (sandbox).
|
|
31
|
+
*
|
|
28
32
|
* hipay: prepared only. The merchant's page gives HiPay's hosted fields 20 seconds after Pay, too soon for an
|
|
29
33
|
* approval after Pay. Its environments are its two vault hosts: secure2-vault (production) and
|
|
30
34
|
* stage-secure2-vault (sandbox).
|
|
31
35
|
*/
|
|
32
|
-
export type PreparationProcessor = 'square' | 'braintree' | 'worldpay' | 'bambora' | 'mercado_pago' | 'recurly' | 'spreedly' | 'adyen' | 'checkout_com' | 'paysafe' | 'fiserv' | 'cybersource_flex' | 'aci' | 'creditguard' | 'worldpay_eprotect' | 'amadeus_checkout' | 'verifone' | 'cybersource_secure_acceptance' | 'paddle_vgs' | 'wix_payments' | 'hipay';
|
|
36
|
+
export type PreparationProcessor = 'square' | 'braintree' | 'worldpay' | 'bambora' | 'mercado_pago' | 'recurly' | 'spreedly' | 'adyen' | 'checkout_com' | 'paysafe' | 'fiserv' | 'cybersource_flex' | 'aci' | 'creditguard' | 'worldpay_eprotect' | 'amadeus_checkout' | 'verifone' | 'cybersource_secure_acceptance' | 'paddle_vgs' | 'wix_payments' | 'paygent' | 'hipay';
|
|
33
37
|
export type PreparationEnvironment = 'production' | 'sandbox' | 'shared';
|
|
34
38
|
/**
|
|
35
39
|
* How the approved card reaches the processor: the device's own request (token), or
|
|
@@ -66,7 +70,8 @@ export declare function preparedApprovalAnswersRetry(psp: string): boolean;
|
|
|
66
70
|
* its own signing keys. A Verifone preparation pays in the environment of the key its reviewed
|
|
67
71
|
* profile pins. CyberSource Secure Acceptance's are separate hosts too: secureacceptance is
|
|
68
72
|
* live, testsecureacceptance is test. So are Paddle VGS's two card URLs: vault is live,
|
|
69
|
-
* sandbox-vault is test. So are
|
|
73
|
+
* sandbox-vault is test. So are Paygent's two token hosts: token is live, sandbox is test. So are
|
|
74
|
+
* HiPay's two vault hosts: secure2-vault is live, stage-secure2-vault is test.
|
|
70
75
|
*/
|
|
71
76
|
export declare function validPreparationEnvironment(psp: string, environment: string): boolean;
|
|
72
77
|
/**
|
|
@@ -15,6 +15,7 @@ import { isPreparedVerifoneRequest } from './verifone.js';
|
|
|
15
15
|
import { isPreparedSecureAcceptanceRequest, secureAcceptanceEnvironment, secureAcceptancePreparationUrl, secureAcceptanceRequestRefusal, } from './cybersource-secure-acceptance.generated.js';
|
|
16
16
|
import { PADDLE_VGS_CARDS_URLS, isPreparedPaddleVgsRequest } from './paddle-vgs.generated.js';
|
|
17
17
|
import { WIX_PAYMENTS_TOKENIZE_URL, isPreparedWixPaymentsRequest } from './wix-payments.generated.js';
|
|
18
|
+
import { paygentEnvironment, paygentPreparationUrl, paygentRequestRefusal } from './paygent.generated.js';
|
|
18
19
|
import { HIPAY_TOKEN_URLS, hipayRequestRefusal, hipayTokenEnvironment, isPreparedHipayRequest } from './hipay.generated.js';
|
|
19
20
|
export function preparationMode(psp) {
|
|
20
21
|
return psp === 'adyen' || psp === 'fiserv' || psp === 'verifone' ? 'cse' : 'token';
|
|
@@ -50,7 +51,8 @@ export function preparedApprovalAnswersRetry(psp) {
|
|
|
50
51
|
* its own signing keys. A Verifone preparation pays in the environment of the key its reviewed
|
|
51
52
|
* profile pins. CyberSource Secure Acceptance's are separate hosts too: secureacceptance is
|
|
52
53
|
* live, testsecureacceptance is test. So are Paddle VGS's two card URLs: vault is live,
|
|
53
|
-
* sandbox-vault is test. So are
|
|
54
|
+
* sandbox-vault is test. So are Paygent's two token hosts: token is live, sandbox is test. So are
|
|
55
|
+
* HiPay's two vault hosts: secure2-vault is live, stage-secure2-vault is test.
|
|
54
56
|
*/
|
|
55
57
|
export function validPreparationEnvironment(psp, environment) {
|
|
56
58
|
if (psp === 'bambora' || psp === 'mercado_pago' || psp === 'recurly' || psp === 'spreedly')
|
|
@@ -59,7 +61,7 @@ export function validPreparationEnvironment(psp, environment) {
|
|
|
59
61
|
if (psp === 'wix_payments')
|
|
60
62
|
return environment === 'production';
|
|
61
63
|
return ['square', 'braintree', 'worldpay', 'adyen', 'checkout_com', 'paysafe', 'fiserv', 'cybersource_flex', 'aci', 'creditguard', 'worldpay_eprotect', 'amadeus_checkout', 'verifone',
|
|
62
|
-
'cybersource_secure_acceptance', 'paddle_vgs', 'hipay'].includes(psp) && ['production', 'sandbox'].includes(environment);
|
|
64
|
+
'cybersource_secure_acceptance', 'paddle_vgs', 'paygent', 'hipay'].includes(psp) && ['production', 'sandbox'].includes(environment);
|
|
63
65
|
}
|
|
64
66
|
/**
|
|
65
67
|
* ACI's prepared endpoint, the literal the API names (backend checkout-prepared-processor.ts): its
|
|
@@ -107,6 +109,9 @@ export function preparationEndpoint(psp, environment) {
|
|
|
107
109
|
// Wix Payments: the tokenize URL, the only URL the claim takes for it.
|
|
108
110
|
if (psp === 'wix_payments')
|
|
109
111
|
return WIX_PAYMENTS_TOKENIZE_URL;
|
|
112
|
+
// Paygent: the token URL on the environment's host, the only URL the claim takes for it.
|
|
113
|
+
if (psp === 'paygent')
|
|
114
|
+
return paygentPreparationUrl(environment);
|
|
110
115
|
// HiPay: the token create on the environment's vault, the only URL the claim takes for it.
|
|
111
116
|
if (psp === 'hipay')
|
|
112
117
|
return HIPAY_TOKEN_URLS[environment];
|
|
@@ -267,6 +272,15 @@ export function matchesPreparedRequest(psp, environment, requestUrl, method, bod
|
|
|
267
272
|
// site's app instance and the card frame's body), the rule the API and the Vault bind with too.
|
|
268
273
|
if (psp === 'wix_payments')
|
|
269
274
|
return isPreparedWixPaymentsRequest(requestUrl, method.toUpperCase(), body ?? null, environment, headers ?? {});
|
|
275
|
+
// Paygent: the environment's own token URL and payment-core's whole request rule (the script's text/plain
|
|
276
|
+
// and createToken's body byte for byte), the rule the API and the Vault bind with too. The method as the page
|
|
277
|
+
// sent it: the device sends only an uppercase POST. Which merchant_id and token key a live request may name
|
|
278
|
+
// is the API's to judge at the bind and the Vault's before it writes the card, against the reviewed pins
|
|
279
|
+
// each of them holds, so a merchant a later release reviews needs no new build of this library.
|
|
280
|
+
if (psp === 'paygent') {
|
|
281
|
+
return paygentEnvironment(requestUrl) === environment
|
|
282
|
+
&& paygentRequestRefusal({ url: requestUrl, method, headers: headers ?? {}, body: body ?? null }) === null;
|
|
283
|
+
}
|
|
270
284
|
// HiPay: the environment's own vault and payment-core's whole request rule (a JSON content type, a public username of
|
|
271
285
|
// that environment and a complete create, never the hosted fields' number-only post), the rule the API and the Vault
|
|
272
286
|
// bind with too.
|