@agent-cards/sdk 0.23.14 → 0.23.16
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 +6 -0
- package/LICENSE +1 -1
- package/PREFLIGHT.md +2 -0
- package/README.md +2 -0
- package/dist/amadeus.d.ts +5 -2
- package/dist/amadeus.js +17 -3
- package/dist/card-fields.generated.js +237 -17
- package/dist/cdp.js +16 -8
- package/dist/client.d.ts +11 -0
- package/dist/client.js +58 -8
- package/dist/lifecycle.d.ts +5 -1
- package/dist/lifecycle.js +3 -0
- package/dist/paypal-card-forms.d.ts +73 -0
- package/dist/paypal-card-forms.js +126 -0
- package/dist/pre-claim.d.ts +1 -0
- package/dist/pre-claim.js +59 -3
- package/dist/prepared-processor.d.ts +5 -1
- package/dist/prepared-processor.js +11 -0
- package/dist/primer.generated.js +248 -28
- package/dist/stripe-checkout.generated.js +79 -1
- package/dist/wix-payments.generated.d.ts +42 -0
- package/dist/wix-payments.generated.js +241 -0
- package/package.json +3 -3
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
|
|
@@ -1091,6 +1102,19 @@ const LYRA_SESSION = /;jsessionid=[^/;?#]*/gi;
|
|
|
1091
1102
|
function maskLyraSession(path) {
|
|
1092
1103
|
return path.replace(LYRA_SESSION, ';jsessionid={session}');
|
|
1093
1104
|
}
|
|
1105
|
+
/**
|
|
1106
|
+
* PayMongo's hosted checkout sends its card form's attach to its own page URL,
|
|
1107
|
+
* https://checkout.paymongo.com/<session> (payment-core paymongo.js), and the session id is the only
|
|
1108
|
+
* credential there, no cookies: with it anyone can open that checkout, its amount and its merchant, and
|
|
1109
|
+
* pay it. Every route of the host is a session page, so on it any run of 24 or more letters and digits,
|
|
1110
|
+
* with or without its cs_ prefix, in any case, after an escaped slash or with any character
|
|
1111
|
+
* percent-encoded (a path keeps %36 where it means 6), reads {session}.
|
|
1112
|
+
*/
|
|
1113
|
+
const PAYMONGO_CHECKOUT_HOST = /^checkout\.paymongo\.com\.?$/i;
|
|
1114
|
+
const PAYMONGO_SESSION = /(?:cs_)?(?:[A-Za-z0-9]|%[0-9A-Fa-f]{2}){24,}/gi;
|
|
1115
|
+
function maskPaymongoSession(path) {
|
|
1116
|
+
return path.replace(PAYMONGO_SESSION, '{session}');
|
|
1117
|
+
}
|
|
1094
1118
|
/**
|
|
1095
1119
|
* The processors whose card request carries its own credential in the URL path, with the hosts
|
|
1096
1120
|
* that send it, the text that names those hosts in a string that is not a URL, and the mask. The
|
|
@@ -1108,6 +1132,17 @@ const REDSYS_SESSION = /((?:;|%3b)jsessionid(?:=|%3d))[^/?#;]*/gi;
|
|
|
1108
1132
|
function maskRedsysSession(path) {
|
|
1109
1133
|
return path.replace(REDSYS_SESSION, '$1{session}');
|
|
1110
1134
|
}
|
|
1135
|
+
/**
|
|
1136
|
+
* A PayPal order id opens PayPal's own checkout page for that order (/checkoutnow?token=<order id>) to
|
|
1137
|
+
* anyone who holds it, and PayPal's card confirms carry it in the path:
|
|
1138
|
+
* /v2/checkout/orders/<order id>/confirm-payment-source on www, api-m and cors.api. On PayPal's hosts the
|
|
1139
|
+
* segment after /orders/, in any case or after an escaped slash, reads {order}.
|
|
1140
|
+
*/
|
|
1141
|
+
const PAYPAL_HOST = /(?:^|\.)paypal\.com\.?$/i;
|
|
1142
|
+
const PAYPAL_ORDER = /(\/orders(?:\/|%2f))[^/]*/gi;
|
|
1143
|
+
function maskPaypalOrder(path) {
|
|
1144
|
+
return path.replace(PAYPAL_ORDER, '$1{order}');
|
|
1145
|
+
}
|
|
1111
1146
|
const PATH_CREDENTIALS = [
|
|
1112
1147
|
{ host: CREDITGUARD_HOST, named: /creditguard\.co\.il/i, mask: maskCreditguardTxId },
|
|
1113
1148
|
{ host: GRAVY_HOST, named: /gr4vy\.app/i, mask: maskGravySession },
|
|
@@ -1118,6 +1153,8 @@ const PATH_CREDENTIALS = [
|
|
|
1118
1153
|
{ host: PADDLE_CHECKOUT_HOST, named: /checkout-service\.paddle\.com/i, mask: maskPaddleCheckout },
|
|
1119
1154
|
{ host: REDSYS_HOST, named: /redsys\.es/i, mask: maskRedsysSession },
|
|
1120
1155
|
{ host: LYRA_HOST, named: /(?:payzen\.eu|systempay\.fr|societegenerale\.eu|lyra\.com)/i, mask: maskLyraSession },
|
|
1156
|
+
{ host: PAYPAL_HOST, named: /paypal\.com/i, mask: maskPaypalOrder },
|
|
1157
|
+
{ host: PAYMONGO_CHECKOUT_HOST, named: /checkout\.paymongo\.com/i, mask: maskPaymongoSession },
|
|
1121
1158
|
];
|
|
1122
1159
|
/**
|
|
1123
1160
|
* A URL as it may appear in an error message: origin + path only. A paused
|
|
@@ -1138,6 +1175,9 @@ const PATH_CREDENTIALS = [
|
|
|
1138
1175
|
* On Redsys's hosts the session id after `;jsessionid=` reads `{session}`:
|
|
1139
1176
|
* https://sis.redsys.es/sis/pagoTarjeta;jsessionid={session}.
|
|
1140
1177
|
* On Lyra's API hosts the form token's session id reads `{session}`.
|
|
1178
|
+
* On PayPal's hosts an order id reads `{order}`:
|
|
1179
|
+
* https://www.paypal.com/v2/checkout/orders/{order}/confirm-payment-source.
|
|
1180
|
+
* On PayMongo's checkout host the session id reads `{session}`: https://checkout.paymongo.com/{session}.
|
|
1141
1181
|
* A string that is not a URL keeps the part before any `?` or `#`, with the
|
|
1142
1182
|
* same segments masked.
|
|
1143
1183
|
*/
|
|
@@ -1226,17 +1266,26 @@ const SECURE_ACCEPTANCE_PREPARATION_REFUSALS = [
|
|
|
1226
1266
|
const PADDLE_VGS_PREPARATION_REFUSALS = [
|
|
1227
1267
|
'processor_unavailable', 'sandbox_host_on_live_row', 'live_host_on_sandbox_row', 'merchant_profile_mismatch', 'paddle_vgs_card_unsupported',
|
|
1228
1268
|
];
|
|
1269
|
+
/**
|
|
1270
|
+
* The API's refusals of a Wix Payments preparation, before any preparation exists, that prepareCheckout
|
|
1271
|
+
* surfaces by name: the lane is held to Agentcard's own account (`processor_unavailable`), a test client
|
|
1272
|
+
* asked for it (`live_host_on_sandbox_row`: Wix has no test environment), and a checkout's merchant is not
|
|
1273
|
+
* the name the reviewed store pin carries (`merchant_profile_mismatch`). An unreviewed store answers
|
|
1274
|
+
* `unsupported_checkout`, which PREPARATION_REFUSALS names for every checkout. Only for a Wix checkout.
|
|
1275
|
+
*/
|
|
1276
|
+
const WIX_PAYMENTS_PREPARATION_REFUSALS = ['processor_unavailable', 'live_host_on_sandbox_row', 'merchant_profile_mismatch'];
|
|
1229
1277
|
/**
|
|
1230
1278
|
* The reason the cardholder's device declines a bound prepared row with, per processor, when its own
|
|
1231
1279
|
* 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
|
|
1233
|
-
* names the same known non-payment the adapters' own send window
|
|
1234
|
-
* close later, so authorize() ends the attempt the way that window
|
|
1235
|
-
* with that reason, and never as the cardholder's "no".
|
|
1280
|
+
* the checkout unbound): a prepared Amadeus SDK add, a prepared Secure Acceptance token create and a
|
|
1281
|
+
* prepared Wix tokenize request. It names the same known non-payment the adapters' own send window
|
|
1282
|
+
* closes on (amadeus.ts), which can close later, so authorize() ends the attempt the way that window
|
|
1283
|
+
* does, as a CheckoutPreparationError with that reason, and never as the cardholder's "no".
|
|
1236
1284
|
*/
|
|
1237
1285
|
const PREPARED_SEND_WINDOW_DECLINES = Object.freeze({
|
|
1238
1286
|
amadeus_checkout: 'amadeus_send_window_closed',
|
|
1239
1287
|
[SECURE_ACCEPTANCE_PSP]: 'secure_acceptance_send_window_closed',
|
|
1288
|
+
[WIX_PAYMENTS_PSP]: 'wix_payments_send_window_closed',
|
|
1240
1289
|
});
|
|
1241
1290
|
/**
|
|
1242
1291
|
* Refusals a CyberSource Flex preparation that tokenizes before Pay answers (4xx) before any
|
|
@@ -1918,6 +1967,7 @@ export class VaultClient {
|
|
|
1918
1967
|
|| (input.psp === 'fiserv' && FISERV_PREPARATION_REFUSALS.includes(error.code))
|
|
1919
1968
|
|| (input.psp === EPROTECT_PSP && EPROTECT_PREPARATION_REFUSALS.includes(error.code))
|
|
1920
1969
|
|| (input.psp === PADDLE_VGS_PSP && PADDLE_VGS_PREPARATION_REFUSALS.includes(error.code))
|
|
1970
|
+
|| (input.psp === WIX_PAYMENTS_PSP && WIX_PAYMENTS_PREPARATION_REFUSALS.includes(error.code))
|
|
1921
1971
|
|| (!!flexContext && CYBERSOURCE_FLEX_PREPARATION_REFUSALS.includes(error.code))))
|
|
1922
1972
|
|| (input.psp === 'fiserv' && error.status === 502 && error.code === 'cse_key_unavailable')))
|
|
1923
1973
|
throw fail(error.code);
|
package/dist/lifecycle.d.ts
CHANGED
|
@@ -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;
|
|
@@ -0,0 +1,126 @@
|
|
|
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 const PAYPAL_CARD_FIELDS_REASON = 'unsupported_paypal_card_fields';
|
|
44
|
+
export const PAYPAL_GUEST_CHECKOUT_REASON = 'unsupported_paypal_guest_checkout';
|
|
45
|
+
/** The hosts Card Fields sends its confirm to: v5 on www, v6 on api-m, live and sandbox. */
|
|
46
|
+
export const PAYPAL_CARD_FIELDS_HOSTS = Object.freeze(['www.paypal.com', 'www.sandbox.paypal.com',
|
|
47
|
+
'api-m.paypal.com', 'api-m.sandbox.paypal.com']);
|
|
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 const PAYPAL_GRAPHQL_HOSTS = Object.freeze(['www.paypal.com', 'www.sandbox.paypal.com']);
|
|
50
|
+
const CONFIRM_PATH = /^\/v2\/checkout\/orders\/[^/]+\/confirm-payment-source\/?$/;
|
|
51
|
+
const GRAPHQL_PATH = /^\/graphql\/?$/;
|
|
52
|
+
/** The two GraphQL operations that carry a card, as PayPal's clients name them in the query string. */
|
|
53
|
+
const CARD_OPERATIONS = ['OnboardGuestMutation', 'UpdateVaultSetupToken'];
|
|
54
|
+
/**
|
|
55
|
+
* CDP Fetch patterns, armed on every attachment: the confirm on its four hosts and GraphQL on PayPal's
|
|
56
|
+
* two page hosts. Chrome sends the canonical URL, whose host is lower case, and the trailing `*` keeps a
|
|
57
|
+
* query or a trailing slash paused. Nothing else on www.paypal.com is armed.
|
|
58
|
+
*/
|
|
59
|
+
export const PAYPAL_CARD_FORM_PATTERNS = Object.freeze([
|
|
60
|
+
...PAYPAL_CARD_FIELDS_HOSTS.map((host) => `https://${host}/v2/checkout/orders/*/confirm-payment-source*`),
|
|
61
|
+
...PAYPAL_GRAPHQL_HOSTS.map((host) => `https://${host}/graphql*`),
|
|
62
|
+
]);
|
|
63
|
+
function paypalUrl(url, hosts, path) {
|
|
64
|
+
let parsed;
|
|
65
|
+
try {
|
|
66
|
+
parsed = new URL(url);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
return parsed.protocol === 'https:' && !parsed.port && !parsed.username && !parsed.password
|
|
72
|
+
&& hosts.includes(parsed.hostname.toLowerCase()) && path.test(parsed.pathname) ? parsed : null;
|
|
73
|
+
}
|
|
74
|
+
/** Whether this URL is the Card Fields confirm on one of its four hosts (https, standard port, no credentials). */
|
|
75
|
+
export function isPaypalCardFieldsConfirm(url) {
|
|
76
|
+
return paypalUrl(url, PAYPAL_CARD_FIELDS_HOSTS, CONFIRM_PATH) !== null;
|
|
77
|
+
}
|
|
78
|
+
/** Whether this URL is GraphQL on one of PayPal's two page hosts. */
|
|
79
|
+
export function isPaypalGraphql(url) {
|
|
80
|
+
return paypalUrl(url, PAYPAL_GRAPHQL_HOSTS, GRAPHQL_PATH) !== null;
|
|
81
|
+
}
|
|
82
|
+
/** Whether this URL is any request the guard judges, for the Playwright route's predicate. */
|
|
83
|
+
export function isPaypalCardFormUrl(url) {
|
|
84
|
+
return isPaypalCardFieldsConfirm(url) || isPaypalGraphql(url);
|
|
85
|
+
}
|
|
86
|
+
/** Whether a GraphQL URL's query names one of the two card operations (`/graphql?OnboardGuestMutation`). */
|
|
87
|
+
export function paypalGraphqlNamesCardOperation(url) {
|
|
88
|
+
const parsed = paypalUrl(url, PAYPAL_GRAPHQL_HOSTS, GRAPHQL_PATH);
|
|
89
|
+
return parsed !== null && CARD_OPERATIONS.some((name) => parsed.searchParams.has(name));
|
|
90
|
+
}
|
|
91
|
+
const record = (value) => !!value && typeof value === 'object' && !Array.isArray(value);
|
|
92
|
+
const present = (value) => value !== undefined && value !== null && value !== '';
|
|
93
|
+
/**
|
|
94
|
+
* What a GraphQL post carries, read as PayPal reads it (the last of a repeated key wins in both), for one
|
|
95
|
+
* operation or a batch of them: 'guest_card' when an operation's variables.card.cardNumber holds anything
|
|
96
|
+
* but null or an empty string, 'saved_card' when an operation's variables.paymentSource.card is an object,
|
|
97
|
+
* 'no_card' for any other JSON object or array of them, and 'unreadable' for a body the adapter could not
|
|
98
|
+
* read (null), an empty one, or one that is neither.
|
|
99
|
+
*/
|
|
100
|
+
export function paypalGraphqlCard(body) {
|
|
101
|
+
if (typeof body !== 'string' || body === '')
|
|
102
|
+
return 'unreadable';
|
|
103
|
+
let parsed;
|
|
104
|
+
try {
|
|
105
|
+
parsed = JSON.parse(body);
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
return 'unreadable';
|
|
109
|
+
}
|
|
110
|
+
const operations = Array.isArray(parsed) ? parsed : [parsed];
|
|
111
|
+
if (operations.length === 0 || !operations.every(record))
|
|
112
|
+
return 'unreadable';
|
|
113
|
+
let carried = 'no_card';
|
|
114
|
+
for (const operation of operations) {
|
|
115
|
+
const variables = operation.variables;
|
|
116
|
+
if (!record(variables))
|
|
117
|
+
continue;
|
|
118
|
+
if (record(variables.card) && present(variables.card.cardNumber))
|
|
119
|
+
return 'guest_card';
|
|
120
|
+
if (record(variables.paymentSource) && record(variables.paymentSource.card))
|
|
121
|
+
carried = 'saved_card';
|
|
122
|
+
}
|
|
123
|
+
return carried;
|
|
124
|
+
}
|
|
125
|
+
/** What a Card Fields confirm carries: its body is the Orders v2 shape Hosted Fields also sends. */
|
|
126
|
+
export const paypalCardFieldsBody = paypalHostedFieldsBody;
|
package/dist/pre-claim.d.ts
CHANGED
|
@@ -252,6 +252,7 @@ export declare function isArmedCreditguardCall(vault: {
|
|
|
252
252
|
export declare const ekashuPreClaim: PreClaimGate;
|
|
253
253
|
export declare const redsysPreClaim: PreClaimGate;
|
|
254
254
|
export declare const paypalHostedFieldsPreClaim: PreClaimGate;
|
|
255
|
+
export declare const paypalCardFormsPreClaim: PreClaimGate;
|
|
255
256
|
export declare const cybersourceSecureAcceptancePreClaim: PreClaimGate;
|
|
256
257
|
export declare const worldlineMyCheckoutPreClaim: PreClaimGate;
|
|
257
258
|
export declare const paddleVgsPayPreClaim: PreClaimGate;
|
package/dist/pre-claim.js
CHANGED
|
@@ -16,8 +16,9 @@
|
|
|
16
16
|
// card-saving bodies, WSPay's confirm URL, which also carries bodies with
|
|
17
17
|
// no new card, Shiji STS's getTokenId and getCvvId, which also carry
|
|
18
18
|
// requests the vault must never pay, PayPal's legacy Hosted Fields
|
|
19
|
-
// confirm
|
|
20
|
-
// no Vault mode takes over
|
|
19
|
+
// confirm, PayPal's Card Fields and guest card form, and CyberSource Secure
|
|
20
|
+
// Acceptance's Silent Order POST, whose card no Vault mode takes over until a
|
|
21
|
+
// recognizer does, Worldline MyCheckout's card form, held to the
|
|
21
22
|
// card product its page chose, and EBANX's 3-D Secure calls and hosted confirm,
|
|
22
23
|
// which send the card again after its token and leave only from the
|
|
23
24
|
// cardholder's device, under the token request's approval.
|
|
@@ -80,6 +81,7 @@ import { classifyVerifoneProfileRequest, verifoneTemplatedUrl } from './verifone
|
|
|
80
81
|
import { ekashuEntryUrl, isEkashuEntry, isEkashuHost } from './ekashu.js';
|
|
81
82
|
import { isRedsysEntry, isRedsysHost, redsysEntryUrl } from './redsys.js';
|
|
82
83
|
import { PAYPAL_HOSTED_FIELDS_REASON, isPaypalHostedFieldsConfirm, paypalHostedFieldsBody } from './paypal-hosted-fields.js';
|
|
84
|
+
import { PAYPAL_CARD_FIELDS_REASON, PAYPAL_GUEST_CHECKOUT_REASON, isPaypalCardFieldsConfirm, isPaypalGraphql, paypalCardFieldsBody, paypalGraphqlCard, paypalGraphqlNamesCardOperation, } from './paypal-card-forms.js';
|
|
83
85
|
import { CYBERSOURCE_SECURE_ACCEPTANCE_REASON, CYBERSOURCE_SECURE_ACCEPTANCE_RECIPIENT, cybersourceSecureAcceptanceRequest, isCybersourceSecureAcceptanceUrl, isSecureAcceptanceFramePost, } from './cybersource-secure-acceptance.js';
|
|
84
86
|
import { isWorldlineMyCheckoutEndpoint } from './worldline-mycheckout.js';
|
|
85
87
|
import { paddleVgsPayEventUrl } from './paddle-vgs-pay.js';
|
|
@@ -1671,6 +1673,60 @@ async function paypalHostedFieldsUnreadable(ctx) {
|
|
|
1671
1673
|
await ctx.effects.abort();
|
|
1672
1674
|
return { kind: 'abort' };
|
|
1673
1675
|
}
|
|
1676
|
+
// PayPal's Card Fields and guest card form (paypal-card-forms.ts). Every company's adapters hand each
|
|
1677
|
+
// POST to the Card Fields confirm (www and api-m, live and sandbox) and to GraphQL on www (live and
|
|
1678
|
+
// sandbox) to this gate:
|
|
1679
|
+
// - a confirm with a card number at payment_source.card.number aborts as an unsupported checkout,
|
|
1680
|
+
// reason `unsupported_paypal_card_fields`, with no claim, create or prompt, unless the synced
|
|
1681
|
+
// registry recognizes it as a card request: then it defers, and the PayPal Card Fields lane pauses
|
|
1682
|
+
// it for the cardholder's approval, judging the body itself;
|
|
1683
|
+
// - a GraphQL operation with a card aborts the same way whatever the registry serves:
|
|
1684
|
+
// `unsupported_paypal_guest_checkout` for the guest form's variables.card.cardNumber,
|
|
1685
|
+
// `unsupported_paypal_card_fields` for a card saved with no purchase (variables.paymentSource.card);
|
|
1686
|
+
// - a confirm the adapter could not read, and a GraphQL post it could not read whose query names one
|
|
1687
|
+
// of the two card operations, abort that request alone with a `blocked` event,
|
|
1688
|
+
// `unreadable_paypal_request`, and do not hold the attachment;
|
|
1689
|
+
// - anything else (a PayPal wallet confirm, a saved card, the buttons' other GraphQL operations, a GET
|
|
1690
|
+
// or a preflight) defers, and the arbiter continues it untouched.
|
|
1691
|
+
// Synchronous until it must abort, like every gate. Exported for the gate registry's tests.
|
|
1692
|
+
export const paypalCardFormsPreClaim = (ctx) => {
|
|
1693
|
+
const { url, method } = ctx.request;
|
|
1694
|
+
if (String(method).toUpperCase() !== 'POST')
|
|
1695
|
+
return undefined;
|
|
1696
|
+
const confirm = isPaypalCardFieldsConfirm(url);
|
|
1697
|
+
if (!confirm && !isPaypalGraphql(url))
|
|
1698
|
+
return undefined;
|
|
1699
|
+
if (confirm && ctx.vault.isCardRequest(url, method))
|
|
1700
|
+
return undefined;
|
|
1701
|
+
let body;
|
|
1702
|
+
// A reader that throws (Playwright's postData() can) proves nothing either way.
|
|
1703
|
+
try {
|
|
1704
|
+
body = ctx.request.body;
|
|
1705
|
+
}
|
|
1706
|
+
catch {
|
|
1707
|
+
body = null;
|
|
1708
|
+
}
|
|
1709
|
+
if (confirm) {
|
|
1710
|
+
const carried = paypalCardFieldsBody(body);
|
|
1711
|
+
if (carried === 'no_card')
|
|
1712
|
+
return undefined;
|
|
1713
|
+
return carried === 'card' ? paypalCardFormAbort(ctx, PAYPAL_CARD_FIELDS_REASON) : paypalHostedFieldsUnreadable(ctx);
|
|
1714
|
+
}
|
|
1715
|
+
const carried = paypalGraphqlCard(body);
|
|
1716
|
+
if (carried === 'guest_card')
|
|
1717
|
+
return paypalCardFormAbort(ctx, PAYPAL_GUEST_CHECKOUT_REASON);
|
|
1718
|
+
if (carried === 'saved_card')
|
|
1719
|
+
return paypalCardFormAbort(ctx, PAYPAL_CARD_FIELDS_REASON);
|
|
1720
|
+
return carried === 'unreadable' && paypalGraphqlNamesCardOperation(url) ? paypalHostedFieldsUnreadable(ctx) : undefined;
|
|
1721
|
+
};
|
|
1722
|
+
async function paypalCardFormAbort(ctx, reason) {
|
|
1723
|
+
const { url, method } = ctx.request;
|
|
1724
|
+
ctx.preparationGate.invalidate('unsupported_checkout');
|
|
1725
|
+
ctx.lifecycle.unsupported(reason);
|
|
1726
|
+
ctx.onEvent?.({ type: 'unsupported_checkout', detail: { url: eventUrl(ctx.vault, url), method, reason } });
|
|
1727
|
+
await ctx.effects.abort();
|
|
1728
|
+
return { kind: 'abort' };
|
|
1729
|
+
}
|
|
1674
1730
|
// CyberSource Secure Acceptance's Silent Order POST (cybersource-secure-acceptance.ts). The merchant's
|
|
1675
1731
|
// page posts the card the agent typed, beside the fields its server signed, to a /silent/ path on
|
|
1676
1732
|
// CyberSource's Secure Acceptance hosts, which no Vault mode takes over, so every company's adapters
|
|
@@ -2092,7 +2148,7 @@ async function unsupportedContinue(ctx) {
|
|
|
2092
2148
|
* after Stripe is never offered a step Stripe claimed: Stripe answers, aborts or
|
|
2093
2149
|
* pauses each one itself. */
|
|
2094
2150
|
export const PSP_PRE_CLAIM_GATES = [cardEndpointResendPreClaim, cardEndpointPreClaim, mercadoPreClaim, juspayPreClaim, braintreePreClaim, stripePreClaim, merchantHostedPreClaim, verifonePreClaim, fiservPreClaim, gmoPreClaim, cybersourceFlexPreClaim, datatransPreClaim, pelecardPreClaim, aciPreClaim, creditguardPreClaim, primerPreClaim, payrailsPreClaim, convergePreClaim, eprotectPreClaim, wspayPreClaim, shijiStsPreClaim, ekashuPreClaim, redsysPreClaim, paypalHostedFieldsPreClaim,
|
|
2095
|
-
cybersourceSecureAcceptancePreClaim, worldlineMyCheckoutPreClaim, paddleVgsPayPreClaim, ebanxPreClaim];
|
|
2151
|
+
paypalCardFormsPreClaim, cybersourceSecureAcceptancePreClaim, worldlineMyCheckoutPreClaim, paddleVgsPayPreClaim, ebanxPreClaim];
|
|
2096
2152
|
/** Run each gate in order; the first to return a decision wins. If none does,
|
|
2097
2153
|
* the terminal arbiter decides between continue, abort (unsupported) and pause.
|
|
2098
2154
|
* Returns synchronously while every gate defers synchronously (an ordinary card
|
|
@@ -20,8 +20,12 @@
|
|
|
20
20
|
* paddle_vgs: prepared only. Paddle's checkout frame aborts its card request to its VGS card vault 10
|
|
21
21
|
* seconds after Pay and sends it once more, too soon for an approval after Pay. Its environments are its
|
|
22
22
|
* two card URLs: vault.paddle.com (production) and sandbox-vault.paddle.com (sandbox).
|
|
23
|
+
*
|
|
24
|
+
* wix_payments: prepared only. Wix's payment widget fails the payment 30 seconds after it asks Wix
|
|
25
|
+
* Cashier's card frame for a token, too soon for an approval after Pay. Its one environment is
|
|
26
|
+
* production: Wix's tokenizer has no test host.
|
|
23
27
|
*/
|
|
24
|
-
export type PreparationProcessor = 'square' | 'braintree' | 'worldpay' | 'bambora' | 'mercado_pago' | 'recurly' | 'spreedly' | 'adyen' | 'checkout_com' | 'paysafe' | 'fiserv' | 'cybersource_flex' | 'aci' | 'creditguard' | 'worldpay_eprotect' | 'amadeus_checkout' | 'verifone' | 'cybersource_secure_acceptance' | 'paddle_vgs';
|
|
28
|
+
export type PreparationProcessor = 'square' | 'braintree' | 'worldpay' | 'bambora' | 'mercado_pago' | 'recurly' | 'spreedly' | 'adyen' | 'checkout_com' | 'paysafe' | 'fiserv' | 'cybersource_flex' | 'aci' | 'creditguard' | 'worldpay_eprotect' | 'amadeus_checkout' | 'verifone' | 'cybersource_secure_acceptance' | 'paddle_vgs' | 'wix_payments';
|
|
25
29
|
export type PreparationEnvironment = 'production' | 'sandbox' | 'shared';
|
|
26
30
|
/**
|
|
27
31
|
* How the approved card reaches the processor: the device's own request (token), or
|
|
@@ -14,6 +14,7 @@ import { amadeusEnvironment, amadeusPreparationUrls, amadeusRequestRefusal, isPr
|
|
|
14
14
|
import { isPreparedVerifoneRequest } from './verifone.js';
|
|
15
15
|
import { isPreparedSecureAcceptanceRequest, secureAcceptanceEnvironment, secureAcceptancePreparationUrl, secureAcceptanceRequestRefusal, } from './cybersource-secure-acceptance.generated.js';
|
|
16
16
|
import { PADDLE_VGS_CARDS_URLS, isPreparedPaddleVgsRequest } from './paddle-vgs.generated.js';
|
|
17
|
+
import { WIX_PAYMENTS_TOKENIZE_URL, isPreparedWixPaymentsRequest } from './wix-payments.generated.js';
|
|
17
18
|
export function preparationMode(psp) {
|
|
18
19
|
return psp === 'adyen' || psp === 'fiserv' || psp === 'verifone' ? 'cse' : 'token';
|
|
19
20
|
}
|
|
@@ -53,6 +54,9 @@ export function preparedApprovalAnswersRetry(psp) {
|
|
|
53
54
|
export function validPreparationEnvironment(psp, environment) {
|
|
54
55
|
if (psp === 'bambora' || psp === 'mercado_pago' || psp === 'recurly' || psp === 'spreedly')
|
|
55
56
|
return environment === 'shared';
|
|
57
|
+
// Wix Payments has production alone: its tokenizer has no test host.
|
|
58
|
+
if (psp === 'wix_payments')
|
|
59
|
+
return environment === 'production';
|
|
56
60
|
return ['square', 'braintree', 'worldpay', 'adyen', 'checkout_com', 'paysafe', 'fiserv', 'cybersource_flex', 'aci', 'creditguard', 'worldpay_eprotect', 'amadeus_checkout', 'verifone',
|
|
57
61
|
'cybersource_secure_acceptance', 'paddle_vgs'].includes(psp) && ['production', 'sandbox'].includes(environment);
|
|
58
62
|
}
|
|
@@ -99,6 +103,9 @@ export function preparationEndpoint(psp, environment) {
|
|
|
99
103
|
// Paddle VGS: the environment's one card URL, the only URL the claim takes for it.
|
|
100
104
|
if (psp === 'paddle_vgs')
|
|
101
105
|
return PADDLE_VGS_CARDS_URLS[environment];
|
|
106
|
+
// Wix Payments: the tokenize URL, the only URL the claim takes for it.
|
|
107
|
+
if (psp === 'wix_payments')
|
|
108
|
+
return WIX_PAYMENTS_TOKENIZE_URL;
|
|
102
109
|
// A Verifone endpoint is its reviewed profile's leg, never one per environment (verifone.ts).
|
|
103
110
|
if (psp === 'verifone')
|
|
104
111
|
throw new Error('unsupported_preparation_processor');
|
|
@@ -252,6 +259,10 @@ export function matchesPreparedRequest(psp, environment, requestUrl, method, bod
|
|
|
252
259
|
// the JSON:API content type and the frame's body), the rule the API and the Vault bind with too.
|
|
253
260
|
if (psp === 'paddle_vgs')
|
|
254
261
|
return isPreparedPaddleVgsRequest(requestUrl, method.toUpperCase(), body ?? null, environment, headers ?? {});
|
|
262
|
+
// Wix Payments: production, the tokenize URL and payment-core's whole request rule (a JSON content type, the
|
|
263
|
+
// site's app instance and the card frame's body), the rule the API and the Vault bind with too.
|
|
264
|
+
if (psp === 'wix_payments')
|
|
265
|
+
return isPreparedWixPaymentsRequest(requestUrl, method.toUpperCase(), body ?? null, environment, headers ?? {});
|
|
255
266
|
if (psp === 'creditguard')
|
|
256
267
|
return matchesPreparedCreditguard(environment, requestUrl, body, headers, binding);
|
|
257
268
|
// A Verifone request is judged only through the profile its preparation names (matchesPreparation).
|