@agent-cards/sdk 0.24.0 → 0.24.2

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 (44) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +61 -4
  3. package/dist/adyen-merchant-hosted.generated.d.ts +1 -1
  4. package/dist/adyen-merchant-hosted.generated.js +128 -35
  5. package/dist/agent-amount.generated.js +1 -1
  6. package/dist/aurus.d.ts +33 -0
  7. package/dist/aurus.js +75 -0
  8. package/dist/builtin-registry.generated.js +1 -1
  9. package/dist/capabilities.generated.js +1 -1
  10. package/dist/card-fields.generated.js +1854 -440
  11. package/dist/cardlink-vpos.d.ts +43 -0
  12. package/dist/cardlink-vpos.js +90 -0
  13. package/dist/cdp.js +22 -0
  14. package/dist/checkout-com.generated.js +5 -1
  15. package/dist/client.d.ts +75 -0
  16. package/dist/client.js +75 -0
  17. package/dist/cybersource-flex.generated.d.ts +39 -1
  18. package/dist/cybersource-flex.generated.js +100 -11
  19. package/dist/eghl.d.ts +40 -0
  20. package/dist/eghl.js +72 -0
  21. package/dist/gmo.generated.js +7 -2
  22. package/dist/hosted-entry.js +2 -0
  23. package/dist/lifecycle.d.ts +10 -0
  24. package/dist/lifecycle.js +25 -0
  25. package/dist/paddle-tokenex.generated.js +7 -2
  26. package/dist/payrails.generated.js +7 -2
  27. package/dist/pre-claim.d.ts +5 -0
  28. package/dist/pre-claim.js +90 -2
  29. package/dist/preflight-catalog.json +179 -1
  30. package/dist/preflight-schemas.json +16 -0
  31. package/dist/preflight.generated.d.ts +5 -0
  32. package/dist/preflight.generated.js +49 -3
  33. package/dist/preparation.d.ts +7 -0
  34. package/dist/preparation.js +21 -0
  35. package/dist/primer.generated.js +1856 -442
  36. package/dist/shiji-sts.generated.js +7 -2
  37. package/dist/stripe-checkout.generated.js +1837 -475
  38. package/dist/substitutions.generated.js +94 -1
  39. package/dist/tap-payments.generated.js +7 -2
  40. package/dist/token-repeats.d.ts +32 -0
  41. package/dist/token-repeats.js +64 -0
  42. package/dist/twoc2p.generated.js +7 -2
  43. package/examples/preflight/kernel-native/inventory.json +1 -1
  44. package/package.json +2 -2
package/dist/pre-claim.js CHANGED
@@ -88,10 +88,13 @@ import { isRedsysEntry, isRedsysHost, redsysEntryUrl } from './redsys.js';
88
88
  import { isArmedPrzelewy24Url, isPrzelewy24PayStep } from './przelewy24.js';
89
89
  import { isArmedBarionUrl, isBarionPayStep } from './barion.js';
90
90
  import { isArmedPayplugUrl, isPayplugPayStep } from './payplug.js';
91
+ import { isArmedCardlinkVposUrl, isCardlinkVposEntry } from './cardlink-vpos.js';
92
+ import { isArmedEghlUrl, isEghlPayStep } from './eghl.js';
91
93
  import { isQuickpayCardLookup, isQuickpayEntry, quickpayEntryUrl } from './quickpay.js';
92
94
  import { isArmedComgateUrl } from './comgate.js';
93
95
  import { isArmedEximbayUrl, isEximbayEntry } from './eximbay.js';
94
96
  import { isArmedOceanpaymentUrl, isOceanpaymentSendPay } from './oceanpayment.js';
97
+ import { aurusPreClaim } from './aurus.js';
95
98
  import { PAYPAL_HOSTED_FIELDS_REASON, isPaypalHostedFieldsConfirm, paypalHostedFieldsBody } from './paypal-hosted-fields.js';
96
99
  import { PAYPAL_CARD_FIELDS_REASON, PAYPAL_GUEST_CHECKOUT_REASON, isPaypalCardFieldsConfirm, isPaypalGraphql, paypalCardFieldsBody, paypalGraphqlCard, paypalGraphqlNamesCardOperation, } from './paypal-card-forms.js';
97
100
  import { CYBERSOURCE_SECURE_ACCEPTANCE_REASON, CYBERSOURCE_SECURE_ACCEPTANCE_RECIPIENT, cybersourceSecureAcceptanceRequest, isCybersourceSecureAcceptanceUrl, isSecureAcceptanceFramePost, } from './cybersource-secure-acceptance.js';
@@ -999,6 +1002,50 @@ const tokenexIframePreClaim = (ctx) => {
999
1002
  return ctx.lifecycle.getState().status === 'awaiting_merchant'
1000
1003
  ? repeatAfterHandoff(ctx, repeat, TOKENEX_IFRAME_PSP) : answerRepeat(ctx, repeat, TOKENEX_IFRAME_PSP);
1001
1004
  };
