@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.
Files changed (56) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/PREFLIGHT.md +4 -0
  3. package/README.md +53 -4
  4. package/dist/aci.generated.js +3 -3
  5. package/dist/agent-amount.generated.d.ts +7 -0
  6. package/dist/agent-amount.generated.js +3 -0
  7. package/dist/amadeus-checkout.generated.d.ts +6 -1
  8. package/dist/amadeus-checkout.generated.js +26 -2
  9. package/dist/capabilities.generated.d.ts +2 -0
  10. package/dist/capabilities.generated.js +3 -0
  11. package/dist/card-fields.generated.js +2574 -186
  12. package/dist/cdp.js +103 -29
  13. package/dist/client.d.ts +130 -9
  14. package/dist/client.js +304 -115
  15. package/dist/creditguard.generated.js +4 -2
  16. package/dist/cse-body.js +11 -0
  17. package/dist/ebanx.d.ts +1 -1
  18. package/dist/ebanx.js +1 -1
  19. package/dist/eximbay.d.ts +46 -0
  20. package/dist/eximbay.js +69 -0
  21. package/dist/hosted-entry.js +2 -1
  22. package/dist/hosted-form.d.ts +5 -0
  23. package/dist/hosted-form.js +5 -0
  24. package/dist/lifecycle.d.ts +9 -4
  25. package/dist/lifecycle.js +16 -4
  26. package/dist/paygent.generated.d.ts +60 -0
  27. package/dist/paygent.generated.js +425 -0
  28. package/dist/payrexx.d.ts +91 -0
  29. package/dist/payrexx.generated.d.ts +91 -0
  30. package/dist/payrexx.generated.js +536 -0
  31. package/dist/payrexx.js +141 -0
  32. package/dist/paytrail.d.ts +58 -0
  33. package/dist/paytrail.js +98 -0
  34. package/dist/pre-claim.d.ts +27 -0
  35. package/dist/pre-claim.js +175 -20
  36. package/dist/prepared-processor.d.ts +7 -2
  37. package/dist/prepared-processor.js +16 -2
  38. package/dist/primer.generated.js +2709 -321
  39. package/dist/registry.d.ts +4 -3
  40. package/dist/registry.js +12 -4
  41. package/dist/sbps.d.ts +57 -0
  42. package/dist/sbps.generated.d.ts +96 -0
  43. package/dist/sbps.generated.js +427 -0
  44. package/dist/sbps.js +90 -0
  45. package/dist/stripe-checkout.generated.js +744 -27
  46. package/dist/toast-seal.generated.d.ts +37 -0
  47. package/dist/toast-seal.generated.js +625 -0
  48. package/dist/toast.generated.d.ts +41 -0
  49. package/dist/toast.generated.js +113 -0
  50. package/dist/transbank.d.ts +33 -0
  51. package/dist/transbank.js +62 -0
  52. package/dist/url-mask-parts.d.ts +24 -0
  53. package/dist/url-mask-parts.js +22 -0
  54. package/dist/url-masks.generated.d.ts +3 -0
  55. package/dist/url-masks.generated.js +2 -0
  56. package/package.json +4 -4
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
2
  // Generated from @agent-cards/payment-core. Do not edit.
3
- // artifact-sha256: 0110d9fe2e862aad2c1191c5927ebb98dcc4be9905554ed46e18719a0bad05fb
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 ebanxMaySend).
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 ebanxMaySend).
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;
@@ -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
+ }
@@ -3,7 +3,8 @@
3
3
  * processor's own page with a link (a redirect, or a page or frame location set by script) rather than a form post.
4
4
  *
5
5
  * Such an entry carries no card. The cardholder's device takes it over (mode hosted_form): it makes the processor's
