@agent-cards/sdk 0.23.14 → 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 CHANGED
@@ -18,6 +18,8 @@
18
18
  - Pay a Lyra payment form (PayZen, Systempay or Sogecommerce) for a company Agentcard turned Lyra on for (dark launch): the SDK declares `lyra_krypton_payment`, pauses the form's card payment and hands the form Lyra's answer with the payment id its 3-D Secure step needs.
19
19
  - Keep a Lyra payment's session id out of your events and error messages. Lyra's Krypton payment form (PayZen, Systempay, Sogecommerce, Lyra Collect) sends its payment to `/api-payment/V4/Charge/Public/ProcessPayment/2;jsessionid=<id>` on the brand's API host, and that id, with the form token the page holds, continues the payment on Lyra's side. `redactUrl`, every event and every error message show it as `{session}`, as in `https://api.systempay.fr/api-payment/V4/Charge/Public/ProcessPayment/2;jsessionid={session}`. Lyra stays dark for every company Agentcard has not turned it on for, and no API or Vault release is needed.
20
20
 
21
+ - Stop PayPal's Card Fields and PayPal's guest card form from sending the card your agent typed to PayPal. A checkout that loads PayPal's JS SDK with `components=card-fields`, such as a WooCommerce PayPal Payments store's "Debit & Credit Cards" option, takes the card in frames on `www.paypal.com/smart/card-field` and sends it to `https://www.paypal.com/v2/checkout/orders/{id}/confirm-payment-source`; PayPal's v6 SDK sends the same request to `api-m.paypal.com`, and PayPal's sandbox uses `www.sandbox.paypal.com` and `api-m.sandbox.paypal.com`. PayPal's black "Debit or Credit Card" button takes the card on PayPal's own guest form, which sends it to `https://www.paypal.com/graphql?OnboardGuestMutation`, and Card Fields saves a card with no purchase through `graphql?UpdateVaultSetupToken`. No Agentcard payment took any of these over, and earlier releases let them through, so PayPal received the dummy card and declined it. Both adapters now fail each of them in the browser for every company, and the controller reads `unsupported` with reason `unsupported_paypal_card_fields`, or `unsupported_paypal_guest_checkout` for the guest form, and holds: to pay another way on the same page, attach again. A request with no card in it, such as a PayPal wallet confirm or the buttons' other GraphQL calls, continues untouched. A confirm whose body the SDK cannot read is failed with a `blocked` event, `unreadable_paypal_request`, and the checkout is not held; a GraphQL post it cannot read is failed the same way only when its URL names one of the two card operations. A guest form that PayPal opens in a popup window runs in another page, which the SDK covers only when you attach it to that page as well. Events and error messages now name a PayPal order as `{order}`, as in `https://www.paypal.com/v2/checkout/orders/{order}/confirm-payment-source`, on every PayPal host, legacy Hosted Fields' `cors.api.paypal.com` included: an order id opens PayPal's own checkout page for that order to anyone who holds it. TypeScript: the controller's `unsupported()` reasons gain `unsupported_paypal_card_fields` and `unsupported_paypal_guest_checkout`; code that switches exhaustively over them needs the new cases.
22
+
21
23
  - Keep a Rapyd hosted page's id and a Stripe Checkout Session's id out of your events and error messages. Rapyd's checkout page sends the card to `/v1/checkout/checkout_<id>` on `api.rapyd.net` (a card page to `/v1/hosted/collect/card/hp_card_<id>/payment_method`) with no auth header, so the page's id is the only credential that request needs: anyone who holds it can read the page and post a card to it until it expires. Stripe Checkout confirms a session at `/v1/payment_pages/<session id>/confirm` with the merchant's publishable key, which is public, so the session id is what lets anyone confirm a payment on it. Earlier releases named both ids in the `card_request_paused` event and in the errors `authorize()` throws, so they reached your `onEvent` handler and every log that recorded the event or the error. `redactUrl`, every event and every error message now show them as `{token}` and `{session}`, as in `https://api.rapyd.net/v1/checkout/{token}` and `https://api.stripe.com/v1/payment_pages/{session}/confirm`. `redactUrl` also masks an ACI checkout id in the shapes it used to keep: a host with a trailing dot, an escaped or doubled slash, and a string that is not a URL. A PaymentIntent or SetupIntent id stays, since confirming one also needs its client_secret. No API or Vault release is needed.
22
24
 
23
25
  - Pay a store on Paysafe Checkout's current build, 1.16.1. The loader Paysafe tells merchants to include, `checkout/v1/latest`, now runs version 1.16.1, and that build sends the card to `api.paysafe.com/checkout/api/v1/tokenize` (`api.test.paysafe.com` in its test environment), where 1.8.0 sent it to `hosted.paysafe.com`. Earlier releases did not recognize that request, so it was never paused and the agent's placeholder card reached Paysafe. The SDK now pauses it and keeps the three headers the build sends beside its credential: `X-Internal-Correlation-Id`, `X-App-Version` and `X-TransactionSource`. Paysafe.js latest sends the same three, and its replay keeps them too. `prepare({ psp: 'paysafe' })` binds a request only to a Checkout build Agentcard read, by the version the request names: 1.8.0 on `hosted.paysafe.com`, or 1.16.1 on `api.paysafe.com`, each with its own headers. A request from any other build stops with `checkout_changed`, and nothing is sent. An SDK that syncs its registry pauses the 1.16.1 request once the API release deploys; a prepared 1.16.1 checkout needs this release. Both need a Vault release after 0.6.2.
@@ -135,6 +137,8 @@
135
137
 
136
138
  - Pay a live Pelecard checkout, for a company Agentcard turned Pelecard on for. Pelecard's test and live terminals share `gateway21.pelecard.biz` and `gateway20.pelecard.biz`, and neither the payment page nor its request says which kind a page is on, so the API refused every live Pelecard create with `400 pelecard_live_unsupported`, before any row or prompt. On 2026-10-11 Agentcard accepted that a live payment page could sit on one of Pelecard's public test terminals, and a live create now parks like a test one. The cardholder approves under Pelecard's note, which says the merchant may have Pelecard keep the card, since a merchant can set `CreateToken` when it creates the payment page, and only a card the cardholder stored pays: the API refuses a card a company added as `card_not_stored`. A test-mode checkout still takes only a documented test card. No SDK upgrade is needed. A payment also needs the matching API, Vault and checkout relay releases, with `CHECKOUT_PELECARD_RELAY_ENABLED` on and the company listed for Pelecard.
137
139
 
140
+ - Pay a Wix checkout whose card goes to Wix's own tokenizer, from Agentcard's own account only for now (dark launch): Agentcard turns it on for another company once it checks that the site instance Wix's card frame sends belongs to the reviewed store. Every Wix checkout mounts Wix Cashier's card frame, and for Wix Payments and classic Stripe on Wix that frame posts the card to `https://cashier-pci.wixapps.net/_api/payment-gateway-web/tokenize/v2/tokens`. Wix's payment widget fails the payment 30 seconds after it asks the frame for a token, too soon for an approval after Pay, so the SDK pays a Wix checkout only through `prepare({ psp: 'wix_payments', environment: 'production' })`, at a store Agentcard reviewed (ParaHouse Magazine, Psalms & Potions and Alexandra Hagel today), with `amount` and `currency`, the total the cardholder approves: the request names none. Wix has no test environment, so a test client's `prepare()` fails with `live_host_on_sandbox_row`. The sync now also asks for `capabilities=wix_payments_tokenize`. Once the cardholder approves, the frame's request pauses, the cardholder's device sends the card through the checkout relay, and the frame receives Wix's token. The frame sends its card request once more under a fresh site instance after Wix answers 401 or 403: the SDK refuses that second request in the browser and never answers it from the first approval. The SDK fails a paused request the cardholder's device has not sent 20 seconds after the pause, of the 30 seconds Wix waits, with reason `wix_payments_send_window_closed`, as it fails a prepared Secure Acceptance token create, and the device sends nothing past its own earlier boundary.
141
+
138
142
  ## 0.23.0
