@agent-cards/sdk 0.23.27 → 0.24.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/CHANGELOG.md +66 -0
- package/PREFLIGHT.md +7 -1
- package/README.md +137 -99
- package/dist/aci.d.ts +52 -22
- package/dist/aci.js +79 -15
- package/dist/adyen-merchant-hosted.generated.d.ts +1 -1
- package/dist/adyen-merchant-hosted.generated.js +459 -21
- package/dist/agent-amount.generated.js +1 -1
- package/dist/agentcard.d.ts +4 -5
- package/dist/agentcard.js +4 -5
- package/dist/amadeus.d.ts +9 -3
- package/dist/amadeus.js +33 -4
- package/dist/api-module.d.ts +1 -7
- package/dist/api-module.js +3 -5
- package/dist/{voice-retry.js → api-retry.js} +1 -1
- package/dist/api-types.d.ts +53 -0
- package/dist/{voice-types.js → api-types.js} +7 -2
- package/dist/approvals.d.ts +166 -0
- package/dist/approvals.js +213 -0
- package/dist/buy.d.ts +20 -101
- package/dist/buy.js +19 -74
- package/dist/capabilities.generated.js +1 -1
- package/dist/card-fields.generated.js +1398 -106
- package/dist/cdp.d.ts +3 -13
- package/dist/cdp.js +231 -175
- package/dist/client.d.ts +104 -22
- package/dist/client.js +215 -40
- package/dist/creditguard.generated.d.ts +4 -4
- package/dist/datatrans.generated.js +22 -1
- package/dist/elavon-converge.generated.js +5 -3
- package/dist/hold.d.ts +8 -0
- package/dist/hold.js +43 -2
- package/dist/hosted-entry.js +2 -0
- package/dist/index.d.ts +9 -15
- package/dist/index.js +6 -10
- package/dist/juspay-gate.js +2 -2
- package/dist/juspay.generated.d.ts +2 -2
- package/dist/juspay.generated.js +174 -4
- package/dist/lifecycle.d.ts +9 -61
- package/dist/lifecycle.js +24 -10
- package/dist/merchant-card-endpoints.generated.d.ts +6 -1
- package/dist/merchant-card-endpoints.generated.js +344 -19
- package/dist/merchant-hosted.d.ts +8 -1
- package/dist/nike-order.d.ts +51 -0
- package/dist/nike-order.js +81 -0
- package/dist/oceanpayment.d.ts +38 -0
- package/dist/oceanpayment.js +70 -0
- package/dist/paddle-tokenex.generated.js +105 -10
- package/dist/payplug.d.ts +41 -0
- package/dist/payplug.js +71 -0
- package/dist/payrails.generated.js +27 -7
- package/dist/payrexx.generated.js +176 -2
- package/dist/pre-claim.d.ts +9 -0
- package/dist/pre-claim.js +86 -7
- package/dist/preflight-capabilities.generated.d.ts +0 -4
- package/dist/preflight-capabilities.generated.js +0 -5
- package/dist/preflight-catalog.json +46 -5
- package/dist/preflight-playwright.d.ts +2 -2
- package/dist/preflight-playwright.js +63 -14
- package/dist/preflight-schemas.json +4 -0
- package/dist/preflight.generated.d.ts +0 -4
- package/dist/preflight.generated.js +24 -1
- package/dist/prepared-processor.d.ts +18 -5
- package/dist/prepared-processor.js +48 -8
- package/dist/primer.generated.js +1418 -120
- package/dist/processout.generated.d.ts +61 -0
- package/dist/processout.generated.js +577 -0
- package/dist/requests.js +1 -1
- package/dist/shiji-sts.generated.js +105 -10
- package/dist/stripe-checkout.generated.js +1405 -234
- package/dist/substitutions.generated.js +460 -26
- package/dist/tap-payments.generated.js +105 -10
- package/dist/twoc2p.generated.js +105 -10
- package/dist/url-masks/bluesnap.d.ts +2 -0
- package/dist/url-masks/bluesnap.js +15 -0
- package/dist/url-masks/oceanpayment.d.ts +2 -0
- package/dist/url-masks/oceanpayment.js +13 -0
- package/dist/url-masks/payplug.d.ts +2 -0
- package/dist/url-masks/payplug.js +13 -0
- package/dist/url-masks/vtex_payments.d.ts +2 -0
- package/dist/url-masks/vtex_payments.js +12 -0
- package/dist/url-masks.generated.d.ts +1 -1
- package/dist/url-masks.generated.js +6 -2
- package/dist/verifone.generated.js +42 -2
- package/dist/vtex-payments.generated.d.ts +127 -0
- package/dist/vtex-payments.generated.js +544 -0
- package/dist/webhooks.d.ts +2 -2
- package/dist/webhooks.js +2 -2
- package/dist/wspay.generated.d.ts +1 -1
- package/dist/wspay.generated.js +175 -3
- package/examples/preflight/kernel-native/inventory.json +1 -1
- package/package.json +6 -8
- package/dist/languages.d.ts +0 -23
- package/dist/languages.js +0 -76
- package/dist/voice-pkce.d.ts +0 -49
- package/dist/voice-pkce.js +0 -147
- package/dist/voice-stream.generated.d.ts +0 -118
- package/dist/voice-stream.generated.js +0 -170
- package/dist/voice-types.d.ts +0 -735
- package/dist/voice.d.ts +0 -373
- package/dist/voice.js +0 -815
- package/readme.test.mjs +0 -53
- /package/dist/{voice-retry.d.ts → api-retry.d.ts} +0 -0
package/dist/pre-claim.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { type MerchantProfile } from './merchant-hosted.js';
|
|
|
12
12
|
import type { MerchantHandoffWatch } from './merchant-handoff.js';
|
|
13
13
|
import { type CybersourceFlexDecision, type CybersourceFlexPause, type FlexRequest } from './cybersource-flex.js';
|
|
14
14
|
import { type CardEndpointProfile } from './card-endpoint.js';
|
|
15
|
+
import { type NikeOrders } from './nike-order.js';
|
|
15
16
|
import { type PayrailsSessionCapture, type PayrailsSidecar } from './payrails.js';
|
|
16
17
|
import { type VerifoneProfile } from './verifone.js';
|
|
17
18
|
import { type WorldlineMyCheckoutProducts } from './worldline-mycheckout.js';
|
|
@@ -250,6 +251,8 @@ export interface PreClaimContext {
|
|
|
250
251
|
* card frame is refused.
|
|
251
252
|
*/
|
|
252
253
|
payrexx?: PayrexxFollowUps;
|
|
254
|
+
/** The approval Nike's order is held to once a card went through Nike's profile (nike-order.ts). Absent: Nike's order is left alone. */
|
|
255
|
+
nikeOrders?: NikeOrders;
|
|
253
256
|
}
|
|
254
257
|
/**
|
|
255
258
|
* The URL an event may name for a request. For an armed merchant profile's
|
|
@@ -265,6 +268,10 @@ export declare function eventUrl(vault: {
|
|
|
265
268
|
/** A gate returns a decision when it handles the request, undefined to defer to
|
|
266
269
|
* the next gate, or a promise of either when it must do I/O first. */
|
|
267
270
|
export type PreClaimGate = (ctx: PreClaimContext) => PreClaimDecision | undefined | Promise<PreClaimDecision | undefined>;
|
|
271
|
+
/** What the Nike order gate reads of a paused request and its attachment. */
|
|
272
|
+
export type NikeOrderGateContext = Pick<PreClaimContext, 'request' | 'nikeOrders' | 'lifecycle' | 'effects' | 'onEvent' | 'lifecycleAborted' | 'terminal'>;
|
|
273
|
+
/** The Nike order gate's decision, already performed, or undefined when the request is not its to judge. */
|
|
274
|
+
export declare function nikeOrderGate(ctx: NikeOrderGateContext): Promise<PreClaimDecision> | undefined;
|
|
268
275
|
export declare const MERCHANT_BODY_UNREADABLE = "the paused request carries no body the SDK could read, so Agentcard cannot tell whether it carries a card";
|
|
269
276
|
export declare const verifonePreClaim: PreClaimGate;
|
|
270
277
|
export declare const fiservPreClaim: PreClaimGate;
|
|
@@ -280,6 +287,7 @@ export declare function isArmedCreditguardCall(vault: {
|
|
|
280
287
|
} | undefined, url: string): boolean;
|
|
281
288
|
export declare const przelewy24PreClaim: PreClaimGate;
|
|
282
289
|
export declare const barionPreClaim: PreClaimGate;
|
|
290
|
+
export declare const payplugPreClaim: PreClaimGate;
|
|
283
291
|
export declare const ekashuPreClaim: PreClaimGate;
|
|
284
292
|
export declare const transbankPreClaim: PreClaimGate;
|
|
285
293
|
export declare const paytrailPreClaim: PreClaimGate;
|
|
@@ -287,6 +295,7 @@ export declare const redsysPreClaim: PreClaimGate;
|
|
|
287
295
|
export declare const quickpayPreClaim: PreClaimGate;
|
|
288
296
|
export declare const comgatePreClaim: PreClaimGate;
|
|
289
297
|
export declare const eximbayPreClaim: PreClaimGate;
|
|
298
|
+
export declare const oceanpaymentPreClaim: PreClaimGate;
|
|
290
299
|
export declare const paypalHostedFieldsPreClaim: PreClaimGate;
|
|
291
300
|
export declare const paypalCardFormsPreClaim: PreClaimGate;
|
|
292
301
|
export declare const cybersourceSecureAcceptancePreClaim: PreClaimGate;
|
package/dist/pre-claim.js
CHANGED
|
@@ -66,7 +66,7 @@ import { datatransPauseDecision, isDatatransHost } from './datatrans.js';
|
|
|
66
66
|
import { DATATRANS_INVALID_REQUEST } from './datatrans.generated.js';
|
|
67
67
|
import { INVALID_TOKENEX_IFRAME_REQUEST, TOKENEX_IFRAME_PSP, isTokenexIframePath, servesTokenexIframe, tokenexIframePauseDecision, } from './tokenex-iframe.js';
|
|
68
68
|
import { isPelecardHost, pelecardRefusal } from './pelecard.js';
|
|
69
|
-
import { ACI_CHECKOUT_REUSED } from './aci.js';
|
|
69
|
+
import { ACI_CHECKOUT_REUSED, SPLIT_CARD_REUSED } from './aci.js';
|
|
70
70
|
import { ACI_EXPIRY_UNSTRIPPABLE } from './aci.generated.js';
|
|
71
71
|
import { CREDITGUARD_PPS_HOSTS, classifyCreditguardRequest, creditguardCompanionAnswer, creditguardCompanionCall, creditguardNuveiRefusal, creditguardProcessRefusal, creditguardProcessTxId, } from './creditguard.generated.js';
|
|
72
72
|
import { isPrimerPciHost, primerRequestVerdict } from './primer.js';
|
|
@@ -78,6 +78,7 @@ import { isFiservCaptureHost, isFiservPausableBody } from './fiserv.js';
|
|
|
78
78
|
import { CYBERSOURCE_FLEX_PSP, isCybersourceFlexHost } from './cybersource-flex.js';
|
|
79
79
|
import { cardEndpointCarriesCard, cardEndpointDetail, cardEndpointFor, cardEndpointLive, cardEndpointPasses, cardEndpointResendFor, cardEndpointReviewed, } from './card-endpoint.js';
|
|
80
80
|
import { cardEndpointStoppedPage, refusedNavigationOutcome } from './card-endpoint-page.js';
|
|
81
|
+
import { NIKE_ORDER_DETAIL } from './nike-order.js';
|
|
81
82
|
import { PAYRAILS_HOLDING_REASONS, PAYRAILS_SESSION_MESSAGE, isPayrailsHost, isPayrailsPaymentUrl, isPayrailsStaticHost, payrailsKeyRefusal, payrailsPaymentRefusal, payrailsRequestKind, payrailsSaveRefusal, } from './payrails.js';
|
|
82
83
|
import { classifyVerifoneProfileRequest, verifoneTemplatedUrl } from './verifone.js';
|
|
83
84
|
import { isPaymentHighwayCardLookup, isPaymentHighwayHost, isPaytrailCardMethodUrl, isPaytrailEntry, isPaytrailServed } from './paytrail.js';
|
|
@@ -86,9 +87,11 @@ import { isArmedTransbankUrl } from './transbank.js';
|
|
|
86
87
|
import { isRedsysEntry, isRedsysHost, redsysEntryUrl } from './redsys.js';
|
|
87
88
|
import { isArmedPrzelewy24Url, isPrzelewy24PayStep } from './przelewy24.js';
|
|
88
89
|
import { isArmedBarionUrl, isBarionPayStep } from './barion.js';
|
|
90
|
+
import { isArmedPayplugUrl, isPayplugPayStep } from './payplug.js';
|
|
89
91
|
import { isQuickpayCardLookup, isQuickpayEntry, quickpayEntryUrl } from './quickpay.js';
|
|
90
92
|
import { isArmedComgateUrl } from './comgate.js';
|
|
91
93
|
import { isArmedEximbayUrl, isEximbayEntry } from './eximbay.js';
|
|
94
|
+
import { isArmedOceanpaymentUrl, isOceanpaymentSendPay } from './oceanpayment.js';
|
|
92
95
|
import { PAYPAL_HOSTED_FIELDS_REASON, isPaypalHostedFieldsConfirm, paypalHostedFieldsBody } from './paypal-hosted-fields.js';
|
|
93
96
|
import { PAYPAL_CARD_FIELDS_REASON, PAYPAL_GUEST_CHECKOUT_REASON, isPaypalCardFieldsConfirm, isPaypalGraphql, paypalCardFieldsBody, paypalGraphqlCard, paypalGraphqlNamesCardOperation, } from './paypal-card-forms.js';
|
|
94
97
|
import { CYBERSOURCE_SECURE_ACCEPTANCE_REASON, CYBERSOURCE_SECURE_ACCEPTANCE_RECIPIENT, cybersourceSecureAcceptanceRequest, isCybersourceSecureAcceptanceUrl, isSecureAcceptanceFramePost, } from './cybersource-secure-acceptance.js';
|
|
@@ -287,6 +290,38 @@ async function cardEndpointUnsupported(ctx, profile, reviewed) {
|
|
|
287
290
|
await ctx.effects.abort();
|
|
288
291
|
return { kind: 'abort' };
|
|
289
292
|
}
|
|
293
|
+
// Nike's order after its card request (nike-order.ts, payment-core merchant-card-endpoint-nike-order.js), Felipe's amount
|
|
294
|
+
// rule C: the one request off a profile's endpoint the SDK holds. Once the adapters asked the cardholder to pay a card
|
|
295
|
+
// request through Nike's profile on this attachment, every write to Nike's API host is judged here. One reviewed order
|
|
296
|
+
// whose total and currency are the approved amount continues with its body unchanged, and only while the checkout still
|
|
297
|
+
// names that approval as under way (followUpMaySend); after it, only a byte-identical retry does. An order that fails the
|
|
298
|
+
// rule aborts, so Nike never authorizes the card, and the checkout ends failed with nothing charged
|
|
299
|
+
// (lifecycle.merchantOrderRefused); so does every order while no approved amount was read, and every later order under
|
|
300
|
+
// that approval. Another order after the one let go, or one the checkout no longer names as under way, aborts and leaves
|
|
301
|
+
// the checkout's state as it is. Anything else, every request of an attachment where no card went through Nike's
|
|
302
|
+
// profile included, defers. The adapters also run nikeOrderGate on a request paused at the browser target.
|
|
303
|
+
const nikeOrderPreClaim = (ctx) => nikeOrderGate(ctx);
|
|
304
|
+
/** The Nike order gate's decision, already performed, or undefined when the request is not its to judge. */
|
|
305
|
+
export function nikeOrderGate(ctx) {
|
|
306
|
+
const verdict = ctx.nikeOrders?.judge(ctx.request.url, ctx.request.method, () => ctx.request.body, (authorizationId) => followUpMaySend(ctx, { authorizationId })) ?? null;
|
|
307
|
+
if (!verdict)
|
|
308
|
+
return undefined;
|
|
309
|
+
return verdict.refusal === null ? nikeOrderReleased(ctx, verdict.authorizationId) : nikeOrderRefused(ctx, verdict.authorizationId, verdict.refusal);
|
|
310
|
+
}
|
|
311
|
+
// The refusals that stop one order and leave the checkout's state as it is.
|
|
312
|
+
const NIKE_ORDER_STOPS = new Set(['another_order', 'approval_not_current', 'earlier_order_refused']);
|
|
313
|
+
async function nikeOrderReleased(ctx, authorizationId) {
|
|
314
|
+
ctx.onEvent?.({ type: 'merchant_order_released', detail: { authorizationId, ...NIKE_ORDER_DETAIL } });
|
|
315
|
+
await ctx.effects.continueRequest().catch(() => { });
|
|
316
|
+
return { kind: 'continue' };
|
|
317
|
+
}
|
|
318
|
+
async function nikeOrderRefused(ctx, authorizationId, reason) {
|
|
319
|
+
if (!NIKE_ORDER_STOPS.has(reason))
|
|
320
|
+
ctx.lifecycle.merchantOrderRefused(`merchant_order_${reason}`);
|
|
321
|
+
ctx.onEvent?.({ type: 'merchant_order_refused', detail: { authorizationId, ...NIKE_ORDER_DETAIL, reason } });
|
|
322
|
+
await ctx.effects.abort();
|
|
323
|
+
return { kind: 'abort' };
|
|
324
|
+
}
|
|
290
325
|
// Mercado Pago's native Checkout Pro shares one origin between its BIN-lookup
|
|
291
326
|
// configuration and its card association. A request that is not for that origin
|
|
292
327
|
// defers synchronously; a POST to it is handled asynchronously (a document read
|
|
@@ -1034,6 +1069,12 @@ async function pelecardBlock(ctx, reason) {
|
|
|
1034
1069
|
// Everything else on ACI's hosts (the widget script, /bins, /v1/collect, GETs)
|
|
1035
1070
|
// is not a POST to a checkout and defers. Synchronous for the card-number
|
|
1036
1071
|
// request, so it pauses in the microtask it paused in.
|
|
1072
|
+
// A JSON split card the registry serves (aci.ts) takes the same path, keyed by
|
|
1073
|
+
// the URL its legs share: its card request defers to the arbiter unless that URL
|
|
1074
|
+
// already has one answered, or one running with no approval open
|
|
1075
|
+
// (split_card_reused), its code and expiry requests are held, a holder request
|
|
1076
|
+
// continues, and anything else is refused with the processor's code or
|
|
1077
|
+
// split_card_leg_unsupported. It has no /payment.
|
|
1037
1078
|
const aciPreClaim = (ctx) => {
|
|
1038
1079
|
const leg = ctx.aci?.classify(ctx.request.url, ctx.request.method, ctx.request.body);
|
|
1039
1080
|
if (!leg)
|
|
@@ -1050,8 +1091,15 @@ const aciPreClaim = (ctx) => {
|
|
|
1050
1091
|
return aciPayment(ctx);
|
|
1051
1092
|
// The card-number request: the arbiter pauses it for the vault claim flow,
|
|
1052
1093
|
// unless this checkout already has one running or answered (AciGate.begin).
|
|
1053
|
-
|
|
1054
|
-
|
|
1094
|
+
// While a JSON split card's approval is still open, its card request again is
|
|
1095
|
+
// the page's retry of the one it gave up on: the adapters bind that retry to
|
|
1096
|
+
// the open approval, or refuse it there as a second purchase, so the page's
|
|
1097
|
+
// retry gets the late approval's answer instead of a refusal here.
|
|
1098
|
+
if (ctx.aci.reused(leg)) {
|
|
1099
|
+
if ('group' in leg && ctx.awaitingApproval())
|
|
1100
|
+
return undefined;
|
|
1101
|
+
return aciRefuse(ctx, 'group' in leg ? SPLIT_CARD_REUSED : ACI_CHECKOUT_REUSED);
|
|
1102
|
+
}
|
|
1055
1103
|
return undefined;
|
|
1056
1104
|
};
|
|
1057
1105
|
async function aciContinue(ctx) {
|
|
@@ -1059,16 +1107,17 @@ async function aciContinue(ctx) {
|
|
|
1059
1107
|
return { kind: 'continue' };
|
|
1060
1108
|
}
|
|
1061
1109
|
async function aciHold(ctx, leg) {
|
|
1110
|
+
const prefix = 'group' in leg ? 'split_card' : 'aci';
|
|
1062
1111
|
const answer = await ctx.aci.hold(leg);
|
|
1063
1112
|
if (answer && !ctx.interceptionAborted() && !ctx.lifecycleAborted()) {
|
|
1064
1113
|
try {
|
|
1065
1114
|
await ctx.effects.answer(answer);
|
|
1066
|
-
ctx.onEvent?.({ type:
|
|
1115
|
+
ctx.onEvent?.({ type: `${prefix}_leg_absorbed`, detail: { url: redactUrl(ctx.request.url) } });
|
|
1067
1116
|
return { kind: 'answer' };
|
|
1068
1117
|
}
|
|
1069
1118
|
catch { /* the page's request is gone; nothing was forwarded */ }
|
|
1070
1119
|
}
|
|
1071
|
-
ctx.onEvent?.({ type: 'blocked', detail:
|
|
1120
|
+
ctx.onEvent?.({ type: 'blocked', detail: `${prefix}_leg_unanswered` });
|
|
1072
1121
|
await ctx.effects.abort();
|
|
1073
1122
|
return { kind: 'abort' };
|
|
1074
1123
|
}
|
|
@@ -1680,6 +1729,20 @@ export const barionPreClaim = (ctx) => {
|
|
|
1680
1729
|
return undefined;
|
|
1681
1730
|
return processorPageAbort(ctx);
|
|
1682
1731
|
};
|
|
1732
|
+
// PayPlug's payment page (payplug.ts). Once this build's registry serves PayPlug's entry (a capability the API serves
|
|
1733
|
+
// only to Agentcard's own company), every request to PayPlug's page host pauses. The merchant's redirect to the page,
|
|
1734
|
+
// a GET of /pay/<payment id> or /pay/test/<payment id> exactly, is no step of this gate's: it defers, and the terminal
|
|
1735
|
+
// arbiter pauses it for the claim flow like any card request, so the cardholder's device pays it. Every step toward
|
|
1736
|
+
// paying on the page itself aborts as an unsupported checkout: every POST to the page's host, the card post among
|
|
1737
|
+
// them. So PayPlug never sees the card the agent typed. The page's own GETs, its scripts, styles, images and frames,
|
|
1738
|
+
// continue. With PayPlug not served, the gate defers, and every request continues as before. Synchronous until it must
|
|
1739
|
+
// abort, like every gate. Exported for the gate registry's tests.
|
|
1740
|
+
export const payplugPreClaim = (ctx) => {
|
|
1741
|
+
const { url, method } = ctx.request;
|
|
1742
|
+
if (!isPayplugPayStep(url, method) || !isArmedPayplugUrl(ctx.vault, url))
|
|
1743
|
+
return undefined;
|
|
1744
|
+
return processorPageAbort(ctx);
|
|
1745
|
+
};
|
|
1683
1746
|
// NMI's hosted payment page (ekashu.ts). Once this build's registry serves NMI's entry (a
|
|
1684
1747
|
// capability the API serves only to a company Agentcard turned NMI on for), every request to
|
|
1685
1748
|
// NMI's two hosts pauses, and this gate judges the POSTs:
|
|
@@ -1844,6 +1907,21 @@ export const eximbayPreClaim = (ctx) => {
|
|
|
1844
1907
|
return undefined;
|
|
1845
1908
|
return processorPageAbort(ctx);
|
|
1846
1909
|
};
|
|
1910
|
+
// Oceanpayment's hosted payment page (oceanpayment.ts). Once this build's registry serves Oceanpayment's card post (a
|
|
1911
|
+
// capability the API serves only to the company the gate turns Oceanpayment on for), every request to its two hosts
|
|
1912
|
+
// pauses, and this gate judges the ones that are not a GET:
|
|
1913
|
+
// - the page's card post, exactly as its form action writes it, defers, and the terminal arbiter pauses it for the
|
|
1914
|
+
// claim flow like any card request: the cardholder's device pays it;
|
|
1915
|
+
// - every other one (Cardinal's device-data call, which carries the typed number, a card post of another spelling, the
|
|
1916
|
+
// page's cancel) aborts as an unsupported checkout, so Oceanpayment never sees the card the agent typed.
|
|
1917
|
+
// A GET (the page, its scripts, its log) is not this gate's and continues. With Oceanpayment not served, the gate defers
|
|
1918
|
+
// and every request continues as before. Synchronous until it must abort, like every gate. Exported for its tests.
|
|
1919
|
+
export const oceanpaymentPreClaim = (ctx) => {
|
|
1920
|
+
const { url, method } = ctx.request;
|
|
1921
|
+
if (String(method).toUpperCase() === 'GET' || !isArmedOceanpaymentUrl(ctx.vault, url) || isOceanpaymentSendPay(url, method))
|
|
1922
|
+
return undefined;
|
|
1923
|
+
return processorPageAbort(ctx);
|
|
1924
|
+
};
|
|
1847
1925
|
// PayPal's legacy Hosted Fields (paypal-hosted-fields.ts). Its tokenization frame posts the card the
|
|
1848
1926
|
// agent typed to the Orders v2 confirm-payment-source on cors.api.paypal.com (or its sandbox), which
|
|
1849
1927
|
// no Vault mode takes over, so every company's adapters hand each POST there to this gate:
|
|
@@ -2499,8 +2577,9 @@ async function unsupportedContinue(ctx) {
|
|
|
2499
2577
|
* arbiter runs after all of them and is not part of this list. A gate appended
|
|
2500
2578
|
* after Stripe is never offered a step Stripe claimed: Stripe answers, aborts or
|
|
2501
2579
|
* pauses each one itself. */
|
|
2502
|
-
export const PSP_PRE_CLAIM_GATES = [cardEndpointResendPreClaim, cardEndpointPreClaim, mercadoPreClaim, juspayPreClaim, braintreePreClaim, stripePreClaim, merchantHostedPreClaim, verifonePreClaim, fiservPreClaim, gmoPreClaim, cybersourceFlexPreClaim, datatransPreClaim, tokenexIframePreClaim, pelecardPreClaim, aciPreClaim, creditguardPreClaim, primerPreClaim, payrailsPreClaim, convergePreClaim, eprotectPreClaim, sbpsPreClaim, wspayPreClaim, shijiStsPreClaim, ekashuPreClaim, redsysPreClaim, quickpayPreClaim, comgatePreClaim, przelewy24PreClaim, transbankPreClaim, eximbayPreClaim, barionPreClaim, paypalHostedFieldsPreClaim,
|
|
2503
|
-
paypalCardFormsPreClaim, cybersourceSecureAcceptancePreClaim, worldlineMyCheckoutPreClaim, paddleVgsPayPreClaim, ebanxPreClaim, payrexxPreClaim, hipayPreClaim, paytrailPreClaim
|
|
2580
|
+
export const PSP_PRE_CLAIM_GATES = [cardEndpointResendPreClaim, cardEndpointPreClaim, nikeOrderPreClaim, mercadoPreClaim, juspayPreClaim, braintreePreClaim, stripePreClaim, merchantHostedPreClaim, verifonePreClaim, fiservPreClaim, gmoPreClaim, cybersourceFlexPreClaim, datatransPreClaim, tokenexIframePreClaim, pelecardPreClaim, aciPreClaim, creditguardPreClaim, primerPreClaim, payrailsPreClaim, convergePreClaim, eprotectPreClaim, sbpsPreClaim, wspayPreClaim, shijiStsPreClaim, ekashuPreClaim, redsysPreClaim, quickpayPreClaim, comgatePreClaim, przelewy24PreClaim, transbankPreClaim, eximbayPreClaim, barionPreClaim, payplugPreClaim, paypalHostedFieldsPreClaim,
|
|
2581
|
+
paypalCardFormsPreClaim, cybersourceSecureAcceptancePreClaim, worldlineMyCheckoutPreClaim, paddleVgsPayPreClaim, ebanxPreClaim, payrexxPreClaim, hipayPreClaim, paytrailPreClaim,
|
|
2582
|
+
oceanpaymentPreClaim];
|
|
2504
2583
|
/** Run each gate in order; the first to return a decision wins. If none does,
|
|
2505
2584
|
* the terminal arbiter decides between continue, abort (unsupported) and pause.
|
|
2506
2585
|
* Returns synchronously while every gate defers synchronously (an ordinary card
|
|
@@ -1193,10 +1193,6 @@ export declare const CHECKOUT_PREFLIGHT_CAPABILITIES: {
|
|
|
1193
1193
|
readonly psp: "vgs";
|
|
1194
1194
|
readonly reason: "iframe_bound_tokenization";
|
|
1195
1195
|
readonly action: "human_checkout";
|
|
1196
|
-
}, {
|
|
1197
|
-
readonly psp: "bluesnap";
|
|
1198
|
-
readonly reason: "multi_request_tokenization_not_supported";
|
|
1199
|
-
readonly action: "human_checkout";
|
|
1200
1196
|
}, {
|
|
1201
1197
|
readonly psp: "stripe";
|
|
1202
1198
|
readonly reason: "unbound_token_to_payment_intent_continuation";
|
|
@@ -1840,11 +1840,6 @@ export const CHECKOUT_PREFLIGHT_CAPABILITIES = {
|
|
|
1840
1840
|
"reason": "iframe_bound_tokenization",
|
|
1841
1841
|
"action": "human_checkout"
|
|
1842
1842
|
},
|
|
1843
|
-
{
|
|
1844
|
-
"psp": "bluesnap",
|
|
1845
|
-
"reason": "multi_request_tokenization_not_supported",
|
|
1846
|
-
"action": "human_checkout"
|
|
1847
|
-
},
|
|
1848
1843
|
{
|
|
1849
1844
|
"psp": "stripe",
|
|
1850
1845
|
"reason": "unbound_token_to_payment_intent_continuation",
|
|
@@ -2139,6 +2139,52 @@
|
|
|
2139
2139
|
"hostname_pattern": "^cdn\\.sandbox\\.[a-z0-9-]+\\.gr4vy\\.app$",
|
|
2140
2140
|
"pathname_pattern": "^\\/secure-fields\\/(?:latest|[0-9]{1,3}(?:\\.[0-9]{1,3}){0,2})\\/secure-fields\\.js$"
|
|
2141
2141
|
},
|
|
2142
|
+
{
|
|
2143
|
+
"id": "bambora-na-custom-checkout-fields",
|
|
2144
|
+
"psp": "bambora",
|
|
2145
|
+
"kinds": [
|
|
2146
|
+
"frame",
|
|
2147
|
+
"iframe",
|
|
2148
|
+
"document"
|
|
2149
|
+
],
|
|
2150
|
+
"origin": "https://libs.na.bambora.com",
|
|
2151
|
+
"path_pattern": "/customcheckout/1.:minor.:patch{,-:build}/iframe.html",
|
|
2152
|
+
"sources": [
|
|
2153
|
+
{
|
|
2154
|
+
"kind": "primary_source",
|
|
2155
|
+
"reference": "https://docs.na.worldline-solutions.com/build-your-integration/checkout-form/custom-checkout/reference",
|
|
2156
|
+
"reviewed_on": "2026-09-11"
|
|
2157
|
+
},
|
|
2158
|
+
{
|
|
2159
|
+
"kind": "saved_observation",
|
|
2160
|
+
"reference": "catalog-psp-scan-2026-10-23:kent-ca-custom-checkout-1.0.2-card-fields",
|
|
2161
|
+
"reviewed_on": "2026-10-23"
|
|
2162
|
+
}
|
|
2163
|
+
],
|
|
2164
|
+
"hostname_pattern": "^libs\\.na\\.bambora\\.com$",
|
|
2165
|
+
"pathname_pattern": "^\\/customcheckout\\/1\\.[0-9]{1,3}\\.[0-9]{1,3}(?:-[0-9]{1,4})?\\/iframe\\.html$"
|
|
2166
|
+
},
|
|
2167
|
+
{
|
|
2168
|
+
"id": "worldpay-wpg-hosted-payment-page",
|
|
2169
|
+
"psp": "worldpay",
|
|
2170
|
+
"kinds": [
|
|
2171
|
+
"document",
|
|
2172
|
+
"frame",
|
|
2173
|
+
"iframe"
|
|
2174
|
+
],
|
|
2175
|
+
"origin": "https://payments.worldpay.com",
|
|
2176
|
+
"path_pattern": "/app/{hpp,hpp-iframe}/*",
|
|
2177
|
+
"sources": [
|
|
2178
|
+
{
|
|
2179
|
+
"kind": "saved_observation",
|
|
2180
|
+
"reference": "catalog-psp-scan-2026-10-23:razer-worldpay-hosted-payment-page",
|
|
2181
|
+
"reviewed_on": "2026-10-23"
|
|
2182
|
+
}
|
|
2183
|
+
],
|
|
2184
|
+
"variant_unverified": "The implemented Worldpay adapter covers Access Checkout card sessions; Worldpay hosted payment pages under payments.worldpay.com/app/hpp take the card on Worldpay's own page and are not admitted.",
|
|
2185
|
+
"hostname_pattern": "^payments\\.worldpay\\.com$",
|
|
2186
|
+
"pathname_pattern": "^\\/app\\/hpp(?:-iframe)?\\/"
|
|
2187
|
+
},
|
|
2142
2188
|
{
|
|
2143
2189
|
"id": "paypal-hosted-fields-payments-sdk",
|
|
2144
2190
|
"psp": "paypal",
|
|
@@ -6958,11 +7004,6 @@
|
|
|
6958
7004
|
"reason": "iframe_bound_tokenization",
|
|
6959
7005
|
"action": "human_checkout"
|
|
6960
7006
|
},
|
|
6961
|
-
{
|
|
6962
|
-
"psp": "bluesnap",
|
|
6963
|
-
"reason": "multi_request_tokenization_not_supported",
|
|
6964
|
-
"action": "human_checkout"
|
|
6965
|
-
},
|
|
6966
7007
|
{
|
|
6967
7008
|
"psp": "stripe",
|
|
6968
7009
|
"reason": "unbound_token_to_payment_intent_continuation",
|
|
@@ -20,9 +20,9 @@ export interface CheckoutCollectionOptions {
|
|
|
20
20
|
timeoutMs?: number;
|
|
21
21
|
/** Maximum frame count. Default and maximum 64. */
|
|
22
22
|
maxFrames?: number;
|
|
23
|
-
/** Maximum document and asset observations. Default and maximum 2,048. */
|
|
23
|
+
/** Maximum document and asset observations. Default and maximum 2,048. An asset no reviewed rule can match is skipped and not counted. */
|
|
24
24
|
maxSignals?: number;
|
|
25
|
-
/** Maximum transient observation and returned snapshot size. Default and maximum 262,144 bytes; minimum 512 bytes. */
|
|
25
|
+
/** Maximum transient observation and returned snapshot size. Default and maximum 262,144 bytes; minimum 512 bytes. Skipped assets cost nothing. */
|
|
26
26
|
maxSnapshotBytes?: number;
|
|
27
27
|
}
|
|
28
28
|
export type InspectCheckoutOptions = CheckoutPreflightOptions & {
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
import { normalizeCheckoutSignals, assessCheckoutSupport, cardEntryAttributable, } from './preflight.js';
|
|
1
|
+
import { normalizeCheckoutSignals, assessCheckoutSupport, cardEntryAttributable, getCheckoutPreflightCatalog, CHECKOUT_PREFLIGHT_LIMITS, } from './preflight.js';
|
|
2
2
|
const EVENTS = ['framenavigated', 'frameattached', 'framedetached'];
|
|
3
3
|
const DEADLINE = Symbol('checkout inspection deadline');
|
|
4
4
|
const DEFAULTS = { timeoutMs: 1_500, maxFrames: 64, maxSignals: 2_048, maxSnapshotBytes: 262_144 };
|
|
5
5
|
/** Frames at one nesting depth are read together. A remote CDP connection pays per round trip, not per frame. */
|
|
6
6
|
const CONCURRENCY = 8;
|
|
7
|
+
/** Script, iframe and form elements one frame's read examines, skipped ones included, so a page cannot keep the read walking. */
|
|
8
|
+
const ELEMENT_LIMIT = 16_384;
|
|
7
9
|
const encoder = new TextEncoder();
|
|
10
|
+
let reviewedHosts;
|
|
11
|
+
/** Hostname patterns of the reviewed rules. A URL on any other host can never become evidence. */
|
|
12
|
+
const reviewedHostPatterns = () => reviewedHosts ??= [...new Set(getCheckoutPreflightCatalog().rules.map(rule => rule.hostname_pattern))];
|
|
8
13
|
function bounded(value, fallback, maximum, minimum = 1) {
|
|
9
14
|
if (value === undefined)
|
|
10
15
|
return fallback;
|
|
@@ -185,7 +190,7 @@ export async function collectCheckoutSignals(page, options = {}) {
|
|
|
185
190
|
}
|
|
186
191
|
}
|
|
187
192
|
visibility.set(frame, visible);
|
|
188
|
-
const data = await beforeDeadline(() => frame.evaluate(({
|
|
193
|
+
const data = await beforeDeadline(() => frame.evaluate(({ signalRoom, byteBudget, hosts, elementLimit, urlLength, rawUrlLength }) => {
|
|
189
194
|
const collected = [];
|
|
190
195
|
let bytes = 0;
|
|
191
196
|
let signalLimit = false;
|
|
@@ -203,9 +208,37 @@ export async function collectCheckoutSignals(page, options = {}) {
|
|
|
203
208
|
const rect = element.getBoundingClientRect();
|
|
204
209
|
return rect.width > 0 && rect.height > 0;
|
|
205
210
|
};
|
|
211
|
+
// The normalizer drops a URL short enough to match without a trace when it is not https, carries credentials
|
|
212
|
+
// or a port, or sits on a host no reviewed rule names (preflight.ts). Such a URL can never become evidence,
|
|
213
|
+
// so the read skips it before it costs any signal or byte budget, and a store's own scripts (hundreds on a
|
|
214
|
+
// RequireJS checkout) no longer spend the budget before the read reaches the card frames. A URL kept here is
|
|
215
|
+
// still matched against the reviewed rules by the normalizer, so the page cannot add evidence this way. The
|
|
216
|
+
// patterns are tested case-insensitively: a hostname is lowercase, so this keeps every host a rule can match.
|
|
217
|
+
const reviewed = hosts.map(source => new RegExp(source, 'i'));
|
|
218
|
+
const named = new Map();
|
|
219
|
+
const silent = (url) => {
|
|
220
|
+
if (url.href.length > rawUrlLength || url.origin.length + url.pathname.length > urlLength)
|
|
221
|
+
return false;
|
|
222
|
+
if (url.protocol !== 'https:' || url.username || url.password || url.port)
|
|
223
|
+
return true;
|
|
224
|
+
let known = named.get(url.hostname);
|
|
225
|
+
if (known === undefined) {
|
|
226
|
+
known = reviewed.some(pattern => pattern.test(url.hostname));
|
|
227
|
+
named.set(url.hostname, known);
|
|
228
|
+
}
|
|
229
|
+
return !known;
|
|
230
|
+
};
|
|
231
|
+
const silentAddress = (address) => { try {
|
|
232
|
+
return silent(new URL(address));
|
|
233
|
+
}
|
|
234
|
+
catch {
|
|
235
|
+
return false;
|
|
236
|
+
} };
|
|
237
|
+
// The frame's own address takes a signal slot only when it is appended, which a silent one never is.
|
|
238
|
+
const remaining = Math.max(0, signalRoom - (silentAddress(document.URL) ? 0 : 1));
|
|
206
239
|
const elements = document.querySelectorAll('script[src], iframe[src], form[action]');
|
|
207
240
|
for (let index = 0; index < elements.length; index++) {
|
|
208
|
-
if (index >=
|
|
241
|
+
if (index >= elementLimit) {
|
|
209
242
|
signalLimit = true;
|
|
210
243
|
break;
|
|
211
244
|
}
|
|
@@ -214,23 +247,29 @@ export async function collectCheckoutSignals(page, options = {}) {
|
|
|
214
247
|
const source = element.getAttribute(kind === 'form' ? 'action' : 'src');
|
|
215
248
|
if (!source)
|
|
216
249
|
continue;
|
|
250
|
+
let url = null;
|
|
251
|
+
try {
|
|
252
|
+
url = new URL(source, document.baseURI);
|
|
253
|
+
}
|
|
254
|
+
catch { /* an unparsable location is skipped below unless it is oversized */ }
|
|
255
|
+
if (url && silent(url))
|
|
256
|
+
continue;
|
|
217
257
|
if (source.length > byteBudget - bytes) {
|
|
218
258
|
byteLimit = true;
|
|
219
259
|
break;
|
|
220
260
|
}
|
|
221
|
-
|
|
222
|
-
try {
|
|
223
|
-
url = new URL(source, document.baseURI).href;
|
|
224
|
-
}
|
|
225
|
-
catch {
|
|
261
|
+
if (!url)
|
|
226
262
|
continue;
|
|
263
|
+
if (collected.length >= remaining) {
|
|
264
|
+
signalLimit = true;
|
|
265
|
+
break;
|
|
227
266
|
}
|
|
228
|
-
bytes += url.length * 3 + 128;
|
|
267
|
+
bytes += url.href.length * 3 + 128;
|
|
229
268
|
if (bytes > byteBudget) {
|
|
230
269
|
byteLimit = true;
|
|
231
270
|
break;
|
|
232
271
|
}
|
|
233
|
-
collected.push({ kind, url, visible: kind === 'script' ? null : shown(element) });
|
|
272
|
+
collected.push({ kind, url: url.href, visible: kind === 'script' ? null : shown(element) });
|
|
234
273
|
}
|
|
235
274
|
// Card-entry detection reads field metadata only: the autocomplete token or the
|
|
236
275
|
// control's name and id. Values, labels and page text are never read.
|
|
@@ -248,11 +287,20 @@ export async function collectCheckoutSignals(page, options = {}) {
|
|
|
248
287
|
if (cardField && shown(input))
|
|
249
288
|
cardEntry = true;
|
|
250
289
|
}
|
|
290
|
+
// The frame's own address follows the same rule, so an ad or widget frame's long address is not charged
|
|
291
|
+
// either: it neither trips the byte budget nor is blanked. It still comes back whole, since the navigation
|
|
292
|
+
// and card-entry checks below need it, and a silent address is at most rawUrlLength characters long.
|
|
251
293
|
const documentUrl = document.URL;
|
|
252
|
-
|
|
294
|
+
const documentSilent = silentAddress(documentUrl);
|
|
295
|
+
const oversized = !documentSilent && documentUrl.length * 3 > byteBudget;
|
|
296
|
+
if (oversized)
|
|
253
297
|
byteLimit = true;
|
|
254
|
-
return { documentUrl:
|
|
255
|
-
}, {
|
|
298
|
+
return { documentUrl: oversized ? '' : documentUrl, documentSilent, collected, signalLimit, byteLimit, cardEntry };
|
|
299
|
+
}, {
|
|
300
|
+
signalRoom: Math.max(0, limits.maxSignals - signals.length), byteBudget: Math.max(0, limits.maxSnapshotBytes - transientBytes),
|
|
301
|
+
hosts: reviewedHostPatterns(), elementLimit: ELEMENT_LIMIT,
|
|
302
|
+
urlLength: CHECKOUT_PREFLIGHT_LIMITS.url_length, rawUrlLength: CHECKOUT_PREFLIGHT_LIMITS.raw_url_length,
|
|
303
|
+
}), deadline);
|
|
256
304
|
const releaseError = released ? await released : undefined;
|
|
257
305
|
if (releaseError !== undefined)
|
|
258
306
|
throw releaseError;
|
|
@@ -286,7 +334,8 @@ export async function collectCheckoutSignals(page, options = {}) {
|
|
|
286
334
|
if (!outcome)
|
|
287
335
|
continue;
|
|
288
336
|
const { data, frame_id, parent_frame_id, nested, visible } = outcome;
|
|
289
|
-
|
|
337
|
+
if (!data.documentSilent)
|
|
338
|
+
append({ kind: nested ? 'frame' : 'document', url: data.documentUrl, frame_id, parent_frame_id, visible });
|
|
290
339
|
for (const signal of data.collected) {
|
|
291
340
|
if (!append({ ...signal, frame_id, parent_frame_id, visible: visible === false ? false : signal.kind === 'script' ? visible : visible === null ? null : signal.visible }))
|
|
292
341
|
break;
|
|
@@ -466,6 +466,8 @@
|
|
|
466
466
|
"mercado-pago-checkout-pro-card-form",
|
|
467
467
|
"gravy-secure-fields-script",
|
|
468
468
|
"gravy-secure-fields-script-sandbox",
|
|
469
|
+
"bambora-na-custom-checkout-fields",
|
|
470
|
+
"worldpay-wpg-hosted-payment-page",
|
|
469
471
|
"paypal-hosted-fields-payments-sdk",
|
|
470
472
|
"paypal-card-fields-v5",
|
|
471
473
|
"paypal-card-fields-v6",
|
|
@@ -1102,6 +1104,8 @@
|
|
|
1102
1104
|
"mercado-pago-checkout-pro-card-form",
|
|
1103
1105
|
"gravy-secure-fields-script",
|
|
1104
1106
|
"gravy-secure-fields-script-sandbox",
|
|
1107
|
+
"bambora-na-custom-checkout-fields",
|
|
1108
|
+
"worldpay-wpg-hosted-payment-page",
|
|
1105
1109
|
"paypal-hosted-fields-payments-sdk",
|
|
1106
1110
|
"paypal-card-fields-v5",
|
|
1107
1111
|
"paypal-card-fields-v6",
|
|
@@ -1340,10 +1340,6 @@ export declare function getCheckoutPreflightCatalog(): {
|
|
|
1340
1340
|
readonly psp: "vgs";
|
|
1341
1341
|
readonly reason: "iframe_bound_tokenization";
|
|
1342
1342
|
readonly action: "human_checkout";
|
|
1343
|
-
}, {
|
|
1344
|
-
readonly psp: "bluesnap";
|
|
1345
|
-
readonly reason: "multi_request_tokenization_not_supported";
|
|
1346
|
-
readonly action: "human_checkout";
|
|
1347
1343
|
}, {
|
|
1348
1344
|
readonly psp: "stripe";
|
|
1349
1345
|
readonly reason: "unbound_token_to_payment_intent_continuation";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Generated from @agent-cards/payment-core. Do not edit.
|
|
2
|
-
// source-sha256:
|
|
2
|
+
// source-sha256: 761b59c7c043a43a8d462a840e204c1677c55c0022f37e6be4a007d025357af8
|
|
3
3
|
import { CHECKOUT_PREFLIGHT_CAPABILITIES } from './preflight-capabilities.generated.js';
|
|
4
4
|
/** Advisory page discovery. These rules never admit a payment destination. */
|
|
5
5
|
export const CHECKOUT_PREFLIGHT_VERSION = '1';
|
|
@@ -69,6 +69,29 @@ RULES.push({ id: 'tranzila-terminal-hosted-page', psp: 'tranzila', kinds: ['docu
|
|
|
69
69
|
{ id: 'gravy-secure-fields-script', psp: 'gravy', kinds: ['script'], hostname: /^cdn\.[a-z0-9-]+\.gr4vy\.app$/, pathname: GRAVY_SECURE_FIELDS_SCRIPT, origin: 'https://cdn.:merchant.gr4vy.app', path_pattern: '/secure-fields/{latest,:version}/secure-fields.js',
|
|
70
70
|
sources: GRAVY_SOURCES }, { id: 'gravy-secure-fields-script-sandbox', psp: 'gravy', kinds: ['script'], hostname: /^cdn\.sandbox\.[a-z0-9-]+\.gr4vy\.app$/, pathname: GRAVY_SECURE_FIELDS_SCRIPT, origin: 'https://cdn.sandbox.:merchant.gr4vy.app', path_pattern: '/secure-fields/{latest,:version}/secure-fields.js',
|
|
71
71
|
sources: GRAVY_SOURCES });
|
|
72
|
+
// Card frames the catalog scan of 2026-10-23 read at stores' card forms (no card typed, nothing paid). Each
|
|
73
|
+
// rule names its processor from a frame on the processor's own host. A file on the store's own host that only
|
|
74
|
+
// carries the processor's name, such as the copy of Bambora's customcheckout.js that Kent serves itself, names
|
|
75
|
+
// nothing.
|
|
76
|
+
const catalogScan = (reference) => ({ kind: 'saved_observation', reference: `catalog-psp-scan-2026-10-23:${reference}`, reviewed_on: '2026-10-23' });
|
|
77
|
+
RULES.push(
|
|
78
|
+
// Bambora Custom Checkout draws each card field as an iframe from the release its library was built for:
|
|
79
|
+
// /customcheckout/1/customcheckout.js draws 1.0.5-39 (the reviewed rule above), and Kent's own copy draws
|
|
80
|
+
// 1.0.2. The release names the frame and nothing more. Payment-core's bambora entry matches the card request
|
|
81
|
+
// on its own (/scripts/tokenization/tokens), so a release whose frame sent the card anywhere else would send
|
|
82
|
+
// only the placeholder card the agent typed.
|
|
83
|
+
{ id: 'bambora-na-custom-checkout-fields', psp: 'bambora', kinds: ['frame', 'iframe', 'document'], hostname: /^libs\.na\.bambora\.com$/,
|
|
84
|
+
pathname: /^\/customcheckout\/1\.[0-9]{1,3}\.[0-9]{1,3}(?:-[0-9]{1,4})?\/iframe\.html$/, origin: 'https://libs.na.bambora.com', path_pattern: '/customcheckout/1.:minor.:patch{,-:build}/iframe.html',
|
|
85
|
+
sources: [{ kind: 'primary_source', reference: 'https://docs.na.worldline-solutions.com/build-your-integration/checkout-form/custom-checkout/reference', reviewed_on: '2026-09-11' },
|
|
86
|
+
catalogScan('kent-ca-custom-checkout-1.0.2-card-fields')] },
|
|
87
|
+
// Worldpay's hosted payment pages on payments.worldpay.com: Razer's checkout opens
|
|
88
|
+
// /app/hpp-iframe/integration/wpg/corporate in an iframe, which lands on /app/hpp/<build>/payment/start, where
|
|
89
|
+
// the shopper types the card on Worldpay's own page. The SDK's worldpay entry takes over Access Checkout's card
|
|
90
|
+
// session only, so the page names worldpay and stays unknown, as the secure.worldpay.com/wcc pages do.
|
|
91
|
+
{ id: 'worldpay-wpg-hosted-payment-page', psp: 'worldpay', kinds: ['document', 'frame', 'iframe'], hostname: /^payments\.worldpay\.com$/,
|
|
92
|
+
pathname: /^\/app\/hpp(?:-iframe)?\//, origin: 'https://payments.worldpay.com', path_pattern: '/app/{hpp,hpp-iframe}/*',
|
|
93
|
+
sources: [catalogScan('razer-worldpay-hosted-payment-page')],
|
|
94
|
+
variant_unverified: 'The implemented Worldpay adapter covers Access Checkout card sessions; Worldpay hosted payment pages under payments.worldpay.com/app/hpp take the card on Worldpay\'s own page and are not admitted.' });
|
|
72
95
|
// PayPal's legacy Hosted Fields (its JS SDK's components=hosted-fields), reviewed 2026-10-07 from Planet Golf
|
|
73
96
|
// UK's payment step (read live 2026-10-06, SDK 5.0.580) and the two frame files it loads. The SDK renders each
|
|
74
97
|
// card field as braintree-web's 3.32.0-payments-sdk-dev hosted-fields-input-frame.min.html (sha256
|
|
@@ -37,8 +37,20 @@
|
|
|
37
37
|
* approval after Pay. Its environments are its API hosts: api.openpay.<mx|co|pe> (production) and
|
|
38
38
|
* sandbox-api.openpay.<mx|co|pe> (sandbox). The token URL names the merchant in its path, so no URL is
|
|
39
39
|
* prepared in advance: the claim binds the request by its host's environment and its shape, as ACI's.
|
|
40
|
+
*
|
|
41
|
+
* vtex_payments: prepared only. Ollie's headless checkout aborts its card post to the store's VTEX vault 12 seconds after
|
|
42
|
+
* it starts it, too soon for an approval after Pay. Its one environment is production: VTEX has no test host. The card
|
|
43
|
+
* URL names the store's account in its host and VTEX's transaction in its path, neither known before Pay, so the claim
|
|
44
|
+
* binds the request by its shape, as Openpay's. Ollie sends the same post again on a non-OK answer or a network error,
|
|
45
|
+
* then once more to api.vtexvault.com: the first post spends the approval, and each later one is refused like any
|
|
46
|
+
* request on a spent preparation, so one approval is one card use.
|
|
47
|
+
*
|
|
48
|
+
* processout: prepared only. ProcessOut.js gives its card frame 20 seconds from the tokenize message before it calls
|
|
49
|
+
* the page's error callback, too soon for an approval after the shop's continue press. Its environments share one
|
|
50
|
+
* host, api.processout.com: the project id in the card URL's query names them, proj_ (production) and test-proj_
|
|
51
|
+
* (sandbox), so the claim binds the request by its project's environment and its shape, as Openpay's.
|
|
40
52
|
*/
|
|
41
|
-
export type PreparationProcessor = 'square' | 'braintree' | 'worldpay' | 'bambora' | 'mercado_pago' | 'recurly' | 'spreedly' | 'adyen' | 'checkout_com' | 'paysafe' | 'fiserv' | 'cybersource_flex' | 'aci' | 'creditguard' | 'worldpay_eprotect' | 'amadeus_checkout' | 'verifone' | 'cybersource_secure_acceptance' | 'paddle_vgs' | 'wix_payments' | 'paygent' | 'hipay' | 'openpay_bbva';
|
|
53
|
+
export type PreparationProcessor = 'square' | 'braintree' | 'worldpay' | 'bambora' | 'mercado_pago' | 'recurly' | 'spreedly' | 'adyen' | 'checkout_com' | 'paysafe' | 'fiserv' | 'cybersource_flex' | 'aci' | 'creditguard' | 'worldpay_eprotect' | 'amadeus_checkout' | 'verifone' | 'cybersource_secure_acceptance' | 'paddle_vgs' | 'wix_payments' | 'paygent' | 'hipay' | 'openpay_bbva' | 'vtex_payments' | 'processout';
|
|
42
54
|
export type PreparationEnvironment = 'production' | 'sandbox' | 'shared';
|
|
43
55
|
/**
|
|
44
56
|
* How the approved card reaches the processor: the device's own request (token), or
|
|
@@ -77,7 +89,8 @@ export declare function preparedApprovalAnswersRetry(psp: string): boolean;
|
|
|
77
89
|
* live, testsecureacceptance is test. So are Paddle VGS's two card URLs: vault is live,
|
|
78
90
|
* sandbox-vault is test. So are Paygent's two token hosts: token is live, sandbox is test. So are
|
|
79
91
|
* HiPay's two vault hosts: secure2-vault is live, stage-secure2-vault is test. So are Openpay's API
|
|
80
|
-
* hosts: api.openpay.<mx|co|pe> is live, sandbox-api.openpay.<mx|co|pe> is test.
|
|
92
|
+
* hosts: api.openpay.<mx|co|pe> is live, sandbox-api.openpay.<mx|co|pe> is test. ProcessOut's share
|
|
93
|
+
* one host, and the card URL's project id attests them: proj_ is live, test-proj_ is test.
|
|
81
94
|
*/
|
|
82
95
|
export declare function validPreparationEnvironment(psp: string, environment: string): boolean;
|
|
83
96
|
/**
|
|
@@ -90,9 +103,9 @@ export declare function aciPreparationUrl(environment: PreparationEnvironment):
|
|
|
90
103
|
/**
|
|
91
104
|
* A processor whose card request names an id the merchant mints only at Pay time (ACI's checkout
|
|
92
105
|
* id), or the merchant's own id (Openpay's token URL carries the merchant id in its path and the
|
|
93
|
-
* country in its host
|
|
94
|
-
*
|
|
95
|
-
* only names the preparation.
|
|
106
|
+
* country in its host, ProcessOut's card URL the project id in its query), so no URL can be prepared
|
|
107
|
+
* in advance: whether the adapters can intercept it is asked of the registry
|
|
108
|
+
* (VaultClient.recognizesProcessor), not of the prepared endpoint, which only names the preparation.
|
|
96
109
|
*/
|
|
97
110
|
export declare function preparationBindsByShape(psp: string): boolean;
|
|
98
111
|
/**
|