6
- * own calls for the payment the link names, and the paused navigation gets this SDK's submitted_on_device notice.
6
+ * own calls for the payment the link names, and the paused navigation gets this SDK's submitted_on_device notice, or,
7
+ * for a Webpay shop Agentcard reviewed with its return page, that return page (transbank.ts transbankMerchantReturn).
7
8
  * A GET recognizer otherwise reads as a card request carried in the URL (Worldpay eProtect's registration), which
8
9
  * this build completes only for a grammar it checks, so a hosted page joins this table with the exact link
9
10
  * payment-core's resolveRecognizerForUrl admits for it, and nothing else: a URL the table does not admit is never
@@ -18,6 +18,11 @@
18
18
  * completed this payment on their own device, do not resubmit, confirm the
19
19
  * order with the merchant. This page says that, for a person and for an
20
20
  * agent, and nothing else.
21
+ *
22
+ * Webpay is the one hosted page whose merchant hears of a payment only from
23
+ * the buyer's browser, returning to the merchant's own page with Webpay's
24
+ * token. A paid Webpay entry is therefore sent to the reviewed shop's return
25
+ * page instead of this one (transbank.ts transbankMerchantReturn).
21
26
  */
22
27
  export interface HostedFormSubmittedPageInput {
23
28
  /** The approved authorization (`cauth_…`). */
@@ -18,6 +18,11 @@
18
18
  * completed this payment on their own device, do not resubmit, confirm the
19
19
  * order with the merchant. This page says that, for a person and for an
20
20
  * agent, and nothing else.
21
+ *
22
+ * Webpay is the one hosted page whose merchant hears of a payment only from
23
+ * the buyer's browser, returning to the merchant's own page with Webpay's
24
+ * token. A paid Webpay entry is therefore sent to the reviewed shop's return
25
+ * page instead of this one (transbank.ts transbankMerchantReturn).
21
26
  */
22
27
  /** The outcome word on the page, the header and the JSON: one spelling everywhere. */
23
28
  export const HOSTED_FORM_SUBMITTED_OUTCOME = 'submitted_on_device';
@@ -159,6 +159,7 @@ export declare class CheckoutLifecycle implements CheckoutController {
159
159
  private stripeContinuationChecks;
160
160
  /** The handoff in progress is WSPay's 3-D Secure step; see handedOff. */
161
161
  private wspayChallenge;
162
+ private heldBeforeHandoff;
162
163
  private stripeContinuedReason;
163
164
  private approvedPaymentMethod;
164
165
  private ownedShopOrderId;
@@ -191,7 +192,8 @@ export declare class CheckoutLifecycle implements CheckoutController {
191
192
  preparationFailed(error: CheckoutPreparationError): void;
192
193
  isBlocked(): boolean;
193
194
  /**
194
- * An EBANX send left for the cardholder's device under this attachment's approval (pre-claim.ts ebanxFollowUp). Until
195
+ * An EBANX or Payrexx send left for the cardholder's device under this attachment's approval (pre-claim.ts ebanxFollowUp,
196
+ * payrexxFollowUp). Until
195
197
  * the returned function runs, once the send's answer reached the page or the send failed, reconcile() and
196
198
  * retryAfterMerchantFailure() throw, as they do while a card request is active: a confirm may still pay. The returned
197
199
  * function settles the send once, however often it runs.
@@ -200,7 +202,7 @@ export declare class CheckoutLifecycle implements CheckoutController {
200
202
  /** Whether a reconcile() is still waiting on the application's merchant resolver; pre-claim.ts claims no EBANX send then. */
201
203
  isReconciling(): boolean;
202
204
  /**
203
- * Whether an EBANX send this attachment claimed is still out (followUpStarted). Both adapters refuse a new card
205
+ * Whether an EBANX or Payrexx send this attachment claimed is still out (followUpStarted). Both adapters refuse a new card
204
206
  * request meanwhile, as they do while an approval is outstanding: a confirm that may pay is never hidden behind
205
207
  * another payment's state.
206
208
  */
@@ -284,10 +286,13 @@ export declare class CheckoutLifecycle implements CheckoutController {
284
286
  * paddle-vgs-pay.ts reasons), or the typed card that EBANX's 3-D Secure calls or
285
287
  * its hosted page's confirm send again after the token, when no approved token
286
288
  * request on this attachment covers that send or the cardholder's device did not
287
- * send it (unsupported_ebanx_card_resend, ebanx.ts): once an approval exists the
289
+ * send it (unsupported_ebanx_card_resend, ebanx.ts), or the typed card Payrexx's card
290
+ * frame sends again for a 3-D Secure step when no approved card request on this
291
+ * attachment covers that send or the cardholder's device did not send it
292
+ * (unsupported_payrexx_card_resend, payrexx.ts): once an approval exists the
288
293
  * state keeps it, and only the hold changes.
289
294
  */
290
- unsupported(reason?: 'unrecognized_payment_endpoint' | 'merchant_profile_observe' | 'merchant_request_unsupported' | GmoUnsupportedReason | 'microform_unsupported' | 'juspay_request_unsupported' | 'merchant_card_endpoint_not_enabled' | 'merchant_card_endpoint_resend_refused' | 'creditguard_three_d_secure' | 'unsupported_primer_sdk' | 'unsupported_primer_request' | PayrailsUnsupportedReason | ShijiStsUnsupportedReason | 'processor_card_page' | 'unsupported_paypal_hosted_fields' | PaypalCardFormReason | 'unsupported_cybersource_secure_acceptance' | PaddleVgsPayRefusal | 'unsupported_ebanx_card_resend'): void;
295
+ unsupported(reason?: 'unrecognized_payment_endpoint' | 'merchant_profile_observe' | 'merchant_request_unsupported' | GmoUnsupportedReason | 'microform_unsupported' | 'juspay_request_unsupported' | 'merchant_card_endpoint_not_enabled' | 'merchant_card_endpoint_resend_refused' | 'creditguard_three_d_secure' | 'unsupported_primer_sdk' | 'unsupported_primer_request' | PayrailsUnsupportedReason | ShijiStsUnsupportedReason | 'processor_card_page' | 'unsupported_paypal_hosted_fields' | PaypalCardFormReason | 'unsupported_cybersource_secure_acceptance' | PaddleVgsPayRefusal | 'unsupported_ebanx_card_resend' | 'unsupported_payrexx_card_resend'): void;
291
296
  /**
292
297
  * A card request that only a prepared checkout pays (an Adyen merchant
293
298
  * profile's, or a Fiserv card capture) arrived with no preparation on this
package/dist/lifecycle.js CHANGED
@@ -57,6 +57,9 @@ export class CheckoutLifecycle {
57
57
  stripeContinuationChecks = 0;
58
58
  /** The handoff in progress is WSPay's 3-D Secure step; see handedOff. */
59
59
  wspayChallenge = false;
60
+ // Whether the attachment held when the handoff in progress began (prepareHandoff): a hold raised after that, while
61
+ // the answer was still landing, survives handedOff.
62
+ heldBeforeHandoff = false;
60
63
  // What the continuation that went through confirmed: a payment, or a card save.
61
64
  stripeContinuedReason = 'stripe_payment_continued';
62
65
  // The payment method a Stripe /v1/payment_methods approval returned: see approvedStripePaymentMethod.
@@ -120,7 +123,8 @@ export class CheckoutLifecycle {
120
123
  }
121
124
  isBlocked() { return this.held || this.cancelled; }
122
125
  /**
123
- * An EBANX send left for the cardholder's device under this attachment's approval (pre-claim.ts ebanxFollowUp). Until
126
+ * An EBANX or Payrexx send left for the cardholder's device under this attachment's approval (pre-claim.ts ebanxFollowUp,
127
+ * payrexxFollowUp). Until
124
128
  * the returned function runs, once the send's answer reached the page or the send failed, reconcile() and
125
129
  * retryAfterMerchantFailure() throw, as they do while a card request is active: a confirm may still pay. The returned
126
130
  * function settles the send once, however often it runs.
@@ -136,7 +140,7 @@ export class CheckoutLifecycle {
136
140
  /** Whether a reconcile() is still waiting on the application's merchant resolver; pre-claim.ts claims no EBANX send then. */
137
141
  isReconciling() { return this.reconciliation !== null; }
138
142
  /**
139
- * Whether an EBANX send this attachment claimed is still out (followUpStarted). Both adapters refuse a new card
143
+ * Whether an EBANX or Payrexx send this attachment claimed is still out (followUpStarted). Both adapters refuse a new card
140
144
  * request meanwhile, as they do while an approval is outstanding: a confirm that may pay is never hidden behind
141
145
  * another payment's state.
142
146
  */
@@ -283,7 +287,10 @@ export class CheckoutLifecycle {
283
287
  * paddle-vgs-pay.ts reasons), or the typed card that EBANX's 3-D Secure calls or
284
288
  * its hosted page's confirm send again after the token, when no approved token
285
289
  * request on this attachment covers that send or the cardholder's device did not
286
- * send it (unsupported_ebanx_card_resend, ebanx.ts): once an approval exists the
290
+ * send it (unsupported_ebanx_card_resend, ebanx.ts), or the typed card Payrexx's card
291
+ * frame sends again for a 3-D Secure step when no approved card request on this
292
+ * attachment covers that send or the cardholder's device did not send it
293
+ * (unsupported_payrexx_card_resend, payrexx.ts): once an approval exists the
287
294
  * state keeps it, and only the hold changes.
288
295
  */
289
296
  unsupported(reason = 'unrecognized_payment_endpoint') {
@@ -305,6 +312,7 @@ export class CheckoutLifecycle {
305
312
  this.set({ ...this.state, status: 'failed', reason: 'preparation_required' });
306
313
  }
307
314
  prepareHandoff(replay, requestUrl) {
315
+ this.heldBeforeHandoff = this.held;
308
316
  this.wspayChallenge = isWspayChallenge(requestUrl, replay);
309
317
  this.handoffs.push(requestUrl);
310
318
  if (replay.mode === 'token' && replay.executionMode === 'autopilot' && replay.shopOrderId) {
@@ -422,10 +430,14 @@ export class CheckoutLifecycle {
422
430
  return;
423
431
  }
424
432
  const mismatch = (!replay.mode || replay.mode === 'token') && replay.amountVerified === false;
433
+ // A hold raised while the answer was still landing stands: the page may send its first follow-up the moment the
434
+ // answer lands, and an EBANX or Payrexx send that fails then stops the approval's follow-ups for good
435
+ // (pre-claim.ts), so a new card request must not reopen the checkout under an approval that cannot finish.
436
+ const heldDuringHandoff = this.held && !this.heldBeforeHandoff;
425
437
  // A card endpoint answer means the merchant already holds the card: its page's own
426
438
  // retry, or a step-up that sends the card again, is refused until the application
427
439
  // reconciles the order, exactly as for a hosted form the device submitted.
428
- this.held = !!this.options.requireMerchantResult || replay.mode === 'hosted_form' || replay.mode === 'card_endpoint' || mismatch || this.unboundStripeToken;
440
+ this.held = heldDuringHandoff || !!this.options.requireMerchantResult || replay.mode === 'hosted_form' || replay.mode === 'card_endpoint' || mismatch || this.unboundStripeToken;
429
441
  if (mismatch)
430
442
  this.stripeTokenPrepared = false;
431
443
  this.set({ status: 'awaiting_merchant', authorizationId: replay.authorizationId, mode: replay.mode ?? 'token',
@@ -0,0 +1,60 @@
1
+ declare var PAYGENT_PSP: string;
2
+ declare var PAYGENT_CAPABILITY: string;
3
+ declare var PAYGENT_OPERATION: string;
4
+ declare var PAYGENT_TOKEN_HOSTS: Readonly<{
5
+ production: readonly string[];
6
+ sandbox: readonly string[];
7
+ }>;
8
+ declare var PAYGENT_TOKEN_PATH: string;
9
+ declare var PAYGENT_CONTENT_TYPE: string;
10
+ declare var PAYGENT_BODY_KEYS: readonly string[];
11
+ declare var PAYGENT_REFUSAL_CODES: readonly string[];
12
+ declare function paygentEnvironment(url: any): "production" | "sandbox" | null;
13
+ declare function isPaygentTokenUrl(url: any): boolean;
14
+ declare function paygentBodyVerdict(body: any): Readonly<{
15
+ verdict: "refuse";
16
+ code: any;
17
+ }> | Readonly<{
18
+ verdict: "card";
19
+ }>;
20
+ declare function paygentRequestVerdict(url: any, body: any): Readonly<{
21
+ verdict: "refuse";
22
+ code: any;
23
+ }> | Readonly<{
24
+ verdict: "card";
25
+ }>;
26
+ declare function paygentRequestRefusal(request: any): any;
27
+ declare function paygentMerchantId(body: any): string | null;
28
+ declare function paygentBodyMerchant(body: any): {
29
+ merchantId: string;
30
+ tokenKey: string;
31
+ } | null;
32
+ declare function paygentPreparationUrl(environment: any): string;
33
+ declare var PAYGENT_MERCHANT_PINS: readonly any[];
34
+ declare function paygentMerchantPin(merchantOrigin: any, merchant: any, pins?: readonly any[]): any;
35
+ declare function paygentMerchantRefusal(environment: any, merchantOrigin: any, merchant: any, facts?: {}, pins?: readonly any[]): "unsupported_environment" | "paygent_merchant_unreviewed" | "paygent_currency_mismatch" | "paygent_merchant_mismatch" | null;
36
+ declare function isPreparedPaygentRequest(url: any, method: any, body: any, environment: any, headers: any, binding?: {}, pins?: readonly any[]): boolean;
37
+ declare function injectPaygentCard(body: any, card: any): {
38
+ body: string;
39
+ where: any[];
40
+ };
41
+ declare var PAYGENT_ANSWER_REFUSAL_CODES: readonly string[];
42
+ declare function paygentAnswerOutcome(status: any, text: any, card: any): {
43
+ outcome: string;
44
+ code: any;
45
+ reason?: undefined;
46
+ body?: undefined;
47
+ } | {
48
+ outcome: string;
49
+ reason: string | undefined;
50
+ code?: undefined;
51
+ body?: undefined;
52
+ } | {
53
+ outcome: string;
54
+ body: string;
55
+ code?: undefined;
56
+ reason?: undefined;
57
+ };
58
+ declare function paygentRefusalCode(text: any): any;
59
+ declare function paygentRefusalMessage(code: any): any;
60
+ export { PAYGENT_ANSWER_REFUSAL_CODES, PAYGENT_BODY_KEYS, PAYGENT_CAPABILITY, PAYGENT_CONTENT_TYPE, PAYGENT_MERCHANT_PINS, PAYGENT_OPERATION, PAYGENT_PSP, PAYGENT_REFUSAL_CODES, PAYGENT_TOKEN_HOSTS, PAYGENT_TOKEN_PATH, injectPaygentCard, isPaygentTokenUrl, isPreparedPaygentRequest, paygentAnswerOutcome, paygentBodyMerchant, paygentBodyVerdict, paygentEnvironment, paygentMerchantId, paygentMerchantPin, paygentMerchantRefusal, paygentPreparationUrl, paygentRefusalCode, paygentRefusalMessage, paygentRequestRefusal, paygentRequestVerdict };