139
143
 
140
144
  ### Upgrading from 0.22.0
package/PREFLIGHT.md CHANGED
@@ -203,6 +203,8 @@ WSPay Components (`wspay`) is identified from its component scripts and its card
203
203
 
204
204
  Shiji STS (`shiji_sts`), the card leg of MyCheck Wallet V3 at La Quinta by Wyndham, is identified from the in-page wallet script `wallet-sdk-v3.mycheckapp.com/{version}/static/js/main.js` (and its `-sandbox` and `-test` hosts) and from Shiji's proxy `cdn.shijipayment.com/sts/sts.proxy.v2.1.js` (and its `cdn.shijipayment.dev` copy), but it is not in this table. It launches dark: the direct SDK acts on it only after `syncRegistry()` and only for an org Agentcard has enabled, and even then it refuses every card request as card on file (`shiji_sts_keep_on_file`) until Agentcard can ask the cardholder to let a hotel keep the card, so the bundled catalog leaves it out and a Shiji checkout stays `unknown`. MyCheck's iframe wallet (`sdk.js`, `wallet-iframe.html`) and Shiji's `shijipayments.latest.min.js` name their processor and return `unknown` with `processor_variant_unverified`. Read the [Shiji STS section of the README](./README.md#shiji-sts-mycheck-wallet-v3).
205
205
 
206
+ Wix Payments (`wix_payments`) has no discovery rule in this table. Wix Cashier's card frame on `cashier-pci.wixapps.net` is the same for every provider a Wix site connects, and for Square and Wix's Stripe Gateway it sends the card to the processor's own SDK rather than to Wix's tokenizer, so the frame on a page is no evidence of this lane, and a Wix checkout stays `unknown`. The direct SDK pauses the card request the frame sends to Wix's tokenizer only after `syncRegistry()`, only through a prepared checkout, and only for an org Agentcard has enabled. Read the Wix row of the [README](./README.md) processor table.
207
+
206
208
  Gravy Secure Fields (`gravy`) is identified from the loader its merchants load, `/secure-fields/latest/secure-fields.js` on `cdn.<merchant>.gr4vy.app` (or `cdn.sandbox.<merchant>.gr4vy.app`), but it is not in this table. It launches dark: the direct SDK pauses Gravy's card request, a `PUT` from Gravy's controller frame, only after `syncRegistry()` and only for an org Agentcard has enabled, so the bundled catalog leaves it out and a Gravy checkout stays `unknown`.
207
209
 
208
210
  Paddle (`paddle_vgs`) has no discovery rule in this table. Paddle's checkout frame on `buy.paddle.com` names the tokenizer it sends the card through only after the buyer's first step, and Paddle can name another one for each checkout, so nothing on the page before that step says which one a checkout uses, and a Paddle checkout stays `unknown`. The direct SDK pauses the card request a VGS checkout sends to `vault.paddle.com/cards` only after `syncRegistry()`, only through a prepared checkout, and only for an org Agentcard has enabled. Read the Paddle row of the [README](./README.md) processor table for what the SDK covers.
package/README.md CHANGED
@@ -255,6 +255,7 @@ Coverage is specific to the processor request format, merchant setup, browser tr
255
255
  | Mercado Pago | Card tokenization and prepared checkout are implemented. Guest Checkout Pro in Mexico also corrects the issuer for one native card association when the selected card has the same brand and type. One live MXN 40 Lotería Chida purchase with published SDK 0.10.0 completed automatically through Pay; the merchant confirmed paid status and PDF fulfillment. The historical SDK result remains unknown because the private receipt adapter rejected a relative download URL; a separate read with the corrected adapter confirms that same paid receipt. Independent processor capture/settlement and other country or integration paths remain unverified. |
256
256
  | VGS Collect (Very Good Security; Wolt) | not supported: VGS's proxy aliases only submissions from its own iframe, so a replay from the cardholder's device is refused by the merchant (verified on Wolt, 2026-09-03). Not recognized, so the agent's browser is not paused there |
