@agent-cards/checkout 0.19.0 → 0.21.0
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/README.md +6 -753
- package/cdp.d.ts +1 -0
- package/cdp.js +2 -0
- package/index.d.ts +1 -0
- package/index.js +2 -0
- package/package.json +33 -33
- package/playwright.d.ts +1 -0
- package/playwright.js +2 -0
- package/preflight.d.ts +1 -0
- package/preflight.js +2 -0
- package/CHANGELOG.md +0 -132
- package/PREFLIGHT.md +0 -312
- package/dist/adyen-merchant-hosted.generated.d.ts +0 -277
- package/dist/adyen-merchant-hosted.generated.js +0 -1902
- package/dist/adyen.generated.d.ts +0 -24
- package/dist/adyen.generated.js +0 -64
- package/dist/attachment.d.ts +0 -11
- package/dist/attachment.js +0 -50
- package/dist/braintree.d.ts +0 -2
- package/dist/braintree.generated.d.ts +0 -10
- package/dist/braintree.generated.js +0 -302
- package/dist/braintree.js +0 -2
- package/dist/builtin-registry.generated.d.ts +0 -2
- package/dist/builtin-registry.generated.js +0 -1
- package/dist/card-fields.generated.d.ts +0 -3
- package/dist/card-fields.generated.js +0 -46
- package/dist/cdp.d.ts +0 -192
- package/dist/cdp.js +0 -2393
- package/dist/checkout-com.generated.d.ts +0 -4
- package/dist/checkout-com.generated.js +0 -183
- package/dist/client.d.ts +0 -849
- package/dist/client.js +0 -1754
- package/dist/cse-body.d.ts +0 -25
- package/dist/cse-body.js +0 -41
- package/dist/fiserv.d.ts +0 -65
- package/dist/fiserv.generated.d.ts +0 -73
- package/dist/fiserv.generated.js +0 -830
- package/dist/fiserv.js +0 -104
- package/dist/hosted-form.d.ts +0 -44
- package/dist/hosted-form.js +0 -78
- package/dist/index.d.ts +0 -18
- package/dist/index.js +0 -10
- package/dist/lifecycle.d.ts +0 -179
- package/dist/lifecycle.js +0 -395
- package/dist/mercado-checkout.d.ts +0 -20
- package/dist/mercado-checkout.generated.d.ts +0 -52
- package/dist/mercado-checkout.generated.js +0 -198
- package/dist/mercado-checkout.js +0 -108
- package/dist/merchant-handoff.d.ts +0 -54
- package/dist/merchant-handoff.js +0 -100
- package/dist/merchant-hosted.d.ts +0 -140
- package/dist/merchant-hosted.js +0 -170
- package/dist/merchant-total-watch.d.ts +0 -115
- package/dist/merchant-total-watch.js +0 -268
- package/dist/merchant-total.d.ts +0 -257
- package/dist/merchant-total.js +0 -383
- package/dist/owned-shop.generated.d.ts +0 -24
- package/dist/owned-shop.generated.js +0 -108
- package/dist/paysafe.generated.d.ts +0 -12
- package/dist/paysafe.generated.js +0 -87
- package/dist/playwright.d.ts +0 -3
- package/dist/playwright.js +0 -3
- package/dist/pre-claim.d.ts +0 -123
- package/dist/pre-claim.js +0 -386
- package/dist/preflight-capabilities.generated.d.ts +0 -1253
- package/dist/preflight-capabilities.generated.js +0 -1929
- package/dist/preflight-catalog.json +0 -4727
- package/dist/preflight-playwright.d.ts +0 -34
- package/dist/preflight-playwright.js +0 -355
- package/dist/preflight-schemas.json +0 -1122
- package/dist/preflight.d.ts +0 -1
- package/dist/preflight.generated.d.ts +0 -1965
- package/dist/preflight.generated.js +0 -570
- package/dist/preflight.js +0 -2
- package/dist/preparation.d.ts +0 -38
- package/dist/preparation.js +0 -191
- package/dist/prepared-processor.d.ts +0 -43
- package/dist/prepared-processor.js +0 -172
- package/dist/recurly.generated.d.ts +0 -1
- package/dist/recurly.generated.js +0 -87
- package/dist/registry.d.ts +0 -121
- package/dist/registry.js +0 -310
- package/dist/spreedly.generated.d.ts +0 -10
- package/dist/spreedly.generated.js +0 -332
- package/dist/stripe-checkout.d.ts +0 -81
- package/dist/stripe-checkout.generated.d.ts +0 -82
- package/dist/stripe-checkout.generated.js +0 -1093
- package/dist/stripe-checkout.js +0 -140
- package/dist/substitute.d.ts +0 -38
- package/dist/substitute.js +0 -23
- package/dist/substitutions.generated.d.ts +0 -11
- package/dist/substitutions.generated.js +0 -818
- package/examples/existing-browser.mjs +0 -63
- package/examples/preflight/classify-direct.mjs +0 -21
- package/examples/preflight/classify-kernel.mjs +0 -30
- package/examples/preflight/inspect-browser.mjs +0 -44
- package/examples/preflight/kernel-native/README.md +0 -112
- package/examples/preflight/kernel-native/documented-adapters.json +0 -113
- package/examples/preflight/kernel-native/inventory.json +0 -233
- package/examples/preflight/kernel-native/qualification.mjs +0 -182
- package/examples/preflight/kernel-profile.empty.json +0 -11
- package/examples/preflight/mollie-hosted.observations.json +0 -23
- package/examples/preflight/mollie-hosted.result.json +0 -103
- package/examples/preflight/stripe-script.direct.result.json +0 -92
- package/examples/preflight/stripe-script.observations.json +0 -16
- package/examples/preflight/stripe-script.result.json +0 -87
|
@@ -1,570 +0,0 @@
|
|
|
1
|
-
// Generated from @agent-cards/payment-core. Do not edit.
|
|
2
|
-
// source-sha256: 7c76900599ba4ac29a8d1ca541170591ddae58d35c78560e5d37562e0050534a
|
|
3
|
-
import { CHECKOUT_PREFLIGHT_CAPABILITIES } from './preflight-capabilities.generated.js';
|
|
4
|
-
/** Advisory page discovery. These rules never admit a payment destination. */
|
|
5
|
-
export const CHECKOUT_PREFLIGHT_VERSION = '1';
|
|
6
|
-
export const CHECKOUT_PREFLIGHT_CATALOG_VERSION = '2026-09-15.1';
|
|
7
|
-
// `url_length` bounds the origin and path that discovery matches. `raw_url_length` bounds the
|
|
8
|
-
// observed location including its query, which never takes part in matching or evidence.
|
|
9
|
-
export const CHECKOUT_PREFLIGHT_LIMITS = Object.freeze({ frames: 64, signals: 2048, snapshot_bytes: 262144, url_length: 4096, raw_url_length: 65536 });
|
|
10
|
-
// Identification-only IDs, checked against the canonical catalog by the core tests.
|
|
11
|
-
// No card destination, request method, or request body pattern lives here.
|
|
12
|
-
const KNOWN_PSPS = CHECKOUT_PREFLIGHT_CAPABILITIES.processors.map(processor => processor.psp);
|
|
13
|
-
const PROCESSOR_BY_ID = new Map(CHECKOUT_PREFLIGHT_CAPABILITIES.processors.map(processor => [processor.psp, processor]));
|
|
14
|
-
const KINDS = ['document', 'frame', 'script', 'iframe', 'form'];
|
|
15
|
-
const SCENARIOS = ['one_time', 'save_card', 'subscription_initial', 'subscription_renewal'];
|
|
16
|
-
const OBSERVATION_REASONS = ['collection_timeout', 'frame_limit', 'signal_limit', 'snapshot_limit', 'frame_unavailable', 'navigation_changed', 'invalid_observation', 'invalid_url', 'card_entry_unrecognized', 'collection_incomplete'];
|
|
17
|
-
const RULES = [
|
|
18
|
-
{ id: 'stripe-js-v3', psp: 'stripe', kinds: ['script', 'frame', 'iframe'], hostname: /^js\.stripe\.com$/, pathname: /^\/v3(?:\/|$)/, origin: 'https://js.stripe.com', path_pattern: '/v3/*' },
|
|
19
|
-
{ id: 'square-web-sdk', psp: 'square', kinds: ['script', 'frame', 'iframe'], hostname: /^web\.squarecdn\.com$/, pathname: /^\/v1\/square\.js$/, origin: 'https://web.squarecdn.com', path_pattern: '/v1/square.js' },
|
|
20
|
-
{ id: 'mollie-components-script', psp: 'mollie', kinds: ['script'], hostname: /^js\.mollie\.com$/, pathname: /^\/v2\/mollie\.js$/, origin: 'https://js.mollie.com', path_pattern: '/v2/mollie.js' },
|
|
21
|
-
{ id: 'mollie-components-v1-script', psp: 'mollie', kinds: ['script'], hostname: /^js\.mollie\.com$/, pathname: /^\/v1\/mollie\.js$/, origin: 'https://js.mollie.com', path_pattern: '/v1/mollie.js' },
|
|
22
|
-
{ id: 'mollie-hosted-credit-card', psp: 'mollie', kinds: ['document', 'frame', 'iframe'], hostname: /^www\.mollie\.com$/, pathname: /^\/checkout\/credit-card\/session\/[A-Za-z0-9_-]+\/?$/, origin: 'https://www.mollie.com', path_pattern: '/checkout/credit-card/session/:session', flow: 'mollie.hosted_components' },
|
|
23
|
-
{ id: 'braintree-web-sdk', psp: 'braintree', kinds: ['script'], hostname: /^js\.braintreegateway\.com$/, pathname: /^\/web\/[^/]+\/js\//, origin: 'https://js.braintreegateway.com', path_pattern: '/web/:version/js/*' },
|
|
24
|
-
{ id: 'braintree-hosted-fields', psp: 'braintree', kinds: ['frame', 'iframe'], hostname: /^assets\.braintreegateway\.com$/, pathname: /^\/web\//, origin: 'https://assets.braintreegateway.com', path_pattern: '/web/*' },
|
|
25
|
-
{ 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}/*' },
|
|
26
|
-
{ 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/*' },
|
|
27
|
-
{ id: 'authorize-net-accept', psp: 'authorize_net', kinds: ['script'], hostname: /^js\.authorize\.net$/, pathname: /^\/v[13]\/Accept(?:UI)?\.js$/, origin: 'https://js.authorize.net', path_pattern: '/v{1,3}/Accept{UI}.js' },
|
|
28
|
-
{ id: 'razorpay-checkout-script', psp: 'razorpay', kinds: ['script'], hostname: /^checkout\.razorpay\.com$/, pathname: /^\/v1\/checkout\.js$/, origin: 'https://checkout.razorpay.com', path_pattern: '/v1/checkout.js' },
|
|
29
|
-
{ id: 'vgs-collect-script', psp: 'vgs', kinds: ['script'], hostname: /^js\.verygoodvault\.com$/, pathname: /^\/vgs-collect\//, origin: 'https://js.verygoodvault.com', path_pattern: '/vgs-collect/*' },
|
|
30
|
-
{ id: 'vgs-collect-frame', psp: 'vgs', kinds: ['frame', 'iframe'], hostname: /^[a-z0-9-]+\.(?:live|sandbox)\.verygoodproxy\.com$/, pathname: /^\//, origin: 'https://:tenant.:environment.verygoodproxy.com', path_pattern: '/*' },
|
|
31
|
-
];
|
|
32
|
-
// SDK/page fingerprints identify implemented processor families, not an active payment operation.
|
|
33
|
-
RULES.push({ "id": "checkout-frames-v2-script", "psp": "checkout_com", "kinds": ["script"], "origin": "https://cdn.checkout.com", "path_pattern": "^/js/framesv2\\.min\\.js$", "sources": [{ "kind": "primary_source", "reference": "https://checkoutdocs.readme.io/docs/frames-reference", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://cdn.checkout.com/js/framesv2.min.js", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^cdn\\.checkout\\.com$"), pathname: new RegExp("^/js/framesv2\\.min\\.js$") }, { "id": "adyen-web-legacy-live", "psp": "adyen", "kinds": ["script"], "origin": "https://checkoutshopper-live.adyen.com", "path_pattern": "^/checkoutshopper/sdk/[0-9]+\\.[0-9]+\\.[0-9]+/adyen\\.js$", "sources": [{ "kind": "primary_source", "reference": "https://docs.adyen.com/online-payments/web-best-practices/", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^checkoutshopper\\-live\\.adyen\\.com$"), pathname: new RegExp("^/checkoutshopper/sdk/[0-9]+\\.[0-9]+\\.[0-9]+/adyen\\.js$") }, { "id": "adyen-secured-fields-live", "psp": "adyen", "kinds": ["frame", "iframe", "document"], "origin": "https://checkoutshopper-live.adyen.com", "path_pattern": "^/checkoutshopper/securedfields/[^/]+/[0-9]+\\.[0-9]+\\.[0-9]+/securedFields\\.html$", "sources": [{ "kind": "primary_source", "reference": "https://checkoutshopper-live.cdn.adyen.com/checkoutshopper/sdk/6.11.0/adyen.js", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://docs.adyen.com/development-resources/live-endpoints/", "reviewed_on": "2026-09-15" }, { "kind": "partner_observation", "reference": "kernel-discovery-2026-09-14:adyen-secured-fields-4.9.0-live-us", "reviewed_on": "2026-09-15" }], hostname: new RegExp("^checkoutshopper\\-live\\.adyen\\.com$"), pathname: new RegExp("^/checkoutshopper/securedfields/[^/]+/[0-9]+\\.[0-9]+\\.[0-9]+/securedFields\\.html$") }, { "id": "adyen-web-legacy-test", "psp": "adyen", "kinds": ["script"], "origin": "https://checkoutshopper-test.adyen.com", "path_pattern": "^/checkoutshopper/sdk/[0-9]+\\.[0-9]+\\.[0-9]+/adyen\\.js$", "sources": [{ "kind": "primary_source", "reference": "https://docs.adyen.com/online-payments/web-best-practices/", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^checkoutshopper\\-test\\.adyen\\.com$"), pathname: new RegExp("^/checkoutshopper/sdk/[0-9]+\\.[0-9]+\\.[0-9]+/adyen\\.js$") }, { "id": "adyen-secured-fields-test", "psp": "adyen", "kinds": ["frame", "iframe", "document"], "origin": "https://checkoutshopper-test.adyen.com", "path_pattern": "^/checkoutshopper/securedfields/[^/]+/[0-9]+\\.[0-9]+\\.[0-9]+/securedFields\\.html$", "sources": [{ "kind": "primary_source", "reference": "https://checkoutshopper-live.cdn.adyen.com/checkoutshopper/sdk/6.11.0/adyen.js", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://docs.adyen.com/development-resources/live-endpoints/", "reviewed_on": "2026-09-15" }], hostname: new RegExp("^checkoutshopper\\-test\\.adyen\\.com$"), pathname: new RegExp("^/checkoutshopper/securedfields/[^/]+/[0-9]+\\.[0-9]+\\.[0-9]+/securedFields\\.html$") }, { "id": "stripe-js-named", "psp": "stripe", "kinds": ["script"], "origin": "https://js.stripe.com", "path_pattern": "^/(?:acacia|basil|clover|dahlia)/stripe\\.js$", "sources": [{ "kind": "primary_source", "reference": "https://docs.stripe.com/sdks/stripejs-versioning", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://docs.stripe.com/sdks/stripejs-versioning?locale=en-GB", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://docs.stripe.com/checkout/elements-with-checkout-sessions-api/changelog?locale=en-GB", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^js\\.stripe\\.com$"), pathname: new RegExp("^/(?:acacia|basil|clover|dahlia)/stripe\\.js$") }, { "id": "shopify-card-fields-script", "psp": "shopify", "kinds": ["script"], "origin": "https://checkout.pci.shopifyinc.com", "path_pattern": "^/build/[a-f0-9]+/card_fields\\.js$", "sources": [{ "kind": "primary_source", "reference": "https://checkout.pci.shopifyinc.com/build/04ed4e1/card_fields.js", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^checkout\\.pci\\.shopifyinc\\.com$"), pathname: new RegExp("^/build/[a-f0-9]+/card_fields\\.js$") }, { "id": "shopify-card-number-frame", "psp": "shopify", "kinds": ["frame", "iframe", "document"], "origin": "https://checkout.pci.shopifyinc.com", "path_pattern": "^/build/[a-f0-9]+/number-(?:ltr|rtl)\\.html$", "sources": [{ "kind": "primary_source", "reference": "https://checkout.pci.shopifyinc.com/build/04ed4e1/card_fields.js", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^checkout\\.pci\\.shopifyinc\\.com$"), pathname: new RegExp("^/build/[a-f0-9]+/number-(?:ltr|rtl)\\.html$") }, { "id": "shopify-card-fields-legacy-script", "psp": "shopify", "kinds": ["script"], "origin": "https://checkout.shopifycs.com", "path_pattern": "^/dist/card_fields\\.js$", "sources": [{ "kind": "primary_source", "reference": "https://checkout.shopifycs.com/dist/card_fields.js", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^checkout\\.shopifycs\\.com$"), pathname: new RegExp("^/dist/card_fields\\.js$") }, { "id": "stripe-js-script", "psp": "stripe", "kinds": ["script"], "origin": "https://js.stripe.com", "path_pattern": "^/v3/?$", "sources": [{ "kind": "primary_source", "reference": "https://docs.stripe.com/js/including", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^js\\.stripe\\.com$"), pathname: new RegExp("^/v3/?$") }, { "id": "braintree-dropin-script", "psp": "braintree", "kinds": ["script"], "origin": "https://js.braintreegateway.com", "path_pattern": "^/web/dropin/[0-9]+\\.[0-9]+\\.[0-9]+/js/dropin(?:\\.min)?\\.js$", "sources": [{ "kind": "primary_source", "reference": "https://developer.paypal.com/braintree/docs/start/hello-client/javascript/v3/", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^js\\.braintreegateway\\.com$"), pathname: new RegExp("^/web/dropin/[0-9]+\\.[0-9]+\\.[0-9]+/js/dropin(?:\\.min)?\\.js$") }, { "id": "checkout-flow-script", "psp": "checkout_com", "kinds": ["script"], "origin": "https://checkout-web-components.checkout.com", "path_pattern": "^/index\\.js$", "sources": [{ "kind": "primary_source", "reference": "https://www.checkout.com/docs/get-started", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://checkout-web-components.checkout.com/index.js", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^checkout\\-web\\-components\\.checkout\\.com$"), pathname: new RegExp("^/index\\.js$") }, { "id": "checkout-flow-frame", "psp": "checkout_com", "kinds": ["frame", "iframe", "document"], "origin": "https://checkout-web-components.checkout.com", "path_pattern": "^/pages/[0-9]+\\.[0-9]+\\.[0-9]+/index\\.html$", "sources": [{ "kind": "primary_source", "reference": "https://checkout-web-components.checkout.com/index.js", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^checkout\\-web\\-components\\.checkout\\.com$"), pathname: new RegExp("^/pages/[0-9]+\\.[0-9]+\\.[0-9]+/index\\.html$") }, { "id": "adyen-web-script", "psp": "adyen", "kinds": ["script"], "origin": "https://checkoutshopper-live.cdn.adyen.com", "path_pattern": "^/checkoutshopper/sdk/[0-9]+\\.[0-9]+\\.[0-9]+/adyen\\.js$", "sources": [{ "kind": "primary_source", "reference": "https://docs.adyen.com/standard/integration/drop-in/best-practices", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://docs.adyen.com/online-payments/build-your-integration/sessions-flow/", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^checkoutshopper\\-live\\.cdn\\.adyen\\.com$"), pathname: new RegExp("^/checkoutshopper/sdk/[0-9]+\\.[0-9]+\\.[0-9]+/adyen\\.js$") }, { "id": "adyen-web-script-host-2", "psp": "adyen", "kinds": ["script"], "origin": "https://checkoutshopper-test.cdn.adyen.com", "path_pattern": "^/checkoutshopper/sdk/[0-9]+\\.[0-9]+\\.[0-9]+/adyen\\.js$", "sources": [{ "kind": "primary_source", "reference": "https://docs.adyen.com/standard/integration/drop-in/best-practices", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://docs.adyen.com/online-payments/build-your-integration/sessions-flow/", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^checkoutshopper\\-test\\.cdn\\.adyen\\.com$"), pathname: new RegExp("^/checkoutshopper/sdk/[0-9]+\\.[0-9]+\\.[0-9]+/adyen\\.js$") }, { "id": "adyen-web-script-host-3", "psp": "adyen", "kinds": ["script"], "origin": "https://checkoutshopper-live-us.cdn.adyen.com", "path_pattern": "^/checkoutshopper/sdk/[0-9]+\\.[0-9]+\\.[0-9]+/adyen\\.js$", "sources": [{ "kind": "primary_source", "reference": "https://docs.adyen.com/standard/integration/drop-in/best-practices", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://docs.adyen.com/online-payments/build-your-integration/sessions-flow/", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^checkoutshopper\\-live\\-us\\.cdn\\.adyen\\.com$"), pathname: new RegExp("^/checkoutshopper/sdk/[0-9]+\\.[0-9]+\\.[0-9]+/adyen\\.js$") }, { "id": "adyen-web-script-host-4", "psp": "adyen", "kinds": ["script"], "origin": "https://checkoutshopper-live-au.cdn.adyen.com", "path_pattern": "^/checkoutshopper/sdk/[0-9]+\\.[0-9]+\\.[0-9]+/adyen\\.js$", "sources": [{ "kind": "primary_source", "reference": "https://docs.adyen.com/standard/integration/drop-in/best-practices", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://docs.adyen.com/online-payments/build-your-integration/sessions-flow/", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^checkoutshopper\\-live\\-au\\.cdn\\.adyen\\.com$"), pathname: new RegExp("^/checkoutshopper/sdk/[0-9]+\\.[0-9]+\\.[0-9]+/adyen\\.js$") }, { "id": "adyen-web-script-host-5", "psp": "adyen", "kinds": ["script"], "origin": "https://checkoutshopper-live-nea.cdn.adyen.com", "path_pattern": "^/checkoutshopper/sdk/[0-9]+\\.[0-9]+\\.[0-9]+/adyen\\.js$", "sources": [{ "kind": "primary_source", "reference": "https://docs.adyen.com/standard/integration/drop-in/best-practices", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://docs.adyen.com/online-payments/build-your-integration/sessions-flow/", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^checkoutshopper\\-live\\-nea\\.cdn\\.adyen\\.com$"), pathname: new RegExp("^/checkoutshopper/sdk/[0-9]+\\.[0-9]+\\.[0-9]+/adyen\\.js$") }, { "id": "adyen-web-script-host-6", "psp": "adyen", "kinds": ["script"], "origin": "https://checkoutshopper-live-in.cdn.adyen.com", "path_pattern": "^/checkoutshopper/sdk/[0-9]+\\.[0-9]+\\.[0-9]+/adyen\\.js$", "sources": [{ "kind": "primary_source", "reference": "https://docs.adyen.com/standard/integration/drop-in/best-practices", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://docs.adyen.com/online-payments/build-your-integration/sessions-flow/", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^checkoutshopper\\-live\\-in\\.cdn\\.adyen\\.com$"), pathname: new RegExp("^/checkoutshopper/sdk/[0-9]+\\.[0-9]+\\.[0-9]+/adyen\\.js$") }, { "id": "tranzila-hosted-page", "psp": "tranzila", "kinds": ["frame", "iframe", "document", "form"], "origin": "https://direct.tranzila.com", "path_pattern": "^/[A-Za-z0-9_-]+/iframenew\\.php$", "sources": [{ "kind": "primary_source", "reference": "https://docs.tranzila.com/docs/payments-and-billing/iframe-integration", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://docs.tranzila.com/docs/payments-and-billing/iframe-integration-directng", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://docs.tranzila.com/docs/emv-pinpad/emv-iframe-integration", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^direct\\.tranzila\\.com$"), pathname: new RegExp("^/[A-Za-z0-9_-]+/iframenew\\.php$") }, { "id": "tranzila-hosted-page-host-2", "psp": "tranzila", "kinds": ["frame", "iframe", "document", "form"], "origin": "https://directng.tranzila.com", "path_pattern": "^/[A-Za-z0-9_-]+/iframenew\\.php$", "sources": [{ "kind": "primary_source", "reference": "https://docs.tranzila.com/docs/payments-and-billing/iframe-integration", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://docs.tranzila.com/docs/payments-and-billing/iframe-integration-directng", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://docs.tranzila.com/docs/emv-pinpad/emv-iframe-integration", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^directng\\.tranzila\\.com$"), pathname: new RegExp("^/[A-Za-z0-9_-]+/iframenew\\.php$") }, { "id": "square-web-script", "psp": "square", "kinds": ["script"], "origin": "https://web.squarecdn.com", "path_pattern": "^/v1/square\\.js$", "sources": [{ "kind": "primary_source", "reference": "https://developer.squareup.com/docs/web-payments/quickstart/add-sdk-to-web-client", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^web\\.squarecdn\\.com$"), pathname: new RegExp("^/v1/square\\.js$") }, { "id": "square-web-script-host-2", "psp": "square", "kinds": ["script"], "origin": "https://sandbox.web.squarecdn.com", "path_pattern": "^/v1/square\\.js$", "sources": [{ "kind": "primary_source", "reference": "https://developer.squareup.com/docs/web-payments/quickstart/add-sdk-to-web-client", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^sandbox\\.web\\.squarecdn\\.com$"), pathname: new RegExp("^/v1/square\\.js$") }, { "id": "authorize-net-accept-script", "psp": "authorize_net", "kinds": ["script"], "origin": "https://js.authorize.net", "path_pattern": "^/v1/Accept\\.js$", "sources": [{ "kind": "primary_source", "reference": "https://developer.authorize.net/api/reference/features/acceptjs.html", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^js\\.authorize\\.net$"), pathname: new RegExp("^/v1/Accept\\.js$") }, { "id": "authorize-net-accept-script-host-2", "psp": "authorize_net", "kinds": ["script"], "origin": "https://jstest.authorize.net", "path_pattern": "^/v1/Accept\\.js$", "sources": [{ "kind": "primary_source", "reference": "https://developer.authorize.net/api/reference/features/acceptjs.html", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^jstest\\.authorize\\.net$"), pathname: new RegExp("^/v1/Accept\\.js$") }, { "id": "authorize-net-acceptui-script", "psp": "authorize_net", "kinds": ["script"], "origin": "https://js.authorize.net", "path_pattern": "^/v3/AcceptUI\\.js$", "sources": [{ "kind": "primary_source", "reference": "https://developer.authorize.net/api/reference/features/acceptjs.html", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^js\\.authorize\\.net$"), pathname: new RegExp("^/v3/AcceptUI\\.js$") }, { "id": "authorize-net-acceptui-script-host-2", "psp": "authorize_net", "kinds": ["script"], "origin": "https://jstest.authorize.net", "path_pattern": "^/v3/AcceptUI\\.js$", "sources": [{ "kind": "primary_source", "reference": "https://developer.authorize.net/api/reference/features/acceptjs.html", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^jstest\\.authorize\\.net$"), pathname: new RegExp("^/v3/AcceptUI\\.js$") }, { "id": "worldpay-checkout-script", "psp": "worldpay", "kinds": ["script"], "origin": "https://access.worldpay.com", "path_pattern": "^/access-checkout/v2/checkout\\.js$", "sources": [{ "kind": "primary_source", "reference": "https://docs.worldpay.com/access/products/checkout/web", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^access\\.worldpay\\.com$"), pathname: new RegExp("^/access-checkout/v2/checkout\\.js$") }, { "id": "worldpay-checkout-script-host-2", "psp": "worldpay", "kinds": ["script"], "origin": "https://try.access.worldpay.com", "path_pattern": "^/access-checkout/v2/checkout\\.js$", "sources": [{ "kind": "primary_source", "reference": "https://docs.worldpay.com/access/products/checkout/web", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^try\\.access\\.worldpay\\.com$"), pathname: new RegExp("^/access-checkout/v2/checkout\\.js$") }, { "id": "nuvei-websdk-script", "psp": "nuvei", "kinds": ["script"], "origin": "https://cdn.safecharge.com", "path_pattern": "^/safecharge_resources/v1/websdk/safecharge\\.js$", "sources": [{ "kind": "primary_source", "reference": "https://docs.nuvei.com/documentation/accept-payment/web-sdk/quick-start-for-web-sdk/", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://cdn.safecharge.com/safecharge_resources/v1/websdk/safecharge.js", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^cdn\\.safecharge\\.com$"), pathname: new RegExp("^/safecharge_resources/v1/websdk/safecharge\\.js$") }, { "id": "nuvei-card-fields-frame", "psp": "nuvei", "kinds": ["frame", "iframe", "document"], "origin": "https://cdn.safecharge.com", "path_pattern": "^/safecharge_resources/v1/websdk/sfc_inner_card\\.html$", "sources": [{ "kind": "primary_source", "reference": "https://docs.nuvei.com/documentation/accept-payment/web-sdk/nuvei-fields/", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://cdn.safecharge.com/safecharge_resources/v1/websdk/sfc_inner_card.html", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^cdn\\.safecharge\\.com$"), pathname: new RegExp("^/safecharge_resources/v1/websdk/sfc_inner_card\\.html$") }, { "id": "airwallex-components-script", "psp": "airwallex", "kinds": ["script"], "origin": "https://static.airwallex.com", "path_pattern": "^/components/sdk/v1/index\\.js$", "sources": [{ "kind": "primary_source", "reference": "https://www.airwallex.com/docs/payments/get-started/quickstart", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://www.airwallex.com/docs/payments/test-and-go-live/upgrade-to-airwallex.js", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://www.airwallex.com/docs/payouts/test-and-go-live/upgrade-to-airwallex.js", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^static\\.airwallex\\.com$"), pathname: new RegExp("^/components/sdk/v1/index\\.js$") }, { "id": "airwallex-elements-legacy-script", "psp": "airwallex", "kinds": ["script"], "origin": "https://checkout.airwallex.com", "path_pattern": "^/assets/elements\\.bundle\\.min\\.js$", "sources": [{ "kind": "primary_source", "reference": "https://www.airwallex.com/docs/payments/test-and-go-live/upgrade-to-airwallex.js", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^checkout\\.airwallex\\.com$"), pathname: new RegExp("^/assets/elements\\.bundle\\.min\\.js$") }, { "id": "rapyd-checkout-toolkit-script", "psp": "rapyd", "kinds": ["script"], "origin": "https://checkouttoolkit.rapyd.net", "path_pattern": "^/$", "sources": [{ "kind": "primary_source", "reference": "https://docs.rapyd.net/en/checkout-toolkit-integration.html", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^checkouttoolkit\\.rapyd\\.net$"), pathname: new RegExp("^/$") }, { "id": "rapyd-checkout-toolkit-script-host-2", "psp": "rapyd", "kinds": ["script"], "origin": "https://sandboxcheckouttoolkit.rapyd.net", "path_pattern": "^/$", "sources": [{ "kind": "primary_source", "reference": "https://docs.rapyd.net/en/checkout-toolkit-integration.html", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^sandboxcheckouttoolkit\\.rapyd\\.net$"), pathname: new RegExp("^/$") }, { "id": "dlocal-smart-fields-script", "psp": "dlocal", "kinds": ["script"], "origin": "https://js.dlocal.com", "path_pattern": "^/$", "sources": [{ "kind": "primary_source", "reference": "https://docs.dlocal.com/docs/set-up-smart-fields", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://js.dlocal.com/", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://static.dlocal.com/modules/fields/6.18.2/iframe.js", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^js\\.dlocal\\.com$"), pathname: new RegExp("^/$") }, { "id": "dlocal-smart-fields-sandbox-script", "psp": "dlocal", "kinds": ["script"], "origin": "https://js-sandbox.dlocal.com", "path_pattern": "^/$", "sources": [{ "kind": "primary_source", "reference": "https://docs.dlocal.com/docs/set-up-smart-fields", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://js.dlocal.com/", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://static.dlocal.com/modules/fields/6.18.2/iframe.js", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^js\\-sandbox\\.dlocal\\.com$"), pathname: new RegExp("^/$") }, { "id": "dlocal-smart-fields-parent-6-18-2", "psp": "dlocal", "kinds": ["script"], "origin": "https://static.dlocal.com", "path_pattern": "^/modules/fields/6\\.18\\.2/parent\\.js$", "sources": [{ "kind": "primary_source", "reference": "https://docs.dlocal.com/docs/set-up-smart-fields", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://js.dlocal.com/", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://static.dlocal.com/modules/fields/6.18.2/iframe.js", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^static\\.dlocal\\.com$"), pathname: new RegExp("^/modules/fields/6\\.18\\.2/parent\\.js$") }, { "id": "dlocal-smart-card-fields-6-18-2", "psp": "dlocal", "kinds": ["frame", "iframe", "document"], "origin": "https://static.dlocal.com", "path_pattern": "^/modules/fields/6\\.18\\.2/inner-(?:pan|card)\\.html$", "sources": [{ "kind": "primary_source", "reference": "https://docs.dlocal.com/docs/set-up-smart-fields", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://js.dlocal.com/", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://static.dlocal.com/modules/fields/6.18.2/iframe.js", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^static\\.dlocal\\.com$"), pathname: new RegExp("^/modules/fields/6\\.18\\.2/inner-(?:pan|card)\\.html$") }, { "id": "ebanx-js-latest", "psp": "ebanx", "kinds": ["script"], "origin": "https://ebanx-js.ebanx.com", "path_pattern": "^/latest/dist/ebanx\\.min\\.js$", "sources": [{ "kind": "primary_source", "reference": "https://docs.ebanx.com/docs/pay-in/features/cards/tokenization/tokenization-ebanx-js", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://ebanx-js.ebanx.com/latest/dist/ebanx.min.js", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^ebanx\\-js\\.ebanx\\.com$"), pathname: new RegExp("^/latest/dist/ebanx\\.min\\.js$") }, { "id": "mercado-pago-sdk-v2", "psp": "mercado_pago", "kinds": ["script"], "origin": "https://sdk.mercadopago.com", "path_pattern": "^/js/v2$", "sources": [{ "kind": "primary_source", "reference": "https://github.com/mercadopago/sdk-js", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://sdk.mercadopago.com/js/v2", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^sdk\\.mercadopago\\.com$"), pathname: new RegExp("^/js/v2$") }, { "id": "payu-gpo-sdk", "psp": "payu", "kinds": ["script"], "origin": "https://secure.payu.com", "path_pattern": "^/javascript/sdk$", "sources": [{ "kind": "primary_source", "reference": "https://developers.payu.com/europe/docs/checkout/secure-elements/", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://secure.payu.com/javascript/sdk", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^secure\\.payu\\.com$"), pathname: new RegExp("^/javascript/sdk$") }, { "id": "payu-gpo-sdk-sandbox", "psp": "payu", "kinds": ["script"], "origin": "https://secure.snd.payu.com", "path_pattern": "^/javascript/sdk$", "sources": [{ "kind": "primary_source", "reference": "https://developers.payu.com/europe/docs/checkout/secure-elements/", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://secure.payu.com/javascript/sdk", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^secure\\.snd\\.payu\\.com$"), pathname: new RegExp("^/javascript/sdk$") }, { "id": "payu-gpo-sdk-sandbox-host-2", "psp": "payu", "kinds": ["script"], "origin": "https://merch-prod.snd.payu.com", "path_pattern": "^/javascript/sdk$", "sources": [{ "kind": "primary_source", "reference": "https://developers.payu.com/europe/docs/checkout/secure-elements/", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://secure.payu.com/javascript/sdk", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^merch\\-prod\\.snd\\.payu\\.com$"), pathname: new RegExp("^/javascript/sdk$") }, { "id": "payu-gpo-secure-form", "psp": "payu", "kinds": ["frame", "iframe", "document"], "origin": "https://secure.payu.com", "path_pattern": "^/front/secure-form/form/$", "sources": [{ "kind": "primary_source", "reference": "https://developers.payu.com/europe/docs/checkout/secure-elements/", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://secure.payu.com/javascript/sdk", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^secure\\.payu\\.com$"), pathname: new RegExp("^/front/secure-form/form/$") }, { "id": "razorpay-standard-checkout-v1", "psp": "razorpay", "kinds": ["script"], "origin": "https://checkout.razorpay.com", "path_pattern": "^/v1/checkout\\.js$", "sources": [{ "kind": "primary_source", "reference": "https://razorpay.com/docs/payments/payment-gateway/web-integration/standard/integration-steps/", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://checkout.razorpay.com/v1/checkout.js", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^checkout\\.razorpay\\.com$"), pathname: new RegExp("^/v1/checkout\\.js$") }, { "id": "mollie-components-v1", "psp": "mollie", "kinds": ["script"], "origin": "https://js.mollie.com", "path_pattern": "^/v1/mollie\\.js$", "sources": [{ "kind": "primary_source", "reference": "https://docs.mollie.com/docs/mollie-components", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://docs.mollie.com/docs/custom-checkout-components", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://js.mollie.com/v2/mollie.js", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^js\\.mollie\\.com$"), pathname: new RegExp("^/v1/mollie\\.js$") }, { "id": "mollie-components-v2", "psp": "mollie", "kinds": ["script"], "origin": "https://js.mollie.com", "path_pattern": "^/v2/mollie\\.js$", "sources": [{ "kind": "primary_source", "reference": "https://docs.mollie.com/docs/mollie-components", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://docs.mollie.com/docs/custom-checkout-components", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://js.mollie.com/v2/mollie.js", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^js\\.mollie\\.com$"), pathname: new RegExp("^/v2/mollie\\.js$") }, { "id": "paysafe-js-v1-latest", "psp": "paysafe", "kinds": ["script"], "origin": "https://hosted.paysafe.com", "path_pattern": "^/js/v1/latest/paysafe\\.min\\.js$", "sources": [{ "kind": "primary_source", "reference": "https://developer.paysafe.com/en/api-docs/paysafe-js/overview/", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://hosted.paysafe.com/js/v1/latest/paysafe.min.js", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://developer.paysafe.com/en/api-docs/3ds/using-the-sdk/including-the-3d-secure-2-sdk/", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^hosted\\.paysafe\\.com$"), pathname: new RegExp("^/js/v1/latest/paysafe\\.min\\.js$") }, { "id": "paysafe-js-v1-fields", "psp": "paysafe", "kinds": ["frame", "iframe", "document"], "origin": "https://hosted.paysafe.com", "path_pattern": "^/js/v1/latest/index\\.html$", "sources": [{ "kind": "primary_source", "reference": "https://developer.paysafe.com/en/api-docs/paysafe-js/overview/", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://hosted.paysafe.com/js/v1/latest/paysafe.min.js", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://developer.paysafe.com/en/api-docs/3ds/using-the-sdk/including-the-3d-secure-2-sdk/", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^hosted\\.paysafe\\.com$"), pathname: new RegExp("^/js/v1/latest/index\\.html$") }, { "id": "paysafe-js-v1-fields-host-2", "psp": "paysafe", "kinds": ["frame", "iframe", "document"], "origin": "https://hosted.test.paysafe.com", "path_pattern": "^/js/v1/latest/index\\.html$", "sources": [{ "kind": "primary_source", "reference": "https://developer.paysafe.com/en/api-docs/paysafe-js/overview/", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://hosted.paysafe.com/js/v1/latest/paysafe.min.js", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://developer.paysafe.com/en/api-docs/3ds/using-the-sdk/including-the-3d-secure-2-sdk/", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^hosted\\.test\\.paysafe\\.com$"), pathname: new RegExp("^/js/v1/latest/index\\.html$") }, { "id": "spreedly-iframe-v1-script", "psp": "spreedly", "kinds": ["script"], "origin": "https://core.spreedly.com", "path_pattern": "^/iframe/iframe-v1\\.min\\.js$", "sources": [{ "kind": "primary_source", "reference": "https://core.spreedly.com/iframe/iframe-v1.min.js", "reviewed_on": "2026-09-16" }], hostname: new RegExp("^core\\.spreedly\\.com$"), pathname: new RegExp("^/iframe/iframe-v1\\.min\\.js$") }, { "id": "spreedly-native-card-frame", "psp": "spreedly", "kinds": ["frame", "iframe", "document"], "origin": "https://core.spreedly.com", "path_pattern": "^/v1/embedded/(?:number|cvv)-frame-1\\.[0-9]{1,4}\\.html$", "sources": [{ "kind": "primary_source", "reference": "https://core.spreedly.com/iframe/iframe-v1.min.js", "reviewed_on": "2026-09-16" }], hostname: new RegExp("^core\\.spreedly\\.com$"), pathname: new RegExp("^/v1/embedded/(?:number|cvv)-frame-1\\.[0-9]{1,4}\\.html$") }, { "id": "recurly-js-v4", "psp": "recurly", "kinds": ["script"], "origin": "https://js.recurly.com", "path_pattern": "^/v4/recurly\\.js$", "sources": [{ "kind": "primary_source", "reference": "https://recurly.com/developers/reference/recurly-js/index.html", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://github.com/recurly/recurly-js", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://js.recurly.com/v4/recurly.js", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^js\\.recurly\\.com$"), pathname: new RegExp("^/v4/recurly\\.js$") }, { "id": "recurly-hosted-field-v1", "psp": "recurly", "kinds": ["frame", "iframe", "document"], "origin": "https://api.recurly.com", "path_pattern": "^/js/v1/field\\.html$", "sources": [{ "kind": "primary_source", "reference": "https://recurly.com/developers/reference/recurly-js/index.html", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://github.com/recurly/recurly-js", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://js.recurly.com/v4/recurly.js", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^api\\.recurly\\.com$"), pathname: new RegExp("^/js/v1/field\\.html$") }, { "id": "recurly-hosted-field-v1-host-2", "psp": "recurly", "kinds": ["frame", "iframe", "document"], "origin": "https://api.eu.recurly.com", "path_pattern": "^/js/v1/field\\.html$", "sources": [{ "kind": "primary_source", "reference": "https://recurly.com/developers/reference/recurly-js/index.html", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://github.com/recurly/recurly-js", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://js.recurly.com/v4/recurly.js", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^api\\.eu\\.recurly\\.com$"), pathname: new RegExp("^/js/v1/field\\.html$") }, { "id": "moneris-hosted-tokenization", "psp": "moneris", "kinds": ["frame", "iframe", "document"], "origin": "https://www3.moneris.com", "path_pattern": "^/HPPtoken/index\\.php$", "sources": [{ "kind": "primary_source", "reference": "https://developer.moneris.com/hosted-solutions/docs/setup-guide-tokenization", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://developer.moneris.com/moneris-api/docs/purchase-with-payment-token", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://www3.moneris.com/HPPtoken/hpp_common.js", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^www3\\.moneris\\.com$"), pathname: new RegExp("^/HPPtoken/index\\.php$") }, { "id": "moneris-hosted-tokenization-host-2", "psp": "moneris", "kinds": ["frame", "iframe", "document"], "origin": "https://esqa.moneris.com", "path_pattern": "^/HPPtoken/index\\.php$", "sources": [{ "kind": "primary_source", "reference": "https://developer.moneris.com/hosted-solutions/docs/setup-guide-tokenization", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://developer.moneris.com/moneris-api/docs/purchase-with-payment-token", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://www3.moneris.com/HPPtoken/hpp_common.js", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^esqa\\.moneris\\.com$"), pathname: new RegExp("^/HPPtoken/index\\.php$") }, { "id": "moneris-new-io-hosted-tokenization", "psp": "moneris", "kinds": ["frame", "iframe", "document"], "origin": "https://mpg1t.moneris.io", "path_pattern": "^/HPPtoken/index\\.php$", "sources": [{ "kind": "primary_source", "reference": "https://developer.moneris.com/hosted-solutions/docs/setup-guide-tokenization", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://developer.moneris.com/moneris-api/docs/purchase-with-payment-token", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://www3.moneris.com/HPPtoken/hpp_common.js", "reviewed_on": "2026-09-11" }], "variant_unverified": "The current canonical Moneris recognizer contains moneris.com hosts only; moneris.io is not admitted.", hostname: new RegExp("^mpg1t\\.moneris\\.io$"), pathname: new RegExp("^/HPPtoken/index\\.php$") }, { "id": "bambora-na-custom-checkout-1", "psp": "bambora", "kinds": ["script"], "origin": "https://libs.na.bambora.com", "path_pattern": "^/customcheckout/1/customcheckout\\.js$", "sources": [{ "kind": "primary_source", "reference": "https://docs.na.worldline-solutions.com/build-your-integration/checkout-form/custom-checkout/reference", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://libs.na.bambora.com/customcheckout/1/customcheckout.js", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://libs.na.bambora.com/customcheckout/1.0.5-39/customcheckoutremote.js", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^libs\\.na\\.bambora\\.com$"), pathname: new RegExp("^/customcheckout/1/customcheckout\\.js$") }, { "id": "bambora-na-fields-1-0-5-39", "psp": "bambora", "kinds": ["frame", "iframe", "document"], "origin": "https://libs.na.bambora.com", "path_pattern": "^/customcheckout/1\\.0\\.5-39/iframe\\.html$", "sources": [{ "kind": "primary_source", "reference": "https://docs.na.worldline-solutions.com/build-your-integration/checkout-form/custom-checkout/reference", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://libs.na.bambora.com/customcheckout/1/customcheckout.js", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://libs.na.bambora.com/customcheckout/1.0.5-39/customcheckoutremote.js", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^libs\\.na\\.bambora\\.com$"), pathname: new RegExp("^/customcheckout/1\\.0\\.5-39/iframe\\.html$") }, { "id": "global-payments-js-4-1-3", "psp": "global_payments", "kinds": ["script"], "origin": "https://js.globalpay.com", "path_pattern": "^/4\\.1\\.3/globalpayments\\.js$", "sources": [{ "kind": "primary_source", "reference": "https://developer.globalpayments.com/docs/integration-options/sdk/javascript", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://github.com/globalpayments/globalpayments-js", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://js.globalpay.com/4.1.3/globalpayments.js", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://js.globalpay.com/v1/globalpayments.js", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^js\\.globalpay\\.com$"), pathname: new RegExp("^/4\\.1\\.3/globalpayments\\.js$") }, { "id": "global-payments-js-v1-alias", "psp": "global_payments", "kinds": ["script"], "origin": "https://js.globalpay.com", "path_pattern": "^/v1/globalpayments\\.js$", "sources": [{ "kind": "primary_source", "reference": "https://developer.globalpayments.com/docs/integration-options/sdk/javascript", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://github.com/globalpayments/globalpayments-js", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://js.globalpay.com/4.1.3/globalpayments.js", "reviewed_on": "2026-09-11" }, { "kind": "primary_source", "reference": "https://js.globalpay.com/v1/globalpayments.js", "reviewed_on": "2026-09-11" }], hostname: new RegExp("^js\\.globalpay\\.com$"), pathname: new RegExp("^/v1/globalpayments\\.js$") });
|
|
34
|
-
// Hosted, regional and versioned product variants seen on live checkouts (Kernel discovery report,
|
|
35
|
-
// 2026-09-14). A variant the implemented adapter does not admit still identifies its processor and
|
|
36
|
-
// stays unknown through `variant_unverified`; no entry here expands a recognized card destination.
|
|
37
|
-
const documented = (reference) => ({ kind: 'primary_source', reference, reviewed_on: '2026-09-15' });
|
|
38
|
-
const observed = (reference) => ({ kind: 'partner_observation', reference: `kernel-discovery-2026-09-14:${reference}`, reviewed_on: '2026-09-15' });
|
|
39
|
-
RULES.push({ id: 'tranzila-terminal-hosted-page', psp: 'tranzila', kinds: ['document', 'frame', 'iframe', 'form'], hostname: /^direct\.tranzila\.com$/, pathname: /^\/(?!process(?:\/|$)|done(?:\/|$))[A-Za-z0-9_-]+\/?$/, origin: 'https://direct.tranzila.com', path_pattern: '/:terminal/',
|
|
40
|
-
sources: [documented('https://docs.tranzila.com/docs/payments-and-billing/hosted-payment-page'), observed('tranzila-terminal-root-hosted-page')],
|
|
41
|
-
variant_unverified: 'The implemented Tranzila hosted form covers direct.tranzila.com/:terminal/iframenew.php; a terminal-root hosted payment page is not admitted.' }, { id: 'square-card-element-frame', psp: 'square', kinds: ['frame', 'iframe'], hostname: /^web\.squarecdn\.com$/, pathname: /^\/[0-9]+\.[0-9]+\.[0-9]+\/single-card-element-iframe\.html$/, origin: 'https://web.squarecdn.com', path_pattern: '/:version/single-card-element-iframe.html',
|
|
42
|
-
sources: [documented('https://developer.squareup.com/docs/web-payments/take-card-payment'), observed('square-single-card-element-iframe-1.84.5')] }, { id: 'authorize-net-sim-hosted-form', psp: 'authorize_net', kinds: ['document', 'frame', 'iframe', 'form'], hostname: /^secure\.authorize\.net$/, pathname: /^\/gateway\/transact\.dll$/, origin: 'https://secure.authorize.net', path_pattern: '/gateway/transact.dll',
|
|
43
|
-
sources: [documented('https://developer.authorize.net/api/upgrade_guide.html'), observed('authorize-net-hosted-transact-form')],
|
|
44
|
-
variant_unverified: 'The implemented Authorize.Net adapter covers Accept.js card requests; the hosted SIM payment form at secure.authorize.net/gateway/transact.dll posts the card as a top-level form and is not admitted.' }, { id: 'worldpay-hosted-payment-page', psp: 'worldpay', kinds: ['document', 'frame', 'iframe', 'form'], hostname: /^secure\.worldpay\.com$/, pathname: /^\/wcc\/(?:purchase|card)$/, origin: 'https://secure.worldpay.com', path_pattern: '/wcc/{purchase,card}',
|
|
45
|
-
sources: [documented('https://docs.worldpay.com/access/products/checkout/web'), observed('worldpay-hosted-payment-page-card')],
|
|
46
|
-
variant_unverified: 'The implemented Worldpay adapter covers Access Checkout card sessions; Worldpay hosted payment pages under secure.worldpay.com/wcc post the card to Worldpay directly and are not admitted.' }, { id: 'rapyd-hosted-checkout-page', psp: 'rapyd', kinds: ['document', 'frame', 'iframe'], hostname: /^checkout\.rapyd\.net$/, pathname: /^\/$/, origin: 'https://checkout.rapyd.net', path_pattern: '/',
|
|
47
|
-
sources: [documented('https://docs.rapyd.net/en/hosted-checkout-page.html'), observed('rapyd-hosted-checkout-page')] }, { id: 'dlocal-smart-fields-parent', psp: 'dlocal', kinds: ['script'], hostname: /^static\.dlocal\.com$/, pathname: /^\/modules\/fields\/[0-9]+\.[0-9]+\.[0-9]+\/(?:parent|iframe)\.js$/, origin: 'https://static.dlocal.com', path_pattern: '/modules/fields/:version/{parent,iframe}.js',
|
|
48
|
-
sources: [documented('https://docs.dlocal.com/docs/set-up-smart-fields'), observed('dlocal-smart-fields-6.8.3')] }, { id: 'dlocal-smart-card-fields', psp: 'dlocal', kinds: ['frame', 'iframe', 'document'], hostname: /^static\.dlocal\.com$/, pathname: /^\/modules\/fields\/[0-9]+\.[0-9]+\.[0-9]+\/inner-(?:pan|card)\.html$/, origin: 'https://static.dlocal.com', path_pattern: '/modules/fields/:version/inner-{pan,card}.html',
|
|
49
|
-
sources: [documented('https://docs.dlocal.com/docs/set-up-smart-fields'), observed('dlocal-smart-fields-6.8.3')] }, { id: 'mercado-pago-secure-fields-frame', psp: 'mercado_pago', kinds: ['frame', 'iframe', 'document'], hostname: /^secure-fields\.mercadopago\.com$/, pathname: /^\/$/, origin: 'https://secure-fields.mercadopago.com', path_pattern: '/',
|
|
50
|
-
sources: [documented('https://sdk.mercadopago.com/js/v2'), observed('mercado-pago-secure-fields-frames')] }, { id: 'mercado-pago-checkout-pro-card-form', psp: 'mercado_pago', kinds: ['document', 'frame', 'iframe'], hostname: /^www\.mercadopago\.com\.ar$/, pathname: /^\/checkout\/v1\/payment\/redirect\/[^/]+\/card-form\/?$/, origin: 'https://www.mercadopago.com.ar', path_pattern: '/checkout/v1/payment/redirect/:preference/card-form/',
|
|
51
|
-
sources: [documented('https://www.mercadopago.com.ar/developers/es/docs/checkout-pro/landing'), observed('mercado-pago-checkout-pro-guest-card-form')] });
|
|
52
|
-
// Fiserv Commerce Hub, read 2026-09-23 from Home Depot's OrangePay frame and Fiserv's
|
|
53
|
-
// docs: payment-fields.js renders one Secure Data Capture iframe per card field, and
|
|
54
|
-
// the Checkout JS SDK is Commerce Hub's other browser entry. Fiserv ships dark (its
|
|
55
|
-
// definition names a capability), so the bundled catalog declares no support for it:
|
|
56
|
-
// these assets identify fiserv and the result stays unknown.
|
|
57
|
-
const fiservSource = (reference) => ({ kind: 'primary_source', reference, reviewed_on: '2026-09-23' });
|
|
58
|
-
RULES.push({ id: 'fiserv-commercehub-payment-fields', psp: 'fiserv', kinds: ['script'], hostname: /^commercehub-checkout\.fiservapps\.com$/, pathname: /^\/sdk\/[0-9]+\.[0-9]+\.[0-9]+\/payment-fields\.js$/, origin: 'https://commercehub-checkout.fiservapps.com', path_pattern: '/sdk/:version/payment-fields.js',
|
|
59
|
-
sources: [fiservSource('https://commercehub-checkout.fiservapps.com/sdk/3.8.14/payment-fields.js'), fiservSource('https://orangepay-ecommerce.hdpayments.homedepot.com/env.js')] }, { id: 'fiserv-commercehub-checkout-script', psp: 'fiserv', kinds: ['script'], hostname: /^commercehub-checkout\.fiservapps\.com$/, pathname: /^\/sdk\/[0-9]+\.[0-9]+\.[0-9]+\/checkout\.js$/, origin: 'https://commercehub-checkout.fiservapps.com', path_pattern: '/sdk/:version/checkout.js',
|
|
60
|
-
sources: [fiservSource('https://developer.fiserv.com/product/CommerceHub/docs/Online-Commerce/Integration-Options/Hosted-Checkout/Hosted-Checkout-Version-Release')] }, { id: 'fiserv-secure-data-capture-frame', psp: 'fiserv', kinds: ['frame', 'iframe', 'document'], hostname: /^commercehub-secure-data-capture\.fiservapps\.com$/, pathname: /^\/sdk-secure\/[0-9]+\.[0-9]+\.[0-9]+\/iframe\.html$/, origin: 'https://commercehub-secure-data-capture.fiservapps.com', path_pattern: '/sdk-secure/:version/iframe.html',
|
|
61
|
-
sources: [fiservSource('https://commercehub-checkout.fiservapps.com/sdk/3.8.14/payment-fields.js'), fiservSource('https://commercehub-secure-data-capture.fiservapps.com/sdk-secure/3.8.14/iframe.html')] });
|
|
62
|
-
// Keep sandbox evidence truthful instead of labelling it with a production origin.
|
|
63
|
-
for (const [baseId, suffix, hostname, origin] of [
|
|
64
|
-
['square-web-sdk', 'sandbox', /^sandbox\.web\.squarecdn\.com$/, 'https://sandbox.web.squarecdn.com'],
|
|
65
|
-
['paysafe-js', 'test', /^hosted\.test\.paysafe\.com$/, 'https://hosted.test.paysafe.com'],
|
|
66
|
-
['worldpay-checkout-sdk', 'try', /^try\.access\.worldpay\.com$/, 'https://try.access.worldpay.com'],
|
|
67
|
-
['authorize-net-accept', 'test', /^jstest\.authorize\.net$/, 'https://jstest.authorize.net'],
|
|
68
|
-
['tranzila-terminal-hosted-page', 'directng', /^directng\.tranzila\.com$/, 'https://directng.tranzila.com'],
|
|
69
|
-
['square-card-element-frame', 'sandbox', /^sandbox\.web\.squarecdn\.com$/, 'https://sandbox.web.squarecdn.com'],
|
|
70
|
-
['authorize-net-sim-hosted-form', 'secure2', /^secure2\.authorize\.net$/, 'https://secure2.authorize.net'],
|
|
71
|
-
['worldpay-hosted-payment-page', 'test', /^secure-test\.worldpay\.com$/, 'https://secure-test.worldpay.com'],
|
|
72
|
-
['rapyd-hosted-checkout-page', 'sandbox', /^sandboxcheckout\.rapyd\.net$/, 'https://sandboxcheckout.rapyd.net'],
|
|
73
|
-
// Adyen's regional live hosts (docs.adyen.com/development-resources/live-endpoints/).
|
|
74
|
-
['adyen-secured-fields-live', 'us', /^checkoutshopper-live-us\.adyen\.com$/, 'https://checkoutshopper-live-us.adyen.com'],
|
|
75
|
-
['adyen-secured-fields-live', 'au', /^checkoutshopper-live-au\.adyen\.com$/, 'https://checkoutshopper-live-au.adyen.com'],
|
|
76
|
-
['adyen-secured-fields-live', 'apse', /^checkoutshopper-live-apse\.adyen\.com$/, 'https://checkoutshopper-live-apse.adyen.com'],
|
|
77
|
-
['adyen-secured-fields-live', 'in', /^checkoutshopper-live-in\.adyen\.com$/, 'https://checkoutshopper-live-in.adyen.com'],
|
|
78
|
-
['adyen-secured-fields-live', 'nea', /^checkoutshopper-live-nea\.adyen\.com$/, 'https://checkoutshopper-live-nea.adyen.com'],
|
|
79
|
-
// Commerce Hub's "Sandbox and Cert" environment (payment-fields.js 3.8.14 environment table).
|
|
80
|
-
['fiserv-commercehub-payment-fields', 'cert', /^commercehub-checkout-cert\.fiservapps\.com$/, 'https://commercehub-checkout-cert.fiservapps.com'],
|
|
81
|
-
['fiserv-commercehub-checkout-script', 'cert', /^commercehub-checkout-cert\.fiservapps\.com$/, 'https://commercehub-checkout-cert.fiservapps.com'],
|
|
82
|
-
['fiserv-secure-data-capture-frame', 'cert', /^commercehub-secure-data-capture-cert\.fiservapps\.com$/, 'https://commercehub-secure-data-capture-cert.fiservapps.com'],
|
|
83
|
-
]) {
|
|
84
|
-
RULES.push({ ...RULES.find(rule => rule.id === baseId), id: `${baseId}-${suffix}`, hostname, origin });
|
|
85
|
-
}
|
|
86
|
-
const SOURCES = {
|
|
87
|
-
stripe: [{ kind: 'official_documentation', reference: 'https://docs.stripe.com/js/including', reviewed_on: '2026-09-11' }],
|
|
88
|
-
square: [{ kind: 'official_documentation', reference: 'https://developer.squareup.com/docs/web-payments/quickstart/add-sdk-to-web-client', reviewed_on: '2026-09-11' }],
|
|
89
|
-
mollie: [{ kind: 'saved_observation', reference: 'mollie-haak-2026-09-11:hosted-credit-card-document-and-v2-script', reviewed_on: '2026-09-11' }],
|
|
90
|
-
braintree: [{ kind: 'official_documentation', reference: 'https://developer.paypal.com/braintree/docs/start/hello-client/javascript/v3/', reviewed_on: '2026-09-11' }],
|
|
91
|
-
paysafe: [{ kind: 'official_documentation', reference: 'https://developer.paysafe.com/en/api-docs/paysafe-js/overview/', reviewed_on: '2026-09-11' }],
|
|
92
|
-
worldpay: [{ kind: 'official_documentation', reference: 'https://developer.worldpay.com/products/checkout/web', reviewed_on: '2026-09-11' }],
|
|
93
|
-
authorize_net: [{ kind: 'official_documentation', reference: 'https://developer.authorize.net/api/reference/features/acceptjs.html', reviewed_on: '2026-09-11' }],
|
|
94
|
-
razorpay: [{ kind: 'official_documentation', reference: 'https://razorpay.com/docs/payments/payment-gateway/web-integration/standard/integration-steps/', reviewed_on: '2026-09-11' }],
|
|
95
|
-
vgs: [{ kind: 'official_documentation', reference: 'https://docs.verygoodsecurity.com/vault/developer-tools/vgs-collect/js/integration', reviewed_on: '2026-09-11' }],
|
|
96
|
-
};
|
|
97
|
-
const FLOWS = [
|
|
98
|
-
{ id: 'mollie.hosted_components', psp: 'mollie', operation: 'mollie.card_request', operation_version: 1, mode: 'token', server_constraint: 'eligible', limitations: [
|
|
99
|
-
'The payment request must match the supported Mollie Components card-token format.',
|
|
100
|
-
'Authentication and merchant confirmation must finish in the merchant browser.',
|
|
101
|
-
'Merchant configuration, card eligibility and processor approval still determine whether the purchase succeeds.',
|
|
102
|
-
] },
|
|
103
|
-
{ id: 'vgs.iframe_bound_tokenization', psp: 'vgs', operation: 'vgs.iframe_bound_tokenization', operation_version: 1, mode: 'token', server_constraint: 'unsupported', limitations: [
|
|
104
|
-
'VGS requires tokenization from its own iframe; the Vault cannot replay this flow from the approval page.',
|
|
105
|
-
] },
|
|
106
|
-
];
|
|
107
|
-
const FLOW_BY_ID = new Map(FLOWS.map(flow => [flow.id, flow]));
|
|
108
|
-
const RULE_BY_ID = new Map(RULES.map(rule => [rule.id, rule]));
|
|
109
|
-
const DEFAULT_PROFILE = {
|
|
110
|
-
schema_version: 1, profile_version: 'preflight-2', catalog_version: CHECKOUT_PREFLIGHT_CATALOG_VERSION,
|
|
111
|
-
integration: { id: 'direct_sdk', version: 'bundled' },
|
|
112
|
-
processor_entries: CHECKOUT_PREFLIGHT_CAPABILITIES.processors.map(processor => ({
|
|
113
|
-
psp: processor.psp, mode: processor.mode, scenario: 'one_time', status: 'supported',
|
|
114
|
-
})),
|
|
115
|
-
entries: [{ flow: 'mollie.hosted_components', operation: 'mollie.card_request', operation_version: 1, mode: 'token', scenario: 'one_time', status: 'supported' }],
|
|
116
|
-
};
|
|
117
|
-
const clone = (value) => JSON.parse(JSON.stringify(value));
|
|
118
|
-
const record = (value) => !!value && typeof value === 'object' && !Array.isArray(value);
|
|
119
|
-
const exactKeys = (value, keys) => Object.keys(value).every(key => keys.includes(key));
|
|
120
|
-
const id = (value) => typeof value === 'string' && /^[A-Za-z0-9][A-Za-z0-9._+-]{0,119}$/.test(value);
|
|
121
|
-
const frameId = (value) => Number.isSafeInteger(value) && value >= 0 && value < CHECKOUT_PREFLIGHT_LIMITS.frames;
|
|
122
|
-
const unique = (items) => [...new Set(items)];
|
|
123
|
-
function dateTime(value) {
|
|
124
|
-
if (typeof value !== 'string' || value.length > 40)
|
|
125
|
-
return false;
|
|
126
|
-
const match = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.\d{1,9})?(?:Z|[+-](\d{2}):(\d{2}))$/.exec(value);
|
|
127
|
-
if (!match)
|
|
128
|
-
return false;
|
|
129
|
-
const [year, month, day, hour, minute, second, zoneHour = 0, zoneMinute = 0] = match.slice(1).map(part => part === undefined ? 0 : Number(part));
|
|
130
|
-
const leap = year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
|
|
131
|
-
const days = [31, leap ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
132
|
-
return month >= 1 && month <= 12 && day >= 1 && day <= days[month - 1] && hour <= 23 && minute <= 59 && second <= 59
|
|
133
|
-
&& zoneHour <= 23 && zoneMinute <= 59 && Number.isFinite(Date.parse(value));
|
|
134
|
-
}
|
|
135
|
-
function metadata(value) {
|
|
136
|
-
return KINDS.includes(value.kind) && frameId(value.frame_id) && (value.parent_frame_id === null || frameId(value.parent_frame_id))
|
|
137
|
-
&& (value.frame_id !== 0 || value.parent_frame_id === null)
|
|
138
|
-
&& value.parent_frame_id !== value.frame_id && (value.visible === null || typeof value.visible === 'boolean');
|
|
139
|
-
}
|
|
140
|
-
function consistentParents(signals) {
|
|
141
|
-
const parents = new Map();
|
|
142
|
-
for (const signal of signals) {
|
|
143
|
-
if (parents.has(signal.frame_id) && parents.get(signal.frame_id) !== signal.parent_frame_id)
|
|
144
|
-
return false;
|
|
145
|
-
parents.set(signal.frame_id, signal.parent_frame_id);
|
|
146
|
-
}
|
|
147
|
-
for (const frame of parents.keys()) {
|
|
148
|
-
const visited = new Set();
|
|
149
|
-
let current = frame;
|
|
150
|
-
while (current !== null && current !== undefined) {
|
|
151
|
-
if (visited.has(current))
|
|
152
|
-
return false;
|
|
153
|
-
visited.add(current);
|
|
154
|
-
current = parents.get(current);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
return true;
|
|
158
|
-
}
|
|
159
|
-
function cleanObservation(input) {
|
|
160
|
-
if (!record(input) || !exactKeys(input, ['complete', 'truncated', 'reasons']) || typeof input.complete !== 'boolean' || typeof input.truncated !== 'boolean'
|
|
161
|
-
|| !Array.isArray(input.reasons) || input.reasons.length > 32 || Array.from(input.reasons).some(reason => !OBSERVATION_REASONS.includes(reason))) {
|
|
162
|
-
return { complete: false, truncated: false, reasons: ['invalid_observation'] };
|
|
163
|
-
}
|
|
164
|
-
const reasons = unique(input.reasons);
|
|
165
|
-
const complete = input.complete && !input.truncated && reasons.length === 0;
|
|
166
|
-
return { complete, truncated: input.truncated, reasons: complete ? [] : unique([...reasons, 'collection_incomplete']) };
|
|
167
|
-
}
|
|
168
|
-
const byteLength = (value) => new TextEncoder().encode(JSON.stringify(value)).length;
|
|
169
|
-
function incomplete(observation, reason, truncated = false) {
|
|
170
|
-
observation.complete = false;
|
|
171
|
-
observation.truncated ||= truncated;
|
|
172
|
-
observation.reasons = unique([...observation.reasons, reason]);
|
|
173
|
-
}
|
|
174
|
-
/** Normalize observations locally. Unknown assets are omitted; no URL leaves this function. */
|
|
175
|
-
export function normalizeCheckoutSignals(input) {
|
|
176
|
-
const snapshot = { schema_version: 1, catalog_version: CHECKOUT_PREFLIGHT_CATALOG_VERSION, signals: [], observation: cleanObservation(record(input) ? input.observation : null) };
|
|
177
|
-
if (!record(input) || !exactKeys(input, ['signals', 'observation']) || !Array.isArray(input.signals)) {
|
|
178
|
-
incomplete(snapshot.observation, 'invalid_observation');
|
|
179
|
-
return snapshot;
|
|
180
|
-
}
|
|
181
|
-
if (input.signals.length > CHECKOUT_PREFLIGHT_LIMITS.signals)
|
|
182
|
-
incomplete(snapshot.observation, 'signal_limit', true);
|
|
183
|
-
const seen = new Set();
|
|
184
|
-
for (const raw of input.signals.slice(0, CHECKOUT_PREFLIGHT_LIMITS.signals)) {
|
|
185
|
-
if (!record(raw) || !exactKeys(raw, ['kind', 'url', 'frame_id', 'parent_frame_id', 'visible']) || !metadata(raw)) {
|
|
186
|
-
incomplete(snapshot.observation, 'invalid_observation');
|
|
187
|
-
continue;
|
|
188
|
-
}
|
|
189
|
-
if (typeof raw.url !== 'string' || raw.url.length > CHECKOUT_PREFLIGHT_LIMITS.raw_url_length) {
|
|
190
|
-
incomplete(snapshot.observation, 'invalid_url');
|
|
191
|
-
continue;
|
|
192
|
-
}
|
|
193
|
-
let url;
|
|
194
|
-
try {
|
|
195
|
-
url = new URL(raw.url);
|
|
196
|
-
}
|
|
197
|
-
catch {
|
|
198
|
-
incomplete(snapshot.observation, 'invalid_url');
|
|
199
|
-
continue;
|
|
200
|
-
}
|
|
201
|
-
// Matching reads the origin and path only. A long query string on an unrelated wallet or
|
|
202
|
-
// widget frame is dropped here rather than invalidating the whole observation.
|
|
203
|
-
if (url.origin.length + url.pathname.length > CHECKOUT_PREFLIGHT_LIMITS.url_length) {
|
|
204
|
-
incomplete(snapshot.observation, 'invalid_url');
|
|
205
|
-
continue;
|
|
206
|
-
}
|
|
207
|
-
// Non-HTTPS local/blank frames provide no PSP evidence. Credentials and nondefault ports are refused.
|
|
208
|
-
if (url.protocol !== 'https:' || url.username || url.password || url.port)
|
|
209
|
-
continue;
|
|
210
|
-
for (const rule of RULES) {
|
|
211
|
-
if (!rule.kinds.includes(raw.kind) || !rule.hostname.test(url.hostname) || !rule.pathname.test(url.pathname))
|
|
212
|
-
continue;
|
|
213
|
-
const signal = { rule_id: rule.id, kind: raw.kind, frame_id: raw.frame_id, parent_frame_id: raw.parent_frame_id, visible: raw.visible };
|
|
214
|
-
const key = JSON.stringify(signal);
|
|
215
|
-
if (!seen.has(key)) {
|
|
216
|
-
// One observed asset can match more than one reviewed fingerprint.
|
|
217
|
-
// Bound normalized evidence independently of the raw observation count.
|
|
218
|
-
if (snapshot.signals.length >= CHECKOUT_PREFLIGHT_LIMITS.signals) {
|
|
219
|
-
incomplete(snapshot.observation, 'signal_limit', true);
|
|
220
|
-
continue;
|
|
221
|
-
}
|
|
222
|
-
snapshot.signals.push(signal);
|
|
223
|
-
seen.add(key);
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
while (byteLength(snapshot) > CHECKOUT_PREFLIGHT_LIMITS.snapshot_bytes && snapshot.signals.length) {
|
|
228
|
-
snapshot.signals.pop();
|
|
229
|
-
incomplete(snapshot.observation, 'snapshot_limit', true);
|
|
230
|
-
}
|
|
231
|
-
if (!consistentParents(snapshot.signals))
|
|
232
|
-
incomplete(snapshot.observation, 'invalid_observation');
|
|
233
|
-
return snapshot;
|
|
234
|
-
}
|
|
235
|
-
/** The returned catalog is metadata only. It does not change card destination recognition. */
|
|
236
|
-
export function getCheckoutPreflightCatalog() {
|
|
237
|
-
return clone({
|
|
238
|
-
schema_version: 1, catalog_version: CHECKOUT_PREFLIGHT_CATALOG_VERSION, scope: 'preflight_hint',
|
|
239
|
-
integration_version_note: 'bundled describes the capabilities accompanying this helper, not a claim about another installed SDK version.',
|
|
240
|
-
limits: CHECKOUT_PREFLIGHT_LIMITS,
|
|
241
|
-
known_psps: KNOWN_PSPS.map(psp => ({ psp, detection: RULES.some(rule => rule.psp === psp) ? 'reviewed_rules' : 'unknown' })),
|
|
242
|
-
rules: RULES.map(({ hostname, pathname, ...rule }) => ({ ...rule, hostname_pattern: hostname.source, pathname_pattern: pathname.source, sources: rule.sources ?? SOURCES[rule.psp] })),
|
|
243
|
-
processors: CHECKOUT_PREFLIGHT_CAPABILITIES.processors, exclusions: CHECKOUT_PREFLIGHT_CAPABILITIES.exclusions,
|
|
244
|
-
flows: FLOWS, direct_sdk_profile: DEFAULT_PROFILE,
|
|
245
|
-
kernel_profile_template: { schema_version: 1, profile_version: 'kernel-template-1', catalog_version: CHECKOUT_PREFLIGHT_CATALOG_VERSION,
|
|
246
|
-
integration: { id: 'kernel_native', version: 'REPLACE-WITH-ADAPTER-VERSION' }, entries: [], processor_entries: [] },
|
|
247
|
-
observation_reason_codes: OBSERVATION_REASONS,
|
|
248
|
-
});
|
|
249
|
-
}
|
|
250
|
-
// Registrable-site approximation for provider hosts; a public-suffix list is deliberately not bundled.
|
|
251
|
-
function site(hostname) {
|
|
252
|
-
const labels = hostname.toLowerCase().split('.').filter(Boolean);
|
|
253
|
-
const secondLevel = ['com', 'co', 'net', 'org', 'gov', 'edu', 'ac', 'or', 'ne'];
|
|
254
|
-
const count = labels.length > 2 && labels[labels.length - 1].length === 2 && secondLevel.includes(labels[labels.length - 2]) ? 3 : 2;
|
|
255
|
-
return labels.slice(-count).join('.');
|
|
256
|
-
}
|
|
257
|
-
/**
|
|
258
|
-
* Whether a visible card-entry frame on `hostname` can belong to a processor already evidenced in the
|
|
259
|
-
* snapshot. A collector reports `card_entry_unrecognized` when this is false, so co-loaded SDK scripts
|
|
260
|
-
* cannot be presented as the processor behind card controls that no reviewed fingerprint explains, and
|
|
261
|
-
* a card form with no processor evidence at all is reported rather than passing as an empty page.
|
|
262
|
-
* The hostname stays local to the caller; nothing here enters evidence.
|
|
263
|
-
*/
|
|
264
|
-
export function cardEntryAttributable(input, hostname) {
|
|
265
|
-
if (!validSnapshot(input) || typeof hostname !== 'string' || !hostname)
|
|
266
|
-
return false;
|
|
267
|
-
const evidenced = new Set(input.signals.map(signal => RULE_BY_ID.get(signal.rule_id).psp));
|
|
268
|
-
if (!evidenced.size)
|
|
269
|
-
return false;
|
|
270
|
-
const target = site(hostname);
|
|
271
|
-
return RULES.some(rule => {
|
|
272
|
-
if (!evidenced.has(rule.psp))
|
|
273
|
-
return false;
|
|
274
|
-
if (rule.hostname.test(hostname))
|
|
275
|
-
return true;
|
|
276
|
-
// A templated origin (the VGS tenant frame) is covered by its hostname pattern above.
|
|
277
|
-
try {
|
|
278
|
-
return site(new URL(rule.origin).hostname) === target;
|
|
279
|
-
}
|
|
280
|
-
catch {
|
|
281
|
-
return false;
|
|
282
|
-
}
|
|
283
|
-
});
|
|
284
|
-
}
|
|
285
|
-
function validSnapshot(input) {
|
|
286
|
-
return record(input) && exactKeys(input, ['schema_version', 'catalog_version', 'signals', 'observation'])
|
|
287
|
-
&& input.schema_version === 1 && input.catalog_version === CHECKOUT_PREFLIGHT_CATALOG_VERSION
|
|
288
|
-
&& Array.isArray(input.signals) && input.signals.length <= CHECKOUT_PREFLIGHT_LIMITS.signals
|
|
289
|
-
&& Array.from(input.signals).every(signal => record(signal) && exactKeys(signal, ['rule_id', 'kind', 'frame_id', 'parent_frame_id', 'visible']) && metadata(signal)
|
|
290
|
-
&& id(signal.rule_id) && !!RULE_BY_ID.get(signal.rule_id)?.kinds.includes(signal.kind))
|
|
291
|
-
&& consistentParents(input.signals)
|
|
292
|
-
&& record(input.observation) && exactKeys(input.observation, ['complete', 'truncated', 'reasons'])
|
|
293
|
-
&& typeof input.observation.complete === 'boolean' && typeof input.observation.truncated === 'boolean'
|
|
294
|
-
&& Array.isArray(input.observation.reasons) && input.observation.reasons.length <= 32
|
|
295
|
-
&& Array.from(input.observation.reasons).every(reason => OBSERVATION_REASONS.includes(reason))
|
|
296
|
-
&& byteLength(input) <= CHECKOUT_PREFLIGHT_LIMITS.snapshot_bytes;
|
|
297
|
-
}
|
|
298
|
-
function validIntegration(value) {
|
|
299
|
-
return record(value) && exactKeys(value, ['id', 'version']) && ['direct_sdk', 'kernel_native'].includes(value.id) && (value.version === null || id(value.version));
|
|
300
|
-
}
|
|
301
|
-
function profileError(profile, integration, now) {
|
|
302
|
-
if (!record(profile) || !exactKeys(profile, ['schema_version', 'profile_version', 'catalog_version', 'integration', 'entries', 'processor_entries', 'expires_at'])
|
|
303
|
-
|| profile.schema_version !== 1 || !id(profile.profile_version) || !validIntegration(profile.integration) || !id(profile.integration.version)
|
|
304
|
-
|| !Array.isArray(profile.entries) || profile.entries.length > 256
|
|
305
|
-
|| (profile.processor_entries !== undefined && (!Array.isArray(profile.processor_entries) || profile.processor_entries.length > 256)))
|
|
306
|
-
return 'integration_profile_invalid';
|
|
307
|
-
if (profile.catalog_version !== CHECKOUT_PREFLIGHT_CATALOG_VERSION)
|
|
308
|
-
return 'integration_profile_incompatible';
|
|
309
|
-
if (profile.integration.id !== integration.id || profile.integration.version !== integration.version)
|
|
310
|
-
return 'integration_profile_mismatch';
|
|
311
|
-
if (profile.expires_at !== undefined) {
|
|
312
|
-
const expires = dateTime(profile.expires_at) ? Date.parse(profile.expires_at) : NaN;
|
|
313
|
-
const time = now === undefined ? Date.now() : dateTime(now) ? Date.parse(now) : NaN;
|
|
314
|
-
if (!Number.isFinite(expires) || !Number.isFinite(time))
|
|
315
|
-
return 'integration_profile_invalid';
|
|
316
|
-
if (expires <= time)
|
|
317
|
-
return 'integration_profile_expired';
|
|
318
|
-
}
|
|
319
|
-
const entries = new Set();
|
|
320
|
-
for (const entry of profile.entries) {
|
|
321
|
-
if (!record(entry) || !exactKeys(entry, ['flow', 'operation', 'operation_version', 'mode', 'scenario', 'status', 'limitations'])
|
|
322
|
-
|| !id(entry.flow) || !id(entry.operation) || !SCENARIOS.includes(entry.scenario) || !['supported', 'unsupported'].includes(entry.status)
|
|
323
|
-
|| (entry.limitations !== undefined && (!Array.isArray(entry.limitations) || entry.limitations.length > 16 || Array.from(entry.limitations).some(text => typeof text !== 'string' || text.length > 256 || /[\x00-\x1f]/.test(text)))))
|
|
324
|
-
return 'integration_profile_invalid';
|
|
325
|
-
const flow = FLOW_BY_ID.get(entry.flow);
|
|
326
|
-
if (!flow || entry.operation !== flow.operation || entry.operation_version !== flow.operation_version || entry.mode !== flow.mode)
|
|
327
|
-
return 'integration_profile_incompatible';
|
|
328
|
-
const key = `${entry.flow}:${entry.scenario}`;
|
|
329
|
-
if (entries.has(key))
|
|
330
|
-
return 'integration_profile_invalid';
|
|
331
|
-
entries.add(key);
|
|
332
|
-
}
|
|
333
|
-
const processors = new Set();
|
|
334
|
-
for (const entry of profile.processor_entries ?? []) {
|
|
335
|
-
if (!record(entry) || !exactKeys(entry, ['psp', 'mode', 'scenario', 'status', 'limitations'])
|
|
336
|
-
|| !id(entry.psp) || !SCENARIOS.includes(entry.scenario) || !['supported', 'unsupported'].includes(entry.status)
|
|
337
|
-
|| (entry.limitations !== undefined && (!Array.isArray(entry.limitations) || entry.limitations.length > 16 || Array.from(entry.limitations).some(text => typeof text !== 'string' || text.length > 256 || /[\x00-\x1f]/.test(text)))))
|
|
338
|
-
return 'integration_profile_invalid';
|
|
339
|
-
const processor = PROCESSOR_BY_ID.get(entry.psp);
|
|
340
|
-
if (!processor || processor.mode !== entry.mode)
|
|
341
|
-
return 'integration_profile_incompatible';
|
|
342
|
-
const key = `${entry.psp}:${entry.scenario}`;
|
|
343
|
-
if (processors.has(key))
|
|
344
|
-
return 'integration_profile_invalid';
|
|
345
|
-
processors.add(key);
|
|
346
|
-
}
|
|
347
|
-
return null;
|
|
348
|
-
}
|
|
349
|
-
/** Classify a sanitized snapshot. No browser, HTTP, or payment operations occur here. */
|
|
350
|
-
export function assessCheckoutSupport(input, options = {}) {
|
|
351
|
-
const opts = record(options) ? options : {};
|
|
352
|
-
const fallbackIntegrationId = record(opts.integration) && opts.integration.id === 'kernel_native' ? 'kernel_native' : 'direct_sdk';
|
|
353
|
-
const integration = validIntegration(opts.integration) ? clone(opts.integration) : {
|
|
354
|
-
id: fallbackIntegrationId,
|
|
355
|
-
version: opts.integration === undefined ? 'bundled' : null,
|
|
356
|
-
};
|
|
357
|
-
const result = {
|
|
358
|
-
schema_version: 1, catalog_version: CHECKOUT_PREFLIGHT_CATALOG_VERSION, integration,
|
|
359
|
-
scenario: opts.scenario !== undefined && SCENARIOS.includes(opts.scenario) ? opts.scenario : 'one_time', scenario_defaulted: opts.scenario === undefined,
|
|
360
|
-
psp: null, flow: null, mode: null, status: 'unknown', support_scope: null, checkout_flow_status: 'unknown', candidates: [], reason_codes: [], limitations: [], missing_evidence: [],
|
|
361
|
-
observation: { complete: false, truncated: false, reasons: ['invalid_observation'] }, scope: 'preflight_hint', merchant_confirmation_required: true,
|
|
362
|
-
};
|
|
363
|
-
if (!record(options) || !exactKeys(opts, ['scenario', 'integration', 'profile', 'now']) || (opts.scenario !== undefined && !SCENARIOS.includes(opts.scenario))
|
|
364
|
-
|| (opts.integration !== undefined && !validIntegration(opts.integration)) || (opts.now !== undefined && !dateTime(opts.now))) {
|
|
365
|
-
result.reason_codes = ['invalid_options'];
|
|
366
|
-
return result;
|
|
367
|
-
}
|
|
368
|
-
if (!validSnapshot(input)) {
|
|
369
|
-
result.reason_codes = [record(input) && input.catalog_version !== CHECKOUT_PREFLIGHT_CATALOG_VERSION ? 'catalog_incompatible' : 'invalid_snapshot'];
|
|
370
|
-
return result;
|
|
371
|
-
}
|
|
372
|
-
result.observation = cleanObservation(input.observation);
|
|
373
|
-
const candidates = new Map();
|
|
374
|
-
const activeFlows = new Set();
|
|
375
|
-
const activePsps = new Set();
|
|
376
|
-
const activeFlowFrames = new Set();
|
|
377
|
-
let missingCorroboration = false;
|
|
378
|
-
for (const signal of input.signals) {
|
|
379
|
-
const rule = RULE_BY_ID.get(signal.rule_id);
|
|
380
|
-
const active = signal.visible === true && (['frame', 'iframe', 'form'].includes(signal.kind)
|
|
381
|
-
|| signal.kind === 'document' && signal.frame_id === 0 && signal.parent_frame_id === null);
|
|
382
|
-
const candidate = candidates.get(rule.psp) ?? { psp: rule.psp, relevance: 'undetermined', evidence: [] };
|
|
383
|
-
candidate.evidence.push({ ...clone(signal), origin: rule.origin, path_pattern: rule.path_pattern });
|
|
384
|
-
if (active) {
|
|
385
|
-
candidate.relevance = 'active';
|
|
386
|
-
activePsps.add(rule.psp);
|
|
387
|
-
if (rule.flow) {
|
|
388
|
-
// A hosted route can also display an expired/error page. Require the reviewed
|
|
389
|
-
// Components script in that document; a similarly named asset elsewhere is insufficient.
|
|
390
|
-
const corroborated = rule.flow !== 'mollie.hosted_components' || signal.kind !== 'iframe' && input.signals.some(other => other.rule_id === 'mollie-components-script' && other.kind === 'script' && other.frame_id === signal.frame_id && other.parent_frame_id === signal.parent_frame_id);
|
|
391
|
-
if (corroborated) {
|
|
392
|
-
activeFlows.add(rule.flow);
|
|
393
|
-
activeFlowFrames.add(signal.frame_id);
|
|
394
|
-
}
|
|
395
|
-
else
|
|
396
|
-
missingCorroboration = true;
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
candidates.set(rule.psp, candidate);
|
|
400
|
-
}
|
|
401
|
-
result.candidates = [...candidates.values()].sort((a, b) => a.psp.localeCompare(b.psp));
|
|
402
|
-
if (missingCorroboration && activeFlows.size === 0)
|
|
403
|
-
result.reason_codes.push('flow_corroboration_missing');
|
|
404
|
-
if (activePsps.size === 1)
|
|
405
|
-
result.psp = [...activePsps][0];
|
|
406
|
-
// Script-only evidence names the processor only when the scan saw everything. On a partial scan
|
|
407
|
-
// the sole candidate stays listed as undetermined instead of becoming the selected route.
|
|
408
|
-
else if (activePsps.size === 0 && candidates.size === 1 && result.observation.complete)
|
|
409
|
-
result.psp = [...candidates.keys()][0];
|
|
410
|
-
if (!result.observation.complete)
|
|
411
|
-
result.reason_codes.push('observation_incomplete');
|
|
412
|
-
if (!input.signals.length) {
|
|
413
|
-
result.reason_codes.push('psp_not_detected');
|
|
414
|
-
result.missing_evidence.push('payment_page_signal');
|
|
415
|
-
}
|
|
416
|
-
if (activePsps.size > 1 || activeFlows.size > 1 || activeFlowFrames.size > 1 || activePsps.size === 0 && candidates.size > 1)
|
|
417
|
-
result.reason_codes.push('ambiguous_checkout');
|
|
418
|
-
if (activeFlows.size !== 1 || result.psp === null) {
|
|
419
|
-
result.reason_codes.push('checkout_flow_unidentified');
|
|
420
|
-
result.missing_evidence.push('active_checkout_flow');
|
|
421
|
-
}
|
|
422
|
-
else {
|
|
423
|
-
const flow = FLOW_BY_ID.get([...activeFlows][0]);
|
|
424
|
-
if (flow.psp === result.psp) {
|
|
425
|
-
result.flow = flow.id;
|
|
426
|
-
result.mode = flow.mode;
|
|
427
|
-
result.limitations.push(...flow.limitations);
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
if (!result.flow && result.candidates.length)
|
|
431
|
-
result.limitations.push('Processor assets alone do not establish the active card payment flow.');
|
|
432
|
-
const profile = opts.profile === undefined ? (integration.id === 'direct_sdk' && integration.version === 'bundled' ? DEFAULT_PROFILE : undefined) : opts.profile;
|
|
433
|
-
let error = profile === undefined ? 'integration_profile_missing' : profileError(profile, integration, opts.now);
|
|
434
|
-
if (integration.version === null)
|
|
435
|
-
error = 'integration_version_missing';
|
|
436
|
-
if (error) {
|
|
437
|
-
result.reason_codes.push(error);
|
|
438
|
-
result.missing_evidence.push('compatible_integration_profile');
|
|
439
|
-
}
|
|
440
|
-
result.reason_codes = unique(result.reason_codes);
|
|
441
|
-
const ambiguous = result.reason_codes.includes('ambiguous_checkout');
|
|
442
|
-
result.checkout_flow_status = ambiguous ? 'ambiguous' : result.flow ? 'identified' : 'unknown';
|
|
443
|
-
// Processor capability and observed checkout compatibility answer different questions.
|
|
444
|
-
// Missing flow evidence is advisory when an identified processor has an explicit
|
|
445
|
-
// implementation declaration. Incomplete, contradictory or invalid input stays unknown.
|
|
446
|
-
if (!result.observation.complete || ambiguous || error || !result.psp || missingCorroboration && !result.flow)
|
|
447
|
-
return result;
|
|
448
|
-
const flow = result.flow ? FLOW_BY_ID.get(result.flow) : undefined;
|
|
449
|
-
if (flow?.server_constraint === 'unsupported') {
|
|
450
|
-
result.status = 'unsupported';
|
|
451
|
-
result.support_scope = 'checkout_flow';
|
|
452
|
-
result.reason_codes.push('vault_flow_unsupported');
|
|
453
|
-
return result;
|
|
454
|
-
}
|
|
455
|
-
// A hidden document cannot lend its scripts to a visible card checkout. Script-only
|
|
456
|
-
// observations with no known hidden container can still identify an available adapter.
|
|
457
|
-
const eligible = input.signals.some(signal => RULE_BY_ID.get(signal.rule_id).psp === result.psp
|
|
458
|
-
&& (signal.kind === 'script' ? signal.visible !== false && !input.signals.some(container => container.frame_id === signal.frame_id && ['document', 'frame'].includes(container.kind) && container.visible !== true)
|
|
459
|
-
: signal.visible === true));
|
|
460
|
-
if (!eligible) {
|
|
461
|
-
result.reason_codes.push('payment_signal_inactive');
|
|
462
|
-
return result;
|
|
463
|
-
}
|
|
464
|
-
{
|
|
465
|
-
// A native declaration cannot expand the shared Vault's admitted processor variants.
|
|
466
|
-
const incompatible = input.signals.map(signal => ({ signal, rule: RULE_BY_ID.get(signal.rule_id) }))
|
|
467
|
-
.filter(({ signal, rule }) => rule.psp === result.psp && rule.variant_unverified
|
|
468
|
-
&& (signal.kind === 'script' ? signal.visible !== false : signal.visible === true));
|
|
469
|
-
if (incompatible.length) {
|
|
470
|
-
result.reason_codes.push('processor_variant_unverified');
|
|
471
|
-
result.limitations.push(...incompatible.map(({ rule }) => rule.variant_unverified));
|
|
472
|
-
return result;
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
const processor = PROCESSOR_BY_ID.get(result.psp);
|
|
476
|
-
const scenario = processor?.scenarios[result.scenario];
|
|
477
|
-
if (processor) {
|
|
478
|
-
const bundledSdk = integration.id === 'direct_sdk' && integration.version === 'bundled';
|
|
479
|
-
if (bundledSdk)
|
|
480
|
-
result.limitations.push(...processor.limitations);
|
|
481
|
-
for (const variant of processor.unsupported_variants) {
|
|
482
|
-
if (bundledSdk || variant.constraint === 'vault')
|
|
483
|
-
result.limitations.push(variant.reason);
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
if (scenario && (scenario.status === 'unsupported' || scenario.status === 'outside_vault')) {
|
|
487
|
-
result.status = 'unsupported';
|
|
488
|
-
result.mode = processor.mode;
|
|
489
|
-
result.support_scope = 'processor_integration';
|
|
490
|
-
result.reason_codes.push(scenario.reason);
|
|
491
|
-
return result;
|
|
492
|
-
}
|
|
493
|
-
const profileValue = profile;
|
|
494
|
-
const entry = flow && profileValue.entries.find(entry => entry.flow === flow.id && entry.scenario === result.scenario);
|
|
495
|
-
if (entry) {
|
|
496
|
-
result.status = entry.status;
|
|
497
|
-
result.support_scope = 'checkout_flow';
|
|
498
|
-
result.reason_codes.push(entry.status === 'supported' ? 'flow_supported_by_integration' : 'integration_flow_unsupported');
|
|
499
|
-
result.limitations.push(...(entry.limitations ?? []));
|
|
500
|
-
return result;
|
|
501
|
-
}
|
|
502
|
-
if (!processor)
|
|
503
|
-
return result;
|
|
504
|
-
result.mode = processor.mode;
|
|
505
|
-
const processorEntry = profileValue.processor_entries?.find(entry => entry.psp === processor.psp && entry.scenario === result.scenario);
|
|
506
|
-
if (!processorEntry) {
|
|
507
|
-
result.reason_codes.push(flow ? 'integration_flow_undeclared' : 'integration_processor_undeclared');
|
|
508
|
-
result.missing_evidence.push(flow ? 'integration_flow_capability' : 'integration_processor_capability');
|
|
509
|
-
return result;
|
|
510
|
-
}
|
|
511
|
-
result.status = processorEntry.status;
|
|
512
|
-
result.support_scope = 'processor_integration';
|
|
513
|
-
result.reason_codes.push(processorEntry.status === 'supported' ? 'processor_supported_by_integration' : 'integration_processor_unsupported');
|
|
514
|
-
result.limitations.push(...(processorEntry.limitations ?? []));
|
|
515
|
-
result.limitations = unique(result.limitations);
|
|
516
|
-
return result;
|
|
517
|
-
}
|
|
518
|
-
/** Machine-readable transport shapes; semantic compatibility is checked by the classifier. */
|
|
519
|
-
export function getCheckoutPreflightSchemas() {
|
|
520
|
-
const text = { type: 'string', minLength: 1, maxLength: 120, pattern: '^[A-Za-z0-9][A-Za-z0-9._+-]{0,119}$' };
|
|
521
|
-
const integration = { type: 'object', additionalProperties: false, required: ['id', 'version'], properties: { id: { enum: ['direct_sdk', 'kernel_native'] }, version: { anyOf: [text, { type: 'null' }] } } };
|
|
522
|
-
const observation = { type: 'object', additionalProperties: false, required: ['complete', 'truncated', 'reasons'], properties: { complete: { type: 'boolean' }, truncated: { type: 'boolean' }, reasons: { type: 'array', maxItems: 32, uniqueItems: true, items: { enum: OBSERVATION_REASONS } } } };
|
|
523
|
-
const signal = { type: 'object', additionalProperties: false, required: ['rule_id', 'kind', 'frame_id', 'parent_frame_id', 'visible'], properties: {
|
|
524
|
-
rule_id: { enum: RULES.map(rule => rule.id) }, kind: { enum: KINDS }, frame_id: { type: 'integer', minimum: 0, maximum: 63 },
|
|
525
|
-
parent_frame_id: { anyOf: [{ type: 'integer', minimum: 0, maximum: 63 }, { type: 'null' }] }, visible: { type: ['boolean', 'null'] },
|
|
526
|
-
} };
|
|
527
|
-
const profile = { $schema: 'https://json-schema.org/draft/2020-12/schema', type: 'object', additionalProperties: false,
|
|
528
|
-
required: ['schema_version', 'profile_version', 'catalog_version', 'integration', 'entries'], properties: {
|
|
529
|
-
schema_version: { const: 1 }, profile_version: text, catalog_version: { const: CHECKOUT_PREFLIGHT_CATALOG_VERSION }, integration,
|
|
530
|
-
processor_entries: { type: 'array', maxItems: 256, items: {
|
|
531
|
-
type: 'object', additionalProperties: false, required: ['psp', 'mode', 'scenario', 'status'], properties: {
|
|
532
|
-
psp: { enum: KNOWN_PSPS }, mode: { enum: ['token', 'cse', 'hosted_form'] }, scenario: { enum: SCENARIOS }, status: { enum: ['supported', 'unsupported'] },
|
|
533
|
-
limitations: { type: 'array', maxItems: 16, items: { type: 'string', maxLength: 256, pattern: '^[^\\u0000-\\u001f]*$' } },
|
|
534
|
-
},
|
|
535
|
-
} },
|
|
536
|
-
expires_at: { type: 'string', format: 'date-time', maxLength: 40 }, entries: { type: 'array', maxItems: 256, items: {
|
|
537
|
-
type: 'object', additionalProperties: false, required: ['flow', 'operation', 'operation_version', 'mode', 'scenario', 'status'], properties: {
|
|
538
|
-
flow: { enum: FLOWS.map(flow => flow.id) }, operation: { enum: FLOWS.map(flow => flow.operation) }, operation_version: { const: 1 },
|
|
539
|
-
mode: { enum: ['token', 'cse', 'hosted_form'] }, scenario: { enum: SCENARIOS }, status: { enum: ['supported', 'unsupported'] },
|
|
540
|
-
limitations: { type: 'array', maxItems: 16, items: { type: 'string', maxLength: 256, pattern: '^[^\\u0000-\\u001f]*$' } },
|
|
541
|
-
},
|
|
542
|
-
} },
|
|
543
|
-
} };
|
|
544
|
-
const snapshot = { $schema: 'https://json-schema.org/draft/2020-12/schema', type: 'object', additionalProperties: false,
|
|
545
|
-
required: ['schema_version', 'catalog_version', 'signals', 'observation'], properties: {
|
|
546
|
-
schema_version: { const: 1 }, catalog_version: { const: CHECKOUT_PREFLIGHT_CATALOG_VERSION },
|
|
547
|
-
signals: { type: 'array', maxItems: CHECKOUT_PREFLIGHT_LIMITS.signals, items: signal }, observation,
|
|
548
|
-
} };
|
|
549
|
-
const evidence = { ...signal, required: [...signal.required, 'origin', 'path_pattern'], properties: { ...signal.properties, origin: { type: 'string', maxLength: 256 }, path_pattern: { type: 'string', maxLength: 256 } } };
|
|
550
|
-
const result = { $schema: 'https://json-schema.org/draft/2020-12/schema', type: 'object', additionalProperties: false,
|
|
551
|
-
required: ['schema_version', 'catalog_version', 'integration', 'scenario', 'scenario_defaulted', 'psp', 'flow', 'mode', 'status', 'support_scope', 'checkout_flow_status', 'candidates', 'reason_codes', 'limitations', 'missing_evidence', 'observation', 'scope', 'merchant_confirmation_required'], properties: {
|
|
552
|
-
schema_version: { const: 1 }, catalog_version: { const: CHECKOUT_PREFLIGHT_CATALOG_VERSION }, integration,
|
|
553
|
-
scenario: { enum: SCENARIOS }, scenario_defaulted: { type: 'boolean' }, psp: { type: ['string', 'null'] }, flow: { type: ['string', 'null'] }, mode: { enum: ['token', 'cse', 'hosted_form', null] },
|
|
554
|
-
support_scope: { enum: ['processor_integration', 'checkout_flow', null] }, checkout_flow_status: { enum: ['identified', 'unknown', 'ambiguous'] },
|
|
555
|
-
status: { enum: ['supported', 'unsupported', 'unknown'] }, candidates: { type: 'array', items: { type: 'object', additionalProperties: false, required: ['psp', 'relevance', 'evidence'], properties: {
|
|
556
|
-
psp: { type: 'string' }, relevance: { enum: ['active', 'undetermined'] }, evidence: { type: 'array', items: evidence },
|
|
557
|
-
} } }, reason_codes: { type: 'array', items: { type: 'string' } }, limitations: { type: 'array', items: { type: 'string' } }, missing_evidence: { type: 'array', items: { type: 'string' } }, observation,
|
|
558
|
-
scope: { const: 'preflight_hint' }, merchant_confirmation_required: { const: true },
|
|
559
|
-
} };
|
|
560
|
-
const rawSignalProperties = { ...signal.properties, url: { type: 'string', maxLength: CHECKOUT_PREFLIGHT_LIMITS.raw_url_length } };
|
|
561
|
-
delete rawSignalProperties.rule_id;
|
|
562
|
-
const observations = { $schema: 'https://json-schema.org/draft/2020-12/schema', type: 'object', additionalProperties: false,
|
|
563
|
-
required: ['signals', 'observation'], properties: { signals: { type: 'array', maxItems: CHECKOUT_PREFLIGHT_LIMITS.signals, items: {
|
|
564
|
-
type: 'object', additionalProperties: false, required: ['url', 'kind', 'frame_id', 'parent_frame_id', 'visible'], properties: rawSignalProperties,
|
|
565
|
-
} }, observation } };
|
|
566
|
-
const options = { $schema: 'https://json-schema.org/draft/2020-12/schema', type: 'object', additionalProperties: false, properties: {
|
|
567
|
-
scenario: { enum: SCENARIOS }, integration, profile, now: { type: 'string', format: 'date-time', maxLength: 40 },
|
|
568
|
-
} };
|
|
569
|
-
return clone({ observations, options, snapshot, profile, result });
|
|
570
|
-
}
|