@agent-cards/sdk 0.23.23 → 0.23.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/PREFLIGHT.md +2 -0
  3. package/README.md +13 -1
  4. package/dist/agent-amount.generated.js +1 -1
  5. package/dist/amadeus.d.ts +5 -2
  6. package/dist/amadeus.js +18 -3
  7. package/dist/amazon-payment-services.d.ts +25 -0
  8. package/dist/amazon-payment-services.generated.d.ts +76 -0
  9. package/dist/amazon-payment-services.generated.js +883 -0
  10. package/dist/amazon-payment-services.js +53 -0
  11. package/dist/barion.d.ts +44 -0
  12. package/dist/barion.js +84 -0
  13. package/dist/capabilities.generated.js +1 -1
  14. package/dist/card-fields.generated.js +5 -4
  15. package/dist/cdp.js +70 -4
  16. package/dist/client.d.ts +55 -3
  17. package/dist/client.js +119 -12
  18. package/dist/hosted-entry.js +2 -0
  19. package/dist/index.d.ts +1 -0
  20. package/dist/index.js +1 -0
  21. package/dist/openpay.generated.d.ts +67 -0
  22. package/dist/openpay.generated.js +446 -0
  23. package/dist/paddle-checkout-watch.d.ts +70 -0
  24. package/dist/paddle-checkout-watch.js +239 -0
  25. package/dist/paddle-tokenex.generated.d.ts +29 -1
  26. package/dist/paddle-tokenex.generated.js +175 -26
  27. package/dist/pre-claim.d.ts +1 -0
  28. package/dist/pre-claim.js +18 -1
  29. package/dist/prepared-processor.d.ts +12 -4
  30. package/dist/prepared-processor.js +31 -5
  31. package/dist/primer.generated.js +5 -4
  32. package/dist/stripe-checkout.generated.js +5 -4
  33. package/dist/tap-payments.d.ts +43 -0
  34. package/dist/tap-payments.generated.d.ts +59 -0
  35. package/dist/tap-payments.generated.js +990 -0
  36. package/dist/tap-payments.js +72 -0
  37. package/dist/tokenex-iframe.generated.d.ts +18 -6
  38. package/dist/tokenex-iframe.generated.js +3 -3
  39. package/package.json +2 -2