257
257
  | PayPal Hosted Fields (the legacy card fields of PayPal's JS SDK; Planet Golf UK) | not supported: no Agentcard payment takes over the card these fields send to `cors.api.paypal.com`. The SDK fails that request for every company, so PayPal's payment confirm never receives the dummy card, and the controller reads `unsupported` with reason `unsupported_paypal_hosted_fields` and holds the attachment until you attach again; a PayPal wallet payment continues untouched |
258
+ | PayPal Card Fields (PayPal JS SDK `components=card-fields`, v5 and v6) and PayPal's guest card form (the "Debit or Credit Card" button) | not supported: no Agentcard payment takes over the card these send to `www.paypal.com` or `api-m.paypal.com`. The SDK fails each card request for every company, so PayPal never receives the dummy card, and the controller reads `unsupported` with reason `unsupported_paypal_card_fields` (or `unsupported_paypal_guest_checkout` for the guest form) and holds the attachment until you attach again; a PayPal wallet payment continues untouched |
258
259
  | CyberSource Secure Acceptance Silent Order POST (the merchant's own card form posted to CyberSource; Arrow Electronics) | dark launch: prepared checkout only, for an org Agentcard enabled. After `syncRegistry()`, for such an org, the SDK pauses the token create a merchant's form posts into a hidden iframe (`/silent/embedded/token/create` on `secureacceptance.cybersource.com`, or `testsecureacceptance.cybersource.com` in CyberSource's test environment), the cardholder's device sends the card to CyberSource, and the iframe gets CyberSource's own reply page. See [Pay a CyberSource Secure Acceptance checkout](#pay-a-cybersource-secure-acceptance-checkout-dark-launch). For every other company, and for every other card post to a `/silent/` path on those hosts or on `secureacceptance.in.cybersource.com` (India), no Agentcard payment takes the card over, and the SDK stops the post so CyberSource never receives the dummy card: a form the page submits as a page load, in the page or in a frame, ends on the page that says Agentcard stopped the payment, and a fetch or an XHR fails. The controller reads `unsupported` with reason `unsupported_cybersource_secure_acceptance` and holds the attachment until you attach again; a post with no `card_number`, such as a payment with a stored `payment_token`, continues untouched. The SDK does not stop Hosted Checkout, where your agent types the card on CyberSource's own page |
259
260
  | EBANX (EBANX.js and EBANX's hosted payment page; Nuuvem Colombia) | supported for the token request (`POST /ws/token`): the SDK pauses it, and the cardholder's device sends the card there. EBANX's page then sends the card again. 3-D Secure's `/ws/threedsecureserver-generateToken`, `-authentications` and `-authentication-results` carry the card. The hosted page's confirm, `/ws/checkout-v2/confirm`, carries the card code. For a company Agentcard turned it on for, the approval's read names until when it covers those sends (`followUpsUntil`). While the Vault page stays open, the cardholder's device sends each covered one, bound to the approved request. The cardholder sees no second prompt. The page receives EBANX's answer. The confirm is covered only once 3-D Secure succeeded for the invoice it pays. It pays in one instalment and keeps no card for one-click payments. A card checkout that runs no 3-D Secure, picks instalments or saves the card fails in the browser. Every other such send fails in the browser too, for every company. EBANX never receives the dummy card or code. The page shows its own payment error. The controller reads `unsupported` with reason `unsupported_ebanx_card_resend` and holds the attachment until you attach again. After one such send fails or is refused, the SDK sends nothing more on that attachment. It also sends nothing once the checkout no longer names that approval: a final merchant result such as `completed` or `failed`, a new token request, or a new attempt after a merchant failure, and nothing while a reconciliation runs. While a send is out, `reconcile()` and `retryAfterMerchantFailure()` throw, and a new card request fails in the browser. A confirm with no card code, such as a PSE bank transfer, continues untouched |
260
261
  | Adyen | supported (mode `cse`): the vault encrypts the card for Adyen on the cardholder's device and your browser sends it. Sessions flow: the paused request is `/checkoutshopper/v1/sessions/{id}/payments` on Adyen's own hosts. A merchant that posts the encrypted fields to its own server pauses only when Agentcard reviewed it as a merchant profile. Cinemark and Dick's Sporting Goods' own storefront take payments for a company Agentcard turned them on for; every other reviewed merchant is in `observe`, so its card requests are reported and aborted and nothing pays there yet (see "Adyen merchants that take the card on their own server"). Without a preparation, approval starts at Pay and must land before Adyen Web's own request timeout (observed at 60 seconds on Adyen Web 6.41 and 6.44; not enforced by the SDK); `prepare({ psp: 'adyen' })` moves the approval before Pay |
@@ -278,6 +279,7 @@ Coverage is specific to the processor request format, merchant setup, browser tr
278
279
  | Moneris Hosted Tokenization (Moneris's card frame; Raisin donation pages) | dark launch: after `vault.syncRegistry()`, and only for an org Agentcard has enabled, the SDK pauses the frame's post to `/HPPtoken/request.php` on `www3.moneris.com` or `gateway.moneris.com` (`esqa.moneris.com` for a test row) when it carries the card number, expiry and CVD, always with the cardholder's approval. A live payment needs a merchant Agentcard reviewed: the profile id the frame names must be one pinned for the checkout page's origin (Jack.org's Raisin page today), or the create answers `unsupported_checkout`. A frame that leaves the expiry or CVD to the merchant's page, or a post to any other `request.php` URL, fails in the browser with a `blocked` event, `request_without_card`. The cardholder's device sends the card through the checkout relay, and the page gets Moneris's temporary token, which the merchant charges from its own server: pass `amount` and `currency`, the total the cardholder approves. Moneris Checkout (`/chkt/`, `/chktv2/`) is not supported |
279
280
  | WSPay Components (WSPay's build of Monri Components) | dark launch: the card frame's confirm of a new card, after `vault.syncRegistry()`, with `amount` and `currency`, and only for an org Agentcard has enabled; for any other org the SDK leaves WSPay's requests alone. The cardholder's device sends the card to WSPay and the frame receives WSPay's answer. A confirm that asks WSPay to keep the card on file, as Valamar's does on every booking, is paid only as a hotel's EUR 1.00 card guarantee with a card the cardholder stored. Validated in local Chromium against a model of the card frame; no WSPay sandbox run or live merchant purchase yet. See [Pay a WSPay Components checkout](#pay-a-wspay-components-checkout) |
280
281
  | Shiji STS (MyCheck Wallet V3; Wyndham's booking pages) | dark launch, mode `cse` under a pinned key, and only for an org Agentcard has enabled. The card token a hotel booking mints guarantees the stay, so the cardholder approves with a card they stored, under a line that says the hotel can keep it on file. See [Shiji STS](#shiji-sts-mycheck-wallet-v3) |
282
+ | Wix checkout (Wix Cashier's card frame; Wix Payments and classic Stripe on Wix) | dark launch: only in Agentcard's own account for now, after `vault.syncRegistry()`, and only through `prepare({ psp: 'wix_payments', environment: 'production' })` at a store Agentcard reviewed, with `amount` and `currency`. The frame's post to `cashier-pci.wixapps.net/_api/payment-gateway-web/tokenize/v2/tokens` pauses, the cardholder's device sends the card through the checkout relay, and the frame receives Wix's token. Wix has no test environment. The SDK refuses the frame's second card request after a 401 or 403 in the browser, and fails a request still unsent 20 seconds after the pause, before the card leaves (`wix_payments_send_window_closed`) |
281
283
  | Amadeus Checkout (Air France, KLM) | dark: only for an org Agentcard enabled, and only through `prepare({ psp: 'amadeus_checkout', cardId })`. The Checkout Web SDK's card add pauses; every other action on its URL continues. Air France and KLM keep the expiry in their own form, so the agent types the stored card's real expiry there and the checkout pays only with that card. Every Data Collection Page store is refused as `amadeus_dcp_field_config_unreviewed`. No live purchase yet. See "Prepare an Amadeus Checkout card step" |
282
284
  | Paddle checkout (Paddle's card vault; Rectangle Pro) | dark launch: only in Agentcard's own account for now, after `vault.syncRegistry()`, and only through `prepare({ psp: 'paddle_vgs', environment: 'production' })` (`'sandbox'` for Paddle's sandbox) on an attachment whose `cardId` names the paying card; without one, `prepare()` fails with `card_required`. On a Paddle checkout whose card method names VGS, the frame's post to `vault.paddle.com/cards` pauses, the cardholder's device sends the card itself, and the frame receives the stored card's id; its second request after its 10-second timeout gets the same answer. Type `placeholderCard()`'s facts for that card into Paddle's form, and pass `amount` and `currency`, the total the cardholder approves. Only Visa, Mastercard and American Express cards are paid (`paddle_vgs_card_unsupported` otherwise), and a typed expiry or placeholder that is not the card's fails the create with `paddle_vgs_card_mismatch`. On the live vault only a reviewed seller at its reviewed page is paid (Rectangle Pro at `https://rectangleapp.com`), and the approval says that seller can keep the card on file. Paddle's `/pay` that follows names the approved card's first six and last four digits, expiry and brand: the SDK writes them over the ones Paddle's form read from the placeholder, and aborts a `/pay` that names another stored card or comes more than a minute later. A Paddle checkout that sends the card through TokenEx or Spreedly is not supported, and no live payment has gone through this route yet |
283
285
 
package/dist/amadeus.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  /** How long after the pause a paused Amadeus SDK add may still be sent. */
2
2
  export declare const AMADEUS_SEND_WINDOW_MS = 20000;
3
+ /** How long after the pause a paused Wix tokenize request may still be sent, of the 30 seconds Wix's widget waits. */
4
+ export declare const WIX_PAYMENTS_SEND_WINDOW_MS = 20000;
3
5
  /**
4
6
  * True when a request the adapters refuse must fail as a network error (ERR_FAILED) rather than as
5
7
  * the cancellation (ERR_ABORTED) they use elsewhere. An XMLHttpRequest reports a cancellation only
@@ -9,12 +11,13 @@ export declare const AMADEUS_SEND_WINDOW_MS = 20000;
9
11
  */
10
12
  export declare function failsAsNetworkError(url: string): boolean;
11
13
  /** The processor a send window's events and stop cause name. */
12
- export type SendWindowProcessor = 'amadeus' | 'secure_acceptance';
14
+ export type SendWindowProcessor = 'amadeus' | 'secure_acceptance' | 'wix_payments';
13
15
  /** Why a send window stopped its attempt: the API confirmed the card never left the device and never can. */
14
16
  export type SendWindowClosed = `${SendWindowProcessor}_send_window_closed`;
15
17
  /**
16
18
  * The send window for a request paused under a preparation for `psp`, or null when it has none: a
17
- * prepared Amadeus SDK add, and a prepared CyberSource Secure Acceptance token create, each 20 seconds.
19
+ * prepared Amadeus SDK add, a prepared CyberSource Secure Acceptance token create and a prepared Wix
20
+ * tokenize request, each 20 seconds.
18
21
  */
19
22
  export declare function preparedSendWindowMs(psp: string | undefined, url: string): number | null;
20
23
  /** The processor a prepared request's send window names in its events, or null when it has none. */
package/dist/amadeus.js CHANGED
@@ -14,6 +14,11 @@
14
14
  // without a word. A token CyberSource creates after that point is one the page never reads, so a
15
15
  // paused token create gets the same 20 second window (cybersource-secure-acceptance.ts).
16
16
  //
17
+ // Wix's payment widget fails the payment 30 seconds after it asks Wix Cashier's card frame for a
18
+ // token (cashier-payments-widget 1.4964.0), and the merchant's page charges only a token the frame
19
+ // handed back in time. A token Wix mints after that point is one no charge ever names, so a paused
20
+ // tokenize request gets the same 20 second window.
21
+ //
17
22
  // So when the window closes and no answer is being handed to the page yet, the adapter asks for that
18
23
  // cancel. Confirmed: nothing was sent and nothing can be, so the attempt stops, the page's request
19
24
  // fails (a Secure Acceptance frame gets the stopped page), and the checkout reads failed. Not
@@ -24,13 +29,17 @@
24
29
  // request can bind it, nothing can be sent; when a request already holds it, that authorization gets
25
30
  // the same cancel and the same rule, and when the API confirms neither, the attempt keeps waiting. The
26
31
  // Data Collection Page's store has no client timeout and gets no window. The window's events name the
27
- // processor: `amadeus_send_window_closed` and `amadeus_send_window_unconfirmed`, or
28
- // `secure_acceptance_send_window_closed` and `secure_acceptance_send_window_unconfirmed`.
32
+ // processor: `amadeus_send_window_closed` and `amadeus_send_window_unconfirmed`,
33
+ // `secure_acceptance_send_window_closed` and `secure_acceptance_send_window_unconfirmed`, or
34
+ // `wix_payments_send_window_closed` and `wix_payments_send_window_unconfirmed`.
29
35
  import { amadeusCardUrl } from './amadeus-checkout.generated.js';
30
36
  import { isSecureAcceptanceTokenRequest } from './cybersource-secure-acceptance.generated.js';
31
37
  import { SECURE_ACCEPTANCE_PSP, SECURE_ACCEPTANCE_SEND_WINDOW_MS } from './cybersource-secure-acceptance.js';
38
+ import { WIX_PAYMENTS_PSP, isWixPaymentsTokenizeUrl } from './wix-payments.generated.js';
32
39
  /** How long after the pause a paused Amadeus SDK add may still be sent. */
33
40
  export const AMADEUS_SEND_WINDOW_MS = 20_000;
41
+ /** How long after the pause a paused Wix tokenize request may still be sent, of the 30 seconds Wix's widget waits. */
42
+ export const WIX_PAYMENTS_SEND_WINDOW_MS = 20_000;
34
43
  /**
35
44
  * True when a request the adapters refuse must fail as a network error (ERR_FAILED) rather than as
36
45
  * the cancellation (ERR_ABORTED) they use elsewhere. An XMLHttpRequest reports a cancellation only
@@ -43,7 +52,8 @@ export function failsAsNetworkError(url) {
43
52
  }
44
53
  /**
45
54
  * The send window for a request paused under a preparation for `psp`, or null when it has none: a
46
- * prepared Amadeus SDK add, and a prepared CyberSource Secure Acceptance token create, each 20 seconds.
55
+ * prepared Amadeus SDK add, a prepared CyberSource Secure Acceptance token create and a prepared Wix
56
+ * tokenize request, each 20 seconds.
47
57
  */
48
58
  export function preparedSendWindowMs(psp, url) {
49
59
  if (psp === 'amadeus_checkout')
@@ -58,10 +68,14 @@ export function preparedSendWindowMs(psp, url) {
58
68
  }
59
69
  return tokenCreate ? SECURE_ACCEPTANCE_SEND_WINDOW_MS : null;
60
70
  }
71
+ if (psp === WIX_PAYMENTS_PSP)
72
+ return isWixPaymentsTokenizeUrl(url) ? WIX_PAYMENTS_SEND_WINDOW_MS : null;
61
73
  return null;
62
74
  }
63
75
  /** The processor a prepared request's send window names in its events, or null when it has none. */
64
76
  export function sendWindowProcessor(psp) {
77
+ if (psp === WIX_PAYMENTS_PSP)
78
+ return 'wix_payments';
65
79
  return psp === 'amadeus_checkout' ? 'amadeus' : psp === SECURE_ACCEPTANCE_PSP ? 'secure_acceptance' : null;
66
80
  }
67
81
  /** The send window for a prepared Amadeus SDK add, or null: preparedSendWindowMs for Amadeus alone. */
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
2
  // Generated from @agent-cards/payment-core. Do not edit.
3
- // artifact-sha256: 0fd8db3c00fa0c1aea085fd184efe4b3ebc67c57673b69d2daec5a912991e181
3
+ // artifact-sha256: d16bc471bdb814eb3e7b9da3834c9cbb5b1db7089ce91d3bbfb2215f81c1958d
4
4
  // src/card-number-key.js
5
5
  var CARD_NUMBER_KEY = /^(number|card_number|cardnumber|cardNum|card_num|pan)$/i;
6
6
  // src/json-path.js
@@ -658,10 +658,10 @@ var TYPED_ARRAY = Object.getPrototypeOf(Uint8Array.prototype);
658
658
  var typedArrayName = Object.getOwnPropertyDescriptor(TYPED_ARRAY, Symbol.toStringTag).get;
659
659
  function parseRsaPublicKey(key) {
660
660
  const spki = key && typeof key === "object" ? key.spki : void 0;
661
- const pin3 = key && typeof key === "object" ? key.sha256 : void 0;
661
+ const pin4 = key && typeof key === "object" ? key.sha256 : void 0;
662
662
  if (typeof spki !== "string" || spki.length > 1024 || spki.length % 4 !== 0 || !BASE64.test(spki))
663
663
  throw refuse6("key");
664
- if (typeof pin3 !== "string" || !SHA256_HEX.test(pin3))
664
+ if (typeof pin4 !== "string" || !SHA256_HEX.test(pin4))
665
665
  throw refuse6("key");
666
666
  let binary;
667
667
  try {
@@ -673,7 +673,7 @@ function parseRsaPublicKey(key) {
673
673
  if (btoa(binary) !== spki)
674
674
  throw refuse6("key");
675
675
  const der = Uint8Array.from(binary, (c) => c.charCodeAt(0));
676
- if (sha256Hex(der) !== pin3)
676
+ if (sha256Hex(der) !== pin4)
677
677
  throw refuse6("key");
678
678
  const outer = readElement(der, 0, 48);
679
679
  if (outer.end !== der.length || outer.start + RSA_ALGORITHM.length > der.length)
@@ -1233,10 +1233,93 @@ var LYRA_MERCHANT_PINS = /* @__PURE__ */ Object.freeze([
1233
1233
  hosts: Object.freeze(["api.systempay.fr"])
1234
1234
  })
1235
1235
  ]);
1236
+ // src/wix-payments.js
1237
+ var WIX_PAYMENTS_PSP = "wix_payments";
1238
+ var WIX_PAYMENTS_TOKENIZE_URL = "https://cashier-pci.wixapps.net/_api/payment-gateway-web/tokenize/v2/tokens";
1239
+ var BODY_LIMIT5 = 8192;
1240
+ var ROOT_KEYS3 = /* @__PURE__ */ Object.freeze(["cvv", "creditCard"]);
1241
+ var CARD_KEYS5 = /* @__PURE__ */ Object.freeze(["number", "expiration", "additionalInformation", "billingAddress"]);
1242
+ var EXPIRATION_KEYS = /* @__PURE__ */ Object.freeze(["month", "year"]);
1243
+ var HOLDER_KEYS = /* @__PURE__ */ Object.freeze(["holderName"]);
1244
+ var CARD_NUMBER6 = /^[0-9]{12,19}$/;
1245
+ var SECURITY_CODE5 = /^[0-9]{3,4}$/;
1246
+ var FIRST_YEAR = 2e3;
1247
+ var LAST_YEAR = 2099;
1248
+ var FIELD_NAME = /^[A-Za-z][A-Za-z0-9]{0,63}$/;
1249
+ var MAX_FIELDS = 32;
1250
+ var MAX_NESTED_FIELDS = 8;
1251
+ var TEXT_LIMIT = 256;
1252
+ var CONTROL4 = /[\u0000-\u001f\u007f]/;
1253
+ var record6 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
1254
+ var sameKeys3 = (value, keys) => {
1255
+ const own = Object.keys(value);
1256
+ return own.length === keys.length && own.every((key, at) => key === keys[at]);
1257
+ };
1258
+ var plainText = (value) => typeof value === "string" && value.length <= TEXT_LIMIT && !CONTROL4.test(value) && (value.match(/[0-9]/g) ?? []).length < 12;
1259
+ var refuse9 = (code) => Object.freeze({ verdict: "refuse", code });
1260
+ var CARD8 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
1261
+ function isWixPaymentsTokenizeUrl(url) {
1262
+ return url === WIX_PAYMENTS_TOKENIZE_URL;
1263
+ }
1264
+ function readBody3(body) {
1265
+ if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT5)
1266
+ return null;
1267
+ let value;
1268
+ try {
1269
+ value = JSON.parse(body);
1270
+ if (!record6(value) || JSON.stringify(value) !== body)
1271
+ return null;
1272
+ }
1273
+ catch {
1274
+ return null;
1275
+ }
1276
+ return value;
1277
+ }
1278
+ var billingText = (value) => value === null || plainText(value);
1279
+ function billingFields(value) {
1280
+ if (!record6(value))
1281
+ return false;
1282
+ const names = Object.keys(value);
1283
+ if (names.length > MAX_FIELDS)
1284
+ return false;
1285
+ return names.every((name) => {
1286
+ const field = value[name];
1287
+ if (!FIELD_NAME.test(name))
1288
+ return false;
1289
+ if (!record6(field))
1290
+ return billingText(field);
1291
+ const nested = Object.keys(field);
1292
+ return nested.length <= MAX_NESTED_FIELDS && nested.every((key) => FIELD_NAME.test(key) && billingText(field[key]));
1293
+ });
1294
+ }
1295
+ function wixPaymentsBodyVerdict(body) {
1296
+ const value = readBody3(body);
1297
+ if (value === null || !sameKeys3(value, ROOT_KEYS3) || !record6(value.creditCard) || !sameKeys3(value.creditCard, CARD_KEYS5)) {
1298
+ return refuse9("wix_payments_body_unsupported");
1299
+ }
1300
+ const card = value.creditCard;
1301
+ const expiration = card.expiration;
1302
+ const holder = card.additionalInformation;
1303
+ if (typeof value.cvv !== "string" || !SECURITY_CODE5.test(value.cvv) || typeof card.number !== "string" || !CARD_NUMBER6.test(card.number) || !record6(expiration) || !sameKeys3(expiration, EXPIRATION_KEYS) || !Number.isInteger(expiration.month) || expiration.month < 1 || expiration.month > 12 || !Number.isInteger(expiration.year) || expiration.year < FIRST_YEAR || expiration.year > LAST_YEAR || !record6(holder) || !sameKeys3(holder, HOLDER_KEYS) || !plainText(holder.holderName) || !billingFields(card.billingAddress)) {
1304
+ return refuse9("wix_payments_body_unsupported");
1305
+ }
1306
+ return CARD8;
1307
+ }
1308
+ var pin3 = (fields) => Object.freeze({ ...fields, origins: Object.freeze([...fields.origins]) });
1309
+ var WIX_PAYMENTS_MERCHANT_PINS = /* @__PURE__ */ Object.freeze([
1310
+ pin3({ id: "parahouse_magazine", merchant: "ParaHouse Magazine", origins: ["https://www.parahousemagazine.com"] }),
1311
+ pin3({ id: "psalms_and_potions", merchant: "Psalms & Potions", origins: ["https://www.psalmsandpotions.com"] }),
1312
+ pin3({ id: "alexandra_hagel", merchant: "Alexandra Hagel, LLC", origins: ["https://www.alexandrahagel.com"] })
1313
+ ]);
1236
1314
  // src/card-fields.js
1237
1315
  function processorGate(recognizer, url, body) {
1238
1316
  if (recognizer && recognizer.psp === LYRA_PSP)
1239
1317
  return lyraBodyVerdict(body, url);
1318
+ if (recognizer && recognizer.psp === WIX_PAYMENTS_PSP) {
1319
+ if (url !== void 0 && !isWixPaymentsTokenizeUrl(url))
1320
+ return { verdict: "refuse", code: "wix_payments_url_refused" };
1321
+ return wixPaymentsBodyVerdict(body);
1322
+ }
1240
1323
  if (recognizer && recognizer.psp === PADDLE_VGS_PSP) {
1241
1324
  if (url !== void 0 && !isPaddleVgsCardsUrl(url))
1242
1325
  return { verdict: "refuse", code: "paddle_vgs_url_refused" };
package/dist/cdp.js CHANGED
@@ -19,6 +19,7 @@ import { isArmedEkashuUrl } from './ekashu.js';
19
19
  import { isArmedRedsysUrl } from './redsys.js';
20
20
  import { PAYPAL_HOSTED_FIELDS_PATTERNS, isPaypalHostedFieldsConfirm } from './paypal-hosted-fields.js';
21
21
  import { EBANX_RESEND_PATTERNS, EbanxFollowUps, isEbanxResendUrl } from './ebanx.js';
22
+ import { PAYPAL_CARD_FORM_PATTERNS, isPaypalCardFormUrl } from './paypal-card-forms.js';
22
23
  import { CYBERSOURCE_SECURE_ACCEPTANCE_PATTERNS, CYBERSOURCE_SECURE_ACCEPTANCE_RECIPIENT, SecureAcceptanceFollowUpWatch, isCybersourceSecureAcceptanceUrl, secureAcceptanceFollowUp, secureAcceptanceFrameAnswer, secureAcceptanceReplyLast4, } from './cybersource-secure-acceptance.js';
23
24
  import { CheckoutAttachmentError, attachmentDeadline, attachmentFailure, withinAttachmentDeadline } from './attachment.js';
24
25
  import { cseBody } from './cse-body.js';
@@ -1382,11 +1383,12 @@ function merchantAttempt(lifecycle, survives) {
1382
1383
  let rebound = false;
1383
1384
  let delivering = false;
1384
1385
  let bound = null;
1385
- // A send window (an Amadeus SDK add's, a Secure Acceptance token create's) closes only once the API
1386
- // confirms the card never left the device and never can (amadeus.ts): a known non-payment, so the
1387
- // prepared checkout ends failed with that reason, and a fresh attachment can prepare again. Every
1388
- // 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.
1389
1390
  const error = () => reason === 'amadeus_send_window_closed' || reason === 'secure_acceptance_send_window_closed'
1391
+ || reason === 'wix_payments_send_window_closed'
1390
1392
  ? new CheckoutPreparationError(lifecycle.getState().preparationId ?? null, reason)
1391
1393
  : new PaymentOutcomeUnknownError(lifecycle.getState().authorizationId, reason);
1392
1394
  const attempt = {
@@ -1616,8 +1618,8 @@ function pauseForBusiness(opts, lifecycle, attemptSignal, request, pageOrigin) {
1616
1618
  }
1617
1619
  /**
1618
1620
  * Arm the send window of a request paused under a preparation, when its processor sets one: a
1619
- * prepared Amadeus SDK add and a prepared Secure Acceptance token create do (amadeus.ts
1620
- * 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()
1621
1623
  * cleared the authorization ID, so the one the window reads is this attempt's.
1622
1624
  */
1623
1625
  function armWindowFor(opts, lifecycle, attempt, preparation, url, delivering) {
@@ -2060,6 +2062,10 @@ export async function attachToCdp(cdp, pageSessionId, opts) {
2060
2062
  // PayPal's legacy Hosted Fields confirm is armed for every org, whatever the
2061
2063
  // registry serves: one that carries the typed card is paused only to be
2062
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).
2063
2069
  // CyberSource Secure Acceptance's /silent/ paths are armed the same way, form
2064
2070
  // navigations included (see cybersource-secure-acceptance.ts), and so are
2065
2071
  // EBANX's 3-D Secure calls and hosted confirm, which send the typed card again
@@ -2068,8 +2074,8 @@ export async function attachToCdp(cdp, pageSessionId, opts) {
2068
2074
  const urlPatterns = [...new Set([...(derived.length > 0 ? derived : FALLBACK_CARD_PATTERNS), ...guards.patterns,
2069
2075
  ...(stripeCheckout.isEnabled() ? ['https://api.stripe.com/*'] : []), MERCADO_CHECKOUT_PATTERN, ...merchantPatterns,
2070
2076
  ...(recognizesGmo(opts.vault) ? GMO_TOKEN_V1_PATTERNS : []), ...juspayCheckout.urlPatterns(), ...cardEndpointPatterns(),
2071
- ...(payrails ? PAYRAILS_GUARD_PATTERNS : []), ...PAYPAL_HOSTED_FIELDS_PATTERNS, ...CYBERSOURCE_SECURE_ACCEPTANCE_PATTERNS,
2072
- ...(recognizesPaddleVgs(opts.vault) ? PADDLE_VGS_PAY_PATTERNS : []), ...EBANX_RESEND_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])];
2073
2079
  const arm = async (sessionId, resume = false, worker = false) => {
2074
2080
  const key = sessionId ?? '__root__';
2075
2081
  if (armed.has(key))
@@ -3450,6 +3456,8 @@ export async function attachToPlaywright(page, opts) {
3450
3456
  || isArmedRedsysUrl(opts.vault, url.toString())
3451
3457
  // PayPal's legacy Hosted Fields confirm, for every org, as attachToCdp arms it (paypal-hosted-fields.ts).
3452
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())
3453
3461
  // CyberSource Secure Acceptance's /silent/ paths, for every org, as attachToCdp arms them (cybersource-secure-acceptance.ts).
3454
3462
  || isCybersourceSecureAcceptanceUrl(url.toString())
3455
3463
  // Paddle's checkout services, routed only for an org the API served Paddle VGS to (see attachToCdp).
package/dist/client.d.ts CHANGED
@@ -241,6 +241,14 @@ export declare const SUPPORTED_REGISTRY_FEATURES: readonly string[];
241
241
  * card tab then runs in the agent's browser. The cardholder's device sends the card through the
242
242
  * checkout relay. Served on the same terms: only to a build that lists it, for a company
243
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.
244
252
  */
245
253
  export declare const SUPPORTED_CAPABILITIES: readonly string[];
246
254
  /**
@@ -1164,6 +1172,8 @@ export declare class CheckoutAuthError extends Error {
1164
1172
  * On Redsys's hosts the session id after `;jsessionid=` reads `{session}`:
1165
1173
  * https://sis.redsys.es/sis/pagoTarjeta;jsessionid={session}.
1166
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.
1167
1177
  * A string that is not a URL keeps the part before any `?` or `#`, with the
1168
1178
  * same segments masked.
1169
1179
  */
package/dist/client.js CHANGED
@@ -16,6 +16,7 @@ import { SHIJI_STS_CAPABILITY, SHIJI_STS_PSP, isShijiStsServedCompanion, isShiji
16
16
  import { AMADEUS_CHECKOUT_CAPABILITY, AMADEUS_CHECKOUT_PSP } from './amadeus-checkout.generated.js';
17
17
  import { PADDLE_VGS_CAPABILITY, PADDLE_VGS_PSP, paddleVgsCardFactsOf } from './paddle-vgs.generated.js';
18
18
  import { PADDLE_TOKENEX_CAPABILITY, PADDLE_TOKENEX_PSP, isPaddleTokenexServedFacts, isPaddleTokenexServedSubstitution } from './paddle-tokenex.js';
19
+ import { WIX_PAYMENTS_CAPABILITY, WIX_PAYMENTS_PSP } from './wix-payments.generated.js';
19
20
  import { classifyStripeCheckoutRequest, encodeStripeCheckoutContext, hasStripeCheckoutMarker, parseStripeCheckoutContext, parseStripeCheckoutResponse, STRIPE_CHECKOUT_CONTEXT_HEADER, } from './stripe-checkout.generated.js';
20
21
  import { VoiceModule } from './voice.js';
21
22
  import { BuyModule } from './buy.js';
@@ -224,9 +225,17 @@ export const SUPPORTED_REGISTRY_FEATURES = ['card_fields', 'checkout_sessions'];
224
225
  * card tab then runs in the agent's browser. The cardholder's device sends the card through the
225
226
  * checkout relay. Served on the same terms: only to a build that lists it, for a company
226
227
  * Agentcard turned Payfast on for.
228
+ *
229
+ * `wix_payments_tokenize`: the card request Wix Cashier's card frame sends to Wix's
230
+ * tokenizer (cashier-pci.wixapps.net), only through a prepared checkout: Wix's payment
231
+ * widget fails the payment 30 seconds after it asks the frame for a token. The
232
+ * cardholder's device sends the card through the checkout relay and the frame gets back
233
+ * Wix's token. A second card request from the frame, which Wix's frame sends after a 401
234
+ * or 403 under a fresh instance, is never answered from the same approval. Served on the
235
+ * same terms: only to a build that lists it, for a company Agentcard turned Wix on for.
227
236
  */
228
237
  export const SUPPORTED_CAPABILITIES = ['fiserv_card_capture', GMO_CAPABILITY, CYBERSOURCE_FLEX_CAPABILITY, JUSPAY_CAPABILITY, DATATRANS_CAPABILITY, 'authorize_net_dpm_form', PELECARD_CAPABILITY, ACI_CAPABILITY, 'creditguard_pps_process', PRIMER_CAPABILITY, PAYRAILS_CAPABILITY, CONVERGE_CAPABILITY, EPROTECT_CAPABILITY, WSPAY_CAPABILITY, SHIJI_STS_CAPABILITY, AMADEUS_CHECKOUT_CAPABILITY, 'worldline_mycheckout_form', 'verifone_card_capture', 'ekashu_hosted_payment_page', SECURE_ACCEPTANCE_CAPABILITY, 'gravy_session_fields_put', 'moneris_hosted_tokenization', PADDLE_VGS_CAPABILITY, PADDLE_TOKENEX_CAPABILITY,
229
- 'redsys_hosted_payment_page', 'lyra_krypton_payment', 'payfast_card_pay'];
238
+ 'redsys_hosted_payment_page', 'lyra_krypton_payment', 'payfast_card_pay', WIX_PAYMENTS_CAPABILITY];
230
239
  /**
231
240
  * Processors whose paused request names no amount at all, so the pair the
232
241
  * agent passes is the amount the cardholder approves: authorize() refuses one
@@ -252,14 +261,16 @@ export const SUPPORTED_CAPABILITIES = ['fiserv_card_capture', GMO_CAPABILITY, CY
252
261
  * which the prepared checkout carries, is the total the cardholder approves. Payfast's
253
262
  * card pay carries none either: the merchant's entry bound the total to the payment,
254
263
  * so the agent sends the total Payfast's page shows, above zero (PAYFAST_PSP below),
255
- * and the API holds it to the payment Payfast itself reports.
264
+ * and the API holds it to the payment Payfast itself reports. Wix's tokenize request
265
+ * carries none either: the merchant's page charges Wix's token for its own order, so the
266
+ * agent's pair, which the prepared checkout carries, is the total the cardholder approves.
256
267
  */
257
268
  const MONERIS_PSP = 'moneris';
258
269
  const PAYFAST_PSP = 'payfast';
259
- const AGENT_AMOUNT_PROCESSORS = [GMO_PSP, PELECARD_PSP, WSPAY_PSP, SECURE_ACCEPTANCE_PSP, MONERIS_PSP, PADDLE_VGS_PSP, PAYFAST_PSP];
270
+ const AGENT_AMOUNT_PROCESSORS = [GMO_PSP, PELECARD_PSP, WSPAY_PSP, SECURE_ACCEPTANCE_PSP, MONERIS_PSP, PADDLE_VGS_PSP, PAYFAST_PSP, WIX_PAYMENTS_PSP];
260
271
  /** How AmountRequiredError names a processor. */
261
272
  const PROCESSOR_NAMES = { [GMO_PSP]: 'GMO', [PELECARD_PSP]: 'Pelecard', [WSPAY_PSP]: 'WSPay',
262
- [SECURE_ACCEPTANCE_PSP]: 'CyberSource Secure Acceptance', [MONERIS_PSP]: 'Moneris', [PADDLE_VGS_PSP]: 'Paddle', [PAYFAST_PSP]: 'Payfast' };
273
+ [SECURE_ACCEPTANCE_PSP]: 'CyberSource Secure Acceptance', [MONERIS_PSP]: 'Moneris', [PADDLE_VGS_PSP]: 'Paddle', [PAYFAST_PSP]: 'Payfast', [WIX_PAYMENTS_PSP]: 'Wix' };
263
274
  /**
264
275
  * Processors whose request and answer name no amount at all, so the total the
265
276
  * payment page shows (`pageAmount`) is the one figure that ties the agent's pair
@@ -1108,6 +1119,17 @@ const REDSYS_SESSION = /((?:;|%3b)jsessionid(?:=|%3d))[^/?#;]*/gi;
1108
1119
  function maskRedsysSession(path) {
1109
1120
  return path.replace(REDSYS_SESSION, '$1{session}');
1110
1121
  }
1122
+ /**
1123
+ * A PayPal order id opens PayPal's own checkout page for that order (/checkoutnow?token=<order id>) to
1124
+ * anyone who holds it, and PayPal's card confirms carry it in the path:
1125
+ * /v2/checkout/orders/<order id>/confirm-payment-source on www, api-m and cors.api. On PayPal's hosts the
1126
+ * segment after /orders/, in any case or after an escaped slash, reads {order}.
1127
+ */
1128
+ const PAYPAL_HOST = /(?:^|\.)paypal\.com\.?$/i;
1129
+ const PAYPAL_ORDER = /(\/orders(?:\/|%2f))[^/]*/gi;
1130
+ function maskPaypalOrder(path) {
1131
+ return path.replace(PAYPAL_ORDER, '$1{order}');
1132
+ }
1111
1133
  const PATH_CREDENTIALS = [
1112
1134
  { host: CREDITGUARD_HOST, named: /creditguard\.co\.il/i, mask: maskCreditguardTxId },
1113
1135
  { host: GRAVY_HOST, named: /gr4vy\.app/i, mask: maskGravySession },
@@ -1118,6 +1140,7 @@ const PATH_CREDENTIALS = [
1118
1140
  { host: PADDLE_CHECKOUT_HOST, named: /checkout-service\.paddle\.com/i, mask: maskPaddleCheckout },
1119
1141
  { host: REDSYS_HOST, named: /redsys\.es/i, mask: maskRedsysSession },
1120
1142
  { host: LYRA_HOST, named: /(?:payzen\.eu|systempay\.fr|societegenerale\.eu|lyra\.com)/i, mask: maskLyraSession },
1143
+ { host: PAYPAL_HOST, named: /paypal\.com/i, mask: maskPaypalOrder },
1121
1144
  ];
1122
1145
  /**
1123
1146
  * A URL as it may appear in an error message: origin + path only. A paused
@@ -1138,6 +1161,8 @@ const PATH_CREDENTIALS = [
1138
1161
  * On Redsys's hosts the session id after `;jsessionid=` reads `{session}`:
1139
1162
  * https://sis.redsys.es/sis/pagoTarjeta;jsessionid={session}.
1140
1163
  * On Lyra's API hosts the form token's session id reads `{session}`.
1164
+ * On PayPal's hosts an order id reads `{order}`:
1165
+ * https://www.paypal.com/v2/checkout/orders/{order}/confirm-payment-source.
1141
1166
  * A string that is not a URL keeps the part before any `?` or `#`, with the
1142
1167
  * same segments masked.
1143
1168
  */
@@ -1226,17 +1251,26 @@ const SECURE_ACCEPTANCE_PREPARATION_REFUSALS = [
1226
1251
  const PADDLE_VGS_PREPARATION_REFUSALS = [
1227
1252
  'processor_unavailable', 'sandbox_host_on_live_row', 'live_host_on_sandbox_row', 'merchant_profile_mismatch', 'paddle_vgs_card_unsupported',
1228
1253
  ];
1254
+ /**
1255
+ * The API's refusals of a Wix Payments preparation, before any preparation exists, that prepareCheckout
1256
+ * surfaces by name: the lane is held to Agentcard's own account (`processor_unavailable`), a test client
1257
+ * asked for it (`live_host_on_sandbox_row`: Wix has no test environment), and a checkout's merchant is not
1258
+ * the name the reviewed store pin carries (`merchant_profile_mismatch`). An unreviewed store answers
1259
+ * `unsupported_checkout`, which PREPARATION_REFUSALS names for every checkout. Only for a Wix checkout.
1260
+ */
1261
+ const WIX_PAYMENTS_PREPARATION_REFUSALS = ['processor_unavailable', 'live_host_on_sandbox_row', 'merchant_profile_mismatch'];
1229
1262
  /**
1230
1263
  * The reason the cardholder's device declines a bound prepared row with, per processor, when its own
1231
1264
  * send boundary passed before the card left it (the Vault's sendWindow, 12 seconds after it last saw
1232
- * the checkout unbound): a prepared Amadeus SDK add and a prepared Secure Acceptance token create. It
1233
- * names the same known non-payment the adapters' own send window closes on (amadeus.ts), which can
1234
- * close later, so authorize() ends the attempt the way that window does, as a CheckoutPreparationError
1235
- * with that reason, and never as the cardholder's "no".
1265
+ * the checkout unbound): a prepared Amadeus SDK add, a prepared Secure Acceptance token create and a
1266
+ * prepared Wix tokenize request. It names the same known non-payment the adapters' own send window
1267
+ * closes on (amadeus.ts), which can close later, so authorize() ends the attempt the way that window
1268
+ * does, as a CheckoutPreparationError with that reason, and never as the cardholder's "no".
1236
1269
  */
1237
1270
  const PREPARED_SEND_WINDOW_DECLINES = Object.freeze({
1238
1271
  amadeus_checkout: 'amadeus_send_window_closed',
1239
1272
  [SECURE_ACCEPTANCE_PSP]: 'secure_acceptance_send_window_closed',
1273
+ [WIX_PAYMENTS_PSP]: 'wix_payments_send_window_closed',
1240
1274
  });
1241
1275
  /**
1242
1276
  * Refusals a CyberSource Flex preparation that tokenizes before Pay answers (4xx) before any
@@ -1918,6 +1952,7 @@ export class VaultClient {
1918
1952
  || (input.psp === 'fiserv' && FISERV_PREPARATION_REFUSALS.includes(error.code))
1919
1953
  || (input.psp === EPROTECT_PSP && EPROTECT_PREPARATION_REFUSALS.includes(error.code))
1920
1954
  || (input.psp === PADDLE_VGS_PSP && PADDLE_VGS_PREPARATION_REFUSALS.includes(error.code))
1955
+ || (input.psp === WIX_PAYMENTS_PSP && WIX_PAYMENTS_PREPARATION_REFUSALS.includes(error.code))
1921
1956
  || (!!flexContext && CYBERSOURCE_FLEX_PREPARATION_REFUSALS.includes(error.code))))
1922
1957
  || (input.psp === 'fiserv' && error.status === 502 && error.code === 'cse_key_unavailable')))
1923
1958
  throw fail(error.code);
@@ -5,6 +5,7 @@ import type { Substitutions } from './substitute.js';
5
5
  import type { GmoUnsupportedReason } from './gmo.js';
6
6
  import type { ShijiStsUnsupportedReason } from './shiji-sts.js';
7
7
  import type { PaddleVgsPayRefusal } from './paddle-vgs-pay.js';
8
+ import type { PaypalCardFormReason } from './paypal-card-forms.js';
8
9
  /** The application's resolver confirmed the payment for this checkout authorization. */
9
10
  export interface MerchantPaymentConfirmation {
10
11
  kind: 'merchant_payment';
@@ -263,6 +264,9 @@ export declare class CheckoutLifecycle implements CheckoutController {
263
264
  * the cardholder's device can fill (processor_card_page: NMI's), a card
264
265
  * sent to PayPal's legacy Hosted Fields confirm, which no Vault mode takes
265
266
  * over (unsupported_paypal_hosted_fields, paypal-hosted-fields.ts), a card
267
+ * sent through PayPal's Card Fields with no recognizer to pay it, or through
268
+ * PayPal's guest card form (unsupported_paypal_card_fields and
269
+ * unsupported_paypal_guest_checkout, paypal-card-forms.ts), or a card
266
270
  * a merchant's page posts to CyberSource Secure Acceptance's Silent Order
267
271
  * POST, which no Vault mode takes over either
268
272
  * (unsupported_cybersource_secure_acceptance, cybersource-secure-acceptance.ts), a
@@ -273,7 +277,7 @@ export declare class CheckoutLifecycle implements CheckoutController {
273
277
  * send it (unsupported_ebanx_card_resend, ebanx.ts): once an approval exists the
274
278
  * state keeps it, and only the hold changes.
275
279
  */
276
- 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' | 'unsupported_cybersource_secure_acceptance' | PaddleVgsPayRefusal | 'unsupported_ebanx_card_resend'): void;
280
+ 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;
277
281
  /**
278
282
  * A card request that only a prepared checkout pays (an Adyen merchant
279
283
  * profile's, or a Fiserv card capture) arrived with no preparation on this
package/dist/lifecycle.js CHANGED
@@ -263,6 +263,9 @@ export class CheckoutLifecycle {
263
263
  * the cardholder's device can fill (processor_card_page: NMI's), a card
264
264
  * sent to PayPal's legacy Hosted Fields confirm, which no Vault mode takes
265
265
  * over (unsupported_paypal_hosted_fields, paypal-hosted-fields.ts), a card
266
+ * sent through PayPal's Card Fields with no recognizer to pay it, or through
267
+ * PayPal's guest card form (unsupported_paypal_card_fields and
268
+ * unsupported_paypal_guest_checkout, paypal-card-forms.ts), or a card
266
269
  * a merchant's page posts to CyberSource Secure Acceptance's Silent Order
267
270
  * POST, which no Vault mode takes over either
268
271
  * (unsupported_cybersource_secure_acceptance, cybersource-secure-acceptance.ts), a
@@ -0,0 +1,73 @@
1
+ /**
2
+ * PayPal's Card Fields and PayPal's guest card form, which this SDK refuses for every company until a
3
+ * synced recognizer takes the request.
4
+ *
5
+ * Read 2026-10-15 from PayPal's public bundles and card-free page reads (WooCommerce PayPal Payments
6
+ * 4.1.3 checkouts on PayPal JS SDK 5.0.582, card-field client 1.270.0; web-sdk v6 6.68.0):
7
+ *
8
+ * Card Fields v5 (components=card-fields): each field is a frame on www.paypal.com/smart/card-field,
9
+ * and at submit the number frame sends the typed card as plaintext JSON, a same-origin XHR:
10
+ * POST https://www.paypal.com/v2/checkout/orders/<order id>/confirm-payment-source
11
+ * {"payment_source":{"card":{"number","expiry":"YYYY-MM","security_code","name"?,"billing_address"?}}}
12
+ * Card Fields v6 (web-sdk v6): the same request, sent to api-m.paypal.com.
13
+ * Card Fields saving a card with no purchase: POST https://www.paypal.com/graphql?UpdateVaultSetupToken,
14
+ * the card at variables.paymentSource.card.
15
+ * PayPal's guest card form, behind the black "Debit or Credit Card" button: PayPal's checkout page
16
+ * sends the card as POST https://www.paypal.com/graphql?OnboardGuestMutation, the number at
17
+ * variables.card.cardNumber.
18
+ * PayPal's sandbox serves each on www.sandbox.paypal.com and api-m.sandbox.paypal.com.
19
+ *
20
+ * An SDK without this guard let the agent's placeholder card reach PayPal there, and PayPal declined it.
21
+ * Both adapters arm these paths whatever the synced registry serves, and the pre-claim gate
22
+ * (paypalCardFormsPreClaim, pre-claim.ts) judges each POST:
23
+ * - a Card Fields confirm whose body carries a number at payment_source.card.number aborts, reason
24
+ * `unsupported_paypal_card_fields`, unless the synced registry recognizes it as a card request: an
25
+ * org Agentcard turned PayPal Card Fields on for pauses and pays that confirm through the recognizer,
26
+ * which judges the body itself;
27
+ * - a GraphQL operation carrying a card aborts whatever the registry serves, since no recognizer pays
28
+ * one: the guest form's card as `unsupported_paypal_guest_checkout`, a card saved with no purchase as
29
+ * `unsupported_paypal_card_fields`;
30
+ * - a body with no card (a PayPal wallet confirm, a saved card, every other GraphQL operation the
31
+ * buttons send) continues untouched;
32
+ * - a confirm the adapter could not read aborts that request alone, since nothing proves it carries no
33
+ * card. A GraphQL post it could not read aborts only when its query names one of the two card
34
+ * operations: PayPal's buttons send many others, and failing them would break PayPal's own wallet.
35
+ * Each abort holds the attachment as every unsupported refusal does: the page's next submit would carry
36
+ * the card again, so another way to pay needs a new attachment.
37
+ *
38
+ * A guest form PayPal opens in a popup window runs in another page, which an attachment covers only when
39
+ * the agent attaches the SDK to that page as well. PayPal's BIN lookup (/v2/payments/find-bin-details)
40
+ * reads the first digits the agent types and pays nothing; neither adapter intercepts it.
41
+ */
42
+ import { paypalHostedFieldsBody } from './paypal-hosted-fields.js';
43
+ export declare const PAYPAL_CARD_FIELDS_REASON: "unsupported_paypal_card_fields";
44
+ export declare const PAYPAL_GUEST_CHECKOUT_REASON: "unsupported_paypal_guest_checkout";
45
+ export type PaypalCardFormReason = typeof PAYPAL_CARD_FIELDS_REASON | typeof PAYPAL_GUEST_CHECKOUT_REASON;
46
+ /** The hosts Card Fields sends its confirm to: v5 on www, v6 on api-m, live and sandbox. */
47
+ export declare const PAYPAL_CARD_FIELDS_HOSTS: readonly string[];
48
+ /** The hosts of PayPal's own pages, whose GraphQL endpoint takes the guest form's card and a card saved with no purchase. */
49
+ export declare const PAYPAL_GRAPHQL_HOSTS: readonly string[];
50
+ /**
51
+ * CDP Fetch patterns, armed on every attachment: the confirm on its four hosts and GraphQL on PayPal's
52
+ * two page hosts. Chrome sends the canonical URL, whose host is lower case, and the trailing `*` keeps a
53
+ * query or a trailing slash paused. Nothing else on www.paypal.com is armed.
54
+ */
55
+ export declare const PAYPAL_CARD_FORM_PATTERNS: readonly string[];
56
+ /** Whether this URL is the Card Fields confirm on one of its four hosts (https, standard port, no credentials). */
57
+ export declare function isPaypalCardFieldsConfirm(url: string): boolean;
58
+ /** Whether this URL is GraphQL on one of PayPal's two page hosts. */
59
+ export declare function isPaypalGraphql(url: string): boolean;
60
+ /** Whether this URL is any request the guard judges, for the Playwright route's predicate. */
61
+ export declare function isPaypalCardFormUrl(url: string): boolean;
62
+ /** Whether a GraphQL URL's query names one of the two card operations (`/graphql?OnboardGuestMutation`). */
63
+ export declare function paypalGraphqlNamesCardOperation(url: string): boolean;
64
+ /**
65
+ * What a GraphQL post carries, read as PayPal reads it (the last of a repeated key wins in both), for one
66
+ * operation or a batch of them: 'guest_card' when an operation's variables.card.cardNumber holds anything
67
+ * but null or an empty string, 'saved_card' when an operation's variables.paymentSource.card is an object,
68
+ * 'no_card' for any other JSON object or array of them, and 'unreadable' for a body the adapter could not
69
+ * read (null), an empty one, or one that is neither.
70
+ */
71
+ export declare function paypalGraphqlCard(body: string | null): 'guest_card' | 'saved_card' | 'no_card' | 'unreadable';
72
+ /** What a Card Fields confirm carries: its body is the Orders v2 shape Hosted Fields also sends. */
73
+ export declare const paypalCardFieldsBody: typeof paypalHostedFieldsBody;