@agent-cards/sdk 0.23.11 → 0.23.13
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 +12 -0
- package/LICENSE +38 -0
- package/PREFLIGHT.md +2 -0
- package/README.md +9 -7
- package/dist/builtin-registry.generated.js +1 -1
- package/dist/card-fields.generated.js +74 -1
- package/dist/cdp.js +63 -10
- package/dist/client.d.ts +24 -7
- package/dist/client.js +135 -16
- package/dist/lifecycle.d.ts +11 -2
- package/dist/lifecycle.js +4 -1
- package/dist/paddle-vgs-pay.d.ts +55 -0
- package/dist/paddle-vgs-pay.js +115 -0
- package/dist/paddle-vgs.generated.d.ts +78 -0
- package/dist/paddle-vgs.generated.js +408 -0
- package/dist/payrails.generated.js +8 -12
- package/dist/paysafe.generated.d.ts +5 -7
- package/dist/paysafe.generated.js +50 -18
- package/dist/pre-claim.d.ts +8 -0
- package/dist/pre-claim.js +48 -1
- package/dist/prepared-processor.d.ts +12 -4
- package/dist/prepared-processor.js +17 -5
- package/dist/primer.generated.js +90 -17
- package/dist/stripe-checkout.generated.js +64 -3
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
- 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.
|
|
6
|
+
|
|
7
|
+
- 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.
|
|
8
|
+
|
|
9
|
+
- Keep a Gravy checkout session out of your events and error messages. Gravy's Secure Fields send the card to `/checkout/sessions/<session id>/fields` on the merchant's Gravy host with no auth header, so the session id is the only credential that request needs: anyone who holds it can write card fields into the session until it expires. Earlier releases named the full URL in the `card_request_paused` event and in the error `authorize()` throws for a request in the wrong method, so the session id reached your `onEvent` handler and every log that recorded the event or the error. `redactUrl`, every event and every error message now show it as `{session}`, as in `https://api.<merchant>.gr4vy.app/checkout/sessions/{session}/fields`. No API or Vault release is needed.
|
|
10
|
+
|
|
11
|
+
- Pay FlixBus's checkout on Payrails web SDK 6.7.0. FlixBus's page now loads web SDK 6.7.0 in place of 5.50.0, and 6.7.0's Pay now button sends the card-form payment without the `enrollInstrumentToNetworkOffers` member that 5.50.0 sent as `false`. 0.23.11 required that member and aborted every such payment as `unsupported_payrails_card_payment` before creating anything, so no FlixBus payment reached an approval. A payment that names no `enrollInstrumentToNetworkOffers` now pauses as 5.50.0's does: Payrails reads a missing flag as `false`, and 6.7.0 sends no other member in its place. A payment that sets the flag `true` or keeps the card (`storeInstrument: true`, or `meta.order.processingType` `CardOnFile` or `UnscheduledCardOnFile`) still aborts as `payrails_card_on_file_consent_required`, and the flag in another case, in another place or as anything but a boolean aborts as `unsupported_payrails_card_payment`. A payment also needs the matching API and Vault releases.
|
|
12
|
+
|
|
13
|
+
- Continue a Stripe card save for every company. The API judged a SetupIntent confirm after a `/v1/payment_methods` approval only for a company Agentcard had turned card-save continuations on for, and answered every other company `continuation_invalid`, so the SDK aborted the confirm and the page reported the card could not be added. Every company now gets the card save under the same rules: an approval the cardholder gave on the Vault page, not by voice, with no `amount` and no `currency`, paid with exactly the approved payment method on the same Stripe account, and a SetupIntent Stripe reports still confirmable. No SDK upgrade is needed: 0.22.0 and later continue the confirm once the API release deploys.
|
|
14
|
+
|
|
5
15
|
- Refuse a Worldline MyCheckout card submit whose card product is not the one its page chose. A MyCheckout page that offers several card products asks the shopper to choose one, then looks the typed number's IIN up with Worldline and switches the form to the product the answer names. With the agent's placeholder typed, that answer describes the placeholder: on 2026-10-12 CLZ's page read the Visa placeholder (411111) as Visa Electron (122) and switched the form from the Visa (1) the agent chose, and the cardholder's device, which checks only the card's network, would have submitted a Visa credit card as Visa Electron. Both adapters now remember the product each hosted checkout's select-payment-product step chose (that post carries no card and continues untouched) and abort a card submit that names another, before any create or prompt, with a `blocked` event, `worldline_mycheckout_product_changed`, or `worldline_mycheckout_product_missing` for one that names no product. Like the other per-request refusals it neither holds the attachment nor changes its state. A card-group page, and a hosted checkout whose choice the attachment never saw, are judged as before. `placeholderCard()` also takes `psp`, the processor whose card form the agent types into, so a processor can have its own placeholder for a network; none is set yet, so every processor still gets the network's default. Worldline stays dark for every company Agentcard has not turned it on for. No API or Vault release is needed.
|
|
6
16
|
|
|
7
17
|
- Keep a checkout's outcome when your code cancels the attachment after the checkout ended. `cancel()` rewrote every state: a checkout with an authorization or a card request in flight read `outcome_unknown` with reason `local_cancel`, and any other read `cancelled`, so an integration that cancels at cleanup lost a definite answer. On 2026-10-12 a Rapyd checkout the processor refused read `declined` (`processor_refused`) until the runner's cleanup cancel turned it into `outcome_unknown`; a `completed` checkout would have gone the same way. A checkout that reads `completed`, `declined`, `failed`, `timed_out`, `unsupported`, `cancelled` or `outcome_unknown` now keeps its status and reason through `cancel()` once no card request is in flight, or once the request in flight has its own outcome recorded, so an application that cancels from `onStateChange` or the `failed` event after a processor refusal reads `declined`. `cancel()` still stops polling, aborts any paused request and refuses every later card request, and reports no state change. A checkout still under way is unchanged, and so is one whose card request is still in flight with no outcome of its own, such as a request the page dropped mid-approval, since that authorization can still be approved on the cardholder's device: `outcome_unknown` with reason `local_cancel` once a card request is in flight or an authorization exists, `cancelled` before. No API or Vault release is needed.
|
|
@@ -88,6 +98,8 @@
|
|
|
88
98
|
|
|
89
99
|
- Read the card number on the D-EDGE card frame the way the frame groups each card network: 4-6-5 for an American Express number, 4-6-4 for a Diners Club number starting 36 or 300 to 305, and groups of four for any other. The SDK's copy of D-EDGE's rules read a grouped number only in groups of four, so an American Express or Diners Club placeholder as the frame groups it was not D-EDGE's reviewed card request, and the same number in groups of four, which the frame never posts, was. D-EDGE stays in `observe`, so its card post still gets the page that says Agentcard has not turned it on.
|
|
90
100
|
|
|
101
|
+
- Pay a Paddle checkout that sends the card to Paddle's card vault, from Agentcard's own account only for now (dark launch): Agentcard turns it on for another company once it has confirmed that a card stored for one Paddle seller cannot pay another. On a checkout whose card method names VGS, Paddle's checkout frame on `buy.paddle.com` posts the card to `https://vault.paddle.com/cards` (`https://sandbox-vault.paddle.com/cards` in test) and sends that request once more when it gets no answer within 10 seconds, too soon for an approval after Pay. So the card is paid only through `prepare({ psp: 'paddle_vgs', environment: 'production' })` (`'sandbox'` for Paddle's sandbox) on an attachment whose `cardId` names the card whose `placeholderCard()` facts you typed into Paddle's form; without one, `prepare()` fails with `card_required`, and the approval is locked to that card. The sync now also asks for `capabilities=paddle_vgs_cards`. Once the cardholder approves, the frame's request pauses, the cardholder's device sends the card to Paddle's vault itself, and the frame receives the stored card's id and nothing else; the frame's second request after its 10-second timeout, the same body under the same bearer, gets the same answer, and any other request is refused. Paddle's request names no amount, so the cardholder approves the `amount` and `currency` you pass. The lane pays Visa, Mastercard and American Express cards: `prepare()` fails with `paddle_vgs_card_unsupported` for a card on another network, and the create fails with `paddle_vgs_card_mismatch` when the expiry or placeholder you typed is not the card's. On Paddle's live vault, Agentcard pays only a seller it has reviewed, at the checkout page it reviewed (Rectangle Pro at `https://rectangleapp.com` today), and the approval names that seller and says it can keep the card on file, because the card stays stored in Paddle's vault. Paddle's own `/pay` call, which follows the stored card's id, names the card it pays by its first six and last four digits, expiry and brand, and Paddle's form reads those from the placeholder you typed. The SDK writes the approved card's own over them, the details the cardholder's device read from the card, and changes nothing else in that call. A `/pay` that names another stored card, comes from another frame, comes more than a minute after the id reached the frame, or follows the first one is aborted, and Paddle charges nothing. A Paddle checkout that sends the card through TokenEx or Spreedly is not paid. No live payment has gone through this route yet. A payment also needs the matching API and Vault releases.
|
|
102
|
+
|
|
91
103
|
## 0.23.0
|
|
92
104
|
|
|
93
105
|
### Upgrading from 0.22.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
Copyright (c) 2026 Agentcard Corporation. All rights reserved.
|
|
2
|
+
|
|
3
|
+
This software, including its source, compiled and minified code, models,
|
|
4
|
+
word lists, recognizers and data files (the "Software"), is proprietary to
|
|
5
|
+
Agentcard Corporation and is licensed, not sold.
|
|
6
|
+
|
|
7
|
+
You may install and run the Software only to use Agentcard's services, under
|
|
8
|
+
the terms you accepted when you signed up for them. If you integrate
|
|
9
|
+
Agentcard into an application, you may include the Software, unmodified and
|
|
10
|
+
as Agentcard publishes it, in that application and distribute the application
|
|
11
|
+
to your end users so they can use Agentcard's services through it; this
|
|
12
|
+
license binds every copy you distribute that way. Otherwise you may not, and
|
|
13
|
+
may not help or allow anyone else to:
|
|
14
|
+
|
|
15
|
+
1. copy, modify, translate or create derivative works of the Software, except
|
|
16
|
+
for copies made automatically when installing and running it or included
|
|
17
|
+
in an application as the paragraph above allows;
|
|
18
|
+
2. reverse engineer, decompile, disassemble, deobfuscate or otherwise try to
|
|
19
|
+
derive the source, models, thresholds, word lists, recognizers or data of
|
|
20
|
+
the Software, except to the extent applicable law expressly permits it
|
|
21
|
+
despite this restriction;
|
|
22
|
+
3. extract, scrape or reuse the Software's data, including its merchant,
|
|
23
|
+
processor and passphrase data, in any other product or service;
|
|
24
|
+
4. use the Software, or anything learned from studying it, to build, train,
|
|
25
|
+
tune or benchmark a product or service that competes with Agentcard, or to
|
|
26
|
+
defeat or imitate its security checks;
|
|
27
|
+
5. redistribute, sublicense, sell, rent or publish the Software apart from an
|
|
28
|
+
application as the paragraph above allows, or remove this notice from it.
|
|
29
|
+
|
|
30
|
+
Agentcard keeps dated fingerprints of the Software's data. A match in
|
|
31
|
+
another product or data set is evidence that it was copied from the
|
|
32
|
+
Software.
|
|
33
|
+
|
|
34
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
35
|
+
IMPLIED. IN NO EVENT SHALL AGENTCARD CORPORATION BE LIABLE FOR ANY CLAIM,
|
|
36
|
+
DAMAGES OR OTHER LIABILITY ARISING FROM THE SOFTWARE OR ITS USE.
|
|
37
|
+
|
|
38
|
+
Questions: legal@agentcard.sh
|
package/PREFLIGHT.md
CHANGED
|
@@ -205,6 +205,8 @@ Shiji STS (`shiji_sts`), the card leg of MyCheck Wallet V3 at La Quinta by Wyndh
|
|
|
205
205
|
|
|
206
206
|
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
207
|
|
|
208
|
+
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.
|
|
209
|
+
|
|
208
210
|
The bundled direct SDK profile declares processor support for `one_time` purchases. The catalog carries each processor's request limitations and known exclusions. A detection rule does not cover every product or regional variant sold under the processor's name. For example, Moneris Hosted Tokenization and Moneris Checkout use different payment paths; the implemented adapter covers Hosted Tokenization.
|
|
209
211
|
|
|
210
212
|
The catalog also carries reviewed hosted, regional, and versioned variants observed on live checkouts: Adyen secured fields on the regional live hosts and any release, the Square card element frame, dLocal Smart Fields releases, Mercado Pago secure fields and the guest Checkout Pro card form, and the Rapyd hosted checkout page. A variant the implemented adapter does not admit, such as the Tranzila terminal-root page, the Authorize.Net hosted payment form, or a Worldpay hosted payment page, identifies its processor and returns `unknown` with `processor_variant_unverified`. A new fingerprint never declares payment support by itself.
|
package/README.md
CHANGED
|
@@ -262,7 +262,7 @@ Coverage is specific to the processor request format, merchant setup, browser tr
|
|
|
262
262
|
| Fiserv Commerce Hub | implemented (mode `cse`, prepared checkout only) and off until Agentcard turns it on for your company: the card frame's card capture on `connect.fiservapis.com` (or `connect-cert.fiservapis.com` in the sandbox), with the approved card encrypted on the cardholder's device under a key Agentcard reviewed for the merchant. A merchant whose frame posts to Fiserv's `payment-link` endpoint is not recognized. No live merchant purchase is verified yet |
|
|
263
263
|
| Worldline MyCheckout | implemented (mode `hosted_form`) and off until Agentcard turns it on for your company: the card form on Worldline's hosted payment page, a top-level form POST to `/checkout` on `payment.pay1` or `payment.pay2` under `checkout.worldline-solutions.com` (pre-production: `payment.pay1.preprod` and `payment.pay2.preprod`). The cardholder's device submits Worldline's form with the approved card; the paused navigation resolves to the synthetic page, and you poll the merchant's order state. The form names no amount, so pass `amount` and `currency`, above zero: that is what the cardholder approves. A card submit with a checked "remember" box, a Google Pay token or a Click to Pay answer is refused. Google Pay and Click to Pay payments that carry no card number continue untouched, as the page's cancel and its other payment methods do: no authorization, no prompt. A MyCheckout page on a merchant's own subdomain is not recognized. On a page that asks the shopper to choose a card product first, the adapters hold the card submit to that product: Worldline's IIN lookup on the agent's placeholder can switch the form to another product of the same network (CLZ's page read the Visa placeholder as Visa Electron), and a submit whose `paymentProductId` is not the product chosen is aborted before any create, with a `blocked` event, `worldline_mycheckout_product_changed` (`worldline_mycheckout_product_missing` when it names none), without holding the attachment. `placeholderCard({ psp })` returns a processor's own placeholder for the card's network where one is reviewed; none is yet for Worldline, so its Visa placeholder can still be read as Visa Electron, and that submit is then refused. No live merchant purchase is verified yet |
|
|
264
264
|
| Verifone eCommerce (verifone.js) | implemented (mode `cse`, prepared checkout only) and off until Agentcard turns it on for your company: the SDK pauses a request at a merchant whose page encrypts the card with verifone.js and posts it to the merchant's own server only when Agentcard reviewed that merchant as a Verifone profile. The Container Store is the one profile, in `observe`, and Agentcard has reviewed its card request but not its key yet, so the SDK reports and aborts a request there that carries a verifone.js blob, and nothing pays (see "Verifone merchants that encrypt the card in the page"). Agentcard has not verified a live merchant purchase yet |
|
|
265
|
-
| Gravy (Gr4vy) Secure Fields | dark launch: for an org Agentcard has enabled, after `vault.syncRegistry()`, which declares `gravy_session_fields_put`; for any other org the SDK leaves Gravy's requests alone and the request continues to Gravy untouched. The card request is Secure Fields' update of a checkout session: a JSON `PUT` to `/checkout/sessions/<session id>/fields` on the merchant's own host `api.<merchant>.gr4vy.app` (sandbox: `api.sandbox.<merchant>.gr4vy.app`), sent from Gravy's hidden controller frame and carrying `payment_method.number`, `payment_method.expiration_date` as one `MM/YY` value and `payment_method.security_code`. The SDK pauses that `PUT`, never a `POST` to the same URL; the cardholder's device sends the card as the same `PUT`, and the frame receives Gravy's answer, a `204` with no body. The request names no amount, so pass `amount` and `currency`. Updating the session stores the card with Gravy; the merchant creates the transaction from the session on its own server, so a completed request is not a payment. Gravy Embed, the hosted frame on `embed.<merchant>.gr4vy.app`, is not covered |
|
|
265
|
+
| Gravy (Gr4vy) Secure Fields | dark launch: for an org Agentcard has enabled, after `vault.syncRegistry()`, which declares `gravy_session_fields_put`; for any other org the SDK leaves Gravy's requests alone and the request continues to Gravy untouched. The card request is Secure Fields' update of a checkout session: a JSON `PUT` to `/checkout/sessions/<session id>/fields` on the merchant's own host `api.<merchant>.gr4vy.app` (sandbox: `api.sandbox.<merchant>.gr4vy.app`), sent from Gravy's hidden controller frame and carrying `payment_method.number`, `payment_method.expiration_date` as one `MM/YY` value and `payment_method.security_code`. The SDK pauses that `PUT`, never a `POST` to the same URL; the cardholder's device sends the card as the same `PUT`, and the frame receives Gravy's answer, a `204` with no body. The request names no amount, so pass `amount` and `currency`. Updating the session stores the card with Gravy; the merchant creates the transaction from the session on its own server, so a completed request is not a payment. The session id is the request's only credential, so event URLs and error messages show it as `{session}`. Gravy Embed, the hosted frame on `embed.<merchant>.gr4vy.app`, is not covered |
|
|
266
266
|
| GMO Payment Gateway | dark launch (mode `token`): only for an org Agentcard has enabled; see [Pay a GMO Payment Gateway checkout](#pay-a-gmo-payment-gateway-checkout) |
|
|
267
267
|
| CyberSource Flex Microform | dark launch: Microform 2.12.1 card fields only, after `vault.syncRegistry()`, and only for an org Agentcard has enabled. For any other org the API does not serve the recognizer, so nothing pauses there. The cardholder's device seals the card for CyberSource and the card field receives the transient token. Validated in local Chromium; no live merchant purchase yet. See [Pay a CyberSource Flex Microform checkout](#pay-a-cybersource-flex-microform-checkout) |
|
|
268
268
|
| Juspay Express Checkout | dark launch: the new-card flow Swiggy's website sends from its own page, for an org Agentcard has enabled, after `vault.syncRegistry()`. Validated in local Chromium with no live merchant purchase yet; see [Pay a Juspay checkout](#pay-a-juspay-checkout) |
|
|
@@ -278,6 +278,7 @@ Coverage is specific to the processor request format, merchant setup, browser tr
|
|
|
278
278
|
| 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) |
|
|
279
279
|
| 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) |
|
|
280
280
|
| 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" |
|
|
281
|
+
| 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 |
|
|
281
282
|
|
|
282
283
|
The recognizer list, and the status of each reviewed Adyen merchant profile on
|
|
283
284
|
your client, are fetched from the API at runtime (`agentcard.checkout.syncRegistry()`),
|
|
@@ -1066,9 +1067,9 @@ and the reason becomes `stripe_payment_continued`. One confirm continues per
|
|
|
1066
1067
|
approval; every other follow-up, including an unrelated intent, a changed
|
|
1067
1068
|
amount and a retry, stays blocked.
|
|
1068
1069
|
|
|
1069
|
-
A card save can follow a `/v1/payment_methods` approval the same way,
|
|
1070
|
-
|
|
1071
|
-
|
|
1070
|
+
A card save can follow a `/v1/payment_methods` approval the same way, for
|
|
1071
|
+
every company: the page's SetupIntent confirm pays with the approved payment
|
|
1072
|
+
method. A Payment Element
|
|
1072
1073
|
page that creates the method itself (`paymentMethodCreation: 'manual'`, then
|
|
1073
1074
|
`confirmSetup({ elements, confirmParams: { payment_method } })`) confirms with
|
|
1074
1075
|
that method and no card, and the SDK continues the confirm untouched once the
|
|
@@ -1084,9 +1085,10 @@ emits `stripe_setup_continued` with
|
|
|
1084
1085
|
`{ authorizationId, setupIntentId, rewritten }`, where `rewritten` is true
|
|
1085
1086
|
when the SDK wrote the approved payment method in place of a card the confirm
|
|
1086
1087
|
carried, and the reason becomes `stripe_setup_continued`; the merchant then
|
|
1087
|
-
keeps the card for later charges.
|
|
1088
|
-
|
|
1089
|
-
|
|
1088
|
+
keeps the card for later charges. Refused, the confirm is aborted, and the
|
|
1089
|
+
error's code says why: `amount_mismatch` for an approval that named an
|
|
1090
|
+
amount, for example. Either kind of intent uses up the approval's one
|
|
1091
|
+
continuation.
|
|
1090
1092
|
|
|
1091
1093
|
Unrecognized merchant-server endpoints remain outside this guard unless listed
|
|
1092
1094
|
in `paymentEndpoints`; this is not a guarantee against a merchant charging a
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const BUILTIN_REGISTRY = [{ "psp": "spreedly", "match": /core\.spreedly\.com\/v1\/payment_methods\/restricted\.json/i, "hosts": ["^core\\.spreedly\\.com$"], "encoding": "json", "passthroughHeaders": [/^spreedly-environment-key$/i] }, { "psp": "shopify", "match": /(checkout\.pci\.shopifyinc\.com|deposit\.[a-z0-9-]+\.shopifycs\.com)\/sessions/i, "hosts": ["^checkout\\.pci\\.shopifyinc\\.com$", "^deposit\\.[a-z0-9-]+\\.shopifycs\\.com$"], "encoding": "json", "passthroughHeaders": [/^shopify-identification-signature$/i] }, { "psp": "stripe", "match": /api\.stripe\.com\/v1\/(payment_methods|tokens|sources|confirmation_tokens|setup_intents\/seti_\w+\/confirm|payment_intents\/pi_\w+\/confirm|payment_pages\/cs_(?:test|live)_\w+\/confirm)/i, "hosts": ["^api\\.stripe\\.com$"], "encoding": "form", "passthroughHeaders": [/^authorization$/i, /^stripe-version$/i, /^x-stripe-client-user-agent$/i], "cardFields": ["card[number]", "payment_method_data[card][number]"], "passWithoutCard": "api\\.stripe\\.com/v1/(sources|confirmation_tokens|payment_pages/cs_(?:test|live)_\\w+/confirm)" }, { "psp": "braintree", "match": /payments(\.sandbox)?\.braintree-api\.com\/graphql/i, "hosts": ["^payments\\.braintree-api\\.com$", "^payments\\.sandbox\\.braintree-api\\.com$"], "sandboxHosts": ["^payments\\.sandbox\\.braintree-api\\.com$"], "encoding": "json", "passthroughHeaders": [/^authorization$/i, /^braintree-version$/i] }, { "psp": "checkout_com", "match": /(api|card-acquisition-gateway)(\.sandbox)?\.checkout\.com\/tokens/i, "hosts": ["^api\\.checkout\\.com$", "^api\\.sandbox\\.checkout\\.com$", "^card-acquisition-gateway\\.checkout\\.com$", "^card-acquisition-gateway\\.sandbox\\.checkout\\.com$"], "sandboxHosts": ["^api\\.sandbox\\.checkout\\.com$", "^card-acquisition-gateway\\.sandbox\\.checkout\\.com$"], "encoding": "json", "passthroughHeaders": [/^authorization$/i] }, { "psp": "adyen", "match": /(checkoutshopper-(test|live(-[a-z]+)?)\.adyen\.com|([a-z0-9-]+\.)*adyenpayments\.com)\/checkoutshopper\/v1\/sessions\/[A-Za-z0-9_-]+\/payments/i, "hosts": ["^checkoutshopper-(test|live(-[a-z]+)?)\\.adyen\\.com$", "^([a-z0-9-]+\\.)*adyenpayments\\.com$"], "sandboxHosts": ["^checkoutshopper-test\\.adyen\\.com$"], "encoding": "json", "passthroughHeaders": [], "clientSideEncrypted": true, "mode": "cse" }, { "psp": "tranzila", "match": /(direct\.tranzila\.com\/process\/n\/|directng\.tranzila\.com\/process\/?)/i, "hosts": ["^direct\\.tranzila\\.com$", "^directng\\.tranzila\\.com$"], "encoding": "form", "passthroughHeaders": [], "mode": "hosted_form" }, { "psp": "square", "match": /pci-connect\.squareup(?:sandbox)?\.com\/v2\/card-nonce/i, "hosts": ["^pci-connect\\.squareup\\.com$", "^pci-connect\\.squareupsandbox\\.com$"], "sandboxHosts": ["^pci-connect\\.squareupsandbox\\.com$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "authorize_net", "match": /(api2|apitest)\.authorize\.net\/xml\/v1\/request\.api/i, "hosts": ["^api2\\.authorize\\.net$", "^apitest\\.authorize\\.net$"], "sandboxHosts": ["^apitest\\.authorize\\.net$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "worldpay", "match": /(try\.)?access\.worldpay\.com\/(sessions\/card|verifiedTokens\/sessions)/i, "hosts": ["^access\\.worldpay\\.com$", "^try\\.access\\.worldpay\\.com$"], "sandboxHosts": ["^try\\.access\\.worldpay\\.com$"], "encoding": "json", "passthroughHeaders": [/^accept$/i] }, { "psp": "nuvei", "match": /(secure|ppp-test)\.safecharge\.com\/ppp\/api\/v1\/(?:cardTokenization|clientPayment|websdk\/initPaymentWithCardTokenization)\.do/i, "hosts": ["^secure\\.safecharge\\.com$", "^ppp-test\\.safecharge\\.com$"], "sandboxHosts": ["^ppp-test\\.safecharge\\.com$"], "encoding": "json", "passthroughHeaders": [], "jsonCardFields": [["paymentOption", "card", "cardNumber"], ["cardData", "cardNumber"]], "passWithoutCard": "(?:secure|ppp-test)\\.safecharge\\.com/ppp/api/v1/(?:clientPayment|websdk/initPaymentWithCardTokenization)\\.do" }, { "psp": "airwallex", "match": /(checkout(\.sandbox)?\.airwallex\.com|pci-api(\.sandbox)?\.airwallex\.com)\/api\/v1\/pa\/(payment_intents\/[^/?#]+\/confirm|payment_consents\/[^/?#]+\/verify|payment_methods\/create)(\?|$)/i, "hosts": ["^checkout\\.airwallex\\.com$", "^checkout\\.sandbox\\.airwallex\\.com$", "^pci-api\\.airwallex\\.com$", "^pci-api\\.sandbox\\.airwallex\\.com$"], "sandboxHosts": ["^checkout\\.sandbox\\.airwallex\\.com$", "^pci-api\\.sandbox\\.airwallex\\.com$"], "encoding": "json", "passthroughHeaders": [/^client-secret$/i, /^authorization$/i, /^x-auth-token$/i, /^x-on-behalf-of$/i, /^x-api-version$/i] }, { "psp": "rapyd", "match": /(api|sandboxapi)\.rapyd\.net\/v1\/(?:hosted\/collect\/card\/[^/?#]+\/payment_method|checkout\/checkout_[A-Za-z0-9]+)(?:[?#]|$)/i, "hosts": ["^api\\.rapyd\\.net$", "^sandboxapi\\.rapyd\\.net$"], "sandboxHosts": ["^sandboxapi\\.rapyd\\.net$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "dlocal", "match": /ppmcc(-sandbox)?\.dlocal\.com\/cvault\/credit-card\/temporal/i, "hosts": ["^ppmcc\\.dlocal\\.com$", "^ppmcc-sandbox\\.dlocal\\.com$"], "sandboxHosts": ["^ppmcc-sandbox\\.dlocal\\.com$"], "encoding": "json", "passthroughHeaders": [/^x-fields-api-key$/i, /^x-uow$/i, /^x-dlocal-infrav2$/i] }, { "psp": "ebanx", "match": /(?:(?:customer-frontier|customer|api-local-latam|api|sandbox-local-latam|sandbox)\.ebanx\.com|(?:api-diamond|api|sandbox)\.ebanxpay\.com)\/ws\/token/i, "hosts": ["^customer\\.ebanx\\.com$", "^customer-frontier\\.ebanx\\.com$", "^api\\.ebanx\\.com$", "^sandbox\\.ebanx\\.com$", "^api-local-latam\\.ebanx\\.com$", "^sandbox-local-latam\\.ebanx\\.com$", "^api-diamond\\.ebanxpay\\.com$", "^api\\.ebanxpay\\.com$", "^sandbox\\.ebanxpay\\.com$"], "sandboxHosts": ["^sandbox\\.ebanx\\.com$", "^sandbox-local-latam\\.ebanx\\.com$", "^sandbox\\.ebanxpay\\.com$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "mercado_pago", "match": /api\.mercadopago\.com\/v1\/card_tokens(?![\w/-])/i, "hosts": ["^api\\.mercadopago\\.com$"], "encoding": "json", "passthroughHeaders": [/^x-product-id$/i] }, { "psp": "payu", "match": /(secure\.payu\.com|(merch-prod|secure)\.snd\.payu\.com)\/api\/front\/tokens/i, "hosts": ["^secure\\.payu\\.com$", "^(merch-prod|secure)\\.snd\\.payu\\.com$"], "sandboxHosts": ["^(merch-prod|secure)\\.snd\\.payu\\.com$"], "encoding": "json", "passthroughHeaders": [/^authorization$/i] }, { "psp": "razorpay", "match": /api\.razorpay\.com\/v1\/(?:standard_checkout\/)?payments\/create\/(?:ajax|checkout|fees)/i, "hosts": ["^api\\.razorpay\\.com$"], "encoding": "form", "passthroughHeaders": [/^x-razorpay-sessionid$/i, /^x-customer-access-token$/i] }, { "psp": "mollie", "match": /api\.cc\.mollie\.com\/v1\/card-tokens/i, "hosts": ["^api\\.cc\\.mollie\\.com$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "paysafe", "match": /(?:api(\.test)?\.paysafe\.com\/(?:paymenthub\/v1\/singleusepaymenthandles|js\/api\/v1\/tokenize)|hosted(\.test)?\.paysafe\.com\/checkout\/api\/v1\/tokenize)(?![\w/-])/i, "hosts": ["^api\\.paysafe\\.com$", "^api\\.test\\.paysafe\\.com$", "^hosted\\.paysafe\\.com$", "^hosted\\.test\\.paysafe\\.com$"], "sandboxHosts": ["^api\\.test\\.paysafe\\.com$", "^hosted\\.test\\.paysafe\\.com$"], "encoding": "json", "passthroughHeaders": [/^authorization$/i, /^x-paysafe-credentials$/i, /^correlationid$/i] }, { "psp": "recurly", "match": /api(\.eu)?\.recurly\.com\/js\/v1\/token(?![\w-])/i, "hosts": ["^api\\.recurly\\.com$", "^api\\.eu\\.recurly\\.com$"], "encoding": "form", "passthroughHeaders": [/^recurly-credential-checkout-hostname$/i] }, { "psp": "bambora", "match": /(api\.na\.bambora\.com|api\.bam\.shift4api\.net)\/scripts\/tokenization\/tokens/i, "hosts": ["^api\\.na\\.bambora\\.com$", "^api\\.bam\\.shift4api\\.net$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "global_payments", "match": /(?:api\.heartlandportico\.com\/SecureSubmit\.v1\/api\/token|cert\.api2\.heartlandportico\.com\/Hps\.Exchange\.PosGateway\.Hpf\.v1\/api\/token|apis(?:\.sandbox)?(?:\.eu)?\.globalpay\.com\/ucp\/(?:merchants\/[^/]+\/)?payment-methods)/i, "hosts": ["^api\\.heartlandportico\\.com$", "^cert\\.api2\\.heartlandportico\\.com$", "^apis\\.globalpay\\.com$", "^apis\\.sandbox\\.globalpay\\.com$", "^apis\\.eu\\.globalpay\\.com$", "^apis\\.sandbox\\.eu\\.globalpay\\.com$"], "sandboxHosts": ["^cert\\.api2\\.heartlandportico\\.com$", "^apis\\.sandbox\\.globalpay\\.com$", "^apis\\.sandbox\\.eu\\.globalpay\\.com$"], "encoding": "json", "passthroughHeaders": [/^authorization$/i, /^x-gp-version$/i] }];
|
|
1
|
+
export const BUILTIN_REGISTRY = [{ "psp": "spreedly", "match": /core\.spreedly\.com\/v1\/payment_methods\/restricted\.json/i, "hosts": ["^core\\.spreedly\\.com$"], "encoding": "json", "passthroughHeaders": [/^spreedly-environment-key$/i] }, { "psp": "shopify", "match": /(checkout\.pci\.shopifyinc\.com|deposit\.[a-z0-9-]+\.shopifycs\.com)\/sessions/i, "hosts": ["^checkout\\.pci\\.shopifyinc\\.com$", "^deposit\\.[a-z0-9-]+\\.shopifycs\\.com$"], "encoding": "json", "passthroughHeaders": [/^shopify-identification-signature$/i] }, { "psp": "stripe", "match": /api\.stripe\.com\/v1\/(payment_methods|tokens|sources|confirmation_tokens|setup_intents\/seti_\w+\/confirm|payment_intents\/pi_\w+\/confirm|payment_pages\/cs_(?:test|live)_\w+\/confirm)/i, "hosts": ["^api\\.stripe\\.com$"], "encoding": "form", "passthroughHeaders": [/^authorization$/i, /^stripe-version$/i, /^x-stripe-client-user-agent$/i], "cardFields": ["card[number]", "payment_method_data[card][number]"], "passWithoutCard": "api\\.stripe\\.com/v1/(sources|confirmation_tokens|payment_pages/cs_(?:test|live)_\\w+/confirm)" }, { "psp": "braintree", "match": /payments(\.sandbox)?\.braintree-api\.com\/graphql/i, "hosts": ["^payments\\.braintree-api\\.com$", "^payments\\.sandbox\\.braintree-api\\.com$"], "sandboxHosts": ["^payments\\.sandbox\\.braintree-api\\.com$"], "encoding": "json", "passthroughHeaders": [/^authorization$/i, /^braintree-version$/i] }, { "psp": "checkout_com", "match": /(api|card-acquisition-gateway)(\.sandbox)?\.checkout\.com\/tokens/i, "hosts": ["^api\\.checkout\\.com$", "^api\\.sandbox\\.checkout\\.com$", "^card-acquisition-gateway\\.checkout\\.com$", "^card-acquisition-gateway\\.sandbox\\.checkout\\.com$"], "sandboxHosts": ["^api\\.sandbox\\.checkout\\.com$", "^card-acquisition-gateway\\.sandbox\\.checkout\\.com$"], "encoding": "json", "passthroughHeaders": [/^authorization$/i] }, { "psp": "adyen", "match": /(checkoutshopper-(test|live(-[a-z]+)?)\.adyen\.com|([a-z0-9-]+\.)*adyenpayments\.com)\/checkoutshopper\/v1\/sessions\/[A-Za-z0-9_-]+\/payments/i, "hosts": ["^checkoutshopper-(test|live(-[a-z]+)?)\\.adyen\\.com$", "^([a-z0-9-]+\\.)*adyenpayments\\.com$"], "sandboxHosts": ["^checkoutshopper-test\\.adyen\\.com$"], "encoding": "json", "passthroughHeaders": [], "clientSideEncrypted": true, "mode": "cse" }, { "psp": "tranzila", "match": /(direct\.tranzila\.com\/process\/n\/|directng\.tranzila\.com\/process\/?)/i, "hosts": ["^direct\\.tranzila\\.com$", "^directng\\.tranzila\\.com$"], "encoding": "form", "passthroughHeaders": [], "mode": "hosted_form" }, { "psp": "square", "match": /pci-connect\.squareup(?:sandbox)?\.com\/v2\/card-nonce/i, "hosts": ["^pci-connect\\.squareup\\.com$", "^pci-connect\\.squareupsandbox\\.com$"], "sandboxHosts": ["^pci-connect\\.squareupsandbox\\.com$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "authorize_net", "match": /(api2|apitest)\.authorize\.net\/xml\/v1\/request\.api/i, "hosts": ["^api2\\.authorize\\.net$", "^apitest\\.authorize\\.net$"], "sandboxHosts": ["^apitest\\.authorize\\.net$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "worldpay", "match": /(try\.)?access\.worldpay\.com\/(sessions\/card|verifiedTokens\/sessions)/i, "hosts": ["^access\\.worldpay\\.com$", "^try\\.access\\.worldpay\\.com$"], "sandboxHosts": ["^try\\.access\\.worldpay\\.com$"], "encoding": "json", "passthroughHeaders": [/^accept$/i] }, { "psp": "nuvei", "match": /(secure|ppp-test)\.safecharge\.com\/ppp\/api\/v1\/(?:cardTokenization|clientPayment|websdk\/initPaymentWithCardTokenization)\.do/i, "hosts": ["^secure\\.safecharge\\.com$", "^ppp-test\\.safecharge\\.com$"], "sandboxHosts": ["^ppp-test\\.safecharge\\.com$"], "encoding": "json", "passthroughHeaders": [], "jsonCardFields": [["paymentOption", "card", "cardNumber"], ["cardData", "cardNumber"]], "passWithoutCard": "(?:secure|ppp-test)\\.safecharge\\.com/ppp/api/v1/(?:clientPayment|websdk/initPaymentWithCardTokenization)\\.do" }, { "psp": "airwallex", "match": /(checkout(\.sandbox)?\.airwallex\.com|pci-api(\.sandbox)?\.airwallex\.com)\/api\/v1\/pa\/(payment_intents\/[^/?#]+\/confirm|payment_consents\/[^/?#]+\/verify|payment_methods\/create)(\?|$)/i, "hosts": ["^checkout\\.airwallex\\.com$", "^checkout\\.sandbox\\.airwallex\\.com$", "^pci-api\\.airwallex\\.com$", "^pci-api\\.sandbox\\.airwallex\\.com$"], "sandboxHosts": ["^checkout\\.sandbox\\.airwallex\\.com$", "^pci-api\\.sandbox\\.airwallex\\.com$"], "encoding": "json", "passthroughHeaders": [/^client-secret$/i, /^authorization$/i, /^x-auth-token$/i, /^x-on-behalf-of$/i, /^x-api-version$/i] }, { "psp": "rapyd", "match": /(api|sandboxapi)\.rapyd\.net\/v1\/(?:hosted\/collect\/card\/[^/?#]+\/payment_method|checkout\/checkout_[A-Za-z0-9]+)(?:[?#]|$)/i, "hosts": ["^api\\.rapyd\\.net$", "^sandboxapi\\.rapyd\\.net$"], "sandboxHosts": ["^sandboxapi\\.rapyd\\.net$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "dlocal", "match": /ppmcc(-sandbox)?\.dlocal\.com\/cvault\/credit-card\/temporal/i, "hosts": ["^ppmcc\\.dlocal\\.com$", "^ppmcc-sandbox\\.dlocal\\.com$"], "sandboxHosts": ["^ppmcc-sandbox\\.dlocal\\.com$"], "encoding": "json", "passthroughHeaders": [/^x-fields-api-key$/i, /^x-uow$/i, /^x-dlocal-infrav2$/i] }, { "psp": "ebanx", "match": /(?:(?:customer-frontier|customer|api-local-latam|api|sandbox-local-latam|sandbox)\.ebanx\.com|(?:api-diamond|api|sandbox)\.ebanxpay\.com)\/ws\/token/i, "hosts": ["^customer\\.ebanx\\.com$", "^customer-frontier\\.ebanx\\.com$", "^api\\.ebanx\\.com$", "^sandbox\\.ebanx\\.com$", "^api-local-latam\\.ebanx\\.com$", "^sandbox-local-latam\\.ebanx\\.com$", "^api-diamond\\.ebanxpay\\.com$", "^api\\.ebanxpay\\.com$", "^sandbox\\.ebanxpay\\.com$"], "sandboxHosts": ["^sandbox\\.ebanx\\.com$", "^sandbox-local-latam\\.ebanx\\.com$", "^sandbox\\.ebanxpay\\.com$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "mercado_pago", "match": /api\.mercadopago\.com\/v1\/card_tokens(?![\w/-])/i, "hosts": ["^api\\.mercadopago\\.com$"], "encoding": "json", "passthroughHeaders": [/^x-product-id$/i] }, { "psp": "payu", "match": /(secure\.payu\.com|(merch-prod|secure)\.snd\.payu\.com)\/api\/front\/tokens/i, "hosts": ["^secure\\.payu\\.com$", "^(merch-prod|secure)\\.snd\\.payu\\.com$"], "sandboxHosts": ["^(merch-prod|secure)\\.snd\\.payu\\.com$"], "encoding": "json", "passthroughHeaders": [/^authorization$/i] }, { "psp": "razorpay", "match": /api\.razorpay\.com\/v1\/(?:standard_checkout\/)?payments\/create\/(?:ajax|checkout|fees)/i, "hosts": ["^api\\.razorpay\\.com$"], "encoding": "form", "passthroughHeaders": [/^x-razorpay-sessionid$/i, /^x-customer-access-token$/i] }, { "psp": "mollie", "match": /api\.cc\.mollie\.com\/v1\/card-tokens/i, "hosts": ["^api\\.cc\\.mollie\\.com$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "paysafe", "match": /(?:api(\.test)?\.paysafe\.com\/(?:paymenthub\/v1\/singleusepaymenthandles|js\/api\/v1\/tokenize|checkout\/api\/v1\/tokenize)|hosted(\.test)?\.paysafe\.com\/checkout\/api\/v1\/tokenize)(?![\w/-])/i, "hosts": ["^api\\.paysafe\\.com$", "^api\\.test\\.paysafe\\.com$", "^hosted\\.paysafe\\.com$", "^hosted\\.test\\.paysafe\\.com$"], "sandboxHosts": ["^api\\.test\\.paysafe\\.com$", "^hosted\\.test\\.paysafe\\.com$"], "encoding": "json", "passthroughHeaders": [/^authorization$/i, /^x-paysafe-credentials$/i, /^correlationid$/i, /^x-internal-correlation-id$/i, /^x-app-version$/i, /^x-transactionsource$/i] }, { "psp": "recurly", "match": /api(\.eu)?\.recurly\.com\/js\/v1\/token(?![\w-])/i, "hosts": ["^api\\.recurly\\.com$", "^api\\.eu\\.recurly\\.com$"], "encoding": "form", "passthroughHeaders": [/^recurly-credential-checkout-hostname$/i] }, { "psp": "bambora", "match": /(api\.na\.bambora\.com|api\.bam\.shift4api\.net)\/scripts\/tokenization\/tokens/i, "hosts": ["^api\\.na\\.bambora\\.com$", "^api\\.bam\\.shift4api\\.net$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "global_payments", "match": /(?:api\.heartlandportico\.com\/SecureSubmit\.v1\/api\/token|cert\.api2\.heartlandportico\.com\/Hps\.Exchange\.PosGateway\.Hpf\.v1\/api\/token|apis(?:\.sandbox)?(?:\.eu)?\.globalpay\.com\/ucp\/(?:merchants\/[^/]+\/)?payment-methods)/i, "hosts": ["^api\\.heartlandportico\\.com$", "^cert\\.api2\\.heartlandportico\\.com$", "^apis\\.globalpay\\.com$", "^apis\\.sandbox\\.globalpay\\.com$", "^apis\\.eu\\.globalpay\\.com$", "^apis\\.sandbox\\.eu\\.globalpay\\.com$"], "sandboxHosts": ["^cert\\.api2\\.heartlandportico\\.com$", "^apis\\.sandbox\\.globalpay\\.com$", "^apis\\.sandbox\\.eu\\.globalpay\\.com$"], "encoding": "json", "passthroughHeaders": [/^authorization$/i, /^x-gp-version$/i] }];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
2
|
// Generated from @agent-cards/payment-core. Do not edit.
|
|
3
|
-
// artifact-sha256:
|
|
3
|
+
// artifact-sha256: 5c2d8f5671c901ef8162e61e21996671a0e6e9ca235467ea7f6267274f5c3ee1
|
|
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
|
|
@@ -340,8 +340,81 @@ function amadeusBodyKind(body) {
|
|
|
340
340
|
return record2(value.data) && holdsPan(value.data.mopdata) ? "card" : "other";
|
|
341
341
|
return "other";
|
|
342
342
|
}
|
|
343
|
+
// src/paddle-vgs.js
|
|
344
|
+
var PADDLE_VGS_PSP = "paddle_vgs";
|
|
345
|
+
var PADDLE_VGS_CARDS_URLS = /* @__PURE__ */ Object.freeze({
|
|
346
|
+
production: "https://vault.paddle.com/cards",
|
|
347
|
+
sandbox: "https://sandbox-vault.paddle.com/cards"
|
|
348
|
+
});
|
|
349
|
+
var BODY_LIMIT2 = 4096;
|
|
350
|
+
var ROOT_KEYS2 = /* @__PURE__ */ Object.freeze(["data"]);
|
|
351
|
+
var DATA_KEYS = /* @__PURE__ */ Object.freeze(["type", "attributes"]);
|
|
352
|
+
var ATTRIBUTE_KEYS = /* @__PURE__ */ Object.freeze(["pan", "cvc", "exp_month", "exp_year", "cardholder"]);
|
|
353
|
+
var CARD_NUMBER4 = /^[0-9]{12,19}$/;
|
|
354
|
+
var SECURITY_CODE2 = /^[0-9]{3,4}$/;
|
|
355
|
+
var NAME_LIMIT = 256;
|
|
356
|
+
var CONTROL = /[\u0000-\u001f\u007f]/;
|
|
357
|
+
var cardLikeName = (name) => (name.match(/[0-9]/g) ?? []).length >= 12;
|
|
358
|
+
var record3 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
359
|
+
var sameKeys = (value, keys) => {
|
|
360
|
+
const own = Object.keys(value);
|
|
361
|
+
return own.length === keys.length && own.every((key, at) => key === keys[at]);
|
|
362
|
+
};
|
|
363
|
+
var refuse4 = (code) => Object.freeze({ verdict: "refuse", code });
|
|
364
|
+
var CARD4 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
|
|
365
|
+
function paddleVgsEnvironment(url) {
|
|
366
|
+
if (url === PADDLE_VGS_CARDS_URLS.production)
|
|
367
|
+
return "production";
|
|
368
|
+
if (url === PADDLE_VGS_CARDS_URLS.sandbox)
|
|
369
|
+
return "sandbox";
|
|
370
|
+
return null;
|
|
371
|
+
}
|
|
372
|
+
function isPaddleVgsCardsUrl(url) {
|
|
373
|
+
return paddleVgsEnvironment(url) !== null;
|
|
374
|
+
}
|
|
375
|
+
function readBody2(body) {
|
|
376
|
+
if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT2)
|
|
377
|
+
return null;
|
|
378
|
+
let value;
|
|
379
|
+
try {
|
|
380
|
+
value = JSON.parse(body);
|
|
381
|
+
if (!record3(value) || JSON.stringify(value) !== body)
|
|
382
|
+
return null;
|
|
383
|
+
}
|
|
384
|
+
catch {
|
|
385
|
+
return null;
|
|
386
|
+
}
|
|
387
|
+
return value;
|
|
388
|
+
}
|
|
389
|
+
function paddleVgsBodyVerdict(body) {
|
|
390
|
+
const value = readBody2(body);
|
|
391
|
+
if (value === null || !sameKeys(value, ROOT_KEYS2) || !record3(value.data) || !sameKeys(value.data, DATA_KEYS) || value.data.type !== "cards" || !record3(value.data.attributes) || !sameKeys(value.data.attributes, ATTRIBUTE_KEYS)) {
|
|
392
|
+
return refuse4("paddle_vgs_body_unsupported");
|
|
393
|
+
}
|
|
394
|
+
const card = value.data.attributes;
|
|
395
|
+
const holder = card.cardholder;
|
|
396
|
+
if (typeof card.pan !== "string" || !CARD_NUMBER4.test(card.pan) || typeof card.cvc !== "string" || !SECURITY_CODE2.test(card.cvc) || !Number.isInteger(card.exp_month) || card.exp_month < 1 || card.exp_month > 12 || !Number.isInteger(card.exp_year) || card.exp_year < 0 || card.exp_year > 99 || !record3(holder) || !sameKeys(holder, ["name"]) || typeof holder.name !== "string" || holder.name.length > NAME_LIMIT || CONTROL.test(holder.name) || cardLikeName(holder.name)) {
|
|
397
|
+
return refuse4("paddle_vgs_body_unsupported");
|
|
398
|
+
}
|
|
399
|
+
return CARD4;
|
|
400
|
+
}
|
|
401
|
+
var pin2 = (fields) => Object.freeze({
|
|
402
|
+
...fields,
|
|
403
|
+
origins: Object.freeze([...fields.origins]),
|
|
404
|
+
sellerClaim: fields.sellerClaim ? Object.freeze({ ...fields.sellerClaim }) : null
|
|
405
|
+
});
|
|
406
|
+
var PADDLE_VGS_MERCHANT_PINS = /* @__PURE__ */ Object.freeze([
|
|
407
|
+
pin2({ id: "rectangle_pro", merchant: "Rectangle Pro", origins: ["https://rectangleapp.com"], sellerClaim: null })
|
|
408
|
+
]);
|
|
409
|
+
var FACT_KEYS = /* @__PURE__ */ Object.freeze(["card_first_six", "card_last_four", "expiry_month", "expiry_year", "card_brand"]);
|
|
410
|
+
var METADATA_KEYS = /* @__PURE__ */ Object.freeze(["cardholder_name", ...FACT_KEYS]);
|
|
343
411
|
// src/card-fields.js
|
|
344
412
|
function processorGate(recognizer, url, body) {
|
|
413
|
+
if (recognizer && recognizer.psp === PADDLE_VGS_PSP) {
|
|
414
|
+
if (url !== void 0 && !isPaddleVgsCardsUrl(url))
|
|
415
|
+
return { verdict: "refuse", code: "paddle_vgs_url_refused" };
|
|
416
|
+
return paddleVgsBodyVerdict(body);
|
|
417
|
+
}
|
|
345
418
|
if (recognizer && recognizer.psp === GRAVY_PSP)
|
|
346
419
|
return gravyBodyVerdict(body);
|
|
347
420
|
if (recognizer && recognizer.psp === MONERIS_PSP) {
|
package/dist/cdp.js
CHANGED
|
@@ -10,6 +10,8 @@ import { ACI_CHECKOUT_REUSED, AciGate, playwrightReplacesNavigationBody } from '
|
|
|
10
10
|
import { EprotectGate } from './eprotect.js';
|
|
11
11
|
import { dispatchPreClaim, eventUrl } from './pre-claim.js';
|
|
12
12
|
import { GMO_TOKEN_V1_PATTERNS, gmoRequestShop, isGmoTokenV1Request, recognizesGmo } from './gmo.js';
|
|
13
|
+
import { isPaddleVgsCardsUrl } from './paddle-vgs.generated.js';
|
|
14
|
+
import { PADDLE_VGS_PAY_PATTERNS, PaddleVgsPayGate, isPaddleCheckoutService, recognizesPaddleVgs } from './paddle-vgs-pay.js';
|
|
13
15
|
import { DatatransRepeats } from './datatrans.js';
|
|
14
16
|
import { SHIJI_STS_COMPANION_WINDOW_MS, ShijiStsCompanions, ShijiStsError, isShijiStsHost, shijiStsTokenContinuation, } from './shiji-sts.js';
|
|
15
17
|
import { isArmedEkashuUrl } from './ekashu.js';
|
|
@@ -1241,14 +1243,32 @@ function bodyShape(body) {
|
|
|
1241
1243
|
* the one the Flex gate read from the field iframe (cybersource-flex.ts: microform type, fields,
|
|
1242
1244
|
* the capture context's key id and the context itself), never the ciphertext.
|
|
1243
1245
|
*/
|
|
1244
|
-
function requestIdentity(opts, url, method, body, documentUrl, pageAmount, flexShape) {
|
|
1246
|
+
function requestIdentity(opts, url, method, body, documentUrl, pageAmount, flexShape, headers) {
|
|
1245
1247
|
const shaped = flexShape !== undefined ? { shape: flexShape, namesAmount: false } : bodyShape(body);
|
|
1246
1248
|
// A GMO token is minted for the one shop its request names, and the body's shape leaves that value
|
|
1247
1249
|
// out, so the shop joins the identity: a retry that names another shop needs its own approval.
|
|
1248
1250
|
const shop = gmoRequestShop(url, body);
|
|
1249
|
-
|
|
1251
|
+
const identity = shop === undefined ? shaped.shape : `${shaped.shape};gmo_shop:${JSON.stringify(shop)}`;
|
|
1252
|
+
return { url, method, documentUrl, pageAmount, body: `${identity}${paddleVgsRetryKey(url, body, headers)}`,
|
|
1250
1253
|
amountEvidence: opts.amount != null || pageAmount !== undefined || shaped.namesAmount };
|
|
1251
1254
|
}
|
|
1255
|
+
/**
|
|
1256
|
+
* What a Paddle VGS card request's retry must repeat byte for byte, beyond its shape: Paddle's frame
|
|
1257
|
+
* sends its second request with the same body under the same bearer, and the bearer names the
|
|
1258
|
+
* checkout the card is stored for. So the whole body and the bearer and content type join the
|
|
1259
|
+
* identity: a request under another checkout's bearer, or with any value changed, never receives
|
|
1260
|
+
* the stored card's id the cardholder approved for the first. Empty for every other request.
|
|
1261
|
+
*/
|
|
1262
|
+
function paddleVgsRetryKey(url, body, headers) {
|
|
1263
|
+
if (!isPaddleVgsCardsUrl(url))
|
|
1264
|
+
return '';
|
|
1265
|
+
const record = headers !== null && typeof headers === 'object' ? headers : {};
|
|
1266
|
+
const one = (name) => {
|
|
1267
|
+
const found = Object.keys(record).filter((key) => key.toLowerCase() === name);
|
|
1268
|
+
return found.length === 1 && typeof record[found[0]] === 'string' ? record[found[0]] : null;
|
|
1269
|
+
};
|
|
1270
|
+
return `;paddle_vgs:${JSON.stringify([one('authorization'), one('content-type'), body])}`;
|
|
1271
|
+
}
|
|
1252
1272
|
/** A CDP frame or request URL with its fragment, which CDP reports apart (urlFragment). */
|
|
1253
1273
|
function withFragment(value) {
|
|
1254
1274
|
if (typeof value?.url !== 'string')
|
|
@@ -1291,7 +1311,9 @@ function sameCheckoutRequest(first, retry) {
|
|
|
1291
1311
|
* answer once the page has moved on), a prepared checkout (single use, bound
|
|
1292
1312
|
* to one native request by design) other than a Bambora token create, whose
|
|
1293
1313
|
* card frame gives up 5 seconds after sending it and whose page asks again
|
|
1294
|
-
* with the same body (preparedApprovalAnswersRetry),
|
|
1314
|
+
* with the same body (preparedApprovalAnswersRetry), or a Paddle VGS card
|
|
1315
|
+
* request, whose frame sends its second request byte for byte under the same
|
|
1316
|
+
* bearer (paddleVgsRetryKey), from that same card frame
|
|
1295
1317
|
* only (sameFrame), a native Stripe Checkout step, a
|
|
1296
1318
|
* Mercado Pago request whose claim is bound to one document read, a Juspay
|
|
1297
1319
|
* /txns (the device pays that request's own order; a page that clicks Pay
|
|
@@ -1511,7 +1533,10 @@ function replayOf(result, timeoutMs) {
|
|
|
1511
1533
|
|| !response.headers || typeof response.headers !== 'object' || Array.isArray(response.headers)) {
|
|
1512
1534
|
throw new Error('An approved token read resumes with response, the processor\'s answer (voice.awaitResult carries it once the purchase finished).');
|
|
1513
1535
|
}
|
|
1514
|
-
|
|
1536
|
+
// The read's processor_context rides as it came: a Paddle VGS answer is handed to the page only with the
|
|
1537
|
+
// approved card's details its /pay names (paddle-vgs-pay.ts checks them before the hand-over).
|
|
1538
|
+
return { mode: 'token', authorizationId, status: response.status, headers: { ...response.headers }, body: response.body, amountVerified: null,
|
|
1539
|
+
...(result.processor_context !== undefined ? { processorContext: result.processor_context } : {}), ...execution };
|
|
1515
1540
|
}
|
|
1516
1541
|
/** The recogniser that claimed a paused request, by processor name, so a caller never re-matches the URL; null on a duck-typed vault without the read. */
|
|
1517
1542
|
function recognizerNameOf(opts, url, method) {
|
|
@@ -1998,6 +2023,10 @@ export async function attachToCdp(cdp, pageSessionId, opts) {
|
|
|
1998
2023
|
// committing a new document (Page.frameNavigated, at the top of the event handler).
|
|
1999
2024
|
const shijiCompanions = new ShijiStsCompanions();
|
|
2000
2025
|
lifecycle.abort.signal.addEventListener('abort', () => shijiCompanions.release(), { once: true });
|
|
2026
|
+
// Paddle's /pay after the stored card's id this attachment handed a frame (paddle-vgs-pay.ts): its
|
|
2027
|
+
// checkout services are held only when the synced registry serves Paddle VGS, and a cancel drops the binding.
|
|
2028
|
+
const paddleVgsPay = new PaddleVgsPayGate(() => recognizesPaddleVgs(opts.vault));
|
|
2029
|
+
lifecycle.abort.signal.addEventListener('abort', () => paddleVgsPay.release(), { once: true });
|
|
2001
2030
|
const derived = typeof opts.vault?.cardUrlPatterns === 'function' ? opts.vault.cardUrlPatterns() : [];
|
|
2002
2031
|
// The endpoint and siblings of every merchant profile this build reviewed
|
|
2003
2032
|
// (merchant-hosted.ts), which a VaultClient arms from the start: a profile's card
|
|
@@ -2025,7 +2054,8 @@ export async function attachToCdp(cdp, pageSessionId, opts) {
|
|
|
2025
2054
|
const urlPatterns = [...new Set([...(derived.length > 0 ? derived : FALLBACK_CARD_PATTERNS), ...guards.patterns,
|
|
2026
2055
|
...(stripeCheckout.isEnabled() ? ['https://api.stripe.com/*'] : []), MERCADO_CHECKOUT_PATTERN, ...merchantPatterns,
|
|
2027
2056
|
...(recognizesGmo(opts.vault) ? GMO_TOKEN_V1_PATTERNS : []), ...juspayCheckout.urlPatterns(), ...cardEndpointPatterns(),
|
|
2028
|
-
...(payrails ? PAYRAILS_GUARD_PATTERNS : []), ...PAYPAL_HOSTED_FIELDS_PATTERNS, ...CYBERSOURCE_SECURE_ACCEPTANCE_PATTERNS
|
|
2057
|
+
...(payrails ? PAYRAILS_GUARD_PATTERNS : []), ...PAYPAL_HOSTED_FIELDS_PATTERNS, ...CYBERSOURCE_SECURE_ACCEPTANCE_PATTERNS,
|
|
2058
|
+
...(recognizesPaddleVgs(opts.vault) ? PADDLE_VGS_PAY_PATTERNS : [])])];
|
|
2029
2059
|
const arm = async (sessionId, resume = false, worker = false) => {
|
|
2030
2060
|
const key = sessionId ?? '__root__';
|
|
2031
2061
|
if (armed.has(key))
|
|
@@ -2459,6 +2489,7 @@ export async function attachToCdp(cdp, pageSessionId, opts) {
|
|
|
2459
2489
|
payrails,
|
|
2460
2490
|
shijiSts: { companions: shijiCompanions, page: () => cdpShijiPage(sessionId, frameId) },
|
|
2461
2491
|
worldlineMyCheckout: worldlineProducts,
|
|
2492
|
+
paddleVgsPay,
|
|
2462
2493
|
});
|
|
2463
2494
|
const preClaim = preClaimResult instanceof Promise ? await preClaimResult : preClaimResult;
|
|
2464
2495
|
if (preClaim.kind !== 'pause')
|
|
@@ -2524,7 +2555,7 @@ export async function attachToCdp(cdp, pageSessionId, opts) {
|
|
|
2524
2555
|
if (awaitingApproval && activeRequest?.attempt.lost && !terminal && !setupStop.signal.aborted && !lifecycle.isCancelled()
|
|
2525
2556
|
&& typeof networkId === 'string' && networkId) {
|
|
2526
2557
|
const retryBody = pausedBody(request);
|
|
2527
|
-
const retry = retryBody === null ? null : requestIdentity(opts, request.url, request.method, retryBody, documentKey(await documentUrlOf(readDocumentUrl, lifecycle.abort.signal)), await pageAmountOf(opts), flexPause?.shape);
|
|
2558
|
+
const retry = retryBody === null ? null : requestIdentity(opts, request.url, request.method, retryBody, documentKey(await documentUrlOf(readDocumentUrl, lifecycle.abort.signal)), await pageAmountOf(opts), flexPause?.shape, request.headers);
|
|
2528
2559
|
// A prepared approval is answered only in the card frame it was bound in: the same request from
|
|
2529
2560
|
// another frame (a replacement for a removed one, or a second card frame) is refused below.
|
|
2530
2561
|
if (retry && activeRequest?.attempt.lost && sameCheckoutRequest(activeRequest.identity, retry)
|
|
@@ -2647,7 +2678,7 @@ export async function attachToCdp(cdp, pageSessionId, opts) {
|
|
|
2647
2678
|
}
|
|
2648
2679
|
attempt.bind({ requestId, sessionId, request });
|
|
2649
2680
|
activeRequest = { attempt, requestId, networkId, sessionId, frameId, request,
|
|
2650
|
-
identity: requestIdentity(opts, request.url, request.method, body, undefined, undefined, flexPause?.shape),
|
|
2681
|
+
identity: requestIdentity(opts, request.url, request.method, body, undefined, undefined, flexPause?.shape, request.headers),
|
|
2651
2682
|
preparedFrame: preparation ? { sessionId, frameId } : undefined };
|
|
2652
2683
|
// An ACI card-number request: the page's CVC and expiry requests for its checkout are held
|
|
2653
2684
|
// until this approval ends (see AciGate). One whose checkout already has a card-number
|
|
@@ -2880,6 +2911,15 @@ export async function attachToCdp(cdp, pageSessionId, opts) {
|
|
|
2880
2911
|
// device_encrypt answer (Payrails' 201, which the device obtained) is
|
|
2881
2912
|
// handed over the same way.
|
|
2882
2913
|
const cors = corsDecision(deliverRequest.url, deliverRequest.headers);
|
|
2914
|
+
// A Paddle card request's answer is the stored card's id: the frame's /pay that follows continues only
|
|
2915
|
+
// with the approved card's details, bound to that frame before the id reaches it (paddle-vgs-pay.ts).
|
|
2916
|
+
// An answer that came with no details is not handed over: its /pay could only name the placeholder.
|
|
2917
|
+
try {
|
|
2918
|
+
paddleVgsPay.arm(activeRequest?.frameId || undefined, deliverRequest.url, replay);
|
|
2919
|
+
}
|
|
2920
|
+
catch {
|
|
2921
|
+
throw new PaymentOutcomeUnknownError(replay.authorizationId, 'paddle_vgs_card_facts_unavailable');
|
|
2922
|
+
}
|
|
2883
2923
|
await cdp.send('Fetch.fulfillRequest', {
|
|
2884
2924
|
requestId: deliverTo,
|
|
2885
2925
|
responseCode: replay.status,
|
|
@@ -3110,6 +3150,9 @@ export async function attachToPlaywright(page, opts) {
|
|
|
3110
3150
|
// a new document (the handlers below).
|
|
3111
3151
|
const shijiCompanions = new ShijiStsCompanions();
|
|
3112
3152
|
lifecycle.abort.signal.addEventListener('abort', () => shijiCompanions.release(), { once: true });
|
|
3153
|
+
// Paddle's /pay after the stored card's id this attachment handed a frame, as attachToCdp binds it.
|
|
3154
|
+
const paddleVgsPay = new PaddleVgsPayGate(() => recognizesPaddleVgs(opts.vault));
|
|
3155
|
+
lifecycle.abort.signal.addEventListener('abort', () => paddleVgsPay.release(), { once: true });
|
|
3113
3156
|
// An answer to a request the facts watch records began to arrive: the watch orders what the page sent after a
|
|
3114
3157
|
// record by this moment, since Playwright reports the answer's end after the page's next request. Listened to only
|
|
3115
3158
|
// once the page sent such a request, so a page that never meets a merchant with facts carries no extra listener.
|
|
@@ -3367,7 +3410,9 @@ export async function attachToPlaywright(page, opts) {
|
|
|
3367
3410
|
// PayPal's legacy Hosted Fields confirm, for every org, as attachToCdp arms it (paypal-hosted-fields.ts).
|
|
3368
3411
|
|| isPaypalHostedFieldsConfirm(url.toString())
|
|
3369
3412
|
// CyberSource Secure Acceptance's /silent/ paths, for every org, as attachToCdp arms them (cybersource-secure-acceptance.ts).
|
|
3370
|
-
|| isCybersourceSecureAcceptanceUrl(url.toString())
|
|
3413
|
+
|| isCybersourceSecureAcceptanceUrl(url.toString())
|
|
3414
|
+
// Paddle's checkout services, routed only for an org the API served Paddle VGS to (see attachToCdp).
|
|
3415
|
+
|| (isPaddleCheckoutService(url.toString()) && recognizesPaddleVgs(opts.vault)), async (route) => {
|
|
3371
3416
|
const request = route.request();
|
|
3372
3417
|
// When this request paused, and the page it came from: the merchant's total is read as of now.
|
|
3373
3418
|
const pausedAt = Date.now();
|
|
@@ -3464,6 +3509,7 @@ export async function attachToPlaywright(page, opts) {
|
|
|
3464
3509
|
payrails,
|
|
3465
3510
|
shijiSts: { companions: shijiCompanions, page: async () => (await playwrightShijiDocumentPage(request)) ?? `pw:none:${++playwrightShijiSeq}` },
|
|
3466
3511
|
worldlineMyCheckout: worldlineProducts,
|
|
3512
|
+
paddleVgsPay,
|
|
3467
3513
|
});
|
|
3468
3514
|
const preClaim = preClaimResult instanceof Promise ? await preClaimResult : preClaimResult;
|
|
3469
3515
|
if (preClaim.kind !== 'pause')
|
|
@@ -3515,7 +3561,7 @@ export async function attachToPlaywright(page, opts) {
|
|
|
3515
3561
|
// for, after its own request timed out: bind it to that approval (see
|
|
3516
3562
|
// merchantAttempt and the same check in attachToCdp).
|
|
3517
3563
|
if (awaitingApproval && activeRequest?.attempt.lost && !terminal && !setupStop.signal.aborted && !lifecycle.isCancelled()) {
|
|
3518
|
-
const retry = requestIdentity(opts, request.url(), request.method(), request.postData() ?? '', documentKey(await documentUrlOf(readDocumentUrl, lifecycle.abort.signal)), await pageAmountOf(opts), flexPause?.shape);
|
|
3564
|
+
const retry = requestIdentity(opts, request.url(), request.method(), request.postData() ?? '', documentKey(await documentUrlOf(readDocumentUrl, lifecycle.abort.signal)), await pageAmountOf(opts), flexPause?.shape, request.headers());
|
|
3519
3565
|
const retryFrames = [];
|
|
3520
3566
|
try {
|
|
3521
3567
|
for (let frame = request.frame?.(); frame; frame = frame.parentFrame?.())
|
|
@@ -3638,7 +3684,7 @@ export async function attachToPlaywright(page, opts) {
|
|
|
3638
3684
|
const payToInterceptMs = readPayToInterceptMs(opts.payClickedAt, approvalStartedAt);
|
|
3639
3685
|
attempt.bind({ route, request, frames });
|
|
3640
3686
|
activeRequest = { request, frames, attempt,
|
|
3641
|
-
identity: requestIdentity(opts, request.url(), request.method(), body, undefined, undefined, flexPause?.shape),
|
|
3687
|
+
identity: requestIdentity(opts, request.url(), request.method(), body, undefined, undefined, flexPause?.shape, request.headers()),
|
|
3642
3688
|
preparedFrames: preparation ? [...frames] : undefined };
|
|
3643
3689
|
// An ACI card-number request: see the same step in attachToCdp.
|
|
3644
3690
|
if (!aci.begin(request.url(), request.method(), body, preparation?.merchantOrigin)) {
|
|
@@ -3826,6 +3872,13 @@ export async function attachToPlaywright(page, opts) {
|
|
|
3826
3872
|
// none; written here anyway (replacing a stale value) so a
|
|
3827
3873
|
// cross-origin answer is the same whichever adapter ran.
|
|
3828
3874
|
const cors = corsDecision(deliverRequest.url(), deliverRequest.headers());
|
|
3875
|
+
// See the same step in attachToCdp: a Paddle stored card's id reaches its frame only with its /pay bound.
|
|
3876
|
+
try {
|
|
3877
|
+
paddleVgsPay.arm(frameOf(deliverRequest), deliverRequest.url(), replay);
|
|
3878
|
+
}
|
|
3879
|
+
catch {
|
|
3880
|
+
throw new PaymentOutcomeUnknownError(replay.authorizationId, 'paddle_vgs_card_facts_unavailable');
|
|
3881
|
+
}
|
|
3829
3882
|
await deliverTo.fulfill({ status: replay.status, headers: withCorsHeaders(replay.headers, cors.headers), body: replay.body });
|
|
3830
3883
|
datatransRepeats.remember(frameOf(deliverRequest), deliverRequest.url(), deliverBody, replay);
|
|
3831
3884
|
assertRequestLive();
|
package/dist/client.d.ts
CHANGED
|
@@ -204,6 +204,14 @@ export declare const SUPPORTED_REGISTRY_FEATURES: readonly string[];
|
|
|
204
204
|
* the same terms: only to a build that lists it, for a company Agentcard turned
|
|
205
205
|
* Moneris on for. A gated recognizer never sits in BUILTIN_REGISTRY, so it is paused
|
|
206
206
|
* only after a sync.
|
|
207
|
+
*
|
|
208
|
+
* `paddle_vgs_cards`: the card request Paddle's checkout frame sends to its VGS card
|
|
209
|
+
* vault (vault.paddle.com/cards) on a checkout that names VGS, only through a prepared
|
|
210
|
+
* checkout: the frame aborts the request 10 seconds after Pay and sends it once more,
|
|
211
|
+
* and this build answers that second request from the same approval. The cardholder's
|
|
212
|
+
* device sends the card itself and the frame gets back the stored card's id alone.
|
|
213
|
+
* Served on the same terms: only to a build that lists it, for a company Agentcard
|
|
214
|
+
* turned Paddle on for.
|
|
207
215
|
*/
|
|
208
216
|
export declare const SUPPORTED_CAPABILITIES: readonly string[];
|
|
209
217
|
/**
|
|
@@ -243,7 +251,10 @@ export interface ExecutionMetadata {
|
|
|
243
251
|
* this is the processor's answer to replay into the paused request.
|
|
244
252
|
*/
|
|
245
253
|
export interface TokenReplay extends ExecutionMetadata {
|
|
246
|
-
/**
|
|
254
|
+
/**
|
|
255
|
+
* Authenticated selected-card metadata; the processor response body stays unchanged. Paddle VGS: the
|
|
256
|
+
* approved card's first six and last four digits, expiry and brand, which the frame's /pay names.
|
|
257
|
+
*/
|
|
247
258
|
processorContext?: unknown;
|
|
248
259
|
/** Present only after validating the native TEST Checkout completion. */
|
|
249
260
|
checkoutSessionId?: string;
|
|
@@ -1088,8 +1099,13 @@ export declare class CheckoutAuthError extends Error {
|
|
|
1088
1099
|
* so it reads {txId}, as does any other id-shaped segment there.
|
|
1089
1100
|
* On the Monri and WSPay hosts the secret is a path segment, so it is replaced
|
|
1090
1101
|
* with `{client_secret}`: https://proxy.wspay.biz/v2/payment/{client_secret}/confirm.
|
|
1102
|
+
* On Gravy's hosts the checkout session id is the credential, so it reads
|
|
1103
|
+
* `{session}`: https://api.<merchant>.gr4vy.app/checkout/sessions/{session}/fields.
|
|
1104
|
+
* On Rapyd's hosts the hosted page's id reads `{token}`: https://api.rapyd.net/v1/checkout/{token}.
|
|
1105
|
+
* On api.stripe.com a Checkout Session id reads `{session}`:
|
|
1106
|
+
* https://api.stripe.com/v1/payment_pages/{session}/confirm.
|
|
1091
1107
|
* A string that is not a URL keeps the part before any `?` or `#`, with the
|
|
1092
|
-
* same
|
|
1108
|
+
* same segments masked.
|
|
1093
1109
|
*/
|
|
1094
1110
|
export declare function redactUrl(raw: string): string;
|
|
1095
1111
|
export interface VaultClientOptions {
|
|
@@ -1428,11 +1444,12 @@ export declare class VaultClient {
|
|
|
1428
1444
|
* approval produced: a SetupIntent confirm that carries no card and pays with
|
|
1429
1445
|
* exactly the approved payment method (the page's own, or written by the
|
|
1430
1446
|
* adapters in place of a card the confirm carries again).
|
|
1431
|
-
* The API allows a card save
|
|
1432
|
-
*
|
|
1433
|
-
*
|
|
1434
|
-
*
|
|
1435
|
-
*
|
|
1447
|
+
* The API allows a card save for any company, for an approval given on the
|
|
1448
|
+
* Vault page, not by voice, with no amount, and a SetupIntent Stripe reports
|
|
1449
|
+
* still confirmable on the same Stripe account; any other answer rejects with
|
|
1450
|
+
* a CheckoutApiError whose code says why (for example `amount_mismatch`, or
|
|
1451
|
+
* `continuation_invalid` for a confirm that is not a card-free SetupIntent
|
|
1452
|
+
* confirm). Nothing
|
|
1436
1453
|
* is charged: the adapters continue the page's request once this resolves.
|
|
1437
1454
|
*/
|
|
1438
1455
|
checkStripeSetupContinuation(authorizationId: string, request: {
|