@agent-cards/sdk 0.23.3 → 0.23.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/PREFLIGHT.md +2 -0
- package/README.md +4 -3
- package/dist/adyen-merchant-hosted.generated.js +134 -127
- package/dist/card-endpoint-page.d.ts +5 -3
- package/dist/cdp.js +7 -2
- package/dist/cybersource-secure-acceptance.d.ts +78 -0
- package/dist/cybersource-secure-acceptance.js +214 -0
- package/dist/lifecycle.d.ts +6 -3
- package/dist/lifecycle.js +5 -2
- package/dist/merchant-hosted.js +2 -1
- package/dist/merchant-total.js +4 -1
- package/dist/pre-claim.d.ts +1 -0
- package/dist/pre-claim.js +76 -9
- package/dist/preflight-catalog.json +81 -0
- package/dist/preflight-schemas.json +6 -0
- package/dist/preflight.generated.js +21 -1
- package/dist/substitutions.generated.js +134 -127
- package/examples/preflight/kernel-native/inventory.json +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
- Stop the card your agent typed from reaching CyberSource through Secure Acceptance's Silent Order POST. A merchant that takes the card in its own form, such as Arrow Electronics, has its server sign the order fields, then posts them with the card fields (`card_number`, `card_expiry_date`, `card_cvn`) to a `/silent/` path on `secureacceptance.cybersource.com` (`testsecureacceptance.cybersource.com` in CyberSource's test environment, `secureacceptance.in.cybersource.com` in India); Arrow submits that form into a hidden iframe. No Agentcard payment takes that post over, and earlier releases let it through, so CyberSource received the dummy card. Both adapters now stop it for every company, whatever `syncRegistry()` served: a form the page submits as a page load, in the page or in a frame, gets the page that says Agentcard stopped the payment before the card reached CyberSource, and a fetch or an XHR fails. A `card_number` in the URL's query, as a form with method GET sends it, stops the request the same way. The controller reads `unsupported` with reason `unsupported_cybersource_secure_acceptance` and holds, like every `unsupported` reason: to pay another way on the same page, attach again. A post with no `card_number`, or an empty one, such as a payment with a stored `payment_token`, continues untouched, and so does Hosted Checkout, the same hosts without `/silent/`, where your agent types the card on CyberSource's own page. The SDK stops a post whose body it cannot read with a `blocked` event, `unreadable_cybersource_secure_acceptance_request`, and does not hold the checkout. TypeScript: the controller's `unsupported()` reasons gain `unsupported_cybersource_secure_acceptance`; code that switches exhaustively over them needs the new case.
|
|
6
|
+
|
|
7
|
+
- Name CyberSource Secure Acceptance's Silent Order POST in a preflight inspection. A form, a frame or a document on a `/silent/` path of `secureacceptance.cybersource.com`, `testsecureacceptance.cybersource.com` or `secureacceptance.in.cybersource.com` now names `cybersource_secure_acceptance`, and the result stays `unknown`: `processor_variant_unverified` for a visible form, and `payment_signal_inactive` for a hidden one such as Arrow's. The catalog's `catalog_sha256` changes; `catalog_version` stays `2026-09-15.1`.
|
|
8
|
+
|
|
5
9
|
- Stop PayPal's legacy Hosted Fields from sending the card your agent typed to PayPal's payment confirm. A checkout that loads PayPal's JS SDK with `components=hosted-fields`, such as Planet Golf UK's PayPal Checkout, takes the card in frames on `assets.braintreegateway.com` and sends it to `https://cors.api.paypal.com/v2/checkout/orders/{id}/confirm-payment-source` (`cors.api.sandbox.paypal.com` in PayPal's sandbox). No Agentcard payment takes that request over, and earlier releases let it through, so PayPal received the dummy card and declined it. Both adapters now fail that request in the browser for every company, whatever `syncRegistry()` served, and the controller reads `unsupported` with reason `unsupported_paypal_hosted_fields` and holds, like every `unsupported` reason: to pay another way on the same page, attach again. A confirm with no card number, such as a PayPal wallet payment, continues untouched. A confirm whose body the SDK cannot read is failed with a `blocked` event, `unreadable_paypal_request`, and the checkout is not held. A merchant that turns on PayPal's card installments also has the card number field send each typed number to PayPal's installment lookup, `/v1/credit/calculated-financing-options`; the SDK leaves that lookup alone, and it pays nothing. TypeScript: the controller's `unsupported()` reasons gain `unsupported_paypal_hosted_fields`; code that switches exhaustively over them needs the new case.
|
|
6
10
|
|
|
7
11
|
- Name PayPal's legacy Hosted Fields as PayPal in a preflight inspection, not as Braintree. Their card fields are braintree-web builds whose version carries `-payments-sdk` (`3.32.0-payments-sdk-dev` on Planet Golf UK), and inspection read the page as `braintree` with status `supported`. The frames now name `paypal`, and the result stays `unknown` with `processor_variant_unverified`. A braintree-web script from a `-payments-sdk` build is no longer Braintree evidence either, and a variant seen in several frames lists its limitation once. The catalog's `catalog_sha256` changes; `catalog_version` stays `2026-09-15.1`.
|
|
@@ -10,6 +14,8 @@
|
|
|
10
14
|
|
|
11
15
|
- Recognize Target Optical's card request as its checkout sends it today: a JSON `PUT` to `/wcs/resources/store/12001/cart/@self/addPayment` with the page's `nocache` query, the total in `piAmount` with five decimals (`"49.42000"`). The profile described the form post Target Optical's older checkout sent, which no request matches now, so the adapters let the dummy card reach Target Optical. The profile stays in observe: both adapters now pause that request and refuse it as `unsupported_checkout` before any authorization, let the saved-card body to the same URL through untouched, and abort the card save a signed-in shopper's page sends to `/wcs/resources/store/12001/mypayments` in every status. They also abort, in every status, a post to `/AjaxOrderChangeServicePIAddTO`, the form endpoint the older checkout used, which they refused before and which the storefront still declares in a script it serves, so moving the profile to the `PUT` leaves no path where the dummy card reaches Target Optical. `attachToPlaywright` routes a reviewed card endpoint's request by every method the profiles name; it asked only for `POST`, so a `PUT` card request or resend never reached its gates. A card endpoint create names the profile's own method in `request.method`; an API that reads every card endpoint request as a `POST` refuses a `PUT` create with `invalid_request`, so nothing is charged. TypeScript: `CardEndpointProfile.method` can be `PUT`.
|
|
12
16
|
|
|
17
|
+
- Pay Cinemark and Dick's Sporting Goods' own storefront, two reviewed Adyen merchants that take the card on their own server. Both profiles, `cinemark_initiate` and `dsg_paygate_v2`, ship `enabled`, and the API serves them `enabled` only to a client of a company Agentcard turned them on for. For every other client the adapters keep pausing and aborting their card requests as `merchant_profile_observed`, as before. A payment there needs a preparation for the profile and the cardholder's approval in the Vault, and Autopilot never pays one. The create carries the merchant's own checkout total as your agent's browser read it, and the API refuses a payment whose amount is not that total. Dick's paygate at Golf Galaxy, Public Lands and Going Going Gone moves to its own profile, `dsg_other_stores_paygate_v2`, which ships in `observe`, so the adapters abort those card requests as before. Matching API and Vault releases are required.
|
|
18
|
+
|
|
13
19
|
- Stop the card fields adyen-web 5 encrypts at a reviewed Adyen merchant profile. adyen-web 5 seals each field as an RSA-OAEP / A256CBC-HS512 JWE, where adyen-web 6 writes RSA-OAEP-256 / A256GCM, and the SDK read only adyen-web 6's form. So the card requests of Cathay Pacific's payment page and Dunelm's legacy checkout, and Cathay's charge request after its signing step, reached the merchant with the agent's dummy card. The adapters now read both forms as a card. Both profiles ship in `observe`, so the adapters abort each of these requests before it leaves the browser and report it as `merchant_profile_observed`. The Vault writes only adyen-web 6's form, so the API refuses a create for a card request in adyen-web 5's form with `cse_template_unsupported`, and nothing is charged.
|
|
14
20
|
|
|
15
21
|
- Abort the requests in which IHG's pay page sends the typed card outside its reviewed card request, in every status, as `card_endpoint_refused` with reason `card_resend`. The page posts the same booking to IHG's enrollment service while its pre-ticked "Enroll for free" box stays ticked, posts it on other paths for more than one room, a travel agent or Business Rewards, and at a hotel that asks for 3-D Secure first posts the number to two 3-D Secure calls. The SDK let each of these reach IHG with the agent's dummy card. A booking with the box unticked reaches IHG's reviewed card request, which the adapters refuse as before while IHG is in `observe`.
|
package/PREFLIGHT.md
CHANGED
|
@@ -209,6 +209,8 @@ The catalog also carries reviewed hosted, regional, and versioned variants obser
|
|
|
209
209
|
|
|
210
210
|
PayPal's legacy Hosted Fields (`paypal`) are identified from the card fields PayPal's JS SDK renders with `components=hosted-fields`: braintree-web builds whose version carries `-payments-sdk`, such as `3.32.0-payments-sdk-dev`, served from `assets.braintreegateway.com` as `hosted-fields-input-frame.min.html` and `hosted-fields-payments-sdk-tokenization-frame.min.html`. PayPal's frames send the card to PayPal, not to Braintree, so a page that shows them names `paypal` and returns `unknown` with `processor_variant_unverified`, and no braintree-web file from a `-payments-sdk` build counts as Braintree evidence. The SDK fails the card request those frames send; see the PayPal Hosted Fields row in the [README's processor table](./README.md#supported-processors).
|
|
211
211
|
|
|
212
|
+
An inspection identifies CyberSource Secure Acceptance's Silent Order POST (`cybersource_secure_acceptance`) from the form a merchant's own page posts the card from, and from a frame or a document on the same path: a `/silent/` path, such as `/silent/pay` or `/silent/embedded/token/create`, on `secureacceptance.cybersource.com`, `testsecureacceptance.cybersource.com` or `secureacceptance.in.cybersource.com`. No Vault mode takes that post over, so a page that shows the form names `cybersource_secure_acceptance` and returns `unknown`: with `processor_variant_unverified` when the form is visible, and with `payment_signal_inactive` when it is hidden, as on Arrow Electronics' checkout. An inspection does not name Hosted Checkout, the same hosts without `/silent/`. The SDK stops the card post; see the CyberSource Secure Acceptance row in the [README's processor table](./README.md#supported-processors).
|
|
213
|
+
|
|
212
214
|
Adyen's `supported` covers the Sessions payment request on Adyen's own hosts. Some Adyen merchants post the four encrypted fields to their own server instead, and their pages load the same secured fields, so an inspection identifies Adyen on both and cannot tell the two flows apart. The SDK pays a merchant's own endpoint only through a merchant profile Agentcard reviewed for it; the reviewed profiles (Dunelm and Cinemark) are in `observe`, so the SDK aborts their card requests and nothing is charged. The `actual_payment_request_validation` requirement is where that difference shows: check the paused request's host before treating an Adyen result as payable.
|
|
213
215
|
|
|
214
216
|
Authorize.Net Direct Post Method and SIM ship dark. The SDK pauses their `transact.dll` card form only for an org Agentcard enabled for them (capability `authorize_net_dpm_form`), and the bundled catalog leaves them out, so the table above does not list them and inspection answers for their forms exactly as it did before: the SIM hosted form on `secure.authorize.net` identifies Authorize.Net and returns `unknown` with `processor_variant_unverified`.
|
package/README.md
CHANGED
|
@@ -255,7 +255,8 @@ Coverage is specific to the processor request format, merchant setup, browser tr
|
|
|
255
255
|
| Mercado Pago | Card tokenization and prepared checkout are implemented. Guest Checkout Pro in Mexico also corrects the issuer for one native card association when the selected card has the same brand and type. One live MXN 40 Lotería Chida purchase with published SDK 0.10.0 completed automatically through Pay; the merchant confirmed paid status and PDF fulfillment. The historical SDK result remains unknown because the private receipt adapter rejected a relative download URL; a separate read with the corrected adapter confirms that same paid receipt. Independent processor capture/settlement and other country or integration paths remain unverified. |
|
|
256
256
|
| VGS Collect (Very Good Security; Wolt) | not supported: VGS's proxy aliases only submissions from its own iframe, so a replay from the cardholder's device is refused by the merchant (verified on Wolt, 2026-09-03). Not recognized, so the agent's browser is not paused there |
|
|
257
257
|
| PayPal Hosted Fields (the legacy card fields of PayPal's JS SDK; Planet Golf UK) | not supported: no Agentcard payment takes over the card these fields send to `cors.api.paypal.com`. The SDK fails that request for every company, so PayPal's payment confirm never receives the dummy card, and the controller reads `unsupported` with reason `unsupported_paypal_hosted_fields` and holds the attachment until you attach again; a PayPal wallet payment continues untouched |
|
|
258
|
-
|
|
|
258
|
+
| CyberSource Secure Acceptance Silent Order POST (the merchant's own card form posted to CyberSource; Arrow Electronics) | not supported: no Agentcard payment takes over the card a merchant's page posts to a `/silent/` path on `secureacceptance.cybersource.com` (`testsecureacceptance.cybersource.com` in CyberSource's test environment, `secureacceptance.in.cybersource.com` in India). The SDK stops that post for every company, so CyberSource never receives the dummy card: a form the page submits as a page load, in the page or in a frame, ends on the page that says Agentcard stopped the payment, and a fetch or an XHR fails. The controller reads `unsupported` with reason `unsupported_cybersource_secure_acceptance` and holds the attachment until you attach again; a post with no `card_number`, such as a payment with a stored `payment_token`, continues untouched. The SDK does not stop Hosted Checkout, where your agent types the card on CyberSource's own page |
|
|
259
|
+
| Adyen | supported (mode `cse`): the vault encrypts the card for Adyen on the cardholder's device and your browser sends it. Sessions flow: the paused request is `/checkoutshopper/v1/sessions/{id}/payments` on Adyen's own hosts. A merchant that posts the encrypted fields to its own server pauses only when Agentcard reviewed it as a merchant profile. Cinemark and Dick's Sporting Goods' own storefront take payments for a company Agentcard turned them on for; every other reviewed merchant is in `observe`, so its card requests are reported and aborted and nothing pays there yet (see "Adyen merchants that take the card on their own server"). Without a preparation, approval starts at Pay and must land before Adyen Web's own request timeout (observed at 60 seconds on Adyen Web 6.41 and 6.44; not enforced by the SDK); `prepare({ psp: 'adyen' })` moves the approval before Pay |
|
|
259
260
|
| ACI Worldwide COPYandPAY (Halfords) | dark launch: served only after `syncRegistry()` and only for an org Agentcard enabled; prepared checkout only. The card-number request is replayed from the cardholder's device, the page's own CVC and expiry requests are answered locally, and `/payment` continues once. See [Pay an ACI COPYandPAY checkout](#pay-an-aci-copyandpay-checkout) |
|
|
260
261
|
| Tranzila | supported (mode `hosted_form`): the cardholder finishes on Tranzila's own page; the paused form navigation resolves to a synthetic page, and you poll the merchant's order state |
|
|
261
262
|
| Fiserv Commerce Hub | implemented (mode `cse`, prepared checkout only) and off until Agentcard turns it on for your company: the card frame's card capture on `connect.fiservapis.com` (or `connect-cert.fiservapis.com` in the sandbox), with the approved card encrypted on the cardholder's device under a key Agentcard reviewed for the merchant. A merchant whose frame posts to Fiserv's `payment-link` endpoint is not recognized. No live merchant purchase is verified yet |
|
|
@@ -1252,7 +1253,7 @@ Some Adyen merchants have adyen-web encrypt the card into four fields and post t
|
|
|
1252
1253
|
|
|
1253
1254
|
- A request that carries no encrypted card (a basket query, a preflight) continues as before.
|
|
1254
1255
|
- A body the browser did not hand over (a blob or a file, which neither adapter can read) is not proven card-free, so any request but a `GET`, `HEAD` or `OPTIONS` that carries one is treated as a card request the profile cannot finish. Playwright reports a missing body the same way, so an empty body is treated alike in both adapters.
|
|
1255
|
-
- A profile in `observe` never pays. Its card request is aborted before it reaches the merchant, and the adapters report `merchant_profile_observed` with the profile, the templated URL, the verdict and `keyPathSha256`, the SHA-256 of the body's sorted key paths (never a value; `null` for a body that was not read), then `unsupported_checkout`. The controller reads `unsupported` with reason `merchant_profile_observe`, and no authorization exists.
|
|
1256
|
+
- A profile in `observe` never pays. Its card request is aborted before it reaches the merchant, and the adapters report `merchant_profile_observed` with the profile, the templated URL, the verdict and `keyPathSha256`, the SHA-256 of the body's sorted key paths (never a value; `null` for a body that was not read), then `unsupported_checkout`. The controller reads `unsupported` with reason `merchant_profile_observe`, and no authorization exists. `cinemark_initiate` and `dsg_paygate_v2` (Dick's Sporting Goods' own storefront) ship `enabled`, and the API serves them `enabled` only to a client of a company Agentcard turned them on for. Every other reviewed profile ships in `observe`, `dunelm_was_graphql` and `dsg_other_stores_paygate_v2` (Dick's paygate at Golf Galaxy, Public Lands and Going Going Gone) among them.
|
|
1256
1257
|
- A card request the profile cannot finish (storing the card, a stored card, another operation, three fields instead of four, a sibling endpoint, an unreadable body) is aborted with `unsupported_checkout` and the reason, and reads `unsupported` with reason `merchant_request_unsupported`.
|
|
1257
1258
|
- The profile's own card request, once Agentcard enables the profile for your client and this build, pays only through a preparation for that profile. Without one it is aborted before any pause, prompt or authorization: the adapters report `blocked` with `preparation_required`, the controller reads `failed` with that reason, and `prepare()` is refused on that attachment, as after any first card request. Create a new attachment and prepare before Pay.
|
|
1258
1259
|
|
|
@@ -1266,7 +1267,7 @@ After hand-off, a `5xx` final answer (after any redirect), a network failure, or
|
|
|
1266
1267
|
|
|
1267
1268
|
#### Testing against your own Adyen TEST account
|
|
1268
1269
|
|
|
1269
|
-
A test-mode client can run the same checkout against its own server and its own Adyen TEST account,
|
|
1270
|
+
A test-mode client can run the same checkout against its own server and its own Adyen TEST account, whether or not Agentcard has enabled the reviewed profile. Declare your endpoint on the client, before any attach, as taking the card request of a profile this build reviewed:
|
|
1270
1271
|
|
|
1271
1272
|
```ts
|
|
1272
1273
|
const vault = new VaultClient({ clientId, clientSecret, sandboxMerchants: [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
2
|
// Generated from @agent-cards/payment-core. Do not edit.
|
|
3
|
-
// artifact-sha256:
|
|
3
|
+
// artifact-sha256: 4790fdfc656acbda50ddf8471507933ddd4938f4c5b351ec096a9549a7c8c257
|
|
4
4
|
// src/deep-freeze.js
|
|
5
5
|
function deepFreeze(value) {
|
|
6
6
|
if (value && typeof value === "object" && !Object.isFrozen(value)) {
|
|
@@ -1086,6 +1086,118 @@ function selectMerchantExchanges(profile, stageName, input) {
|
|
|
1086
1086
|
return { ok: true, responses: newestMerchantExchanges(kept) };
|
|
1087
1087
|
}
|
|
1088
1088
|
// src/merchant-profiles.js
|
|
1089
|
+
var DSG_PAYGATE_V2 = /* @__PURE__ */ deepFreeze({
|
|
1090
|
+
method: "POST",
|
|
1091
|
+
path: "/prod/api/paygate/v2/authorization",
|
|
1092
|
+
query: {},
|
|
1093
|
+
// The page sends true for every checkout its translator read, the only checkouts
|
|
1094
|
+
// the amount source below maps; a legacy checkout is not this card request.
|
|
1095
|
+
requires: [{ path: ["isModernOrder"], equals: true }],
|
|
1096
|
+
holder: ["tenders", "encryptedCardTenders", 0],
|
|
1097
|
+
fields: {
|
|
1098
|
+
encryptedCardNumber: "cardNumber",
|
|
1099
|
+
encryptedExpiryMonth: "expirationMonth",
|
|
1100
|
+
encryptedExpiryYear: "expirationYear",
|
|
1101
|
+
encryptedSecurityCode: "cvv"
|
|
1102
|
+
},
|
|
1103
|
+
// cardType and vinBalue describe the dummy the agent typed: the facts below
|
|
1104
|
+
// write the approved card's instead, so nothing is removed.
|
|
1105
|
+
remove: [],
|
|
1106
|
+
refuse: [
|
|
1107
|
+
{ path: ["tenders", "encryptedCardTenders", 0, "saveForLater"], when: "true" },
|
|
1108
|
+
// A saved card, or a second card tender the Vault never encrypted.
|
|
1109
|
+
{ path: ["tenders", "savedCardTender"], when: "present" },
|
|
1110
|
+
{ path: ["tenders", "encryptedCardTenders", 1], when: "present" },
|
|
1111
|
+
// A gift card pays part of the order, so the card pays less than the total.
|
|
1112
|
+
{ path: ["tenders", "giftCardTenders"], when: "present" }
|
|
1113
|
+
],
|
|
1114
|
+
amount: null,
|
|
1115
|
+
// Read Sep 25, 2026 (research amount_source/dickssportinggoods). Every checkout call
|
|
1116
|
+
// on the checkout page answers the whole checkout, camelCase on the wire: the page
|
|
1117
|
+
// load's PATCH (or the create), then every address, shipping, promotion, gift card,
|
|
1118
|
+
// tip and ScoreCard change. pricing.totalRemaining is what the card pays, a string
|
|
1119
|
+
// with exactly two decimals ("123.45"; the page itself drops the dot for minor
|
|
1120
|
+
// units). transactionReference is the checkout key, in the body and the URL. After
|
|
1121
|
+
// payment the order submit and the confirmation read return the placed checkout.
|
|
1122
|
+
amountSource: {
|
|
1123
|
+
id: "dsg_checkout_pricing",
|
|
1124
|
+
origin: "checkout",
|
|
1125
|
+
format: "json",
|
|
1126
|
+
responses: [
|
|
1127
|
+
{ method: "PATCH", path: "/api/v1/checkouts/:checkoutKey", query: {} },
|
|
1128
|
+
{ method: "POST", path: "/api/v1/checkouts", query: {} },
|
|
1129
|
+
{ method: "POST", path: "/api/v1/checkouts/:checkoutKey/addresses", queries: [{}, { type: "billing" }, { type: "shipping" }] },
|
|
1130
|
+
{ method: "PUT", path: "/api/v1/checkouts/:checkoutKey/shipping/selected/groups/:groupNumber/mode", query: {} },
|
|
1131
|
+
{ method: "PUT", path: "/api/v2/checkouts/:checkoutKey/promotion/cart", query: {} },
|
|
1132
|
+
{ method: "DELETE", path: "/api/v2/checkouts/:checkoutKey/promotion/cart", query: {} },
|
|
1133
|
+
{ method: "POST", path: "/api/v1/checkouts/:checkoutKey/gift-cards", query: {} },
|
|
1134
|
+
{ method: "DELETE", path: "/api/v1/checkouts/:checkoutKey/gift-cards/:giftCardIndex", query: {} },
|
|
1135
|
+
{ method: "PUT", path: "/api/v1/checkouts/:checkoutKey/tip", query: {} },
|
|
1136
|
+
{ method: "PUT", path: "/api/v1/checkouts/:checkoutKey/scorecard", query: {} },
|
|
1137
|
+
{ method: "DELETE", path: "/api/v1/checkouts/:checkoutKey/scorecard", query: {} },
|
|
1138
|
+
{ method: "DELETE", path: "/api/v1/checkouts/:checkoutKey/v2/gifts", query: {} }
|
|
1139
|
+
],
|
|
1140
|
+
total: { path: ["pricing", "totalRemaining"], format: "decimal2" },
|
|
1141
|
+
unit: "major",
|
|
1142
|
+
currency: "USD",
|
|
1143
|
+
currencyPath: ["pricing", "currency"],
|
|
1144
|
+
bind: [
|
|
1145
|
+
{ source: ["checkoutKey"], card: ["transactionReference"] },
|
|
1146
|
+
{ placeholder: "checkoutKey", card: ["transactionReference"] }
|
|
1147
|
+
],
|
|
1148
|
+
// The order total and the card's share are the same text. Anything that lowers the
|
|
1149
|
+
// share below the total (a gift card, ScoreCard rewards) or lands in only one of them
|
|
1150
|
+
// (a tip, a donation) is refused until a HAR shows which one the charge follows, so
|
|
1151
|
+
// the approved amount and the placed checkout's total read after payment agree.
|
|
1152
|
+
requires: [{ path: ["pricing", "total"], equalsPath: ["pricing", "totalRemaining"] }],
|
|
1153
|
+
refuse: [
|
|
1154
|
+
// A placed checkout is not the one being paid.
|
|
1155
|
+
{ path: ["orderPlacedTime"], when: "true" },
|
|
1156
|
+
// Gift cards and a checkout with no address yet (tax not estimated) wait for a HAR.
|
|
1157
|
+
{ path: ["payment", "giftCards"], when: "nonEmpty" },
|
|
1158
|
+
{ path: ["addresses"], when: "empty" }
|
|
1159
|
+
],
|
|
1160
|
+
maxAgeMs: 9e5,
|
|
1161
|
+
afterPayment: {
|
|
1162
|
+
origin: "checkout",
|
|
1163
|
+
format: "json",
|
|
1164
|
+
responses: [
|
|
1165
|
+
{ method: "POST", path: "/api/v1/checkouts/:checkoutKey", query: {} },
|
|
1166
|
+
{ method: "GET", path: "/api/v1/checkouts/submitted/:checkoutKey", query: {} }
|
|
1167
|
+
],
|
|
1168
|
+
// The order total, which the requires rule above held equal to the card's share
|
|
1169
|
+
// before payment. totalRemaining is not read here: after placement it can drop to
|
|
1170
|
+
// what is still unpaid, which would hide a higher charge.
|
|
1171
|
+
total: { path: ["pricing", "total"], format: "decimal2" },
|
|
1172
|
+
unit: "major",
|
|
1173
|
+
currency: "USD",
|
|
1174
|
+
currencyPath: ["pricing", "currency"],
|
|
1175
|
+
bind: [
|
|
1176
|
+
{ source: ["checkoutKey"], card: ["transactionReference"] },
|
|
1177
|
+
{ placeholder: "checkoutKey", card: ["transactionReference"] }
|
|
1178
|
+
],
|
|
1179
|
+
refuse: [{ path: ["orderPlacedTime"], when: "unset" }]
|
|
1180
|
+
}
|
|
1181
|
+
},
|
|
1182
|
+
facts: [
|
|
1183
|
+
// adyen-web's brand codes, the ones the page's supported list names; Dick's own
|
|
1184
|
+
// private-label (plcc, comc) cards have no Agentcard brand and are refused.
|
|
1185
|
+
{
|
|
1186
|
+
path: ["tenders", "encryptedCardTenders", 0, "cardType"],
|
|
1187
|
+
fact: "brand",
|
|
1188
|
+
map: { visa: "visa", mastercard: "mc", amex: "amex", discover: "discover", diners: "diners", jcb: "jcb" }
|
|
1189
|
+
},
|
|
1190
|
+
{ path: ["tenders", "encryptedCardTenders", 0, "vinBalue"], fact: "bin6" }
|
|
1191
|
+
],
|
|
1192
|
+
adyen: {
|
|
1193
|
+
environment: "live",
|
|
1194
|
+
clientKey: "live_YJLFKT47JJG2RI7QIYX6HTKKDEDOEGOH",
|
|
1195
|
+
publicKeySha256: "da33611149dff3ab715be8671c0550bb8aec6112983b2473db9ee7afb829c110"
|
|
1196
|
+
}
|
|
1197
|
+
});
|
|
1198
|
+
function dsgPaygateProfile(own) {
|
|
1199
|
+
return { ...own, ...DSG_PAYGATE_V2 };
|
|
1200
|
+
}
|
|
1089
1201
|
var MERCHANT_HOSTED_PROFILES = /* @__PURE__ */ deepFreeze([
|
|
1090
1202
|
{
|
|
1091
1203
|
// Read Sep 23, 2026. assets.dunelm.com checkout-page bundle: submitPayment
|
|
@@ -1181,10 +1293,13 @@ var MERCHANT_HOSTED_PROFILES = /* @__PURE__ */ deepFreeze([
|
|
|
1181
1293
|
// client key from the three securedFields iframes on
|
|
1182
1294
|
// checkoutshopper-live-us.adyen.com (adyen-web 6.x). The request body itself
|
|
1183
1295
|
// was not captured: the guest email gate stopped the run before Pay. Public
|
|
1184
|
-
// key read from checkoutshopper-live-us.adyen.com on 2026-09-25 (UTC).
|
|
1296
|
+
// key read from checkoutshopper-live-us.adyen.com on 2026-09-25 (UTC). Enabled
|
|
1297
|
+
// Oct 7, 2026 under D1 (amountSource, above): live checks on Sep 30 and Oct 6
|
|
1298
|
+
// matched its key pin, its card request as the page's script builds it, and its
|
|
1299
|
+
// checkout total.
|
|
1185
1300
|
id: "cinemark_initiate",
|
|
1186
1301
|
merchant: "Cinemark",
|
|
1187
|
-
status: "
|
|
1302
|
+
status: "enabled",
|
|
1188
1303
|
origins: [{ checkout: "https://www.cinemark.com", endpoint: "https://www.cinemark.com" }],
|
|
1189
1304
|
method: "POST",
|
|
1190
1305
|
path: "/api/adyen/initiatePayment",
|
|
@@ -1257,137 +1372,29 @@ var MERCHANT_HOSTED_PROFILES = /* @__PURE__ */ deepFreeze([
|
|
|
1257
1372
|
publicKeySha256: "9dd5ef549c7454d60ca970ff76c8f4cac36d79f2961e59eca9116791e86cbcc5"
|
|
1258
1373
|
}
|
|
1259
1374
|
},
|
|
1260
|
-
{
|
|
1261
|
-
//
|
|
1262
|
-
//
|
|
1263
|
-
//
|
|
1264
|
-
// beside cardType (adyen-web's first detected brand), saveForLater (the save-card
|
|
1265
|
-
// box) and vinBalue (the six digits onBinValue reports). The page posts it with
|
|
1266
|
-
// transactionReference, customer.device and any giftCardTenders to
|
|
1267
|
-
// <payments host>/prod/api/paygate/v2/authorization, the host picked from the
|
|
1268
|
-
// page's own (Dick's, Golf Galaxy, Public Lands, Going Going Gone). The same slot
|
|
1269
|
-
// carries Afterpay, CashApp and Affirm tenders with literal strings where the JWEs
|
|
1270
|
-
// go, and a saved card goes to tenders.savedCardTender instead. The body names no
|
|
1271
|
-
// amount: the paygate charges the cart it holds for transactionReference.
|
|
1272
|
-
// mountCCForm names the client key and environment 'live'. Public key read from
|
|
1273
|
-
// checkoutshopper-live.adyen.com on 2026-09-25 (UTC).
|
|
1375
|
+
/* @__PURE__ */ dsgPaygateProfile({
|
|
1376
|
+
// Dick's own storefront, the one live checks read on Sep 30 and Oct 6, 2026: its key
|
|
1377
|
+
// pin, its card request as the page's code builds it, its card facts and its checkout
|
|
1378
|
+
// pricing matched DSG_PAYGATE_V2. Enabled Oct 7, 2026 under D1 (amountSource, above).
|
|
1274
1379
|
id: "dsg_paygate_v2",
|
|
1275
1380
|
merchant: "Dick's Sporting Goods",
|
|
1381
|
+
status: "enabled",
|
|
1382
|
+
origins: [
|
|
1383
|
+
{ checkout: "https://www.dickssportinggoods.com", endpoint: "https://payments.dickssportinggoods.com" }
|
|
1384
|
+
]
|
|
1385
|
+
}),
|
|
1386
|
+
/* @__PURE__ */ dsgPaygateProfile({
|
|
1387
|
+
// The same paygate on the three other storefronts its page names. No live check has
|
|
1388
|
+
// read them, so their card requests stay paused and aborted in observe.
|
|
1389
|
+
id: "dsg_other_stores_paygate_v2",
|
|
1390
|
+
merchant: "Golf Galaxy, Public Lands and Going Going Gone",
|
|
1276
1391
|
status: "observe",
|
|
1277
1392
|
origins: [
|
|
1278
|
-
{ checkout: "https://www.dickssportinggoods.com", endpoint: "https://payments.dickssportinggoods.com" },
|
|
1279
1393
|
{ checkout: "https://www.golfgalaxy.com", endpoint: "https://payments.golfgalaxy.com" },
|
|
1280
1394
|
{ checkout: "https://www.publiclands.com", endpoint: "https://payments.publiclands.com" },
|
|
1281
1395
|
{ checkout: "https://www.goinggoinggone.com", endpoint: "https://payments.goinggoinggone.com" }
|
|
1282
|
-
]
|
|
1283
|
-
|
|
1284
|
-
path: "/prod/api/paygate/v2/authorization",
|
|
1285
|
-
query: {},
|
|
1286
|
-
// The page sends true for every checkout its translator read, the only checkouts
|
|
1287
|
-
// the amount source below maps; a legacy checkout is not this card request.
|
|
1288
|
-
requires: [{ path: ["isModernOrder"], equals: true }],
|
|
1289
|
-
holder: ["tenders", "encryptedCardTenders", 0],
|
|
1290
|
-
fields: {
|
|
1291
|
-
encryptedCardNumber: "cardNumber",
|
|
1292
|
-
encryptedExpiryMonth: "expirationMonth",
|
|
1293
|
-
encryptedExpiryYear: "expirationYear",
|
|
1294
|
-
encryptedSecurityCode: "cvv"
|
|
1295
|
-
},
|
|
1296
|
-
// cardType and vinBalue describe the dummy the agent typed: the facts below
|
|
1297
|
-
// write the approved card's instead, so nothing is removed.
|
|
1298
|
-
remove: [],
|
|
1299
|
-
refuse: [
|
|
1300
|
-
{ path: ["tenders", "encryptedCardTenders", 0, "saveForLater"], when: "true" },
|
|
1301
|
-
// A saved card, or a second card tender the Vault never encrypted.
|
|
1302
|
-
{ path: ["tenders", "savedCardTender"], when: "present" },
|
|
1303
|
-
{ path: ["tenders", "encryptedCardTenders", 1], when: "present" },
|
|
1304
|
-
// A gift card pays part of the order, so the card pays less than the total.
|
|
1305
|
-
{ path: ["tenders", "giftCardTenders"], when: "present" }
|
|
1306
|
-
],
|
|
1307
|
-
amount: null,
|
|
1308
|
-
// Read Sep 25, 2026 (research amount_source/dickssportinggoods). Every checkout call
|
|
1309
|
-
// on the checkout page answers the whole checkout, camelCase on the wire: the page
|
|
1310
|
-
// load's PATCH (or the create), then every address, shipping, promotion, gift card,
|
|
1311
|
-
// tip and ScoreCard change. pricing.totalRemaining is what the card pays, a string
|
|
1312
|
-
// with exactly two decimals ("123.45"; the page itself drops the dot for minor
|
|
1313
|
-
// units). transactionReference is the checkout key, in the body and the URL. After
|
|
1314
|
-
// payment the order submit and the confirmation read return the placed checkout.
|
|
1315
|
-
amountSource: {
|
|
1316
|
-
id: "dsg_checkout_pricing",
|
|
1317
|
-
origin: "checkout",
|
|
1318
|
-
format: "json",
|
|
1319
|
-
responses: [
|
|
1320
|
-
{ method: "PATCH", path: "/api/v1/checkouts/:checkoutKey", query: {} },
|
|
1321
|
-
{ method: "POST", path: "/api/v1/checkouts", query: {} },
|
|
1322
|
-
{ method: "POST", path: "/api/v1/checkouts/:checkoutKey/addresses", queries: [{}, { type: "billing" }, { type: "shipping" }] },
|
|
1323
|
-
{ method: "PUT", path: "/api/v1/checkouts/:checkoutKey/shipping/selected/groups/:groupNumber/mode", query: {} },
|
|
1324
|
-
{ method: "PUT", path: "/api/v2/checkouts/:checkoutKey/promotion/cart", query: {} },
|
|
1325
|
-
{ method: "DELETE", path: "/api/v2/checkouts/:checkoutKey/promotion/cart", query: {} },
|
|
1326
|
-
{ method: "POST", path: "/api/v1/checkouts/:checkoutKey/gift-cards", query: {} },
|
|
1327
|
-
{ method: "DELETE", path: "/api/v1/checkouts/:checkoutKey/gift-cards/:giftCardIndex", query: {} },
|
|
1328
|
-
{ method: "PUT", path: "/api/v1/checkouts/:checkoutKey/tip", query: {} },
|
|
1329
|
-
{ method: "PUT", path: "/api/v1/checkouts/:checkoutKey/scorecard", query: {} },
|
|
1330
|
-
{ method: "DELETE", path: "/api/v1/checkouts/:checkoutKey/scorecard", query: {} },
|
|
1331
|
-
{ method: "DELETE", path: "/api/v1/checkouts/:checkoutKey/v2/gifts", query: {} }
|
|
1332
|
-
],
|
|
1333
|
-
total: { path: ["pricing", "totalRemaining"], format: "decimal2" },
|
|
1334
|
-
unit: "major",
|
|
1335
|
-
currency: "USD",
|
|
1336
|
-
currencyPath: ["pricing", "currency"],
|
|
1337
|
-
bind: [
|
|
1338
|
-
{ source: ["checkoutKey"], card: ["transactionReference"] },
|
|
1339
|
-
{ placeholder: "checkoutKey", card: ["transactionReference"] }
|
|
1340
|
-
],
|
|
1341
|
-
// The order total and the card's share are the same text. Anything that lowers the
|
|
1342
|
-
// share below the total (a gift card, ScoreCard rewards) or lands in only one of them
|
|
1343
|
-
// (a tip, a donation) is refused until a HAR shows which one the charge follows, so
|
|
1344
|
-
// the approved amount and the placed checkout's total read after payment agree.
|
|
1345
|
-
requires: [{ path: ["pricing", "total"], equalsPath: ["pricing", "totalRemaining"] }],
|
|
1346
|
-
refuse: [
|
|
1347
|
-
// A placed checkout is not the one being paid.
|
|
1348
|
-
{ path: ["orderPlacedTime"], when: "true" },
|
|
1349
|
-
// Gift cards and a checkout with no address yet (tax not estimated) wait for a HAR.
|
|
1350
|
-
{ path: ["payment", "giftCards"], when: "nonEmpty" },
|
|
1351
|
-
{ path: ["addresses"], when: "empty" }
|
|
1352
|
-
],
|
|
1353
|
-
maxAgeMs: 9e5,
|
|
1354
|
-
afterPayment: {
|
|
1355
|
-
origin: "checkout",
|
|
1356
|
-
format: "json",
|
|
1357
|
-
responses: [
|
|
1358
|
-
{ method: "POST", path: "/api/v1/checkouts/:checkoutKey", query: {} },
|
|
1359
|
-
{ method: "GET", path: "/api/v1/checkouts/submitted/:checkoutKey", query: {} }
|
|
1360
|
-
],
|
|
1361
|
-
// The order total, which the requires rule above held equal to the card's share
|
|
1362
|
-
// before payment. totalRemaining is not read here: after placement it can drop to
|
|
1363
|
-
// what is still unpaid, which would hide a higher charge.
|
|
1364
|
-
total: { path: ["pricing", "total"], format: "decimal2" },
|
|
1365
|
-
unit: "major",
|
|
1366
|
-
currency: "USD",
|
|
1367
|
-
currencyPath: ["pricing", "currency"],
|
|
1368
|
-
bind: [
|
|
1369
|
-
{ source: ["checkoutKey"], card: ["transactionReference"] },
|
|
1370
|
-
{ placeholder: "checkoutKey", card: ["transactionReference"] }
|
|
1371
|
-
],
|
|
1372
|
-
refuse: [{ path: ["orderPlacedTime"], when: "unset" }]
|
|
1373
|
-
}
|
|
1374
|
-
},
|
|
1375
|
-
facts: [
|
|
1376
|
-
// adyen-web's brand codes, the ones the page's supported list names; Dick's own
|
|
1377
|
-
// private-label (plcc, comc) cards have no Agentcard brand and are refused.
|
|
1378
|
-
{
|
|
1379
|
-
path: ["tenders", "encryptedCardTenders", 0, "cardType"],
|
|
1380
|
-
fact: "brand",
|
|
1381
|
-
map: { visa: "visa", mastercard: "mc", amex: "amex", discover: "discover", diners: "diners", jcb: "jcb" }
|
|
1382
|
-
},
|
|
1383
|
-
{ path: ["tenders", "encryptedCardTenders", 0, "vinBalue"], fact: "bin6" }
|
|
1384
|
-
],
|
|
1385
|
-
adyen: {
|
|
1386
|
-
environment: "live",
|
|
1387
|
-
clientKey: "live_YJLFKT47JJG2RI7QIYX6HTKKDEDOEGOH",
|
|
1388
|
-
publicKeySha256: "da33611149dff3ab715be8671c0550bb8aec6112983b2473db9ee7afb829c110"
|
|
1389
|
-
}
|
|
1390
|
-
},
|
|
1396
|
+
]
|
|
1397
|
+
}),
|
|
1391
1398
|
{
|
|
1392
1399
|
// Read Sep 25, 2026, from public code only: the WooCommerce plugin super-payments 1.40.1 and
|
|
1393
1400
|
// cdn.superpayments.com/js/v2/payment.webcomponents.script.js as it stood on Sep 19.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The page a paused card form navigation is answered with when Agentcard stops it
|
|
3
|
-
* (card-endpoint.ts, a profile whose `navigation` is 'top' or 'frame'
|
|
3
|
+
* (card-endpoint.ts, a profile whose `navigation` is 'top' or 'frame', and a form a
|
|
4
|
+
* merchant's page posts to CyberSource Secure Acceptance, cybersource-secure-acceptance.ts).
|
|
4
5
|
*
|
|
5
6
|
* A merchant's form that the page submits as a page load leaves the agent's browser
|
|
6
7
|
* waiting for a page, so an aborted request is the wrong answer: it renders an error
|
|
@@ -24,7 +25,8 @@
|
|
|
24
25
|
* Self-contained HTML: no external resource, no script that runs (the one `<script>` is
|
|
25
26
|
* `application/json`), readable by a person in one paragraph and by an agent through the
|
|
26
27
|
* meta tag, the header and the JSON block. It never carries the endpoint URL, the paused
|
|
27
|
-
* body or the merchant's answer: only the profile's own merchant name,
|
|
28
|
+
* body or the merchant's answer: only the profile's own merchant name, or CyberSource for a
|
|
29
|
+
* Secure Acceptance post, escaped.
|
|
28
30
|
*/
|
|
29
31
|
import type { SyntheticPage } from './hosted-form.js';
|
|
30
32
|
import type { CheckoutState } from './lifecycle.js';
|
|
@@ -45,7 +47,7 @@ export declare function refusedNavigationOutcome(state: {
|
|
|
45
47
|
export interface CardEndpointStoppedPageInput {
|
|
46
48
|
outcome: CardEndpointStoppedOutcome;
|
|
47
49
|
reason: CardEndpointStoppedReason;
|
|
48
|
-
/** The profile's own merchant name (never the integrator's or the page's). */
|
|
50
|
+
/** The profile's own merchant name, or CyberSource for a Secure Acceptance post (never the integrator's or the page's). */
|
|
49
51
|
merchant: string;
|
|
50
52
|
/** The authorization, once one exists. */
|
|
51
53
|
authorizationId?: string | null;
|
package/dist/cdp.js
CHANGED
|
@@ -13,6 +13,7 @@ import { DatatransRepeats } from './datatrans.js';
|
|
|
13
13
|
import { SHIJI_STS_COMPANION_WINDOW_MS, ShijiStsCompanions, ShijiStsError, isShijiStsHost, shijiStsTokenContinuation, } from './shiji-sts.js';
|
|
14
14
|
import { isArmedEkashuUrl } from './ekashu.js';
|
|
15
15
|
import { PAYPAL_HOSTED_FIELDS_PATTERNS, isPaypalHostedFieldsConfirm } from './paypal-hosted-fields.js';
|
|
16
|
+
import { CYBERSOURCE_SECURE_ACCEPTANCE_PATTERNS, isCybersourceSecureAcceptanceUrl } from './cybersource-secure-acceptance.js';
|
|
16
17
|
import { CheckoutAttachmentError, attachmentDeadline, attachmentFailure, withinAttachmentDeadline } from './attachment.js';
|
|
17
18
|
import { cseBody } from './cse-body.js';
|
|
18
19
|
import { STRIPE_SETUP_INTENT_CONFIRM, setupConfirmPayingWith } from './stripe-setup.js';
|
|
@@ -1913,10 +1914,12 @@ export async function attachToCdp(cdp, pageSessionId, opts) {
|
|
|
1913
1914
|
// PayPal's legacy Hosted Fields confirm is armed for every org, whatever the
|
|
1914
1915
|
// registry serves: one that carries the typed card is paused only to be
|
|
1915
1916
|
// refused, and one with no card continues (see paypal-hosted-fields.ts).
|
|
1917
|
+
// CyberSource Secure Acceptance's /silent/ paths are armed the same way, form
|
|
1918
|
+
// navigations included (see cybersource-secure-acceptance.ts).
|
|
1916
1919
|
const urlPatterns = [...new Set([...(derived.length > 0 ? derived : FALLBACK_CARD_PATTERNS), ...guards.patterns,
|
|
1917
1920
|
...(stripeCheckout.isEnabled() ? ['https://api.stripe.com/*'] : []), MERCADO_CHECKOUT_PATTERN, ...merchantPatterns,
|
|
1918
1921
|
...(recognizesGmo(opts.vault) ? GMO_TOKEN_V1_PATTERNS : []), ...juspayCheckout.urlPatterns(), ...cardEndpointPatterns(),
|
|
1919
|
-
...(payrails ? PAYRAILS_GUARD_PATTERNS : []), ...PAYPAL_HOSTED_FIELDS_PATTERNS])];
|
|
1922
|
+
...(payrails ? PAYRAILS_GUARD_PATTERNS : []), ...PAYPAL_HOSTED_FIELDS_PATTERNS, ...CYBERSOURCE_SECURE_ACCEPTANCE_PATTERNS])];
|
|
1920
1923
|
const arm = async (sessionId, resume = false, worker = false) => {
|
|
1921
1924
|
const key = sessionId ?? '__root__';
|
|
1922
1925
|
if (armed.has(key))
|
|
@@ -3189,7 +3192,9 @@ export async function attachToPlaywright(page, opts) {
|
|
|
3189
3192
|
// host: the card page's post and its 3-D Secure calls reach the NMI gate and fail.
|
|
3190
3193
|
|| isArmedEkashuUrl(opts.vault, url.toString())
|
|
3191
3194
|
// PayPal's legacy Hosted Fields confirm, for every org, as attachToCdp arms it (paypal-hosted-fields.ts).
|
|
3192
|
-
|| isPaypalHostedFieldsConfirm(url.toString())
|
|
3195
|
+
|| isPaypalHostedFieldsConfirm(url.toString())
|
|
3196
|
+
// CyberSource Secure Acceptance's /silent/ paths, for every org, as attachToCdp arms them (cybersource-secure-acceptance.ts).
|
|
3197
|
+
|| isCybersourceSecureAcceptanceUrl(url.toString()), async (route) => {
|
|
3193
3198
|
const request = route.request();
|
|
3194
3199
|
// When this request paused, and the page it came from: the merchant's total is read as of now.
|
|
3195
3200
|
const pausedAt = Date.now();
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CyberSource Secure Acceptance's Silent Order POST, which this SDK refuses for every company.
|
|
3
|
+
*
|
|
4
|
+
* CyberSource's Secure Acceptance Checkout API, formerly Silent Order POST, takes the card from a form
|
|
5
|
+
* on the merchant's own page. The merchant's server signs the order fields, and the shopper's browser
|
|
6
|
+
* posts them, with the card fields left unsigned, to a /silent/ path on one of CyberSource's Secure
|
|
7
|
+
* Acceptance hosts: /silent/pay, /silent/token/create, /silent/token/update, and the iframe form of
|
|
8
|
+
* each under /silent/embedded/ (CyberSource's endpoint table, read 2026-10-08). Arrow Electronics'
|
|
9
|
+
* checkout (its public bundles, read 2026-10-08; no card was sent) builds that form once its server
|
|
10
|
+
* has signed the fields and submits it into a hidden iframe:
|
|
11
|
+
*
|
|
12
|
+
* <iframe name="secureAcceptanceiFrame" style="display:none">
|
|
13
|
+
* <form action="https://secureacceptance.cybersource.com/silent/embedded/token/create" method="post"
|
|
14
|
+
* target="secureAcceptanceiFrame">: access_key, profile_id, transaction_type=create_payment_token,
|
|
15
|
+
* amount=0 and the other signed fields with their signature, then card_type, card_number,
|
|
16
|
+
* card_expiry_date (MM-YYYY) and card_cvn
|
|
17
|
+
*
|
|
18
|
+
* No Vault mode takes this post over, so no company can pay it, and an SDK without this guard let the
|
|
19
|
+
* card the agent typed reach CyberSource. Both adapters arm /silent/ on the three hosts whatever the
|
|
20
|
+
* synced registry serves, over https and http, each host also spelled with the trailing dot of a fully
|
|
21
|
+
* qualified name, and the pre-claim gate (cybersourceSecureAcceptancePreClaim, pre-claim.ts) judges
|
|
22
|
+
* each request there, whether a fetch, an XHR or a form navigation of the page or of a frame sent it,
|
|
23
|
+
* by its body and by its URL's query (cybersourceSecureAcceptanceRequest):
|
|
24
|
+
* - a card_number that holds a value: stop it, so CyberSource never receives the card. A form
|
|
25
|
+
* navigation is answered with the stopped page (card-endpoint-page.ts), which names CyberSource,
|
|
26
|
+
* since an aborted page load renders nothing and invites another click on Pay; any other request
|
|
27
|
+
* fails. The checkout reads `unsupported` with reason `unsupported_cybersource_secure_acceptance`
|
|
28
|
+
* and holds, as every unsupported refusal does;
|
|
29
|
+
* - no card_number, or an empty one, as in a payment with a stored payment_token: continue untouched;
|
|
30
|
+
* - a body the adapter could not read: stop that request alone, since nothing proves it carries no card.
|
|
31
|
+
* A request the synced registry recognizes as a card request belongs to that recognizer instead; no
|
|
32
|
+
* build serves one today. Hosted Checkout, the same hosts without /silent/, takes the card on
|
|
33
|
+
* CyberSource's own page, and neither adapter arms it.
|
|
34
|
+
*/
|
|
35
|
+
export declare const CYBERSOURCE_SECURE_ACCEPTANCE_REASON: "unsupported_cybersource_secure_acceptance";
|
|
36
|
+
/** Where the stopped page says the card was going. */
|
|
37
|
+
export declare const CYBERSOURCE_SECURE_ACCEPTANCE_RECIPIENT = "CyberSource";
|
|
38
|
+
/** CyberSource's Secure Acceptance hosts: production, test, and production in India. */
|
|
39
|
+
export declare const CYBERSOURCE_SECURE_ACCEPTANCE_HOSTS: readonly string[];
|
|
40
|
+
/**
|
|
41
|
+
* CDP Fetch patterns for every /silent/ path on the three hosts, armed on every attachment, over https
|
|
42
|
+
* and over http, each host also with its trailing dot: Chrome sends a URL spelled either way unchanged,
|
|
43
|
+
* and DNS reads both spellings as the same host, so a page's form posted to either reaches CyberSource.
|
|
44
|
+
* The * before silent/ also pauses a path that doubles its slash, as a base URL that ends in a slash
|
|
45
|
+
* joined to /silent/pay writes it, which a server that merges slashes reads as /silent/pay. The gate
|
|
46
|
+
* judges each path with its slashes merged (isCybersourceSecureAcceptanceUrl), and anything else the *
|
|
47
|
+
* pauses, such as /billing/silent/pay, continues untouched. A pattern matches the canonical URL Chrome
|
|
48
|
+
* sends, whose host is lower case and whose standard port is dropped; no URL without silent/ is armed.
|
|
49
|
+
*/
|
|
50
|
+
export declare const CYBERSOURCE_SECURE_ACCEPTANCE_PATTERNS: readonly string[];
|
|
51
|
+
/**
|
|
52
|
+
* Whether this URL is a /silent/ path on one of the three hosts: https or http, the host with or without
|
|
53
|
+
* its trailing dot, on the scheme's standard port, with no credentials, and its path read with each run
|
|
54
|
+
* of slashes merged into one, as a server that merges slashes reads it.
|
|
55
|
+
*/
|
|
56
|
+
export declare function isCybersourceSecureAcceptanceUrl(url: string): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* What a request to a /silent/ path carries: 'card' when card_number holds a value in the URL's query,
|
|
59
|
+
* on any method, since a form whose method is GET puts its fields there; otherwise the body's verdict
|
|
60
|
+
* (cybersourceSecureAcceptanceBody) for a method that sends one, and 'no_card' for a GET, a HEAD or a
|
|
61
|
+
* CORS preflight.
|
|
62
|
+
*/
|
|
63
|
+
export declare function cybersourceSecureAcceptanceRequest(url: string, method: string, body: string | null, contentType?: string): 'card' | 'no_card' | 'unreadable';
|
|
64
|
+
/**
|
|
65
|
+
* What a Silent Order POST's body carries: 'card' when any reading of it finds a field named card_number
|
|
66
|
+
* that holds a value, 'no_card' when none does, and 'unreadable' for a body the adapter could not read
|
|
67
|
+
* (null), or a multipart body whose parts cannot be read and in which no reading finds a card, a
|
|
68
|
+
* multipart content type with no boundary included.
|
|
69
|
+
*
|
|
70
|
+
* The page writes both the bytes and their content type, and a server reads the bytes by that type, so
|
|
71
|
+
* the gate trusts no one reading. It reads every body as URL-encoded pairs (split on & and line by line,
|
|
72
|
+
* which also reads a plain-text form's name=value lines), as JSON at any depth, and as a multipart form:
|
|
73
|
+
* by its parts, when its content type names a boundary or it opens with a delimiter line and a part
|
|
74
|
+
* header, and by every part header that names card_number, wherever it sits. A card in any reading stops
|
|
75
|
+
* the post, so a body whose content type names one encoding and whose bytes hold another, a URL-encoded
|
|
76
|
+
* body that also parses as JSON, say, cannot carry the card past the gate.
|
|
77
|
+
*/
|
|
78
|
+
export declare function cybersourceSecureAcceptanceBody(body: string | null, contentType?: string): 'card' | 'no_card' | 'unreadable';
|