@agent-cards/sdk 0.23.19 → 0.23.21
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 +61 -2
- package/PREFLIGHT.md +4 -0
- package/README.md +175 -7
- package/dist/amadeus.d.ts +4 -2
- package/dist/amadeus.js +16 -3
- package/dist/buy.d.ts +84 -2
- package/dist/buy.js +16 -1
- package/dist/card-endpoint-facts.d.ts +2 -1
- package/dist/card-endpoint-facts.js +18 -9
- package/dist/card-endpoint.d.ts +20 -4
- package/dist/card-endpoint.js +38 -4
- package/dist/card-fields.generated.js +1444 -51
- package/dist/cdp.d.ts +29 -0
- package/dist/cdp.js +444 -24
- package/dist/client.d.ts +134 -7
- package/dist/client.js +350 -25
- package/dist/comgate.d.ts +50 -0
- package/dist/comgate.js +80 -0
- package/dist/cybersource-secure-acceptance.generated.d.ts +1 -1
- package/dist/eprotect.generated.d.ts +1 -1
- package/dist/gmo.generated.js +7 -3
- package/dist/hipay.generated.d.ts +56 -0
- package/dist/hipay.generated.js +392 -0
- package/dist/hold.d.ts +180 -0
- package/dist/hold.js +270 -0
- package/dist/hosted-entry.d.ts +4 -0
- package/dist/hosted-entry.js +32 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +1 -0
- package/dist/lifecycle.d.ts +10 -0
- package/dist/lifecycle.js +21 -0
- package/dist/merchant-card-endpoints.generated.js +102 -11
- package/dist/paddle-tokenex.generated.js +7 -3
- package/dist/paddle-vgs.generated.d.ts +3 -2
- package/dist/paddle-vgs.generated.js +9 -5
- package/dist/payrails.generated.js +7 -3
- package/dist/pre-claim.d.ts +20 -0
- package/dist/pre-claim.js +202 -22
- package/dist/preflight-catalog.json +58 -0
- package/dist/preflight-schemas.json +4 -0
- package/dist/preflight.generated.js +26 -2
- package/dist/prepared-processor.d.ts +6 -2
- package/dist/prepared-processor.js +18 -2
- package/dist/primer.generated.js +1487 -94
- package/dist/przelewy24.d.ts +47 -0
- package/dist/przelewy24.js +88 -0
- package/dist/quickpay.d.ts +44 -0
- package/dist/quickpay.js +65 -0
- package/dist/registry.d.ts +6 -5
- package/dist/registry.js +27 -7
- package/dist/shiji-sts.generated.js +7 -3
- package/dist/stripe-checkout.generated.js +744 -13
- package/dist/tokenex-iframe.d.ts +93 -0
- package/dist/tokenex-iframe.generated.d.ts +81 -0
- package/dist/tokenex-iframe.generated.js +403 -0
- package/dist/tokenex-iframe.js +195 -0
- package/dist/transbank.d.ts +45 -0
- package/dist/transbank.js +73 -0
- package/dist/twoc2p.d.ts +54 -0
- package/dist/twoc2p.generated.d.ts +33 -0
- package/dist/twoc2p.generated.js +1149 -0
- package/dist/twoc2p.js +85 -0
- package/dist/voice.d.ts +16 -13
- package/dist/voice.js +13 -10
- package/examples/preflight/kernel-native/inventory.json +1 -1
- package/package.json +3 -3
package/dist/client.js
CHANGED
|
@@ -2,7 +2,11 @@ import { BUILTIN_REGISTRY, cardUrlPatterns as deriveCardUrlPatterns, LOOPBACK_UR
|
|
|
2
2
|
import { armServedProfiles, classifyProfileRequest, declareSandboxMerchant, merchantProfileEnvironment, merchantProfileFor, merchantProfileUrlPatterns, } from './merchant-hosted.js';
|
|
3
3
|
import { merchantAmountExchanges, merchantAmountFromResponses, merchantProfilePricedBySource, merchantTotalWire, MerchantTotalWait, } from './merchant-total.js';
|
|
4
4
|
import { ACI_CAPABILITY, ACI_PSP, aciCardLegAnswer } from './aci.js';
|
|
5
|
+
import { PRZELEWY24_CAPABILITY, PRZELEWY24_PSP } from './przelewy24.js';
|
|
5
6
|
import { EPROTECT_CAPABILITY, EPROTECT_PSP, eprotectCheckoutRefusal, eprotectScriptAnswer, isEprotectRegistration } from './eprotect.js';
|
|
7
|
+
import { COMGATE_CAPABILITY, COMGATE_PSP } from './comgate.js';
|
|
8
|
+
import { isHostedGetEntry } from './hosted-entry.js';
|
|
9
|
+
import { TRANSBANK_CAPABILITY, TRANSBANK_PSP } from './transbank.js';
|
|
6
10
|
import { isMercadoTokenRequest, parseMercadoCheckoutContext, validateMercadoProcessorContext } from './mercado-checkout.generated.js';
|
|
7
11
|
import { matchesPreparation, preparationMode, validPreparationEnvironment } from './prepared-processor.js';
|
|
8
12
|
import { fiservKeyPinById, isFiservSubstitution, requiresFiservPreparation } from './fiserv.js';
|
|
@@ -16,7 +20,9 @@ import { SHIJI_STS_CAPABILITY, SHIJI_STS_PSP, isShijiStsServedCompanion, isShiji
|
|
|
16
20
|
import { AMADEUS_CHECKOUT_CAPABILITY, AMADEUS_CHECKOUT_PSP } from './amadeus-checkout.generated.js';
|
|
17
21
|
import { PADDLE_VGS_CAPABILITY, PADDLE_VGS_PSP, paddleVgsCardFactsOf } from './paddle-vgs.generated.js';
|
|
18
22
|
import { PADDLE_TOKENEX_CAPABILITY, PADDLE_TOKENEX_PSP, isPaddleTokenexServedFacts, isPaddleTokenexServedSubstitution } from './paddle-tokenex.js';
|
|
23
|
+
import { TWOC2P_CAPABILITY, TWOC2P_PSP } from './twoc2p.js';
|
|
19
24
|
import { WIX_PAYMENTS_CAPABILITY, WIX_PAYMENTS_PSP } from './wix-payments.generated.js';
|
|
25
|
+
import { HIPAY_CAPABILITY, HIPAY_PSP } from './hipay.generated.js';
|
|
20
26
|
import { classifyStripeCheckoutRequest, encodeStripeCheckoutContext, hasStripeCheckoutMarker, parseStripeCheckoutContext, parseStripeCheckoutResponse, STRIPE_CHECKOUT_CONTEXT_HEADER, } from './stripe-checkout.generated.js';
|
|
21
27
|
import { VoiceModule } from './voice.js';
|
|
22
28
|
import { BuyModule } from './buy.js';
|
|
@@ -30,6 +36,7 @@ import { JUSPAY_CAPABILITY, JUSPAY_PSP, juspayPageAnswer } from './juspay-gate.j
|
|
|
30
36
|
import { CARD_ENDPOINT_MODE, CARD_ENDPOINT_PSP, CardEndpointRefusedError, cardEndpointById, cardEndpointLive, cardEndpointSessionRefusal, } from './card-endpoint.js';
|
|
31
37
|
import { merchantCardEndpointFactsRefusal as sharedFactsRefusal, readMerchantCardEndpointFacts as sharedReadFacts, } from './merchant-card-endpoints.generated.js';
|
|
32
38
|
import { DATATRANS_CAPABILITY } from './datatrans.js';
|
|
39
|
+
import { TOKENEX_IFRAME_CAPABILITY, TOKENEX_IFRAME_PSP, tokenexIframePageAnswer, tokenexIframePlaceholderFits } from './tokenex-iframe.js';
|
|
33
40
|
import { PELECARD_CAPABILITY, PELECARD_PSP } from './pelecard.js';
|
|
34
41
|
import { PRIMER_CAPABILITY, PRIMER_PSP, primerTokenAnswer } from './primer.js';
|
|
35
42
|
import { PAYRAILS_CAPABILITY, isPayrailsPaymentUrl, payrailsAnswer } from './payrails.js';
|
|
@@ -226,6 +233,13 @@ export const SUPPORTED_REGISTRY_FEATURES = ['card_fields', 'checkout_sessions'];
|
|
|
226
233
|
* checkout relay. Served on the same terms: only to a build that lists it, for a company
|
|
227
234
|
* Agentcard turned Payfast on for.
|
|
228
235
|
*
|
|
236
|
+
* `przelewy24_hosted_payment_page`: Przelewy24's pay wall, whose card-free link
|
|
237
|
+
* (secure.przelewy24.pl/trnRequest/<token>, a plain GET the merchant's redirect or script sends
|
|
238
|
+
* the buyer to) this build pauses for the cardholder's device by its exact link (hosted-entry.ts),
|
|
239
|
+
* and whose card method post, card form post and Saferpay resolver this build never lets the
|
|
240
|
+
* agent's browser send (pre-claim.ts, przelewy24.ts). Served on the same terms as NMI's and
|
|
241
|
+
* Redsys's: only to a build that lists it, for a company Agentcard turned Przelewy24 on for.
|
|
242
|
+
*
|
|
229
243
|
* `wix_payments_tokenize`: the card request Wix Cashier's card frame sends to Wix's
|
|
230
244
|
* tokenizer (cashier-pci.wixapps.net), only through a prepared checkout: Wix's payment
|
|
231
245
|
* widget fails the payment 30 seconds after it asks the frame for a token. The
|
|
@@ -241,9 +255,120 @@ export const SUPPORTED_REGISTRY_FEATURES = ['card_fields', 'checkout_sessions'];
|
|
|
241
255
|
* that the page then runs in the agent's browser. The cardholder's device sends the card through
|
|
242
256
|
* the checkout relay. Served on the same terms: only to a build that lists it, for a company
|
|
243
257
|
* Agentcard turned PayMongo on for.
|
|
258
|
+
*
|
|
259
|
+
* `gopay_card_form`: the card post GoPay's card frame sends to its own URL
|
|
260
|
+
* (secure.gopay.com/gp-card-comm/h/<token>) inside the GoPay gateway a shop opens. This build pauses
|
|
261
|
+
* only the frame's own card post and answers it with GoPay's answer as the API recorded it, the
|
|
262
|
+
* empty JSON object the frame reads; the gateway then reads the payment's end from GoPay and runs
|
|
263
|
+
* 3-D Secure in the agent's browser when the bank asks for it. The cardholder's device sends the card
|
|
264
|
+
* through the checkout relay. Served only to a build that lists it, and only for Agentcard's proof
|
|
265
|
+
* company until a reviewed change binds GoPay's payee and amount to the approval: the post names
|
|
266
|
+
* neither. The API takes it only at a shop Agentcard reviewed.
|
|
267
|
+
*
|
|
268
|
+
* `hipay_vault_token`: the token create HiPay's hosted fields send to HiPay's Secure Vault
|
|
269
|
+
* (secure2-vault.hipay-tpp.com, stage-secure2-vault for a test row), only through a prepared
|
|
270
|
+
* checkout: the merchant's page gives the frame 20 seconds after Pay. The cardholder's device
|
|
271
|
+
* sends the card to HiPay directly and the frame gets back HiPay's token. The number-only post
|
|
272
|
+
* the frame sends while the number is typed, and its /update once it holds a token, fail in the
|
|
273
|
+
* browser (pre-claim.ts hipayPreClaim). Served on the same terms: only to a build that lists it,
|
|
274
|
+
* for a company Agentcard turned HiPay on for.
|
|
275
|
+
*
|
|
276
|
+
* `twoc2p_secure_pay`: the Payment 2C2P's hosted payment page posts to its payment API
|
|
277
|
+
* (pgwv4.2c2p.com), carrying the card only as one field the page encrypts under 2C2P's static
|
|
278
|
+
* key. This build pauses it and writes over the placeholder's field the one the cardholder's
|
|
279
|
+
* device wrote under the key payment-core pins (twoc2p.ts), into that Payment alone; 3-D Secure
|
|
280
|
+
* then runs in the agent's browser. Served only to a build that lists it, and only for Agentcard's
|
|
281
|
+
* proof company, whatever the API's processor lists name: the field is the card under 2C2P's one
|
|
282
|
+
* static key, which any 2C2P merchant could charge.
|
|
283
|
+
*
|
|
284
|
+
* `quickpay_hosted_payment_page`: QuickPay's hosted payment window, whose card-free signed entry
|
|
285
|
+
* this build pauses for the cardholder's device and whose card post, fee lookup, wallet post, 3-D
|
|
286
|
+
* Secure step and card lookup this build never lets the agent's browser send (pre-claim.ts,
|
|
287
|
+
* quickpay.ts). Served on the same terms as NMI's and Redsys's: only to a build that lists it, for a
|
|
288
|
+
* company Agentcard turned QuickPay on for.
|
|
289
|
+
*
|
|
290
|
+
* `revolut_card_field`: the card payment Revolut Business's card field or card popup sends from
|
|
291
|
+
* its frame to /api/public/orders/<order token>/payments on merchant.revolut.com, on a merchant's
|
|
292
|
+
* own page or Revolut's hosted checkout. This build pauses only the frame's card payment and
|
|
293
|
+
* answers it with Revolut's answer as the API recorded it: the payment Revolut created, which the
|
|
294
|
+
* frame then follows, through any 3-D Secure step, in the agent's browser. A payment by Apple Pay,
|
|
295
|
+
* Google Pay or Revolut Pay on the same URL carries no card and continues untouched. Revolut's
|
|
296
|
+
* host answers the Vault's origin, so the cardholder's device sends the card itself, with no relay.
|
|
297
|
+
* Served on the same terms: only to a build that lists it, for a company Agentcard turned Revolut
|
|
298
|
+
* on for.
|
|
299
|
+
*
|
|
300
|
+
* `pay_nl_card_token`: the card token request a shop's card form sends to Pay. (pay.nl),
|
|
301
|
+
* Weeztix's sandboxed frame posting its FormData to payment.pay.nl/v1/Payment/getCardToken/json.
|
|
302
|
+
* This build pauses only the form's own multipart body at that exact URL; the cardholder's
|
|
303
|
+
* device sends the card through the checkout relay, and the frame gets the token answer
|
|
304
|
+
* payment-core's judge rebuilt, with the CORS answer for the frame's own origin, null. The
|
|
305
|
+
* request names no amount, so the agent's pair, above zero, is the one the cardholder approves
|
|
306
|
+
* (PAY_NL_PSP below). Served on the same terms: only to a build that lists it, for a company
|
|
307
|
+
* Agentcard turned Pay. on for.
|
|
308
|
+
*
|
|
309
|
+
* `paypal_card_fields`: PayPal Card Fields' confirm, the POST its v5 frame sends to
|
|
310
|
+
* www.paypal.com and its v6 frame to api-m.paypal.com. This build pauses it only in
|
|
311
|
+
* the frames' own shape, refuses one that asks PayPal to keep the card or forces
|
|
312
|
+
* 3-D Secure in the browser with a `blocked` event, and answers the frame with the
|
|
313
|
+
* order's id and status as the API recorded them. The device sends a v5 confirm
|
|
314
|
+
* through the checkout relay and a v6 one directly. Served on the same terms: only
|
|
315
|
+
* to a build that lists it, for a company Agentcard turned PayPal Card Fields on
|
|
316
|
+
* for. Every other company keeps the checkout guard's refusal (paypal-card-forms.ts).
|
|
317
|
+
*
|
|
318
|
+
* `comgate_hosted_payment_page`: ComGate's payment gateway, whose card-free gateway link
|
|
319
|
+
* (payN.comgate.cz/init?id=<transaction id>, a plain GET) this build pauses for the
|
|
320
|
+
* cardholder's device by its exact link (hosted-entry.ts), in the page, in a frame of it or
|
|
321
|
+
* in a window it opened, and whose card hosts this build never lets the agent's browser post
|
|
322
|
+
* to (pre-claim.ts, comgate.ts). Served on the same terms as NMI's and Redsys's: only to a
|
|
323
|
+
* build that lists it, for a company Agentcard turned ComGate on for.
|
|
324
|
+
*
|
|
325
|
+
* `makecommerce_card_frame`: the card post MakeCommerce's card frame sends to its own card endpoint
|
|
326
|
+
* (cc.maksekeskus.ee/card-payment) under the shop's publishable key. This build pauses only the
|
|
327
|
+
* frame's own one-time card payment and answers it with MakeCommerce's answer as the API recorded
|
|
328
|
+
* it: the URL of MakeCommerce's 3-D Secure page, which the frame then opens in the agent's browser.
|
|
329
|
+
* The cardholder's device sends the card through the checkout relay. Served on the same terms: only
|
|
330
|
+
* to a build that lists it, for a company Agentcard turned MakeCommerce on for.
|
|
331
|
+
*
|
|
332
|
+
* `poynt_collect_nonce`: GoDaddy Payments' card request, the POST Poynt Collect's
|
|
333
|
+
* card frame sends to a store's generate-nonce on services.poynt.net. This build
|
|
334
|
+
* pauses it only as the frame writes it, refuses a body that asks Poynt to keep the
|
|
335
|
+
* card in the browser with a `blocked` event, and answers the frame with the nonce as
|
|
336
|
+
* the API recorded it. The device sends the card through the checkout relay. Served
|
|
337
|
+
* on the same terms: only to a build that lists it, for a company Agentcard turned
|
|
338
|
+
* GoDaddy Payments on for.
|
|
339
|
+
*
|
|
340
|
+
* `tokenex_iframe_tokenize`: the card post TokenEx's hosted iframe v3 sends from its card-number frame
|
|
341
|
+
* to its own document URL on htp.tokenex.com (JetBlue's card form). This build pauses only the PCI frame's
|
|
342
|
+
* own card post with its CVV frame, refuses in the browser every other post on that path that carries a
|
|
343
|
+
* card (tokenex-iframe.ts), answers it with TokenEx's token as the API recorded it, rebuilt from
|
|
344
|
+
* payment-core's allow-list, and answers the same frame's byte-identical repeat from that answer while the
|
|
345
|
+
* approval is being handed off. Served on the same terms: only to a build that lists it, for a company
|
|
346
|
+
* Agentcard turned the TokenEx iframe on for.
|
|
347
|
+
*
|
|
348
|
+
* `transbank_webpay_hosted_payment_page`: Transbank's Webpay Plus, whose card-free entry
|
|
349
|
+
* (webpay3g.transbank.cl/webpayserver/initTransaction?token_ws=<token>, the merchant's
|
|
350
|
+
* redirect, a plain GET) this build pauses for the cardholder's device by its exact link
|
|
351
|
+
* (hosted-entry.ts) in the page or a frame of it, and with attachToCdp also in a window the
|
|
352
|
+
* page opened, and whose hosts this build never lets the agent's browser post to (pre-claim.ts,
|
|
353
|
+
* transbank.ts), so the token is never spent there. attachToPlaywright covers the page it is
|
|
354
|
+
* attached to and that page's frames only, and pauses only a direct or scripted navigation to
|
|
355
|
+
* the entry: its page.route sees no HTTP redirect hop, so a merchant's redirect needs attachToCdp.
|
|
356
|
+
* Served on the same terms as NMI's and Redsys's: only to a build that lists it, for a company
|
|
357
|
+
* Agentcard turned Webpay on for.
|
|
358
|
+
*
|
|
359
|
+
* `sumup_checkout_process`: the card request SumUp's Payment Widget sends from its hidden form frame
|
|
360
|
+
* on gateway.sumup.com, a PUT to https://api.sumup.com/v0.2/checkouts/<checkout id>. This build pauses
|
|
361
|
+
* that PUT as it pauses Gravy's, so only the CDP and Playwright adapters see it (the form frame is
|
|
362
|
+
* cross-origin to the page), and answers the frame with SumUp's own answer as the API recorded it: the
|
|
363
|
+
* paid checkout, or the 3-D Secure step the widget then runs in the agent's browser. The cardholder's
|
|
364
|
+
* device sends the card itself, and the API holds the payment to a merchant Agentcard reviewed, at the
|
|
365
|
+
* amount SumUp holds for the checkout. Served on the same terms: only to a build that lists it, for a
|
|
366
|
+
* company Agentcard turned SumUp on for.
|
|
244
367
|
*/
|
|
245
368
|
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,
|
|
246
|
-
'redsys_hosted_payment_page', 'lyra_krypton_payment', 'payfast_card_pay', WIX_PAYMENTS_CAPABILITY, 'paymongo_checkout_pay'
|
|
369
|
+
'redsys_hosted_payment_page', 'lyra_krypton_payment', 'payfast_card_pay', WIX_PAYMENTS_CAPABILITY, 'paymongo_checkout_pay', 'pay_nl_card_token', HIPAY_CAPABILITY, TWOC2P_CAPABILITY, 'quickpay_hosted_payment_page', 'revolut_card_field', 'paypal_card_fields', 'gopay_card_form', COMGATE_CAPABILITY, PRZELEWY24_CAPABILITY, 'makecommerce_card_frame', 'poynt_collect_nonce',
|
|
370
|
+
TOKENEX_IFRAME_CAPABILITY, TRANSBANK_CAPABILITY,
|
|
371
|
+
'sumup_checkout_process'];
|
|
247
372
|
/**
|
|
248
373
|
* Processors whose paused request names no amount at all, so the pair the
|
|
249
374
|
* agent passes is the amount the cardholder approves: authorize() refuses one
|
|
@@ -275,15 +400,68 @@ export const SUPPORTED_CAPABILITIES = ['fiserv_card_capture', GMO_CAPABILITY, CY
|
|
|
275
400
|
* PayMongo's card attach carries none either: the merchant bound the total, always in
|
|
276
401
|
* Philippine pesos, to the checkout session when it created it, so the agent sends that
|
|
277
402
|
* total, above zero (PAYMONGO_PSP below), and the API holds it to the session PayMongo's
|
|
278
|
-
* own page shows.
|
|
403
|
+
* own page shows. GoPay's card post carries none either: the shop's server set the amount
|
|
404
|
+
* when it created the payment at GoPay, and GoPay's gateway shows it only inside its own
|
|
405
|
+
* session, so the agent sends the total the gateway shows, above zero (GOPAY_PSP below).
|
|
406
|
+
* 2C2P's Payment carries none either: the merchant bound the total to the
|
|
407
|
+
* payment token when it created it, so the agent sends the total 2C2P's page shows, above
|
|
408
|
+
* zero (TWOC2P_PSP), and the API holds it to the amount 2C2P's own PaymentOption answer names.
|
|
409
|
+
* Przelewy24's pay wall link carries none either: the merchant's server registered the amount
|
|
410
|
+
* with Przelewy24 under the link's token, so the agent sends the amount the pay wall shows, above
|
|
411
|
+
* zero (PRZELEWY24_PSP below), and the cardholder's device holds the pay wall to it.
|
|
412
|
+
* HiPay's token create carries none either: the merchant's server charges
|
|
413
|
+
* HiPay's token for its own order, so the agent's pair, which the prepared checkout carries,
|
|
414
|
+
* is the total the cardholder approves, above zero as Moneris's is. Revolut's card payment
|
|
415
|
+
* names the order's amount in minor units but not its currency, which only the order holds,
|
|
416
|
+
* so the number alone is no price the cardholder can approve: the agent sends the pair, above
|
|
417
|
+
* zero (REVOLUT_PSP below), and the API holds its amount to the body's and its currency to
|
|
418
|
+
* one that Revolut and the API both count in hundredths.
|
|
419
|
+
* Pay.'s card token request carries none either: the shop's server charges the token later for
|
|
420
|
+
* its own order total, so the agent's pair, above zero (PAY_NL_PSP below), is the one figure the
|
|
421
|
+
* approval shows.
|
|
422
|
+
* PayPal Card Fields' confirm carries none either: the merchant's server fixed the
|
|
423
|
+
* amount when it created the order, so the agent's pair, above zero (PAYPAL_PSP
|
|
424
|
+
* below), is the one figure the approval shows.
|
|
425
|
+
* ComGate's gateway link carries none either: the merchant's server set
|
|
426
|
+
* the amount when it created the payment at ComGate, so the agent's pair, above zero
|
|
427
|
+
* (COMGATE_PSP below), is the figure the cardholder approves, and the cardholder's device
|
|
428
|
+
* holds ComGate's own figure to it before any card leaves.
|
|
429
|
+
* MakeCommerce's card post carries none either: MakeCommerce's transaction holds the total, in
|
|
430
|
+
* euros, so the agent sends the total the shop's order page shows, above zero (MAKECOMMERCE_PSP
|
|
431
|
+
* below), and the API refuses any other currency.
|
|
432
|
+
* GoDaddy Payments' generate-nonce carries none either: GoDaddy's server charges
|
|
433
|
+
* the nonce later, so its pair must be above zero too (POYNT_PSP below).
|
|
434
|
+
* The TokenEx iframe's card post carries none either: it mints a token into the merchant's TokenEx
|
|
435
|
+
* vault, which the merchant's server charges later for its own order, so the agent sends the total
|
|
436
|
+
* the merchant's page shows, above zero (TOKENEX_IFRAME_PSP), and the API refuses a create without it.
|
|
437
|
+
* Webpay's entry carries none either: the merchant's server bound the total, in Chilean pesos,
|
|
438
|
+
* to the transaction when it created it, so the agent's pair, above zero (TRANSBANK_PSP below),
|
|
439
|
+
* is the figure the cardholder approves, and the cardholder's device holds Webpay's own
|
|
440
|
+
* transaction to it before any card leaves.
|
|
441
|
+
* SumUp's card request carries none either: the merchant's server bound the
|
|
442
|
+
* total and its currency to the checkout when it created it, so the agent sends the total the
|
|
443
|
+
* payment page shows, above zero (SUMUP_PSP below), and the API holds it to the checkout SumUp
|
|
444
|
+
* itself reports.
|
|
279
445
|
*/
|
|
280
446
|
const MONERIS_PSP = 'moneris';
|
|
281
447
|
const PAYFAST_PSP = 'payfast';
|
|
282
448
|
const PAYMONGO_PSP = 'paymongo';
|
|
283
|
-
const
|
|
449
|
+
const REVOLUT_PSP = 'revolut';
|
|
450
|
+
const PAY_NL_PSP = 'pay_nl';
|
|
451
|
+
const PAYPAL_PSP = 'paypal';
|
|
452
|
+
const GOPAY_PSP = 'gopay';
|
|
453
|
+
const MAKECOMMERCE_PSP = 'makecommerce';
|
|
454
|
+
const POYNT_PSP = 'poynt';
|
|
455
|
+
const SUMUP_PSP = 'sumup';
|
|
456
|
+
const AGENT_AMOUNT_PROCESSORS = [GMO_PSP, PELECARD_PSP, WSPAY_PSP, SECURE_ACCEPTANCE_PSP, MONERIS_PSP, PADDLE_VGS_PSP, PAYFAST_PSP, WIX_PAYMENTS_PSP, PAYMONGO_PSP, PAY_NL_PSP, HIPAY_PSP, TWOC2P_PSP, REVOLUT_PSP, PAYPAL_PSP, GOPAY_PSP, COMGATE_PSP,
|
|
457
|
+
PRZELEWY24_PSP, MAKECOMMERCE_PSP, POYNT_PSP, TOKENEX_IFRAME_PSP, TRANSBANK_PSP, SUMUP_PSP];
|
|
284
458
|
/** How AmountRequiredError names a processor. */
|
|
285
459
|
const PROCESSOR_NAMES = { [GMO_PSP]: 'GMO', [PELECARD_PSP]: 'Pelecard', [WSPAY_PSP]: 'WSPay',
|
|
286
|
-
[SECURE_ACCEPTANCE_PSP]: 'CyberSource Secure Acceptance', [MONERIS_PSP]: 'Moneris', [PADDLE_VGS_PSP]: 'Paddle', [PAYFAST_PSP]: 'Payfast', [WIX_PAYMENTS_PSP]: 'Wix', [PAYMONGO_PSP]: 'PayMongo'
|
|
460
|
+
[SECURE_ACCEPTANCE_PSP]: 'CyberSource Secure Acceptance', [MONERIS_PSP]: 'Moneris', [PADDLE_VGS_PSP]: 'Paddle', [PAYFAST_PSP]: 'Payfast', [WIX_PAYMENTS_PSP]: 'Wix', [PAYMONGO_PSP]: 'PayMongo', [PAY_NL_PSP]: 'Pay.', [HIPAY_PSP]: 'HiPay', [TWOC2P_PSP]: '2C2P',
|
|
461
|
+
[REVOLUT_PSP]: 'Revolut', [PAYPAL_PSP]: 'PayPal', [GOPAY_PSP]: 'GoPay',
|
|
462
|
+
[COMGATE_PSP]: 'ComGate', [PRZELEWY24_PSP]: 'Przelewy24',
|
|
463
|
+
[MAKECOMMERCE_PSP]: 'MakeCommerce', [POYNT_PSP]: 'GoDaddy Payments', [TOKENEX_IFRAME_PSP]: 'TokenEx', [TRANSBANK_PSP]: 'Webpay',
|
|
464
|
+
[SUMUP_PSP]: 'SumUp' };
|
|
287
465
|
/**
|
|
288
466
|
* Processors whose request and answer name no amount at all, so the total the
|
|
289
467
|
* payment page shows (`pageAmount`) is the one figure that ties the agent's pair
|
|
@@ -514,13 +692,18 @@ const PROCESSOR_PLACEHOLDER_NUMBERS = Object.freeze({});
|
|
|
514
692
|
/**
|
|
515
693
|
* The placeholder number for a network (lowercase, as GET /api/v2/vault_cards names it) on a
|
|
516
694
|
* processor's page: the processor's own number for that network when `overrides` names one, else
|
|
517
|
-
* the network's default, else undefined for a network with no placeholder.
|
|
695
|
+
* the network's default, else undefined for a network with no placeholder. On a TokenEx iframe
|
|
696
|
+
* (`tokenex_iframe`) the number must also be one TokenEx's frame reads as that network, since the frame
|
|
697
|
+
* names the brand to the page from the typed digits and the cardholder's device refuses a mismatch: the
|
|
698
|
+
* frame's table takes Visa, Mastercard and American Express, so every other network gets undefined.
|
|
518
699
|
*/
|
|
519
700
|
export function placeholderNumber(brand, psp, overrides = PROCESSOR_PLACEHOLDER_NUMBERS) {
|
|
520
701
|
const own = psp !== undefined && Object.prototype.hasOwnProperty.call(overrides, psp) ? overrides[psp] : undefined;
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
702
|
+
const number = own && Object.prototype.hasOwnProperty.call(own, brand) ? own[brand]
|
|
703
|
+
: Object.prototype.hasOwnProperty.call(PLACEHOLDER_NUMBERS, brand) ? PLACEHOLDER_NUMBERS[brand] : undefined;
|
|
704
|
+
if (number !== undefined && psp === TOKENEX_IFRAME_PSP && !tokenexIframePlaceholderFits(brand, number))
|
|
705
|
+
return undefined;
|
|
706
|
+
return number;
|
|
524
707
|
}
|
|
525
708
|
/**
|
|
526
709
|
* The recognizer says this processor is preparation-required, and no preparation
|
|
@@ -546,7 +729,9 @@ export class PreparationRequiredError extends Error {
|
|
|
546
729
|
* when the merchant's server created the payment), so the `amount` and
|
|
547
730
|
* `currency` you pass are what the cardholder approves, and for WSPay the
|
|
548
731
|
* figure the API compares with WSPay's answer when that answer names one (a
|
|
549
|
-
* 3-D Secure step names none).
|
|
732
|
+
* 3-D Secure step names none). A Revolut card payment names the order's
|
|
733
|
+
* amount but not its currency, so it takes the same pair, above zero.
|
|
734
|
+
* Thrown locally before any create or
|
|
550
735
|
* prompt, and terminal: the same request without an amount fails the same
|
|
551
736
|
* way. The API answers 400 amount_required for the same case. A page total
|
|
552
737
|
* (`pageAmount`) does not count.
|
|
@@ -556,7 +741,8 @@ export class AmountRequiredError extends Error {
|
|
|
556
741
|
code = 'amount_required';
|
|
557
742
|
constructor(psp) {
|
|
558
743
|
const processor = PROCESSOR_NAMES[psp] ?? psp;
|
|
559
|
-
|
|
744
|
+
const lacks = psp === REVOLUT_PSP ? 'names its amount but not its currency' : 'names no amount';
|
|
745
|
+
super(`A ${processor} payment request ${lacks}, so pass amount and currency: that is the amount the cardholder approves. Nothing was created and nothing was charged.`);
|
|
560
746
|
this.psp = psp;
|
|
561
747
|
this.name = 'AmountRequiredError';
|
|
562
748
|
}
|
|
@@ -1154,12 +1340,19 @@ function maskPaymongoSession(path) {
|
|
|
1154
1340
|
* https://secure.gopay.com/gp-card-comm/h/<hex token>?lang=..&ver=..&SG=<64 hex> (payment-core gopay.js). The
|
|
1155
1341
|
* token names that payment's card form, and with the SG, which redactUrl drops with the query, anyone who holds
|
|
1156
1342
|
* the URL can open the form and post a card to it. On GoPay's two card frame hosts the segment after /h/, in any
|
|
1157
|
-
* case or after an escaped slash, reads {token}: https://secure.gopay.com/gp-card-comm/h/{token}.
|
|
1343
|
+
* case or after an escaped slash, reads {token}: https://secure.gopay.com/gp-card-comm/h/{token}. Then every run of
|
|
1344
|
+
* 16 or more hex digits left reads {token} too, so a token after a path the frame never writes (an escaped h, a
|
|
1345
|
+
* path parameter) is masked as well; the token is 16 hex digits or more, and no other path the card frame uses holds
|
|
1346
|
+
* such a run. The pattern reads a percent escape as one unit: an escaped hex digit (%61, %2561) counts toward a run,
|
|
1347
|
+
* so escaping some of a token's digits never splits it into runs that show, and any other escape (%2F, %252F, %68)
|
|
1348
|
+
* is kept whole, so its own hex digits never start a run and leave part of a token showing.
|
|
1158
1349
|
*/
|
|
1159
1350
|
const GOPAY_CARD_FORM_HOST = /^secure(?:\.sandbox)?\.gopay\.com\.?$/i;
|
|
1160
1351
|
const GOPAY_CARD_FORM_TOKEN = new RegExp(`(${SLASH}h${SLASH}+)[^/?#]*`, 'gi');
|
|
1352
|
+
const GOPAY_TOKEN_RUN = /(?:[0-9a-f]|%(?:25)*(?:3[0-9]|[46][1-6])){16,}|%(?:25)*[0-9a-f]{2}/gi;
|
|
1353
|
+
const GOPAY_LONE_ESCAPE = /^%(?:25)*[0-9a-f]{2}$/i;
|
|
1161
1354
|
function maskGopayToken(path) {
|
|
1162
|
-
return path.replace(GOPAY_CARD_FORM_TOKEN, '$1{token}');
|
|
1355
|
+
return path.replace(GOPAY_CARD_FORM_TOKEN, '$1{token}').replace(GOPAY_TOKEN_RUN, (run) => (GOPAY_LONE_ESCAPE.test(run) ? run : '{token}'));
|
|
1163
1356
|
}
|
|
1164
1357
|
/**
|
|
1165
1358
|
* KOMOJU's Hosted Fields frame pays a session with POST /api/v1/sessions/<id>/pay on komoju.com under
|
|
@@ -1244,6 +1437,18 @@ const REVOLUT_HOST = /^(?:sandbox-)?(?:merchant|checkout|merchant-mgmt)\.revolut
|
|
|
1244
1437
|
function maskRevolutToken(path) {
|
|
1245
1438
|
return maskUuids(path, '{token}');
|
|
1246
1439
|
}
|
|
1440
|
+
/**
|
|
1441
|
+
* ComGate's gateway pages name the payment by its transaction id in their paths (pay1.comgate.cz/<id>,
|
|
1442
|
+
* /specify/card2/<id>, payment-core processors/comgate.js), and the id alone opens that payment's gateway page, its
|
|
1443
|
+
* amount and its merchant. Its entry link names the id in the query, which redactUrl drops. On every host ComGate
|
|
1444
|
+
* owns, any id of its shape, in any case and with each hyphen in any spelling HYPHEN reads, reads {payment}. The
|
|
1445
|
+
* pattern reads a percent escape as one unit and keeps it, as maskUuids does.
|
|
1446
|
+
*/
|
|
1447
|
+
const COMGATE_HOST = /(?:^|\.)comgate\.cz\.?$/i;
|
|
1448
|
+
const COMGATE_ID = new RegExp(`%(?:25)*[0-9a-f]{2}|[a-z0-9]{4}${HYPHEN}[a-z0-9]{4}${HYPHEN}[a-z0-9]{4}`, 'gi');
|
|
1449
|
+
function maskComgateId(path) {
|
|
1450
|
+
return path.replace(COMGATE_ID, (token) => (token.startsWith('%') ? token : '{payment}'));
|
|
1451
|
+
}
|
|
1247
1452
|
/**
|
|
1248
1453
|
* Paytrail names its payment in the path of every route of its card method
|
|
1249
1454
|
* (/payments/<transaction>/click-to-pay/loading-and-redirect, and its success and cancel routes), and the same id
|
|
@@ -1268,6 +1473,68 @@ function maskPaytrailTransaction(path) {
|
|
|
1268
1473
|
function maskPaymentHighwaySession(path) {
|
|
1269
1474
|
return maskPaytrailId(path, '{session}');
|
|
1270
1475
|
}
|
|
1476
|
+
/**
|
|
1477
|
+
* 2C2P's hosted payment page names its payment token in its hash routes (pgw-ui.2c2p.com/payment/<build>/#/token/
|
|
1478
|
+
* <token>, #/info/<token>, #/mobile/process/<token>), and the token is all a browser needs to open that payment's page
|
|
1479
|
+
* (payment-core twoc2p.js). redactUrl drops a fragment, but a URL whose `#` was escaped carries the route in its path,
|
|
1480
|
+
* and then in any spelling: escaped or doubled separators, escaped letters, parameters. Nothing past the build's folder
|
|
1481
|
+
* on 2C2P's page hosts is worth a log line, so everything after `/payment/<build>/`, its separators in any spelling
|
|
1482
|
+
* SLASH reads, reads {token}, and on any other path everything after its first separator. A string that is not a URL
|
|
1483
|
+
* is cut the same way after a whole page-host authority it names (at the start, or after a space, a quote, a bracket,
|
|
1484
|
+
* a colon such as a `see:` before it, a comma, a semicolon, an equals sign or `//`, and followed by a path, a port or
|
|
1485
|
+
* the end), and only up to the end of that URL, so the message's own words,
|
|
1486
|
+
* another site's path naming the host and a lookalike host stay; a text naming several such URLs has each one cut.
|
|
1487
|
+
* Anchored matches and cuts in one pass: no input makes it backtrack.
|
|
1488
|
+
*/
|
|
1489
|
+
const TWOC2P_PAGE_HOST = /^(?:sandbox-)?pgw-ui\.2c2p\.com\.?$/i;
|
|
1490
|
+
const TWOC2P_PAGE_FOLDER = new RegExp(`^${SLASH}payment${SLASH}4\\.[0-9]{1,2}${SLASH}`, 'i');
|
|
1491
|
+
const TWOC2P_FIRST_SEPARATOR = new RegExp(`^${SLASH}`, 'i');
|
|
1492
|
+
const TWOC2P_PAGE_AUTHORITY = `(?:^|[\\s"'(<\\[:,;=]|//)(?:sandbox-)?pgw-ui\\.2c2p\\.com\\.?(?::[0-9]{1,5})?(?=${SLASH}|$)`;
|
|
1493
|
+
/** One page path, from its first separator: the build's folder stays and the rest reads {token}. */
|
|
1494
|
+
function maskTwoC2pPath(path) {
|
|
1495
|
+
const kept = TWOC2P_PAGE_FOLDER.exec(path) ?? TWOC2P_FIRST_SEPARATOR.exec(path);
|
|
1496
|
+
const end = kept ? kept[0].length : 0;
|
|
1497
|
+
return path.length > end ? `${path.slice(0, end)}{token}` : path;
|
|
1498
|
+
}
|
|
1499
|
+
/**
|
|
1500
|
+
* Text that is not a URL: every whole page-host authority it names, each URL cut only to its own end (the first
|
|
1501
|
+
* space, quote or bracket), so the words between and after them stay. A text that starts with a slash is read the
|
|
1502
|
+
* same way, so another site's protocol-relative URL that names the host keeps its own host and path.
|
|
1503
|
+
*/
|
|
1504
|
+
function maskTwoC2pToken(path) {
|
|
1505
|
+
const authority = new RegExp(TWOC2P_PAGE_AUTHORITY, 'gi');
|
|
1506
|
+
// A closing bracket or parenthesis ends the URL only when no path or token character follows it, so a URL
|
|
1507
|
+
// a message wraps in [] or () keeps the words after it, and a bracket inside the path still cannot end the cut early.
|
|
1508
|
+
const urlEnd = /[\s"'<>]|[\])](?![A-Za-z0-9+/=%\\])/g;
|
|
1509
|
+
let out = '';
|
|
1510
|
+
let done = 0;
|
|
1511
|
+
for (let host = authority.exec(path); host !== null; host = authority.exec(path)) {
|
|
1512
|
+
const start = host.index + host[0].length;
|
|
1513
|
+
urlEnd.lastIndex = start;
|
|
1514
|
+
const stop = urlEnd.exec(path);
|
|
1515
|
+
const end = stop ? stop.index : path.length;
|
|
1516
|
+
out += path.slice(done, start) + maskTwoC2pPath(path.slice(start, end));
|
|
1517
|
+
done = end;
|
|
1518
|
+
authority.lastIndex = end;
|
|
1519
|
+
}
|
|
1520
|
+
return out + path.slice(done);
|
|
1521
|
+
}
|
|
1522
|
+
/**
|
|
1523
|
+
* QuickPay's window names its session as the first segment of its own path (/<32 hex>, then /3ds_auth or
|
|
1524
|
+
* /poll-response), and that id is what carries a card post into the payment the merchant's signed entry
|
|
1525
|
+
* opened; a payment link's id (/payments/<64 hex>) opens one the same way. On QuickPay's host a run of 32 hex
|
|
1526
|
+
* digits or more after a slash, in any case or escaped, reads {session} whatever follows it: a URL parser drops a
|
|
1527
|
+
* newline after the URL, so words after it can run on into the id. The entry, the host's root, carries none.
|
|
1528
|
+
*/
|
|
1529
|
+
const QUICKPAY_HOST = /^payment\.quickpay\.net\.?$/i;
|
|
1530
|
+
const QUICKPAY_SESSION = /(\/|%2f)[0-9a-f]{32,}/gi;
|
|
1531
|
+
function maskQuickpaySession(path) {
|
|
1532
|
+
return path.replace(QUICKPAY_SESSION, '$1{session}');
|
|
1533
|
+
}
|
|
1534
|
+
/**
|
|
1535
|
+
* `mask` reads a text that names the processor's host; `pathMask`, where a processor has one, reads the path of a
|
|
1536
|
+
* URL already parsed on that host, which `mask` reads otherwise.
|
|
1537
|
+
*/
|
|
1271
1538
|
const PATH_CREDENTIALS = [
|
|
1272
1539
|
{ host: PATH_SECRET_HOST, named: /(?:wspay\.biz|monri\.com)/i, mask: maskPathSecret },
|
|
1273
1540
|
{ host: CREDITGUARD_HOST, named: /creditguard\.co\.il/i, mask: maskCreditguardTxId },
|
|
@@ -1286,8 +1553,11 @@ const PATH_CREDENTIALS = [
|
|
|
1286
1553
|
{ host: PRZELEWY24_HOST, named: /przelewy24\.pl/i, mask: maskPrzelewy24Token },
|
|
1287
1554
|
{ host: REVOLUT_HOST, named: /(?:merchant|checkout|merchant-mgmt)\.revolut\.com/i, mask: maskRevolutToken },
|
|
1288
1555
|
{ host: SUMUP_API_HOST, named: /api\.sumup\.com/i, mask: maskSumupCheckout },
|
|
1556
|
+
{ host: COMGATE_HOST, named: /comgate\.cz/i, mask: maskComgateId },
|
|
1289
1557
|
{ host: PAYTRAIL_HOST, named: /paytrail\.com/i, mask: maskPaytrailTransaction },
|
|
1290
1558
|
{ host: PAYMENT_HIGHWAY_HOST, named: /(?:paymenthighway\.io|sph-test-solinor\.com)/i, mask: maskPaymentHighwaySession },
|
|
1559
|
+
{ host: TWOC2P_PAGE_HOST, named: /pgw-ui\.2c2p\.com/i, mask: maskTwoC2pToken, pathMask: maskTwoC2pPath },
|
|
1560
|
+
{ host: QUICKPAY_HOST, named: /quickpay\.net/i, mask: maskQuickpaySession },
|
|
1291
1561
|
];
|
|
1292
1562
|
/**
|
|
1293
1563
|
* A URL as it may appear in an error message: origin + path only. A paused
|
|
@@ -1321,6 +1591,10 @@ const PATH_CREDENTIALS = [
|
|
|
1321
1591
|
* On Paytrail's hosts a payment's id reads `{transaction}`:
|
|
1322
1592
|
* https://services.paytrail.com/payments/{transaction}/click-to-pay/loading-and-redirect, and on Payment
|
|
1323
1593
|
* Highway's a card page's session reads `{session}`.
|
|
1594
|
+
* On 2C2P's page hosts everything after the build's folder reads `{token}`:
|
|
1595
|
+
* https://pgw-ui.2c2p.com/payment/4.1/{token}.
|
|
1596
|
+
* On QuickPay's host the window's session reads `{session}`:
|
|
1597
|
+
* https://payment.quickpay.net/{session}/3ds_auth.
|
|
1324
1598
|
* A string that is not a URL keeps the part before any `?` or `#`, with the
|
|
1325
1599
|
* same segments masked for every processor whose host it names.
|
|
1326
1600
|
* A URL is read by its host only when the parser finds one. Text before a URL
|
|
@@ -1345,7 +1619,7 @@ export function redactUrl(raw) {
|
|
|
1345
1619
|
let path = url.pathname;
|
|
1346
1620
|
for (const rule of PATH_CREDENTIALS)
|
|
1347
1621
|
if (rule.host.test(url.hostname))
|
|
1348
|
-
path = rule.mask(path);
|
|
1622
|
+
path = (rule.pathMask ?? rule.mask)(path);
|
|
1349
1623
|
return maskNamed(`${url.origin}${path}`, url.pathname);
|
|
1350
1624
|
}
|
|
1351
1625
|
/**
|
|
@@ -1429,6 +1703,16 @@ const PADDLE_VGS_PREPARATION_REFUSALS = [
|
|
|
1429
1703
|
* `unsupported_checkout`, which PREPARATION_REFUSALS names for every checkout. Only for a Wix checkout.
|
|
1430
1704
|
*/
|
|
1431
1705
|
const WIX_PAYMENTS_PREPARATION_REFUSALS = ['processor_unavailable', 'live_host_on_sandbox_row', 'merchant_profile_mismatch'];
|
|
1706
|
+
/**
|
|
1707
|
+
* The API's refusals of a HiPay preparation, before any preparation exists, that prepareCheckout surfaces by name:
|
|
1708
|
+
* the company is not turned on for HiPay (`processor_unavailable`), the environment is not the caller's key mode's
|
|
1709
|
+
* (`live_host_on_sandbox_row`, `sandbox_host_on_live_row`), a checkout's merchant is not the name the reviewed pin
|
|
1710
|
+
* carries (`merchant_profile_mismatch`), and the price is zero (`amount_required`), since every create after it would be
|
|
1711
|
+
* refused. An unreviewed origin answers `unsupported_checkout`, which PREPARATION_REFUSALS names for every checkout.
|
|
1712
|
+
* Only for a HiPay checkout.
|
|
1713
|
+
*/
|
|
1714
|
+
const HIPAY_PREPARATION_REFUSALS = ['processor_unavailable', 'live_host_on_sandbox_row', 'sandbox_host_on_live_row', 'merchant_profile_mismatch',
|
|
1715
|
+
'amount_required'];
|
|
1432
1716
|
/**
|
|
1433
1717
|
* The reason the cardholder's device declines a bound prepared row with, per processor, when its own
|
|
1434
1718
|
* send boundary passed before the card left it (the Vault's sendWindow, 12 seconds after it last saw
|
|
@@ -1441,6 +1725,7 @@ const PREPARED_SEND_WINDOW_DECLINES = Object.freeze({
|
|
|
1441
1725
|
amadeus_checkout: 'amadeus_send_window_closed',
|
|
1442
1726
|
[SECURE_ACCEPTANCE_PSP]: 'secure_acceptance_send_window_closed',
|
|
1443
1727
|
[WIX_PAYMENTS_PSP]: 'wix_payments_send_window_closed',
|
|
1728
|
+
[HIPAY_PSP]: 'hipay_send_window_closed',
|
|
1444
1729
|
});
|
|
1445
1730
|
/**
|
|
1446
1731
|
* Refusals a CyberSource Flex preparation that tokenizes before Pay answers (4xx) before any
|
|
@@ -1529,8 +1814,8 @@ export class VaultClient {
|
|
|
1529
1814
|
/**
|
|
1530
1815
|
* Approve purchases by voice inside your own product: connect a person once,
|
|
1531
1816
|
* create the purchase, ask for the key word, read the result. Same
|
|
1532
|
-
* credentials, same token as the checkout calls.
|
|
1533
|
-
*
|
|
1817
|
+
* credentials, same token as the checkout calls. Approves on Agentcard's
|
|
1818
|
+
* page unless `voice: { approval: 'in_app' }` was named at construction.
|
|
1534
1819
|
*/
|
|
1535
1820
|
voice;
|
|
1536
1821
|
/**
|
|
@@ -1644,7 +1929,9 @@ export class VaultClient {
|
|
|
1644
1929
|
// wspay_confirm, shiji_sts_pinned_key, amadeus_checkout_actions.v1,
|
|
1645
1930
|
// worldline_mycheckout_form, verifone_card_capture, ekashu_hosted_payment_page,
|
|
1646
1931
|
// cybersource_sa_token_create, gravy_session_fields_put,
|
|
1647
|
-
// moneris_hosted_tokenization, paddle_vgs_cards,
|
|
1932
|
+
// moneris_hosted_tokenization, paddle_vgs_cards, paddle_tokenex_pay,
|
|
1933
|
+
// redsys_hosted_payment_page, lyra_krypton_payment, payfast_card_pay,
|
|
1934
|
+
// quickpay_hosted_payment_page, tokenex_iframe_tokenize, among others) and
|
|
1648
1935
|
// the caller's company is one Agentcard turned that processor on for, so this
|
|
1649
1936
|
// build arms Fiserv's card capture, GMO's getToken, CyberSource Flex's card
|
|
1650
1937
|
// fields, Juspay's card flow, Datatrans's Secure Fields card post, the
|
|
@@ -1838,7 +2125,9 @@ export class VaultClient {
|
|
|
1838
2125
|
* The facts hold only while the cardholder pays with that card. `psp` names the processor
|
|
1839
2126
|
* whose card form the agent types into (the recognizer's name, `worldline_mycheckout`): a
|
|
1840
2127
|
* processor that needs its own number for the card's network gets it, and every other gets the
|
|
1841
|
-
* network's default.
|
|
2128
|
+
* network's default. On a TokenEx iframe (`tokenex_iframe`, JetBlue) the number is one TokenEx's frame
|
|
2129
|
+
* reads as the card's own network, Visa, Mastercard or American Express, and any other network has no
|
|
2130
|
+
* placeholder there. Throws PlaceholderCardError when there is no such card, its network has no
|
|
1842
2131
|
* placeholder, or it carries no expiry.
|
|
1843
2132
|
*/
|
|
1844
2133
|
async placeholderCard(input) {
|
|
@@ -2123,6 +2412,7 @@ export class VaultClient {
|
|
|
2123
2412
|
|| (input.psp === EPROTECT_PSP && EPROTECT_PREPARATION_REFUSALS.includes(error.code))
|
|
2124
2413
|
|| (input.psp === PADDLE_VGS_PSP && PADDLE_VGS_PREPARATION_REFUSALS.includes(error.code))
|
|
2125
2414
|
|| (input.psp === WIX_PAYMENTS_PSP && WIX_PAYMENTS_PREPARATION_REFUSALS.includes(error.code))
|
|
2415
|
+
|| (input.psp === HIPAY_PSP && HIPAY_PREPARATION_REFUSALS.includes(error.code))
|
|
2126
2416
|
|| (!!flexContext && CYBERSOURCE_FLEX_PREPARATION_REFUSALS.includes(error.code))))
|
|
2127
2417
|
|| (input.psp === 'fiserv' && error.status === 502 && error.code === 'cse_key_unavailable')))
|
|
2128
2418
|
throw fail(error.code);
|
|
@@ -2377,10 +2667,14 @@ export class VaultClient {
|
|
|
2377
2667
|
: `checkout authorization is POST-only; got ${method} for ${redactUrl(input.request.url)}. ` +
|
|
2378
2668
|
'A non-POST tokenizer needs recognizer support before it can be intercepted.');
|
|
2379
2669
|
}
|
|
2380
|
-
// A GET card request is its URL alone. This build completes
|
|
2381
|
-
// eProtect's registration exactly as payment-core admits it, with no body
|
|
2670
|
+
// A GET card request is its URL alone. This build completes two kinds: Worldpay
|
|
2671
|
+
// eProtect's registration exactly as payment-core admits it, with no body, and a
|
|
2672
|
+
// hosted page's entry link exactly as its rule admits it (hosted-entry.ts), with no
|
|
2673
|
+
// body, which the cardholder's device takes over.
|
|
2382
2674
|
const eprotect = rec?.psp === EPROTECT_PSP;
|
|
2383
|
-
|
|
2675
|
+
const hostedGetEntry = mode === 'hosted_form' && !!rec && isHostedGetEntry(rec.psp, input.request.url)
|
|
2676
|
+
&& (input.request.body === undefined || input.request.body === null || input.request.body === '');
|
|
2677
|
+
if (cardMethod === 'GET' && !(eprotect && isEprotectRegistration(input.request)) && !hostedGetEntry) {
|
|
2384
2678
|
throw new Error(`this ${rec?.psp} GET is not a card registration this version of @agent-cards/checkout can complete: ${redactUrl(input.request.url)}.`);
|
|
2385
2679
|
}
|
|
2386
2680
|
// A CyberSource Secure Acceptance token create (always prepared: its recognizer requires it). The
|
|
@@ -2406,10 +2700,26 @@ export class VaultClient {
|
|
|
2406
2700
|
// amount_required.
|
|
2407
2701
|
if (!hasAmount && rec && AGENT_AMOUNT_PROCESSORS.includes(rec.psp))
|
|
2408
2702
|
throw new AmountRequiredError(rec.psp);
|
|
2409
|
-
// A
|
|
2410
|
-
//
|
|
2411
|
-
//
|
|
2412
|
-
|
|
2703
|
+
// A Przelewy24 pay wall charges the amount the merchant's server registered with Przelewy24 under the link's
|
|
2704
|
+
// token, so a zero pair would show the cardholder no price at all: it is refused like a missing one.
|
|
2705
|
+
// A Moneris, a HiPay or a Pay. token, or a GoDaddy Payments nonce, is charged later for whatever the merchant's
|
|
2706
|
+
// server decides, a Payfast pay, a PayMongo attach, a 2C2P Payment, a Revolut card payment or a SumUp card request
|
|
2707
|
+
// charges the total its payment, checkout session, payment token, order or checkout already holds, and a PayPal
|
|
2708
|
+
// order's amount was fixed by the merchant's server and never shown in the confirm, and a GoPay card post charges
|
|
2709
|
+
// the total GoPay's payment already holds, so a zero pair would show the cardholder no price at all: it is refused
|
|
2710
|
+
// like a missing one.
|
|
2711
|
+
// A ComGate payment charges the total ComGate already holds for it, the same way, and a Webpay transaction the
|
|
2712
|
+
// total the merchant's server bound to it.
|
|
2713
|
+
// A Moneris token is charged later for whatever the merchant's server decides, and a Payfast pay, a
|
|
2714
|
+
// PayMongo attach or a MakeCommerce card post charges the total its payment, checkout session or
|
|
2715
|
+
// transaction already holds, so a zero pair would show the cardholder no price at all: it is refused
|
|
2716
|
+
// like a missing one. So is a TokenEx iframe token, which the merchant's server charges later for its own order.
|
|
2717
|
+
if (hasAmount && rec && rec.psp === PRZELEWY24_PSP && Number(input.amount) <= 0)
|
|
2718
|
+
throw new AmountRequiredError(rec.psp);
|
|
2719
|
+
if (hasAmount && rec && (rec.psp === MONERIS_PSP || rec.psp === PAYFAST_PSP || rec.psp === PAYMONGO_PSP || rec.psp === HIPAY_PSP || rec.psp === TWOC2P_PSP
|
|
2720
|
+
|| rec.psp === REVOLUT_PSP || rec.psp === PAY_NL_PSP || rec.psp === PAYPAL_PSP
|
|
2721
|
+
|| rec.psp === GOPAY_PSP || rec.psp === COMGATE_PSP || rec.psp === MAKECOMMERCE_PSP
|
|
2722
|
+
|| rec.psp === POYNT_PSP || rec.psp === TOKENEX_IFRAME_PSP || rec.psp === TRANSBANK_PSP || rec.psp === SUMUP_PSP) && Number(input.amount) <= 0)
|
|
2413
2723
|
throw new AmountRequiredError(rec.psp);
|
|
2414
2724
|
// Nor is the agent's pair tied to the page by anything but the total the
|
|
2415
2725
|
// page shows: without it the cardholder could approve one figure while the
|
|
@@ -2555,8 +2865,11 @@ export class VaultClient {
|
|
|
2555
2865
|
// and the API names 500 ms as such a row's poll interval.
|
|
2556
2866
|
// A prepared Paddle VGS card request too, for 20 seconds: Paddle's frame aborts it 10 seconds after
|
|
2557
2867
|
// Pay and sends it once more, and the API names 500 ms as such a row's poll interval.
|
|
2868
|
+
// A prepared HiPay token create too, for 20 seconds: HiPay's hosted fields give it 20 seconds from Pay, so
|
|
2869
|
+
// an answer the cardholder's device records late in that span still reaches the frame before it gives up,
|
|
2870
|
+
// and the API names 500 ms as such a row's poll interval.
|
|
2558
2871
|
const preparedFastPollUntil = preparation?.psp === 'mercado_pago' ? Date.now() + 10_000
|
|
2559
|
-
: preparation?.psp === PADDLE_VGS_PSP ? Date.now() + 20_000
|
|
2872
|
+
: preparation?.psp === PADDLE_VGS_PSP || preparation?.psp === HIPAY_PSP ? Date.now() + 20_000
|
|
2560
2873
|
: preparation?.psp === EPROTECT_PSP ? Date.now() + 15_000
|
|
2561
2874
|
: preparation?.psp === SECURE_ACCEPTANCE_PSP ? Date.now() + SECURE_ACCEPTANCE_FAST_POLL_MS : 0;
|
|
2562
2875
|
// A preparation that tokenized before Pay: the cardholder's device already holds CyberSource's
|
|
@@ -2924,6 +3237,18 @@ export class VaultClient {
|
|
|
2924
3237
|
response.headers = answer.headers;
|
|
2925
3238
|
response.body = answer.body;
|
|
2926
3239
|
}
|
|
3240
|
+
if (rec?.psp === TOKENEX_IFRAME_PSP) {
|
|
3241
|
+
// TokenEx's answer enters the frame only as TokenEx's 200 with a sound token, rebuilt from payment-core's
|
|
3242
|
+
// allow-list under a JSON content type (tokenex-iframe.ts tokenexIframePageAnswer); the frame adds its own
|
|
3243
|
+
// cardType. Anything else is never handed over: the device may already have sent the card, so the
|
|
3244
|
+
// outcome is unknown rather than declined.
|
|
3245
|
+
const answer = tokenexIframePageAnswer(response.status, response.body);
|
|
3246
|
+
if (!answer)
|
|
3247
|
+
throw new PaymentOutcomeUnknownError(authorizationId, 'tokenex_iframe_token_unconfirmed');
|
|
3248
|
+
response.status = answer.status;
|
|
3249
|
+
response.headers = answer.headers;
|
|
3250
|
+
response.body = answer.body;
|
|
3251
|
+
}
|
|
2927
3252
|
let processorContext;
|
|
2928
3253
|
if (mercadoContext) {
|
|
2929
3254
|
try {
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ComGate's payment gateway (pay1 to pay4.comgate.cz, where most Czech and Slovak e-shops send the buyer), as this
|
|
3
|
+
* SDK reads it.
|
|
4
|
+
*
|
|
5
|
+
* The merchant's server creates the payment at ComGate and sends the buyer's browser to the gateway link ComGate
|
|
6
|
+
* answered with, https://payN.comgate.cz/init?id=<transaction id>, by a redirect or by setting the page's or a
|
|
7
|
+
* frame's location. That GET carries no card and nothing but the payment's id, and it is the one request a build
|
|
8
|
+
* that declares ComGate's capability pauses for ComGate (hosted-entry.ts): the cardholder's device then makes the
|
|
9
|
+
* gateway's own calls for that payment over the end-to-end TLS relay (payment-core processors/comgate.js). Only the
|
|
10
|
+
* link exactly as ComGate writes it is the entry; any other parameter would be handed on to the gateway's own
|
|
11
|
+
* route, which these rules never see.
|
|
12
|
+
*
|
|
13
|
+
* COMGATE_GATEWAY_HOSTS is payment-core's COMGATE_GATEWAY_HOSTS, and isComgateEntryUrl is payment-core's rule of
|
|
14
|
+
* the same name; hosted-entry.test.mjs pins both to payment-core on every case payment-core's own tests list.
|
|
15
|
+
*/
|
|
16
|
+
export declare const COMGATE_PSP = "comgate";
|
|
17
|
+
/** The dark-launch capability the API serves ComGate's recognizer behind (payment-core definitions.js). */
|
|
18
|
+
export declare const COMGATE_CAPABILITY = "comgate_hosted_payment_page";
|
|
19
|
+
/** The four gateway hosts ComGate's create answer names, each a host of its own entry. */
|
|
20
|
+
export declare const COMGATE_GATEWAY_HOSTS: readonly string[];
|
|
21
|
+
/**
|
|
22
|
+
* The hosts that take a card, or part of one, for ComGate: the gateway's API (payments.comgate.cz behind pay1 and pay2,
|
|
23
|
+
* payments-gcp.comgate.cz behind pay3 and pay4), where the gateway posts the card (/client/instructions/card-process,
|
|
24
|
+
* check-card) and ComGate's Web Checkout SDK posts its own (/checkout/provider/*, /checkout/card/check-card), and the
|
|
25
|
+
* card frames' hosts (sec.comgate.cz, sec-gcp.comgate.cz), which post the card's first digits to their /bin-checker.
|
|
26
|
+
* The card is already encrypted in ComGate's frame by then, so no body rule could see it: once ComGate is served, this
|
|
27
|
+
* build fails every request to these hosts but a GET, so the card the agent typed never reaches ComGate.
|
|
28
|
+
*/
|
|
29
|
+
export declare const COMGATE_CARD_HOSTS: readonly string[];
|
|
30
|
+
/** The Fetch.enable globs attachToCdp arms for the card hosts, only while ComGate is served (cdp.ts). */
|
|
31
|
+
export declare const COMGATE_CARD_PATTERNS: readonly string[];
|
|
32
|
+
/** Whether this URL is on one of ComGate's card hosts (https, no credentials, any port, a trailing dot or not). */
|
|
33
|
+
export declare function isComgateCardHost(url: string): boolean;
|
|
34
|
+
/** Whether this build's registry serves ComGate's entry: a company Agentcard turned ComGate on for, on a build that declares it. */
|
|
35
|
+
export declare function servesComgate(vault: {
|
|
36
|
+
isCardRequest(url: string, method?: string): boolean;
|
|
37
|
+
} | undefined): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Whether an adapter must hand this request to the pre-claim gates: it is on one of ComGate's card hosts and this
|
|
40
|
+
* build's registry serves ComGate. attachToPlaywright's route predicate asks this, as attachToCdp arms the hosts.
|
|
41
|
+
*/
|
|
42
|
+
export declare function isArmedComgateUrl(vault: {
|
|
43
|
+
isCardRequest(url: string, method?: string): boolean;
|
|
44
|
+
} | undefined, url: string): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Whether a URL is ComGate's gateway link exactly as ComGate's create answer writes it: https, one of the four
|
|
47
|
+
* gateway hosts in lowercase, the default port, no credentials or fragment, the path /init, and a query of the one
|
|
48
|
+
* `id` parameter holding a transaction id. A string that parses to another spelling is not it.
|
|
49
|
+
*/
|
|
50
|
+
export declare function isComgateEntryUrl(raw: unknown): boolean;
|