1005
+ // Any processor's plain token request, sent again by the page byte for byte after its approved answer reached it
1006
+ // (token-repeats.ts). Last among the gates, so a processor with its own repeat rule (Datatrans, the TokenEx iframe) or
1007
+ // its own hold (Stripe, a card endpoint) decides first. While the lifecycle reads the re-send as answerable
1008
+ // (repeatAnswerable: the same approval awaits the merchant, and nothing but a pending read holds it), the gate asks the
1009
+ // merchant resolver and answers with the stored token only while the order still reads pending, as repeatAfterHandoff
1010
+ // does. Every other card request, another amount or approval among them, defers to the terminal arbiter and the
1011
+ // adapters' hold, as before.
1012
+ const tokenRepeatPreClaim = (ctx) => {
1013
+ const { url, method } = ctx.request;
1014
+ if (!ctx.tokenRepeats || method.toUpperCase() !== 'POST' || !ctx.lifecycle.repeatAnswerable?.() || !ctx.lifecycle.hasMerchantResolver?.())
1015
+ return undefined;
1016
+ // A processor with its own repeat rule keeps its own limits: a re-send its rule declined is a new question.
1017
+ if (isDatatransHost(url) || isTokenexIframePath(url))
1018
+ return undefined;
1019
+ if (ctx.terminal() || ctx.interceptionAborted() || ctx.lifecycleAborted())
1020
+ return undefined;
1021
+ // Read only here, past every cheaper check: a body the adapter cannot read is no re-send of an answered one.
1022
+ let body;
1023
+ try {
1024
+ body = ctx.request.body;
1025
+ }
1026
+ catch {
1027
+ return undefined;
1028
+ }
1029
+ const repeats = ctx.tokenRepeats;
1030
+ const repeat = repeats.answerFor(ctx.frame, url, body, ctx.lifecycle.getState().authorizationId);
1031
+ if (!repeat)
1032
+ return undefined;
1033
+ // A re-send the page never got an answer for gives its place in the count back.
1034
+ return tokenRepeatWhilePending(ctx, repeat).then((decision) => {
1035
+ if (decision?.kind !== 'answer')
1036
+ repeats.released(repeat.authorizationId);
1037
+ return decision;
1038
+ }, (error) => { repeats.released(repeat.authorizationId); throw error; });
1039
+ };
1040
+ async function tokenRepeatWhilePending(ctx, repeat) {
1041
+ if (!await ctx.lifecycle.merchantOrderPending())
1042
+ return undefined;
1043
+ // The resolver answered asynchronously: the same approval must still be the one awaiting the merchant.
1044
+ if (!ctx.lifecycle.repeatAnswerable() || ctx.lifecycle.getState().authorizationId !== repeat.authorizationId
1045
+ || ctx.terminal() || ctx.interceptionAborted() || ctx.lifecycleAborted())
1046
+ return undefined;
1047
+ return answerRepeat(ctx, repeat, 'token');
1048
+ }
1002
1049
  async function tokenexIframeBlock(ctx, reason) {
1003
1050
  ctx.onEvent?.({ type: 'blocked', detail: reason });
1004
1051
  await ctx.effects.abort();
@@ -1743,6 +1790,47 @@ export const payplugPreClaim = (ctx) => {
1743
1790
  return undefined;
1744
1791
  return processorPageAbort(ctx);
1745
1792
  };
1793
+ // eGHL's payment page (eghl.ts). Once this build's registry serves eGHL's entry (a capability the API serves only to
1794
+ // Agentcard's own company), every request to eGHL's hosts pauses. The merchant's entry, a GET of /IPG/payment.aspx whose
1795
+ // query names the payment, is no step of this gate's: it defers, and the terminal arbiter pauses it for the claim flow
1796
+ // like any card request, so the cardholder's device pays it. Every step toward paying on the page itself aborts as an
1797
+ // unsupported checkout: every POST to eGHL's hosts, the card page's card post to the entry's own address among them. So
1798
+ // eGHL never sees the card the agent typed. The page's own GETs continue. With eGHL not served, the gate defers, and
1799
+ // every request continues as before. Synchronous until it must abort, like every gate. Exported for the gate registry's
1800
+ // tests.
1801
+ export const eghlPreClaim = (ctx) => {
1802
+ const { url, method } = ctx.request;
1803
+ if (!isEghlPayStep(url, method) || !isArmedEghlUrl(ctx.vault, url))
1804
+ return undefined;
1805
+ return processorPageAbort(ctx);
1806
+ };
1807
+ // Cardlink's VPOS (cardlink-vpos.ts). Once this build's registry serves the entry (a capability the API serves only to
1808
+ // Agentcard's own company), every request to the VPOS's hosts pauses, and this gate judges the POSTs:
1809
+ // - the merchant's entry, an entry body posted to /vpos/shophandlermpi on one of the three live hosts, defers, and the
1810
+ // terminal arbiter pauses it for the claim flow like any card request: the cardholder's device pays it;
1811
+ // - every other POST (the card page's post and its card check, which share the entry's URL and carry the page's own
1812
+ // fields, a body the adapter could not read, and anything on Cardlink's test hosts) aborts as an unsupported
1813
+ // checkout, so the VPOS never sees the card the agent typed.
1814
+ // A GET (the card page's script, its status poll) is not this gate's and continues. With the lane not served, the gate
1815
+ // defers, and every request continues as before. Synchronous until it must abort, like every gate. Exported for the gate
1816
+ // registry's tests.
1817
+ export const cardlinkVposPreClaim = (ctx) => {
1818
+ const { url, method } = ctx.request;
1819
+ if (String(method).toUpperCase() !== 'POST' || !isArmedCardlinkVposUrl(ctx.vault, url))
1820
+ return undefined;
1821
+ // The body is a getter an adapter can fail in (Playwright's postData() throws on a body it cannot decode): a body that
1822
+ // cannot be read is no entry this gate can tell from a card post, so it fails closed, aborted and reported like one.
1823
+ let body;
1824
+ try {
1825
+ body = ctx.request.body;
1826
+ }
1827
+ catch {
1828
+ return processorPageAbort(ctx);
1829
+ }
1830
+ if (isCardlinkVposEntry(url, method, body))
1831
+ return undefined;
1832
+ return processorPageAbort(ctx);
1833
+ };
1746
1834
  // NMI's hosted payment page (ekashu.ts). Once this build's registry serves NMI's entry (a
1747
1835
  // capability the API serves only to a company Agentcard turned NMI on for), every request to
1748
1836
  // NMI's two hosts pauses, and this gate judges the POSTs:
@@ -2577,9 +2665,9 @@ async function unsupportedContinue(ctx) {
2577
2665
  * arbiter runs after all of them and is not part of this list. A gate appended
2578
2666
  * after Stripe is never offered a step Stripe claimed: Stripe answers, aborts or
2579
2667
  * pauses each one itself. */
2580
- export const PSP_PRE_CLAIM_GATES = [cardEndpointResendPreClaim, cardEndpointPreClaim, nikeOrderPreClaim, mercadoPreClaim, juspayPreClaim, braintreePreClaim, stripePreClaim, merchantHostedPreClaim, verifonePreClaim, fiservPreClaim, gmoPreClaim, cybersourceFlexPreClaim, datatransPreClaim, tokenexIframePreClaim, pelecardPreClaim, aciPreClaim, creditguardPreClaim, primerPreClaim, payrailsPreClaim, convergePreClaim, eprotectPreClaim, sbpsPreClaim, wspayPreClaim, shijiStsPreClaim, ekashuPreClaim, redsysPreClaim, quickpayPreClaim, comgatePreClaim, przelewy24PreClaim, transbankPreClaim, eximbayPreClaim, barionPreClaim, payplugPreClaim, paypalHostedFieldsPreClaim,
2668
+ export const PSP_PRE_CLAIM_GATES = [cardEndpointResendPreClaim, cardEndpointPreClaim, nikeOrderPreClaim, mercadoPreClaim, juspayPreClaim, braintreePreClaim, stripePreClaim, merchantHostedPreClaim, verifonePreClaim, fiservPreClaim, gmoPreClaim, cybersourceFlexPreClaim, datatransPreClaim, tokenexIframePreClaim, pelecardPreClaim, aciPreClaim, creditguardPreClaim, primerPreClaim, payrailsPreClaim, convergePreClaim, eprotectPreClaim, sbpsPreClaim, wspayPreClaim, shijiStsPreClaim, ekashuPreClaim, redsysPreClaim, quickpayPreClaim, comgatePreClaim, przelewy24PreClaim, transbankPreClaim, eximbayPreClaim, barionPreClaim, payplugPreClaim, cardlinkVposPreClaim, eghlPreClaim, paypalHostedFieldsPreClaim,
2581
2669
  paypalCardFormsPreClaim, cybersourceSecureAcceptancePreClaim, worldlineMyCheckoutPreClaim, paddleVgsPayPreClaim, ebanxPreClaim, payrexxPreClaim, hipayPreClaim, paytrailPreClaim,
2582
- oceanpaymentPreClaim];
2670
+ oceanpaymentPreClaim, aurusPreClaim, tokenRepeatPreClaim];
2583
2671
  /** Run each gate in order; the first to return a decision wins. If none does,
2584
2672
  * the terminal arbiter decides between continue, abort (unsupported) and pause.
2585
2673
  * Returns synchronously while every gate defers synchronously (an ordinary card
@@ -211,7 +211,26 @@
211
211
  "origin": "https://js.braintreegateway.com",
212
212
  "path_pattern": "/web/:version/js/*",
213
213
  "hostname_pattern": "^js\\.braintreegateway\\.com$",
214
- "pathname_pattern": "^\\/web\\/(?![^/]*-payments-sdk)[^/]+\\/js\\/",
214
+ "pathname_pattern": "^\\/web\\/(?![^/]*-payments-sdk)[^/]+\\/js\\/(?!(?:client|paypal|paypal-checkout|venmo|apple-pay|google-payment|data-collector|local-payment)(?:\\.min)?\\.js$)",
215
+ "sources": [
216
+ {
217
+ "kind": "official_documentation",
218
+ "reference": "https://developer.paypal.com/braintree/docs/start/hello-client/javascript/v3/",
219
+ "reviewed_on": "2026-09-11"
220
+ }
221
+ ]
222
+ },
223
+ {
224
+ "id": "braintree-web-wallet",
225
+ "psp": "braintree",
226
+ "kinds": [
227
+ "script"
228
+ ],
229
+ "origin": "https://js.braintreegateway.com",
230
+ "path_pattern": "/web/:version/js/{client,paypal,paypal-checkout,venmo,apple-pay,google-payment,data-collector,local-payment}[.min].js",
231
+ "card_free": "braintree-web's client, wallet and fraud components collect no card; Hosted Fields and Drop-in do.",
232
+ "hostname_pattern": "^js\\.braintreegateway\\.com$",
233
+ "pathname_pattern": "^\\/web\\/(?![^/]*-payments-sdk)[^/]+\\/js\\/(?:client|paypal|paypal-checkout|venmo|apple-pay|google-payment|data-collector|local-payment)(?:\\.min)?\\.js$",
215
234
  "sources": [
216
235
  {
217
236
  "kind": "official_documentation",
@@ -2566,6 +2585,92 @@
2566
2585
  "hostname_pattern": "^flex\\.cybersource\\.com$",
2567
2586
  "pathname_pattern": "^\\/microform\\/bundle\\/v2\\.[0-9]+\\.[0-9]+\\/iframe\\.html$"
2568
2587
  },
2588
+ {
2589
+ "id": "cybersource-unified-checkout-script",
2590
+ "psp": "cybersource_flex",
2591
+ "kinds": [
2592
+ "script"
2593
+ ],
2594
+ "origin": "https://up.cybersource.com",
2595
+ "path_pattern": "/uc/v1/assets/:asset/UnifiedCheckout.js",
2596
+ "sources": [
2597
+ {
2598
+ "kind": "saved_observation",
2599
+ "reference": "napaonline-2026-10-31:unified-checkout-v1.8.2-mce-orc-ga-frames",
2600
+ "reviewed_on": "2026-10-31"
2601
+ },
2602
+ {
2603
+ "kind": "official_documentation",
2604
+ "reference": "https://developer.cybersource.com/docs/cybs/en-us/unified-checkout/developer/all/rest/unified-checkout/uc-intro.html",
2605
+ "reviewed_on": "2026-10-31"
2606
+ }
2607
+ ],
2608
+ "hostname_pattern": "^up\\.cybersource\\.com$",
2609
+ "pathname_pattern": "^\\/uc\\/v1\\/assets\\/[A-Za-z0-9_-]{16,1024}\\/UnifiedCheckout\\.js$"
2610
+ },
2611
+ {
2612
+ "id": "cybersource-unified-checkout-frame",
2613
+ "psp": "cybersource_flex",
2614
+ "kinds": [
2615
+ "frame",
2616
+ "iframe",
2617
+ "document"
2618
+ ],
2619
+ "origin": "https://up.cybersource.com",
2620
+ "path_pattern": "/uc/v1/assets/:asset/{mce,orc,ga}/*.html",
2621
+ "sources": [
2622
+ {
2623
+ "kind": "saved_observation",
2624
+ "reference": "napaonline-2026-10-31:unified-checkout-v1.8.2-mce-orc-ga-frames",
2625
+ "reviewed_on": "2026-10-31"
2626
+ },
2627
+ {
2628
+ "kind": "official_documentation",
2629
+ "reference": "https://developer.cybersource.com/docs/cybs/en-us/unified-checkout/developer/all/rest/unified-checkout/uc-intro.html",
2630
+ "reviewed_on": "2026-10-31"
2631
+ }
2632
+ ],
2633
+ "hostname_pattern": "^up\\.cybersource\\.com$",
2634
+ "pathname_pattern": "^\\/uc\\/v1\\/assets\\/[A-Za-z0-9_-]{16,1024}\\/(?:mce\\/mce|orc\\/orc|ga\\/ga)\\.html$"
2635
+ },
2636
+ {
2637
+ "id": "aurus-ecom-iframe",
2638
+ "psp": "aurus",
2639
+ "kinds": [
2640
+ "frame",
2641
+ "iframe",
2642
+ "document"
2643
+ ],
2644
+ "origin": "https://pecst01.aurusepay.com",
2645
+ "path_pattern": "/storeservices/ecom/getiframe",
2646
+ "sources": [
2647
+ {
2648
+ "kind": "saved_observation",
2649
+ "reference": "oreillyauto-2026-10-31:aurus-ecom-getiframe-oneTimeToken",
2650
+ "reviewed_on": "2026-10-31"
2651
+ }
2652
+ ],
2653
+ "hostname_pattern": "^pecst[0-9]{2}\\.aurusepay\\.com$",
2654
+ "pathname_pattern": "^\\/storeservices\\/ecom\\/getiframe$"
2655
+ },
2656
+ {
2657
+ "id": "aurus-ecom-init-script",
2658
+ "psp": "aurus",
2659
+ "kinds": [
2660
+ "script"
2661
+ ],
2662
+ "origin": "https://pecst01.aurusepay.com",
2663
+ "path_pattern": "/storeservices/ecom/ecominitjs",
2664
+ "sources": [
2665
+ {
2666
+ "kind": "saved_observation",
2667
+ "reference": "oreillyauto-2026-10-31:aurus-ecom-getiframe-oneTimeToken",
2668
+ "reviewed_on": "2026-10-31"
2669
+ }
2670
+ ],
2671
+ "hostname_pattern": "^pecst[0-9]{2}\\.aurusepay\\.com$",
2672
+ "pathname_pattern": "^\\/storeservices\\/ecom\\/ecominitjs$"
2673
+ },
2569
2674
  {
2570
2675
  "id": "juspay-hypercheckout-payment-page",
2571
2676
  "psp": "juspay",
@@ -3417,6 +3522,31 @@
3417
3522
  "hostname_pattern": "^payment\\.pay1\\.checkout\\.worldline-solutions\\.com$",
3418
3523
  "pathname_pattern": "^\\/checkout$"
3419
3524
  },
3525
+ {
3526
+ "id": "bigcommerce-hosted-card-field",
3527
+ "psp": "bigcommerce",
3528
+ "kinds": [
3529
+ "document",
3530
+ "frame",
3531
+ "iframe"
3532
+ ],
3533
+ "origin": "https://payments.bigcommerce.com",
3534
+ "path_pattern": "/pay/hosted_forms/:form/field",
3535
+ "sources": [
3536
+ {
3537
+ "kind": "saved_observation",
3538
+ "reference": "drsturm-2026-11-06:bigcommerce-hosted-form-field-1.997.1",
3539
+ "reviewed_on": "2026-11-06"
3540
+ },
3541
+ {
3542
+ "kind": "primary_source",
3543
+ "reference": "https://checkout-sdk.bigcommerce.com/v1/loader-v1.997.1.js",
3544
+ "reviewed_on": "2026-11-06"
3545
+ }
3546
+ ],
3547
+ "hostname_pattern": "^payments\\.bigcommerce\\.com$",
3548
+ "pathname_pattern": "^\\/pay\\/hosted_forms\\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\\/field$"
3549
+ },
3420
3550
  {
3421
3551
  "id": "gmo-mp-token-script-test",
3422
3552
  "psp": "gmo_pg",
@@ -3565,6 +3695,54 @@
3565
3695
  "hostname_pattern": "^testflex\\.cybersource\\.com$",
3566
3696
  "pathname_pattern": "^\\/microform\\/bundle\\/v2\\.[0-9]+\\.[0-9]+\\/iframe\\.html$"
3567
3697
  },
3698
+ {
3699
+ "id": "cybersource-unified-checkout-script-test",
3700
+ "psp": "cybersource_flex",
3701
+ "kinds": [
3702
+ "script"
3703
+ ],
3704
+ "origin": "https://testup.cybersource.com",
3705
+ "path_pattern": "/uc/v1/assets/:asset/UnifiedCheckout.js",
3706
+ "sources": [
3707
+ {
3708
+ "kind": "saved_observation",
3709
+ "reference": "napaonline-2026-10-31:unified-checkout-v1.8.2-mce-orc-ga-frames",
3710
+ "reviewed_on": "2026-10-31"
3711
+ },
3712
+ {
3713
+ "kind": "official_documentation",
3714
+ "reference": "https://developer.cybersource.com/docs/cybs/en-us/unified-checkout/developer/all/rest/unified-checkout/uc-intro.html",
3715
+ "reviewed_on": "2026-10-31"
3716
+ }
3717
+ ],
3718
+ "hostname_pattern": "^testup\\.cybersource\\.com$",
3719
+ "pathname_pattern": "^\\/uc\\/v1\\/assets\\/[A-Za-z0-9_-]{16,1024}\\/UnifiedCheckout\\.js$"
3720
+ },
3721
+ {
3722
+ "id": "cybersource-unified-checkout-frame-test",
3723
+ "psp": "cybersource_flex",
3724
+ "kinds": [
3725
+ "frame",
3726
+ "iframe",
3727
+ "document"
3728
+ ],
3729
+ "origin": "https://testup.cybersource.com",
3730
+ "path_pattern": "/uc/v1/assets/:asset/{mce,orc,ga}/*.html",
3731
+ "sources": [
3732
+ {
3733
+ "kind": "saved_observation",
3734
+ "reference": "napaonline-2026-10-31:unified-checkout-v1.8.2-mce-orc-ga-frames",
3735
+ "reviewed_on": "2026-10-31"
3736
+ },
3737
+ {
3738
+ "kind": "official_documentation",
3739
+ "reference": "https://developer.cybersource.com/docs/cybs/en-us/unified-checkout/developer/all/rest/unified-checkout/uc-intro.html",
3740
+ "reviewed_on": "2026-10-31"
3741
+ }
3742
+ ],
3743
+ "hostname_pattern": "^testup\\.cybersource\\.com$",
3744
+ "pathname_pattern": "^\\/uc\\/v1\\/assets\\/[A-Za-z0-9_-]{16,1024}\\/(?:mce\\/mce|orc\\/orc|ga\\/ga)\\.html$"
3745
+ },
3568
3746
  {
3569
3747
  "id": "cybersource-secure-acceptance-silent-order-post-test",
3570
3748
  "psp": "cybersource_secure_acceptance",
@@ -385,6 +385,7 @@
385
385
  "mollie-components-v1-script",
386
386
  "mollie-hosted-credit-card",
387
387
  "braintree-web-sdk",
388
+ "braintree-web-wallet",
388
389
  "braintree-hosted-fields",
389
390
  "paysafe-js",
390
391
  "worldpay-checkout-sdk",
@@ -483,6 +484,10 @@
483
484
  "gmo-link-hosted-page",
484
485
  "cybersource-flex-microform-script",
485
486
  "cybersource-flex-microform-field",
487
+ "cybersource-unified-checkout-script",
488
+ "cybersource-unified-checkout-frame",
489
+ "aurus-ecom-iframe",
490
+ "aurus-ecom-init-script",
486
491
  "juspay-hypercheckout-payment-page",
487
492
  "pelecard-payment-page",
488
493
  "pelecard-payment-script",
@@ -520,12 +525,15 @@
520
525
  "amadeus-data-collection-page",
521
526
  "worldline-mycheckout-page",
522
527
  "worldline-mycheckout-card-form",
528
+ "bigcommerce-hosted-card-field",
523
529
  "gmo-mp-token-script-test",
524
530
  "gmo-token-v1-script-test",
525
531
  "gmo-elements-card-frame-test",
526
532
  "gmo-link-hosted-page-test",
527
533
  "cybersource-flex-microform-script-test",
528
534
  "cybersource-flex-microform-field-test",
535
+ "cybersource-unified-checkout-script-test",
536
+ "cybersource-unified-checkout-frame-test",
529
537
  "cybersource-secure-acceptance-silent-order-post-test",
530
538
  "cybersource-secure-acceptance-silent-order-post-in",
531
539
  "worldpay-eprotect-js-api-prelive",
@@ -1023,6 +1031,7 @@
1023
1031
  "mollie-components-v1-script",
1024
1032
  "mollie-hosted-credit-card",
1025
1033
  "braintree-web-sdk",
1034
+ "braintree-web-wallet",
1026
1035
  "braintree-hosted-fields",
1027
1036
  "paysafe-js",
1028
1037
  "worldpay-checkout-sdk",
@@ -1121,6 +1130,10 @@
1121
1130
  "gmo-link-hosted-page",
1122
1131
  "cybersource-flex-microform-script",
1123
1132
  "cybersource-flex-microform-field",
1133
+ "cybersource-unified-checkout-script",
1134
+ "cybersource-unified-checkout-frame",
1135
+ "aurus-ecom-iframe",
1136
+ "aurus-ecom-init-script",
1124
1137
  "juspay-hypercheckout-payment-page",
1125
1138
  "pelecard-payment-page",
1126
1139
  "pelecard-payment-script",
@@ -1158,12 +1171,15 @@
1158
1171
  "amadeus-data-collection-page",
1159
1172
  "worldline-mycheckout-page",
1160
1173
  "worldline-mycheckout-card-form",
1174
+ "bigcommerce-hosted-card-field",
1161
1175
  "gmo-mp-token-script-test",
1162
1176
  "gmo-token-v1-script-test",
1163
1177
  "gmo-elements-card-frame-test",
1164
1178
  "gmo-link-hosted-page-test",
1165
1179
  "cybersource-flex-microform-script-test",
1166
1180
  "cybersource-flex-microform-field-test",
1181
+ "cybersource-unified-checkout-script-test",
1182
+ "cybersource-unified-checkout-frame-test",
1167
1183
  "cybersource-secure-acceptance-silent-order-post-test",
1168
1184
  "cybersource-secure-acceptance-silent-order-post-in",
1169
1185
  "worldpay-eprotect-js-api-prelive",
@@ -148,6 +148,11 @@ export declare function getCheckoutPreflightCatalog(): {
148
148
  path_pattern: string;
149
149
  flow?: string;
150
150
  variant_unverified?: string;
151
+ /**
152
+ * Why the asset never takes a card: a wallet button, a fraud collector, or the client those load. When no card frame
153
+ * is active and scripts alone name several processors, one whose every asset says this is not the card form's.
154
+ */
155
+ card_free?: string;
151
156
  }[];
152
157
  processors: readonly [{
153
158
  readonly psp: "spreedly";
@@ -1,5 +1,5 @@
1
1
  // Generated from @agent-cards/payment-core. Do not edit.
2
- // source-sha256: 761b59c7c043a43a8d462a840e204c1677c55c0022f37e6be4a007d025357af8
2
+ // source-sha256: 84246b0b75dadb1798e0c9bd4ab7a8ab8567df86ea490fb20c9f0f890309e7df
3
3
  import { CHECKOUT_PREFLIGHT_CAPABILITIES } from './preflight-capabilities.generated.js';
4
4
  /** Advisory page discovery. These rules never admit a payment destination. */
5
5
  export const CHECKOUT_PREFLIGHT_VERSION = '1';
@@ -23,7 +23,13 @@ const RULES = [
23
23
  // A braintree-web build whose version carries -payments-sdk (3.32.0-payments-sdk-dev) is PayPal's
24
24
  // (paypal-hosted-fields-payments-sdk below): its card goes to PayPal, never to Braintree, so neither
25
25
  // Braintree rule takes one.
26
- { id: 'braintree-web-sdk', psp: 'braintree', kinds: ['script'], hostname: /^js\.braintreegateway\.com$/, pathname: /^\/web\/(?![^/]*-payments-sdk)[^/]+\/js\//, origin: 'https://js.braintreegateway.com', path_pattern: '/web/:version/js/*' },
26
+ { id: 'braintree-web-sdk', psp: 'braintree', kinds: ['script'], hostname: /^js\.braintreegateway\.com$/, pathname: /^\/web\/(?![^/]*-payments-sdk)[^/]+\/js\/(?!(?:client|paypal|paypal-checkout|venmo|apple-pay|google-payment|data-collector|local-payment)(?:\.min)?\.js$)/, origin: 'https://js.braintreegateway.com', path_pattern: '/web/:version/js/*' },
27
+ // braintree-web's client and its wallet and fraud components take no card: a page that loads only these runs a
28
+ // PayPal, Venmo, Apple Pay or Google Pay button through Braintree, and its card boxes belong to another processor.
29
+ // AutoZone's checkout loads client, paypal-checkout and data-collector 3.125.0 beside Worldpay eProtect's JS API, whose
30
+ // script reads the card from the page's own fields (2026-10-31).
31
+ { id: 'braintree-web-wallet', psp: 'braintree', kinds: ['script'], hostname: /^js\.braintreegateway\.com$/, pathname: /^\/web\/(?![^/]*-payments-sdk)[^/]+\/js\/(?:client|paypal|paypal-checkout|venmo|apple-pay|google-payment|data-collector|local-payment)(?:\.min)?\.js$/, origin: 'https://js.braintreegateway.com', path_pattern: '/web/:version/js/{client,paypal,paypal-checkout,venmo,apple-pay,google-payment,data-collector,local-payment}[.min].js',
32
+ card_free: 'braintree-web\'s client, wallet and fraud components collect no card; Hosted Fields and Drop-in do.' },
27
33
  { id: 'braintree-hosted-fields', psp: 'braintree', kinds: ['frame', 'iframe'], hostname: /^assets\.braintreegateway\.com$/, pathname: /^\/web\/(?![^/]*-payments-sdk)/, origin: 'https://assets.braintreegateway.com', path_pattern: '/web/*' },
28
34
  { id: 'paysafe-js', psp: 'paysafe', kinds: ['script', 'frame', 'iframe'], hostname: /^hosted\.paysafe\.com$/, pathname: /^\/(?:js|checkout)\//, origin: 'https://hosted.paysafe.com', path_pattern: '/{js,checkout}/*' },
29
35
  { id: 'worldpay-checkout-sdk', psp: 'worldpay', kinds: ['script', 'frame', 'iframe'], hostname: /^access\.worldpay\.com$/, pathname: /^\/access-checkout\//, origin: 'https://access.worldpay.com', path_pattern: '/access-checkout/*' },
@@ -197,6 +203,27 @@ const cybersourceSources = [
197
203
  RULES.push({ id: 'cybersource-flex-microform-script', psp: 'cybersource_flex', kinds: ['script'], hostname: /^flex\.cybersource\.com$/, pathname: /^\/microform\/bundle\/v2(?:\.[0-9]+\.[0-9]+)?\/flex-microform\.min\.js$/, origin: 'https://flex.cybersource.com', path_pattern: '/microform/bundle/v2{,.:minor.:patch}/flex-microform.min.js',
198
204
  sources: cybersourceSources }, { id: 'cybersource-flex-microform-field', psp: 'cybersource_flex', kinds: ['frame', 'iframe', 'document'], hostname: /^flex\.cybersource\.com$/, pathname: /^\/microform\/bundle\/v2\.[0-9]+\.[0-9]+\/iframe\.html$/, origin: 'https://flex.cybersource.com', path_pattern: '/microform/bundle/v:version/iframe.html',
199
205
  sources: cybersourceSources });
206
+ // CyberSource Unified Checkout v1 sends the card to the same Flex v2 tokens URL, sealed by its orchestrator frame
207
+ // under the capture context (cybersource-unified-checkout.js), so its script and frames name cybersource_flex too.
208
+ // Reviewed 2026-10-31 from napaonline.com's checkout (UnifiedCheckout.js v1.8.2), with no card sent.
209
+ const unifiedCheckoutSources = [
210
+ { kind: 'saved_observation', reference: 'napaonline-2026-10-31:unified-checkout-v1.8.2-mce-orc-ga-frames', reviewed_on: '2026-10-31' },
211
+ { kind: 'official_documentation', reference: 'https://developer.cybersource.com/docs/cybs/en-us/unified-checkout/developer/all/rest/unified-checkout/uc-intro.html', reviewed_on: '2026-10-31' },
212
+ ];
213
+ RULES.push({ id: 'cybersource-unified-checkout-script', psp: 'cybersource_flex', kinds: ['script'], hostname: /^up\.cybersource\.com$/, pathname: /^\/uc\/v1\/assets\/[A-Za-z0-9_-]{16,1024}\/UnifiedCheckout\.js$/, origin: 'https://up.cybersource.com', path_pattern: '/uc/v1/assets/:asset/UnifiedCheckout.js',
214
+ sources: unifiedCheckoutSources }, { id: 'cybersource-unified-checkout-frame', psp: 'cybersource_flex', kinds: ['frame', 'iframe', 'document'], hostname: /^up\.cybersource\.com$/, pathname: /^\/uc\/v1\/assets\/[A-Za-z0-9_-]{16,1024}\/(?:mce\/mce|orc\/orc|ga\/ga)\.html$/, origin: 'https://up.cybersource.com', path_pattern: '/uc/v1/assets/:asset/{mce,orc,ga}/*.html',
215
+ sources: unifiedCheckoutSources });
216
+ // Aurus Pay's ecom card frame (processors/aurus.js): the store frames /storeservices/ecom/getiframe on
217
+ // pecst<NN>.aurusepay.com, the card fields sit inside it, and its own ecominitjs sends the sealed card to
218
+ // /storeservices/ecom/oneTimeToken on the same host. Reviewed 2026-10-31 at oreillyauto.com's payment step, with every
219
+ // aurusepay.com request but a GET aborted and only a public test card typed. Aurus is served dark, so no catalog
220
+ // processor entry backs the candidate and the result stays unknown unless the caller is served Aurus.
221
+ const aurusSources = [
222
+ { kind: 'saved_observation', reference: 'oreillyauto-2026-10-31:aurus-ecom-getiframe-oneTimeToken', reviewed_on: '2026-10-31' },
223
+ ];
224
+ RULES.push({ id: 'aurus-ecom-iframe', psp: 'aurus', kinds: ['frame', 'iframe', 'document'], hostname: /^pecst[0-9]{2}\.aurusepay\.com$/, pathname: /^\/storeservices\/ecom\/getiframe$/, origin: 'https://pecst01.aurusepay.com', path_pattern: '/storeservices/ecom/getiframe',
225
+ sources: aurusSources }, { id: 'aurus-ecom-init-script', psp: 'aurus', kinds: ['script'], hostname: /^pecst[0-9]{2}\.aurusepay\.com$/, pathname: /^\/storeservices\/ecom\/ecominitjs$/, origin: 'https://pecst01.aurusepay.com', path_pattern: '/storeservices/ecom/ecominitjs',
226
+ sources: aurusSources });
200
227
  // Juspay HyperCheckout: Juspay's own hosted payment page (the Session API's payment_links.web),
201
228
  // which a merchant embeds in an iframe (IndiGo's payment step). The card request that page makes
202
229
  // has not been observed, so the Vault does not take it over, and the rule tells the agent so
@@ -344,6 +371,15 @@ RULES.push({ id: 'worldline-mycheckout-page', psp: 'worldline_mycheckout', kinds
344
371
  pathname: /^\/checkout\/(?:payment-product-details\/)?[1-9][0-9]{0,9}-[0-9a-f]{32}:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}:[0-9a-f]{32}$/,
345
372
  origin: 'https://payment.pay1.checkout.worldline-solutions.com', path_pattern: '/checkout/{payment-product-details/}:hosted_checkout', sources: worldlineSources }, { id: 'worldline-mycheckout-card-form', psp: 'worldline_mycheckout', kinds: ['form'], hostname: /^payment\.pay1\.checkout\.worldline-solutions\.com$/, pathname: /^\/checkout$/,
346
373
  origin: 'https://payment.pay1.checkout.worldline-solutions.com', path_pattern: '/checkout', sources: worldlineSources });
374
+ // BigCommerce's own card form, read 2026-11-06 at drsturm.com: the store's /checkout/payment/hosted-field iframes
375
+ // redirect to one field document per card input on payments.bigcommerce.com, which loads checkout-sdk's hosted-form
376
+ // module and sends the card to BigCommerce's payments API (processors/bigcommerce.js), whichever gateway charges it.
377
+ // BigCommerce ships dark, so the field names bigcommerce and the result stays unknown, as GMO's does.
378
+ RULES.push({ id: 'bigcommerce-hosted-card-field', psp: 'bigcommerce', kinds: ['document', 'frame', 'iframe'], hostname: /^payments\.bigcommerce\.com$/,
379
+ pathname: /^\/pay\/hosted_forms\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\/field$/, origin: 'https://payments.bigcommerce.com',
380
+ path_pattern: '/pay/hosted_forms/:form/field',
381
+ sources: [{ kind: 'saved_observation', reference: 'drsturm-2026-11-06:bigcommerce-hosted-form-field-1.997.1', reviewed_on: '2026-11-06' },
382
+ { kind: 'primary_source', reference: 'https://checkout-sdk.bigcommerce.com/v1/loader-v1.997.1.js', reviewed_on: '2026-11-06' }] });
347
383
  // A processor that ships dark (its definition declares a capability) is left out of the bundled
348
384
  // catalog. Datatrans's and the TokenEx iframe's discovery rules wait with it: they join RULES only once KNOWN_PSPS, the
349
385
  // bundled catalog's processors, lists its psp. Until then its assets are not evidence, so a page
@@ -382,6 +418,8 @@ for (const [baseId, suffix, hostname, origin] of [
382
418
  ['gmo-link-hosted-page', 'test', /^pt01\.mul-pay\.jp$/, 'https://pt01.mul-pay.jp'],
383
419
  ['cybersource-flex-microform-script', 'test', /^testflex\.cybersource\.com$/, 'https://testflex.cybersource.com'],
384
420
  ['cybersource-flex-microform-field', 'test', /^testflex\.cybersource\.com$/, 'https://testflex.cybersource.com'],
421
+ ['cybersource-unified-checkout-script', 'test', /^testup\.cybersource\.com$/, 'https://testup.cybersource.com'],
422
+ ['cybersource-unified-checkout-frame', 'test', /^testup\.cybersource\.com$/, 'https://testup.cybersource.com'],
385
423
  // Secure Acceptance's test host and its production host in India serve the same /silent/ paths.
386
424
  ['cybersource-secure-acceptance-silent-order-post', 'test', /^testsecureacceptance\.cybersource\.com$/, 'https://testsecureacceptance.cybersource.com'],
387
425
  ['cybersource-secure-acceptance-silent-order-post', 'in', /^secureacceptance\.in\.cybersource\.com$/, 'https://secureacceptance.in.cybersource.com'],
@@ -788,19 +826,27 @@ export function assessCheckoutSupport(input, options = {}) {
788
826
  result.candidates = [...candidates.values()].sort((a, b) => a.psp.localeCompare(b.psp));
789
827
  if (missingCorroboration && activeFlows.size === 0)
790
828
  result.reason_codes.push('flow_corroboration_missing');
829
+ // Scripts alone naming several processors: one whose every asset is card-free (a wallet button, a fraud collector)
830
+ // is not the card form's. When exactly one other is left, the page's card form is that one's.
831
+ const cardCapable = activePsps.size === 0 && candidates.size > 1
832
+ ? [...candidates.values()].filter(candidate => candidate.evidence.some(evidence => !RULE_BY_ID.get(evidence.rule_id).card_free))
833
+ : [];
834
+ const cardFormPsp = cardCapable.length === 1 ? cardCapable[0].psp : null;
791
835
  if (activePsps.size === 1)
792
836
  result.psp = [...activePsps][0];
793
837
  // Script-only evidence names the processor only when the scan saw everything. On a partial scan
794
838
  // the sole candidate stays listed as undetermined instead of becoming the selected route.
795
839
  else if (activePsps.size === 0 && candidates.size === 1 && result.observation.complete)
796
840
  result.psp = [...candidates.keys()][0];
841
+ else if (cardFormPsp !== null && result.observation.complete)
842
+ result.psp = cardFormPsp;
797
843
  if (!result.observation.complete)
798
844
  result.reason_codes.push('observation_incomplete');
799
845
  if (!input.signals.length) {
800
846
  result.reason_codes.push('psp_not_detected');
801
847
  result.missing_evidence.push('payment_page_signal');
802
848
  }
803
- if (activePsps.size > 1 || activeFlows.size > 1 || activeFlowFrames.size > 1 || activePsps.size === 0 && candidates.size > 1)
849
+ if (activePsps.size > 1 || activeFlows.size > 1 || activeFlowFrames.size > 1 || activePsps.size === 0 && candidates.size > 1 && cardFormPsp === null)
804
850
  result.reason_codes.push('ambiguous_checkout');
805
851
  if (activeFlows.size !== 1 || result.psp === null) {
806
852
  result.reason_codes.push('checkout_flow_unidentified');
@@ -25,6 +25,13 @@ export declare class PreparationGate {
25
25
  * own method is what binds: a POST for most processors, the registration GET for Worldpay eProtect.
26
26
  */
27
27
  claim(requestUrl: string, requestMethod: string, requestBody?: string | null, requestHeaders?: Record<string, string>): PreparedCheckout | undefined;
28
+ /**
29
+ * Whether a same-document navigation of the prepared page to `url` leaves the document this
30
+ * preparation read: the same origin, path and query, whatever the fragment. A single-page checkout
31
+ * that calls history.replaceState with its own URL after each server action (Al's on VTEX) keeps
32
+ * its preparation; a history update to another path or query does not.
33
+ */
34
+ keepsDocument(url: unknown): boolean;
28
35
  assertDocument(): Promise<void>;
29
36
  private readDocument;
30
37
  isEngaged(): boolean;
@@ -3,6 +3,17 @@ import { amountRefusal, validAmountInput } from './client.js';
3
3
  import { matchesPreparation, validPreparationEnvironment, preparationEndpoint, preparationBindsByShape, preparationRequestMethod, preparedRequestRefusal } from './prepared-processor.js';
4
4
  import { SECURE_ACCEPTANCE_PSP, secureAcceptanceCheckoutProfile } from './cybersource-secure-acceptance.js';
5
5
  import { creditguardPageProcessUrl, creditguardProcessTxId } from './creditguard.generated.js';
6
+ /** A page URL without its fragment, or undefined when it does not parse. */
7
+ function documentWithoutFragment(url) {
8
+ try {
9
+ const parsed = new URL(url);
10
+ parsed.hash = '';
11
+ return parsed.href;
12
+ }
13
+ catch {
14
+ return undefined;
15
+ }
16
+ }
6
17
  /** A local, one-use rendezvous. It never starts or retries a merchant request. */
7
18
  export class PreparationGate {
8
19
  opts;
@@ -195,6 +206,16 @@ export class PreparationGate {
195
206
  clearTimeout(this.expiryTimer);
196
207
  return prepared;
197
208
  }
209
+ /**
210
+ * Whether a same-document navigation of the prepared page to `url` leaves the document this
211
+ * preparation read: the same origin, path and query, whatever the fragment. A single-page checkout
212
+ * that calls history.replaceState with its own URL after each server action (Al's on VTEX) keeps
213
+ * its preparation; a history update to another path or query does not.
214
+ */
215
+ keepsDocument(url) {
216
+ const kept = typeof url === 'string' ? documentWithoutFragment(url) : undefined;
217
+ return kept !== undefined && this.documentUrl !== '' && kept === documentWithoutFragment(this.documentUrl);
218
+ }
198
219
  async assertDocument() {
199
220
  if (this.documentUrl && await this.readDocument() !== this.documentUrl)
200
221
  throw new CheckoutPreparationError(this.prepared?.id ?? null, 'merchant_document_changed');