@@ -0,0 +1,53 @@
1
+ // Amazon Payment Services (formerly PayFort; psp `amazon_payment_services`), its custom merchant page: the merchant's own
2
+ // card form posts top-level, as a document navigation, to /FortAPI/paymentPage on checkout.payfort.com (its sandbox,
3
+ // sbcheckout.payfort.com), form encoded, with service_command=TOKENIZATION and the merchant's signed fields beside the
4
+ // card. APS answers the post with a page whose script posts APS's fields to the form's return_url, or with a redirect
5
+ // to that return_url carrying them in its query, and the merchant charges the token in those fields later, from its own
6
+ // server. The rules are payment-core's (amazon-payment-services.generated.ts): the API applies them at create and at the
7
+ // approve, and the cardholder's phone again before it sends the form through the checkout relay.
8
+ //
9
+ // The processor ships dark. The API serves the amazon_payment_services recognizer only to a build that declares the
10
+ // `aps_custom_merchant_page` capability (client.ts SUPPORTED_CAPABILITIES), and only to an org Agentcard enabled for it,
11
+ // so an SDK the API never served it leaves every APS form alone. This module holds the last check before an approval's
12
+ // answer reaches the paused navigation.
13
+ import { APS_CAPABILITY as CORE_CAPABILITY, APS_PAGE_CONTENT_TYPE, APS_PSP as CORE_PSP, apsAnswerOutcome } from './amazon-payment-services.generated.js';
14
+ export const APS_PSP = CORE_PSP;
15
+ export const APS_CAPABILITY = CORE_CAPABILITY;
16
+ /**
17
+ * The answer the paused APS form navigation is fulfilled with, or null. The API stores APS's answer only once
18
+ * payment-core's judge reads it as a token for the paused form (apsAnswerOutcome), and this reads the stored answer
19
+ * again, against the paused request, before the agent's browser gets it:
20
+ * page status 200 under APS's HTML type alone, APS's page byte for byte, whose one form posts APS's fields to
21
+ * the paused form's own return_url;
22
+ * redirect status 302 or 303 with one Location alone: the paused form's return_url, then APS's fields in the query.
23
+ * Anything else is null: a refusal, an unknown answer, another merchant's or another return page's answer, a card
24
+ * number anywhere in it, or a header beside the one each shape carries. A navigation reads no CORS header, so none is
25
+ * added. Autopilot never sends an APS form (payment-core autopilot.js), so the caller refuses an unattended answer.
26
+ */
27
+ export function apsNavigationAnswer(request, response) {
28
+ try {
29
+ const headers = {};
30
+ for (const [name, value] of Object.entries(response.headers ?? {})) {
31
+ const lower = name.toLowerCase();
32
+ if (typeof value !== 'string' || Object.prototype.hasOwnProperty.call(headers, lower))
33
+ return null;
34
+ headers[lower] = value;
35
+ }
36
+ const names = Object.keys(headers);
37
+ // No card is in hand here: the judge reads the answer for any card number, with no card of its own to search for.
38
+ const verdict = apsAnswerOutcome({ status: response.status, headers, bodyText: response.body }, { url: request.url, body: request.body ?? '' }, undefined, undefined);
39
+ if (verdict.outcome !== 'token' || typeof verdict.body !== 'string')
40
+ return null;
41
+ if (verdict.shape === 'page') {
42
+ if (names.length !== 1 || headers['content-type'] !== APS_PAGE_CONTENT_TYPE)
43
+ return null;
44
+ return { status: 200, headers: { 'content-type': APS_PAGE_CONTENT_TYPE }, body: verdict.body };
45
+ }
46
+ if (names.length !== 1 || typeof verdict.location !== 'string' || response.body !== '')
47
+ return null;
48
+ return { status: response.status, headers: { location: verdict.location }, body: '' };
49
+ }
50
+ catch {
51
+ return null;
52
+ }
53
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Barion's Smart Gateway (secure.barion.com, where Hungarian, Czech and Slovak shops send a buyer who pays by card), as
3
+ * this SDK reads it.
4
+ *
5
+ * The merchant's server starts the payment with Barion and sends the buyer's browser to the gateway URL Barion answered
6
+ * with, https://secure.barion.com/Pay?Id=<payment id>, by a redirect or by setting the page's location. That GET carries
7
+ * no card, no amount and no merchant, and it is the one request a build that declares Barion's capability pauses
8
+ * (hosted-entry.ts): the cardholder's device repeats it over the end-to-end TLS relay and makes the gateway's own posts
9
+ * in the session Barion opens (payment-core processors/barion.js). Every post the agent's browser would send the gateway
10
+ * to pay follows that entry and leads to a card: the email check, the card's 3-D Secure version post, the 3-D Secure
11
+ * post and the charge post (/Pay/CheckEmailAddress, /Pay/PrepareCardPaymentForGuest, /ThreeDs/Authenticate,
12
+ * /Pay/CompletePaymentAsGuestWithCard). A build that declares Barion aborts every one of them (pre-claim.ts), so a
13
+ * placeholder card never reaches Barion.
14
+ *
15
+ * BARION_HOSTS is payment-core's BARION_HOSTS, and isBarionEntryUrl is payment-core's isBarionEntryUrl; barion.test.mjs
16
+ * pins both to payment-core on every case payment-core's own tests list.
17
+ */
18
+ export declare const BARION_PSP = "barion";
19
+ /** The dark-launch capability the API serves Barion's recognizer behind (payment-core definitions.js). */
20
+ export declare const BARION_CAPABILITY = "barion_hosted_payment_page";
21
+ /** The gateway's two hosts: live, and Barion's test gateway, which runs the same gateway for Barion's test shops. */
22
+ export declare const BARION_HOSTS: readonly string[];
23
+ /**
24
+ * Whether a URL is the gateway URL exactly as the merchant's redirect writes it: https, one of the two gateway hosts in
25
+ * lowercase, the default port, no credentials or fragment, the path /Pay, and one query parameter, Id or id, holding the
26
+ * payment's id. The gateway acts on other parameters (its script starts a bank transfer by itself for a DefaultBankId),
27
+ * so a URL carrying any is not the entry, and neither is any other page or post of the gateway's host.
28
+ */
29
+ export declare function isBarionEntryUrl(raw: unknown): boolean;
30
+ /**
31
+ * Whether a request on the gateway's hosts is a step toward paying there: any POST (the email check, the card's two
32
+ * posts, the 3-D Secure post, and any other form the gateway posts). The gateway's own pages, scripts and images, its
33
+ * 3-D Secure frames among them, are GETs of no card and are not one.
34
+ */
35
+ export declare function isBarionPayStep(url: string, method: string): boolean;
36
+ /**
37
+ * Whether an adapter must hand this request to the pre-claim gates: it is on a gateway host and this build's registry
38
+ * serves Barion's entry there. The gateway's posts are not the entry, so the registry's card-request test does not name
39
+ * them; the CDP adapter still pauses them through the recognizer's host pattern, and attachToPlaywright's route
40
+ * predicate asks this, so both adapters show the gates every request to the gateway once Barion is armed.
41
+ */
42
+ export declare function isArmedBarionUrl(vault: {
43
+ isCardRequest(url: string, method?: string): boolean;
44
+ } | undefined, url: string): boolean;
package/dist/barion.js ADDED
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Barion's Smart Gateway (secure.barion.com, where Hungarian, Czech and Slovak shops send a buyer who pays by card), as
3
+ * this SDK reads it.
4
+ *
5
+ * The merchant's server starts the payment with Barion and sends the buyer's browser to the gateway URL Barion answered
6
+ * with, https://secure.barion.com/Pay?Id=<payment id>, by a redirect or by setting the page's location. That GET carries
7
+ * no card, no amount and no merchant, and it is the one request a build that declares Barion's capability pauses
8
+ * (hosted-entry.ts): the cardholder's device repeats it over the end-to-end TLS relay and makes the gateway's own posts
9
+ * in the session Barion opens (payment-core processors/barion.js). Every post the agent's browser would send the gateway
10
+ * to pay follows that entry and leads to a card: the email check, the card's 3-D Secure version post, the 3-D Secure
11
+ * post and the charge post (/Pay/CheckEmailAddress, /Pay/PrepareCardPaymentForGuest, /ThreeDs/Authenticate,
12
+ * /Pay/CompletePaymentAsGuestWithCard). A build that declares Barion aborts every one of them (pre-claim.ts), so a
13
+ * placeholder card never reaches Barion.
14
+ *
15
+ * BARION_HOSTS is payment-core's BARION_HOSTS, and isBarionEntryUrl is payment-core's isBarionEntryUrl; barion.test.mjs
16
+ * pins both to payment-core on every case payment-core's own tests list.
17
+ */
18
+ export const BARION_PSP = 'barion';
19
+ /** The dark-launch capability the API serves Barion's recognizer behind (payment-core definitions.js). */
20
+ export const BARION_CAPABILITY = 'barion_hosted_payment_page';
21
+ /** The gateway's two hosts: live, and Barion's test gateway, which runs the same gateway for Barion's test shops. */
22
+ export const BARION_HOSTS = Object.freeze(['secure.barion.com', 'secure.test.barion.com']);
23
+ const ENTRY_PATH = '/Pay';
24
+ // The payment's id, a GUID: 32 hexadecimal digits as the gateway URL writes it, or with its four dashes as Barion's PHP
25
+ // library writes it, in either letter case.
26
+ const PAYMENT_ID = /^(?:[0-9a-f]{32}|[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/i;
27
+ // The entry's whole query: the one parameter Barion's GatewayUrl names (Id) or its PHP library names (id).
28
+ const ENTRY_QUERY = /^\?(?:Id|id)=([^&=]{1,64})$/;
29
+ // An id of that shape, for asking whether this build's registry serves the entry on a host.
30
+ const PROBE_ID = '00000000000000000000000000000000';
31
+ /**
32
+ * Whether a URL is the gateway URL exactly as the merchant's redirect writes it: https, one of the two gateway hosts in
33
+ * lowercase, the default port, no credentials or fragment, the path /Pay, and one query parameter, Id or id, holding the
34
+ * payment's id. The gateway acts on other parameters (its script starts a bank transfer by itself for a DefaultBankId),
35
+ * so a URL carrying any is not the entry, and neither is any other page or post of the gateway's host.
36
+ */
37
+ export function isBarionEntryUrl(raw) {
38
+ if (typeof raw !== 'string' || raw.length > 256)
39
+ return false;
40
+ let url;
41
+ try {
42
+ url = new URL(raw);
43
+ }
44
+ catch {
45
+ return false;
46
+ }
47
+ if (url.protocol !== 'https:' || !BARION_HOSTS.includes(url.hostname) || url.pathname !== ENTRY_PATH
48
+ || url.port || url.username || url.password || url.href !== raw || raw.includes('#'))
49
+ return false;
50
+ const match = ENTRY_QUERY.exec(url.search);
51
+ return !!match && PAYMENT_ID.test(match[1]);
52
+ }
53
+ /** The gateway host a URL is on (https, no credentials, any port, any letter case, a trailing dot or not), or null. */
54
+ function barionHost(raw) {
55
+ let url;
56
+ try {
57
+ url = new URL(raw);
58
+ }
59
+ catch {
60
+ return null;
61
+ }
62
+ if (url.protocol !== 'https:' || url.username || url.password)
63
+ return null;
64
+ const host = url.hostname.toLowerCase().replace(/\.$/, '');
65
+ return BARION_HOSTS.includes(host) ? host : null;
66
+ }
67
+ /**
68
+ * Whether a request on the gateway's hosts is a step toward paying there: any POST (the email check, the card's two
69
+ * posts, the 3-D Secure post, and any other form the gateway posts). The gateway's own pages, scripts and images, its
70
+ * 3-D Secure frames among them, are GETs of no card and are not one.
71
+ */
72
+ export function isBarionPayStep(url, method) {
73
+ return barionHost(url) !== null && String(method).toUpperCase() === 'POST';
74
+ }
75
+ /**
76
+ * Whether an adapter must hand this request to the pre-claim gates: it is on a gateway host and this build's registry
77
+ * serves Barion's entry there. The gateway's posts are not the entry, so the registry's card-request test does not name
78
+ * them; the CDP adapter still pauses them through the recognizer's host pattern, and attachToPlaywright's route
79
+ * predicate asks this, so both adapters show the gates every request to the gateway once Barion is armed.
80
+ */
81
+ export function isArmedBarionUrl(vault, url) {
82
+ const host = barionHost(url);
83
+ return host !== null && typeof vault?.isCardRequest === 'function' && vault.isCardRequest(`https://${host}${ENTRY_PATH}?Id=${PROBE_ID}`, 'GET');
84
+ }
@@ -1,3 +1,3 @@
1
1
  // Written by scripts/generate-capabilities.mjs from capabilities.json. Do not edit; git ignores it.
2
2
  /** capabilities.json's list, sorted; client.ts exports it as SUPPORTED_CAPABILITIES. */
3
- export const DECLARED_CAPABILITIES = ["aci_split_card.v1", "amadeus_checkout_actions.v1", "authorize_net_dpm_form", "capture_context", "clover_card_token", "comgate_hosted_payment_page", "converge_hpp_process", "creditguard_pps_process", "cybersource_sa_token_create", "datatrans_secure_fields_tokenize", "ekashu_hosted_payment_page", "eximbay_hosted_payment_page", "fiserv_card_capture", "gmo_shared_pk", "gopay_card_form", "gravy_session_fields_put", "hipay_vault_token", "juspay_txns.v1", "lyra_krypton_payment", "makecommerce_card_frame", "midtrans_card_token", "moneris_hosted_tokenization", "omise_card_token", "paddle_tokenex_pay", "paddle_vgs_cards", "pay_nl_card_token", "payfast_card_pay", "paygent_token", "paymongo_checkout_pay", "paypal_card_fields", "payrails_device_encrypt", "payrexx_card_frame", "paytrail_hosted_payment_page", "pelecard_transaction", "poynt_collect_nonce", "primer_payment_instruments", "przelewy24_hosted_payment_page", "quickpay_hosted_payment_page", "redsys_hosted_payment_page", "revolut_card_field", "sbps_token_jsonp", "shiji_sts_pinned_key", "sumup_checkout_process", "toast_pinned_key", "tokenex_iframe_tokenize", "transbank_webpay_hosted_payment_page", "twoc2p_secure_pay", "verifone_card_capture", "wix_payments_tokenize", "worldline_mycheckout_form", "worldpay_eprotect_jsonp", "wspay_confirm", "xendit_card_token"];
3
+ export const DECLARED_CAPABILITIES = ["aci_split_card.v1", "amadeus_checkout_actions.v1", "aps_custom_merchant_page", "authorize_net_dpm_form", "barion_hosted_payment_page", "capture_context", "clover_card_token", "comgate_hosted_payment_page", "converge_hpp_process", "creditguard_pps_process", "cybersource_sa_token_create", "datatrans_secure_fields_tokenize", "ekashu_hosted_payment_page", "eximbay_hosted_payment_page", "fastspring_card_payment", "fiserv_card_capture", "gmo_shared_pk", "gopay_card_form", "gravy_session_fields_put", "hipay_vault_token", "juspay_txns.v1", "lyra_krypton_payment", "makecommerce_card_frame", "midtrans_card_token", "moneris_hosted_tokenization", "omise_card_token", "openpay_tokenizer", "paddle_tokenex_pay", "paddle_vgs_cards", "pay_nl_card_token", "payfast_card_pay", "paygent_token", "paymongo_checkout_pay", "paypal_card_fields", "payrails_device_encrypt", "payrexx_card_frame", "paytrail_hosted_payment_page", "pelecard_transaction", "poynt_collect_nonce", "primer_payment_instruments", "przelewy24_hosted_payment_page", "quickpay_hosted_payment_page", "redsys_hosted_payment_page", "revolut_card_field", "sbps_token_jsonp", "shiji_sts_pinned_key", "sumup_checkout_process", "tap_card_sdk_token", "toast_pinned_key", "tokenex_iframe_tokenize", "transbank_webpay_hosted_payment_page", "twoc2p_secure_pay", "verifone_card_capture", "wix_payments_tokenize", "worldline_mycheckout_form", "worldpay_eprotect_jsonp", "wspay_confirm", "xendit_card_token"];
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
2
  // Generated from @agent-cards/payment-core. Do not edit.
3
- // artifact-sha256: d1aac0b870ff4b5f9d63a43d1c2bb0eef03841846206282b5aeca4f540f0e73d
3
+ // artifact-sha256: e6f7697efcf41d051189ca331d0d99f5a701e50cb0b7d3a3f967178bf87d7df1
4
4
  // src/card-number-key.js
5
5
  var CARD_NUMBER_KEY = /^(number|card_number|cardnumber|cardNum|card_num|pan)$/i;
6
6
  // src/json-path.js
@@ -3561,11 +3561,11 @@ var TOKENEX_IFRAME_BODY_KEYS = Object.freeze([
3561
3561
  ]);
3562
3562
  var TOKENEX_IFRAME_TOKEN_SCHEMES = Object.freeze(["sixTOKENfour"]);
3563
3563
  var TOKENEX_IFRAME_REVIEWED_ACCOUNTS = Object.freeze({
3564
- "htp.tokenex.com": Object.freeze({}),
3564
+ "htp.tokenex.com": Object.freeze({ "9014311640612780": "https://www.jetblue.com" }),
3565
3565
  "test-htp.tokenex.com": Object.freeze({})
3566
3566
  });
3567
3567
  var TOKENEX_IFRAME_ACCOUNT_NAMES = Object.freeze({
3568
- "htp.tokenex.com": Object.freeze({}),
3568
+ "htp.tokenex.com": Object.freeze({ "9014311640612780": "JetBlue" }),
3569
3569
  "test-htp.tokenex.com": Object.freeze({})
3570
3570
  });
3571
3571
  var BODY_LIMIT22 = 8192;
@@ -4615,7 +4615,8 @@ function toastBodyVerdict(body) {
4615
4615
  // src/fastspring.js
4616
4616
  var FASTSPRING_PSP = "fastspring";
4617
4617
  var FASTSPRING_STORE_PINS = /* @__PURE__ */ Object.freeze([
4618
- Object.freeze({ environment: "production", store: "daisydisk", storefront: "", merchant: "DaisyDisk" })
4618
+ Object.freeze({ environment: "production", store: "daisydisk", storefront: "", merchant: "DaisyDisk" }),
4619
+ Object.freeze({ environment: "production", store: "stardock", storefront: "/popup-store", merchant: "Stardock" })
4619
4620
  ]);
4620
4621
  var URL_LIMIT11 = 256;
4621
4622
  var BODY_LIMIT28 = 32768;
package/dist/cdp.js CHANGED
@@ -20,10 +20,12 @@ import { isArmedPaytrailUrl } from './paytrail.js';
20
20
  import { SHIJI_STS_COMPANION_WINDOW_MS, ShijiStsCompanions, ShijiStsError, isShijiStsHost, shijiStsTokenContinuation, } from './shiji-sts.js';
21
21
  import { paddleTokenexTokenContinuation } from './paddle-tokenex.js';
22
22
  import { twoC2pContinuation, twoC2pRetire } from './twoc2p.js';
23
+ import { tapPaymentsContinuation } from './tap-payments.js';
23
24
  import { isArmedEkashuUrl } from './ekashu.js';
24
25
  import { isArmedTransbankUrl, transbankMerchantReturn, transbankMerchantReturnAnswer } from './transbank.js';
25
26
  import { isArmedRedsysUrl } from './redsys.js';
26
27
  import { isArmedPrzelewy24Url } from './przelewy24.js';
28
+ import { isArmedBarionUrl } from './barion.js';
27
29
  import { isArmedQuickpayUrl } from './quickpay.js';
28
30
  import { COMGATE_CARD_PATTERNS, isArmedComgateUrl, servesComgate } from './comgate.js';
29
31
  import { isArmedEximbayUrl } from './eximbay.js';
@@ -39,6 +41,7 @@ import { replayTemplatedUrl, reviewedMerchantProfileUrlPatterns } from './mercha
39
41
  import { verifoneTemplatedUrl } from './verifone.js';
40
42
  import { MerchantHandoffWatch } from './merchant-handoff.js';
41
43
  import { MERCHANT_PAGE_WAIT_MS, MerchantTotalWatch } from './merchant-total-watch.js';
44
+ import { PaddleCheckoutWatch } from './paddle-checkout-watch.js';
42
45
  import { hostedFormSubmittedPage } from './hosted-form.js';
43
46
  import { armSendWindow, failsAsNetworkError, preparedSendWindowMs, sendWindowProcessor } from './amadeus.js';
44
47
  import { HoldAnsweredError, HoldEndedError, HoldGate, HoldRefusedError, matchHoldOnlyRule } from './hold.js';
@@ -365,7 +368,7 @@ function cseAuthorizedDetail(replay, url, shijiCvv = null) {
365
368
  * processor takes cseContinuationBody (cse-body.ts cseBody), and `shijiCvv` and
366
369
  * `shijiCvvKeySequenceSha256` are null.
367
370
  */
368
- function cseContinuation(opts, url, body, replay, approved, preparation) {
371
+ function cseContinuation(opts, url, body, replay, approved, preparation, headers) {
369
372
  const shiji = shijiStsTokenContinuation(url, body, replay.substitutions, approved, replay.kind === 'merchant_hosted' || replay.kind === 'verifone' ? undefined : replay.shijiStsCompanion);
370
373
  if (shiji)
371
374
  return { body: shiji.body, shijiCvv: shiji.cvv, shijiCvvKeySequenceSha256: shiji.cvvKeySequenceSha256 };
@@ -384,6 +387,13 @@ function cseContinuation(opts, url, body, replay, approved, preparation) {
384
387
  : null;
385
388
  if (twoc2p)
386
389
  return { body: twoc2p.body, shijiCvv: null, shijiCvvKeySequenceSha256: null };
390
+ // Tap writes one RSA ciphertext at the body root under the merchant's pinned key, which the generic Adyen swap refuses
391
+ // as no JWE, so it is dispatched by the token URL to substituteTapPayments (tap-payments.ts), only into the one request
392
+ // the approval was made for, and only while the request that continues names the merchant's publishable key the
393
+ // approved one named: the browser sends that request's own headers.
394
+ const tap = replay.kind === undefined ? tapPaymentsContinuation(url, body, headers, replay.substitutions, approved) : null;
395
+ if (tap)
396
+ return { body: tap.body, shijiCvv: null, shijiCvvKeySequenceSha256: null };
387
397
  return { body: cseContinuationBody(opts, body, replay, url, preparation), shijiCvv: null, shijiCvvKeySequenceSha256: null };
388
398
  }
389
399
  /**
@@ -1436,7 +1446,7 @@ function merchantAttempt(lifecycle, survives) {
1436
1446
  // known non-payment, so the prepared checkout ends failed with that reason, and a fresh attachment can
1437
1447
  // prepare again. Every other stop leaves the outcome unknown.
1438
1448
  const error = () => reason === 'amadeus_send_window_closed' || reason === 'secure_acceptance_send_window_closed'
1439
- || reason === 'wix_payments_send_window_closed' || reason === 'hipay_send_window_closed'
1449
+ || reason === 'wix_payments_send_window_closed' || reason === 'hipay_send_window_closed' || reason === 'openpay_send_window_closed'
1440
1450
  ? new CheckoutPreparationError(lifecycle.getState().preparationId ?? null, reason)
1441
1451
  : new PaymentOutcomeUnknownError(lifecycle.getState().authorizationId, reason);
1442
1452
  const attempt = {
@@ -2016,6 +2026,8 @@ export async function attachToCdp(cdp, pageSessionId, opts) {
2016
2026
  // The merchant's own total (merchant-total-watch.ts): its checkout responses, recorded
2017
2027
  // read-only from attach on, and the approval a hand-off answers, for the charge report.
2018
2028
  const merchantTotal = new MerchantTotalWatch(opts.onEvent, opts.vault);
2029
+ // Paddle's own checkout answers (paddle-checkout-watch.ts), recorded read-only from attach on for a TokenEx /pay.
2030
+ const paddleCheckout = new PaddleCheckoutWatch();
2019
2031
  // A reviewed card endpoint merchant's own record of the order (card-endpoint-facts.ts).
2020
2032
  const cardEndpointRecord = new CardEndpointFactsWatch();
2021
2033
  let handoffReplay = null;
@@ -2525,6 +2537,7 @@ export async function attachToCdp(cdp, pageSessionId, opts) {
2525
2537
  merchantTotal.sent(key, { method: params.request.method, url: params.request.url,
2526
2538
  ...(typeof params.request.postData === 'string' ? { requestBody: params.request.postData } : {}),
2527
2539
  ...(typeof params.loaderId === 'string' && params.loaderId ? { page: `${owner}:${params.loaderId}` } : {}) });
2540
+ paddleCheckout.sent(key, { method: params.request.method, url: params.request.url });
2528
2541
  cardEndpointRecord.sent(key, { method: params.request.method, url: params.request.url, resourceType: params.type ?? null, networkId: params.requestId });
2529
2542
  }
2530
2543
  if (matchesActive) {
@@ -2564,6 +2577,14 @@ export async function attachToCdp(cdp, pageSessionId, opts) {
2564
2577
  cdp.send('Network.getResponseBody', { requestId: params.requestId }, sessionId).then((read) => merchantTotal.log.read(key, typeof read?.body === 'string'
2565
2578
  ? (read.base64Encoded ? Buffer.from(read.body, 'base64').toString('utf8') : read.body) : null, completedAt), () => merchantTotal.log.read(key, null, completedAt));
2566
2579
  }
2580
+ if (paddleCheckout.tracks(key)) {
2581
+ // One of Paddle's checkout answers: stamped finished at once, so a /pay's pause waits for its text, then read
2582
+ // and cut to the terms by the watch.
2583
+ const completedAt = Date.now();
2584
+ paddleCheckout.finished(key, completedAt);
2585
+ cdp.send('Network.getResponseBody', { requestId: params.requestId }, sessionId).then((read) => paddleCheckout.read(key, typeof read?.body === 'string'
2586
+ ? (read.base64Encoded ? Buffer.from(read.body, 'base64').toString('utf8') : read.body) : null, completedAt), () => paddleCheckout.read(key, null, completedAt));
2587
+ }
2567
2588
  if (payrails && payrailsAnswers.delete(requestKey(sessionId, params.requestId))
2568
2589
  && !(Number(params.encodedDataLength) > PAYRAILS_INIT_BODY_LIMIT)) {
2569
2590
  payrails.reading(cdp.send('Network.getResponseBody', { requestId: params.requestId }, sessionId).then((answer) => {
@@ -2578,6 +2599,7 @@ export async function attachToCdp(cdp, pageSessionId, opts) {
2578
2599
  }
2579
2600
  if (method === 'Network.responseReceived') {
2580
2601
  merchantTotal.log.answered(requestKey(sessionId, params.requestId), params.response?.status);
2602
+ paddleCheckout.answered(requestKey(sessionId, params.requestId), params.response?.status);
2581
2603
  const recordKey = cardEndpointRecord.keyFor(requestKey(sessionId, params.requestId), params.requestId);
2582
2604
  if (recordKey)
2583
2605
  cardEndpointRecord.answered(recordKey, params.response?.status);
@@ -2606,6 +2628,7 @@ export async function attachToCdp(cdp, pageSessionId, opts) {
2606
2628
  || (activeRequest && activeRequest.networkId === params.requestId && activeRequest.sourceSessionId === sessionId)))
2607
2629
  holdGate.lost();
2608
2630
  merchantTotal.log.failed(requestKey(sessionId, params.requestId));
2631
+ paddleCheckout.failed(requestKey(sessionId, params.requestId));
2609
2632
  const recordKey = cardEndpointRecord.keyFor(requestKey(sessionId, params.requestId), params.requestId);
2610
2633
  if (recordKey)
2611
2634
  cardEndpointRecord.failed(recordKey);
@@ -3124,6 +3147,10 @@ export async function attachToCdp(cdp, pageSessionId, opts) {
3124
3147
  // The merchant's own record of the order, as of the pause, for a profile that reads one.
3125
3148
  const cardRecord = cardEndpoint ? await cardEndpointFacts(cardEndpointRecord, cardEndpoint, request.url, pausedAt, attempt.signal) : null;
3126
3149
  attempt.assertLive();
3150
+ // Paddle's own checkout answers as of the pause, once the texts of those that finished before it are read
3151
+ // (a Billing /pay only; sent only with a Paddle TokenEx create, which a pause-only business makes itself).
3152
+ const paddleAnswers = opts.pauseOnly ? undefined : await paddleCheckout.capture(pausedAt, request.url, attempt.signal);
3153
+ attempt.assertLive();
3127
3154
  // Hold mode: nothing is created until the person's total releases the request (hold.ts).
3128
3155
  if (holdGate) {
3129
3156
  if (holdGate.state !== 'watching') {
@@ -3179,6 +3206,8 @@ export async function attachToCdp(cdp, pageSessionId, opts) {
3179
3206
  // What the merchant's own checkout said its total was, as this browser recorded it
3180
3207
  // (read only for a reviewed profile priced by it): the page is the card request's.
3181
3208
  merchantTotal: merchantTotal.capture(pausedAt, cardPage),
3209
+ // Paddle's own checkout answers, as this browser recorded them (sent only with a Paddle TokenEx create).
3210
+ paddleCheckout: paddleAnswers,
3182
3211
  onAuthorizationCreated: (id) => {
3183
3212
  lifecycle.approvalCreated(id);
3184
3213
  if (holdSandbox && !holdRequestFailed) {
@@ -3299,7 +3328,7 @@ export async function attachToCdp(cdp, pageSessionId, opts) {
3299
3328
  // companion cannot arrive first, and dropped if the continue fails.
3300
3329
  // Both go only to the request the approval was created from, from the
3301
3330
  // frame that sent it (cseContinuation refuses any other body).
3302
- const continuation = cseContinuation(opts, deliverRequest.url, deliverBody, replay, { url: request.url, body }, preparation);
3331
+ const continuation = cseContinuation(opts, deliverRequest.url, deliverBody, replay, { url: request.url, body, headers: request.headers }, preparation, deliverRequest.headers);
3303
3332
  const postData = Buffer.from(continuation.body).toString('base64');
3304
3333
  if (continuation.shijiCvv !== null) {
3305
3334
  shijiCompanions.bind({ url: request.url, method: request.method, body }, cdpShijiPage(sessionId, frameId), continuation.shijiCvv, continuation.shijiCvvKeySequenceSha256 ?? []);
@@ -3629,6 +3658,8 @@ export async function attachToPlaywright(page, opts) {
3629
3658
  // but sends no document request, so it keeps the page id, as CDP's loaderId does. Nor does
3630
3659
  // a document request that commits nothing: one that failed, or one answered 204 or 205.
3631
3660
  const merchantTotal = new MerchantTotalWatch(opts.onEvent, opts.vault);
3661
+ // Paddle's own checkout answers, as attachToCdp records them (paddle-checkout-watch.ts).
3662
+ const paddleCheckout = new PaddleCheckoutWatch();
3632
3663
  // A reviewed card endpoint merchant's own record of the order (card-endpoint-facts.ts).
3633
3664
  const cardEndpointRecord = new CardEndpointFactsWatch();
3634
3665
  let documentSerial = 1;
@@ -3690,6 +3721,10 @@ export async function attachToPlaywright(page, opts) {
3690
3721
  ...(typeof body === 'string' ? { requestBody: body } : {}), page: `doc:${documentSerial}` });
3691
3722
  }
3692
3723
  catch { /* a request the page already dropped */ }
3724
+ try {
3725
+ paddleCheckout.sent(keyOf(request), { method: request.method(), url: request.url() });
3726
+ }
3727
+ catch { /* a request the page already dropped */ }
3693
3728
  try {
3694
3729
  cardEndpointRecord.sent(keyOf(request), { method: request.method(), url: request.url(),
3695
3730
  resourceType: typeof request.resourceType === 'function' ? request.resourceType() : null });
@@ -3731,6 +3766,28 @@ export async function attachToPlaywright(page, opts) {
3731
3766
  cardEndpointRecord.read(key, text, finishedAt);
3732
3767
  }).catch(() => cardEndpointRecord.failed(key));
3733
3768
  }
3769
+ if (paddleCheckout.tracks(key)) {
3770
+ // One of Paddle's checkout answers: stamped finished at once, so a /pay's pause waits for its text, then its
3771
+ // status and its text, cut to the terms by the watch.
3772
+ const answeredAt = Date.now();
3773
+ paddleCheckout.finished(key, answeredAt);
3774
+ Promise.resolve().then(async () => {
3775
+ const response = await request.response();
3776
+ if (!response) {
3777
+ paddleCheckout.failed(key);
3778
+ return;
3779
+ }
3780
+ paddleCheckout.answered(key, response.status());
3781
+ let text = null;
3782
+ try {
3783
+ text = await response.text();
3784
+ }
3785
+ catch {
3786
+ text = null;
3787
+ }
3788
+ paddleCheckout.read(key, text, answeredAt);
3789
+ }).catch(() => paddleCheckout.failed(key));
3790
+ }
3734
3791
  if (!merchantTotal.log.tracks(key))
3735
3792
  return;
3736
3793
  const completedAt = Date.now();
@@ -3800,6 +3857,7 @@ export async function attachToPlaywright(page, opts) {
3800
3857
  if (request === documentRequest)
3801
3858
  documentRequest = null;
3802
3859
  merchantTotal.log.failed(keyOf(request));
3860
+ paddleCheckout.failed(keyOf(request));
3803
3861
  cardEndpointRecord.failed(keyOf(request));
3804
3862
  if (activeRequest && activeRequest.request === request && activeRequest.attempt.lose()) {
3805
3863
  // The page's own script gave up on its request; the cardholder's
@@ -3923,6 +3981,9 @@ export async function attachToPlaywright(page, opts) {
3923
3981
  // the hosts: the card method's post, the card form's post and the Saferpay resolver reach the Przelewy24
3924
3982
  // gate and fail.
3925
3983
  || isArmedPrzelewy24Url(opts.vault, url.toString())
3984
+ // Every request to Barion's gateway hosts once its entry is served (barion.ts), as attachToCdp arms the hosts:
3985
+ // the gateway's email check, card posts and 3-D Secure post reach the Barion gate and fail.
3986
+ || isArmedBarionUrl(opts.vault, url.toString())
3926
3987
  // Every request to an NMI host whose entry is served (ekashu.ts), as attachToCdp arms the
3927
3988
  // host: the card page's post and its 3-D Secure calls reach the NMI gate and fail.
3928
3989
  || isArmedEkashuUrl(opts.vault, url.toString())
@@ -4292,6 +4353,9 @@ export async function attachToPlaywright(page, opts) {
4292
4353
  // The merchant's own record of the order, as of the pause (see attachToCdp).
4293
4354
  const cardRecord = cardEndpoint ? await cardEndpointFacts(cardEndpointRecord, cardEndpoint, request.url(), pausedAt, attempt.signal) : null;
4294
4355
  assertRequestLive();
4356
+ // Paddle's own checkout answers as of the pause, once their texts are read (see attachToCdp).
4357
+ const paddleAnswers = await paddleCheckout.capture(pausedAt, request.url(), attempt.signal);
4358
+ assertRequestLive();
4295
4359
  const replay = await opts.vault.authorize({
4296
4360
  user: opts.user,
4297
4361
  merchant: opts.merchant,
@@ -4311,6 +4375,8 @@ export async function attachToPlaywright(page, opts) {
4311
4375
  merchantSignal: attempt.signal,
4312
4376
  // Same as the CDP path: the merchant's total as this browser recorded it.
4313
4377
  merchantTotal: merchantTotal.capture(pausedAt, pausedPage),
4378
+ // And Paddle's own checkout answers, as this browser recorded them.
4379
+ paddleCheckout: paddleAnswers,
4314
4380
  onAuthorizationCreated: (id) => lifecycle.approvalCreated(id),
4315
4381
  onApprovalUrl: (url) => { if (!preparation && !attempt.signal.aborted) {
4316
4382
  lifecycle.approvalUrl(url);
@@ -4381,7 +4447,7 @@ export async function attachToPlaywright(page, opts) {
4381
4447
  // A Shiji STS getTokenId binds the device's cvv to its companion
4382
4448
  // first, exactly as in attachToCdp: only for the request the
4383
4449
  // approval was created from, and its frame.
4384
- const continuation = cseContinuation(opts, deliverRequest.url(), deliverBody, replay, { url: request.url(), body }, preparation);
4450
+ const continuation = cseContinuation(opts, deliverRequest.url(), deliverBody, replay, { url: request.url(), body, headers: request.headers() }, preparation, deliverRequest.headers());
4385
4451
  if (continuation.shijiCvv !== null) {
4386
4452
  // The document the getTokenId paused in. One that cannot be read leaves the CVV nowhere to
4387
4453
  // go, so the card is not tokenized either.
package/dist/client.d.ts CHANGED
@@ -6,6 +6,7 @@ import { type PreparationMode, type PreparationProcessor } from './prepared-proc
6
6
  import { type VerifoneProfile, type VerifoneSubstitutions } from './verifone.js';
7
7
  import { type MerchantSessionCapture } from './merchant-session-probe.js';
8
8
  import { type PaddleTokenexServedFacts } from './paddle-tokenex.js';
9
+ import type { PaddleCheckoutCapture } from './paddle-checkout-watch.js';
9
10
  import { VoiceModule, type VoiceOptions } from './voice.js';
10
11
  import { BuyModule } from './buy.js';
11
12
  import { RequestRegistry } from './requests.js';
@@ -462,6 +463,49 @@ export declare const SUPPORTED_REGISTRY_FEATURES: readonly string[];
462
463
  * Served on the same terms, and the API holds the lane to Agentcard's own company
463
464
  * until a reviewed change binds the client key to the merchant.
464
465
  *
466
+ * `tap_card_sdk_token`: the token request Tap Payments' card frame sends to sdk.tap.company, carrying
467
+ * the card only as one ciphertext the frame writes under the merchant's own RSA key. This build pauses
468
+ * it and writes over the placeholder's ciphertext the one the cardholder's device wrote under the key
469
+ * payment-core pins for the request's publishable key (tap-payments.ts), into that request alone; 3-D
470
+ * Secure and the merchant's charge then run in the agent's browser. Served on the same terms: only to
471
+ * a build that lists it, for a company Agentcard turned Tap on for.
472
+ *
473
+ * `fastspring_card_payment`: the card payment FastSpring's checkout posts, on every store's own
474
+ * host, to <store>.onfastspring.com[/popup-<name>]/session/<id>/payment under the session's
475
+ * X-Session-Token. This build pauses only the checkout's own card body at that exact URL (a card
476
+ * FastSpring saved, a renewal, a gift, a tax id's second card send and a CAPTCHA answer are refused
477
+ * at the pause, and another method's payment with no card continues); the cardholder's device writes
478
+ * the real card into the paused body and sends it through the checkout relay, and the checkout gets
479
+ * FastSpring's answer as payment-core's judge rebuilt it. The request names no amount, so the agent's
480
+ * pair, above zero, is the total the checkout shows. Served on the same terms:
481
+ * only to a build that lists it, for a company Agentcard turned FastSpring on for.
482
+ *
483
+ * `openpay_tokenizer`: the token create openpay.js sends from a merchant's own page to
484
+ * api.openpay.mx/v1/<merchant id>/tokens (api.openpay.co, api.openpay.pe; sandbox-api for a test
485
+ * row), only through a prepared checkout: openpay.js abandons the request 40 seconds after Pay, so
486
+ * the cardholder approves before Pay. The token URL names the merchant, so the claim binds the
487
+ * request by its host's environment and its shape, never by the prepared URL. The cardholder's
488
+ * device sends the card to Openpay itself and the page gets back Openpay's token alone, rebuilt by
489
+ * payment-core's judge. The request names no amount, so the agent's pair, above zero
490
+ * (agent-amount-processors.json), is the one the cardholder approves. Served on the same terms: only
491
+ * to a build that lists it, for a company Agentcard turned Openpay on for.
492
+ *
493
+ * `aps_custom_merchant_page`: Amazon Payment Services' custom merchant page, whose own card form
494
+ * posts top-level to /FortAPI/paymentPage on checkout.payfort.com (sbcheckout.payfort.com on APS's
495
+ * sandbox) with service_command=TOKENIZATION. This build pauses that navigation; the cardholder's
496
+ * phone sends the form with the real card through the checkout relay, and the paused navigation
497
+ * gets APS's own answer, its page or its redirect to the form's return page, only as payment-core's
498
+ * judge reads it for that form (amazon-payment-services.ts apsNavigationAnswer). The form names no
499
+ * amount, so the agent's pair, above zero, is the one the cardholder approves.
500
+ * Served on the same terms: only to a build that lists it, for a company Agentcard turned APS on for.
501
+ *
502
+ * `barion_hosted_payment_page`: Barion's Smart Gateway, whose card-free link
503
+ * (secure.barion.com/Pay?Id=<payment id>, a plain GET the merchant's redirect or script sends
504
+ * the buyer to) this build pauses for the cardholder's device by its exact link (hosted-entry.ts),
505
+ * and whose email check, card posts and 3-D Secure post this build never lets the agent's browser
506
+ * send (pre-claim.ts, barion.ts). Served on the same terms as Przelewy24's: only to a build that
507
+ * lists it, for a company Agentcard turned Barion on for.
508
+ *
465
509
  * The list itself is capabilities.json, sorted, one per line (scripts/generate-capabilities.mjs).
466
510
  */
467
511
  export declare const SUPPORTED_CAPABILITIES: readonly string[];
@@ -964,6 +1008,13 @@ export interface AuthorizeInput extends ExecutionMetadata {
964
1008
  * one from its network events, or the payment is refused before any create.
965
1009
  */
966
1010
  merchantTotal?: MerchantTotalCapture;
1011
+ /**
1012
+ * For a Paddle TokenEx /pay: when it paused and the answers Paddle's checkout service gave the frame before it,
1013
+ * as this browser recorded them (see paddle-checkout-watch.ts). The adapters pass it, and it rides the create only
1014
+ * for that processor. The API holds `amount` to the total they state for today, and admits a free trial's $0.00
1015
+ * only on them; without them a $0.00 Paddle create is refused as before.
1016
+ */
1017
+ paddleCheckout?: PaddleCheckoutCapture;
967
1018
  }
968
1019
  export declare class CardEncryptedError extends Error {
969
1020
  psp: string;
@@ -1625,9 +1676,10 @@ export declare class VaultClient {
1625
1676
  * capability (syncRegistry does), so before a sync, or against an API that
1626
1677
  * withheld it, the adapters leave that processor's traffic exactly as they
1627
1678
  * found it. prepare() asks this for ACI, whose card-number request names a
1628
- * checkout id the merchant mints only at Pay time, and for a processor whose
1629
- * card request is a GET (Worldpay eProtect), since that request is recognized
1630
- * by a query the page has not written yet.
1679
+ * checkout id the merchant mints only at Pay time, for Openpay, whose token
1680
+ * URL names the merchant's own id, and for a processor whose card request is
1681
+ * a GET (Worldpay eProtect), since that request is recognized by a query the
1682
+ * page has not written yet.
1631
1683
  */
1632
1684
  recognizesProcessor(psp: string): boolean;
1633
1685
  /**