@agent-cards/sdk 0.20.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/CHANGELOG.md +4 -0
- package/PREFLIGHT.md +4 -0
- package/README.md +153 -0
- package/dist/cdp.d.ts +2 -1
- package/dist/cdp.js +161 -31
- package/dist/client.d.ts +97 -1
- package/dist/client.js +172 -5
- package/dist/cybersource-flex.d.ts +183 -0
- package/dist/cybersource-flex.generated.d.ts +92 -0
- package/dist/cybersource-flex.generated.js +689 -0
- package/dist/cybersource-flex.js +275 -0
- package/dist/gmo.d.ts +63 -0
- package/dist/gmo.generated.d.ts +60 -0
- package/dist/gmo.generated.js +586 -0
- package/dist/gmo.js +119 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +1 -1
- package/dist/lifecycle.d.ts +8 -3
- package/dist/lifecycle.js +6 -2
- package/dist/pre-claim.d.ts +12 -1
- package/dist/pre-claim.js +135 -9
- package/dist/preflight-catalog.json +116 -0
- package/dist/preflight-schemas.json +8 -0
- package/dist/preflight.generated.js +15 -1
- package/dist/prepared-processor.d.ts +4 -2
- package/dist/prepared-processor.js +12 -2
- package/dist/registry.d.ts +17 -7
- package/dist/stripe-checkout.generated.js +37 -2
- package/examples/preflight/kernel-native/inventory.json +1 -1
- package/package.json +3 -3
package/dist/gmo.js
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
// GMO Payment Gateway, PG Multipayment token v2 (mp-token.js), as the SDK sees it.
|
|
2
|
+
//
|
|
3
|
+
// A GMO merchant page that calls Multipayment.init(shopId) with one argument (teamLab's ticket
|
|
4
|
+
// sites do) sends the card as mp-token.js's getToken: one fetch POST to
|
|
5
|
+
// https://token.mul-pay.jp/payment/CreateToken.json (test host stg.token.mul-pay.jp), as
|
|
6
|
+
// application/json with X-MP-Client-Type: js-legacy, whose body is AES ciphertext of the card with
|
|
7
|
+
// its key wrapped under GMO's shared public key. The agent's page encrypts the placeholder card, so
|
|
8
|
+
// nothing in the paused body can be filled in. The cardholder's device rebuilds the whole envelope
|
|
9
|
+
// with the real card and sends it to GMO itself, and the page receives only GMO's answer: one
|
|
10
|
+
// single-use token, valid 30 minutes and spendable only by the shop's own site (token mode).
|
|
11
|
+
//
|
|
12
|
+
// The registry entry ships dark (capability gmo_shared_pk). This build declares the capability on
|
|
13
|
+
// syncRegistry, and the API serves the entry only to an org Agentcard enabled for GMO, so for every
|
|
14
|
+
// other org nothing here fires: isCardRequest never recognizes a GMO URL and GMO's requests go
|
|
15
|
+
// through untouched, exactly as before.
|
|
16
|
+
//
|
|
17
|
+
// For an org in the dark launch, a POST the registry recognizes on a GMO token host is judged by
|
|
18
|
+
// payment-core's one guard (gmo.generated.ts isGmoSharedPkRequest), the check the API runs at
|
|
19
|
+
// create and the device runs before it rebuilds anything:
|
|
20
|
+
// - mp-token.js's SHARED_PK getToken for one token pauses for approval;
|
|
21
|
+
// - anything else on that URL can never be paid by the vault: UNIQUE_PK (a merchant-registered
|
|
22
|
+
// key nobody can check), GMO Elements (js-iframe), several tokens, a shop id of the other
|
|
23
|
+
// environment's shape, or any serialization mp-token.js does not write. It is aborted as an
|
|
24
|
+
// unsupported checkout before any create or prompt.
|
|
25
|
+
// Token v1 (ext/js/token.js) sends the card as a JSONP GET that no vault mode covers. It is aborted
|
|
26
|
+
// the same way, so the placeholder is never tokenized silently.
|
|
27
|
+
import { GMO_PSP, GMO_TOKEN_URLS, isGmoSharedPkRequest, isGmoTokenHost, sanitizeGmoTokenResponse, } from './gmo.generated.js';
|
|
28
|
+
export { GMO_PSP, isGmoTokenHost };
|
|
29
|
+
/** The dark-launch capability a build declares when it pauses only what isGmoSharedPkRequest accepts. */
|
|
30
|
+
export const GMO_CAPABILITY = 'gmo_shared_pk';
|
|
31
|
+
/** The hosts GMO token v1 (ext/js/token.js) sends its JSONP GET to: production, then test. */
|
|
32
|
+
const GMO_TOKEN_V1_HOSTS = ['p01.mul-pay.jp', 'stg.token.mul-pay.jp'];
|
|
33
|
+
const GMO_TOKEN_V1_PATH = '/ext/api/gettoken';
|
|
34
|
+
/**
|
|
35
|
+
* Fetch interception patterns for GMO token v1's JSONP GET, armed only for an org the API served GMO
|
|
36
|
+
* to. A CDP pattern matches the URL as written, path case included, while isGmoTokenV1Request
|
|
37
|
+
* accepts any path case, a trailing dot on the host and any port. So each v1 host is armed whole,
|
|
38
|
+
* in those four spellings, and the pre-claim gate classifies every paused request with
|
|
39
|
+
* isGmoTokenV1Request: the v1 GET is aborted, and anything else on the host continues untouched.
|
|
40
|
+
* Chrome writes the host in lower case, and it blocks a subresource URL that carries credentials.
|
|
41
|
+
*/
|
|
42
|
+
export const GMO_TOKEN_V1_PATTERNS = GMO_TOKEN_V1_HOSTS.flatMap((host) => [`https://${host}/*`, `https://${host}:*`, `https://${host}./*`, `https://${host}.:*`]);
|
|
43
|
+
/**
|
|
44
|
+
* Whether the vault's current registry recognizes GMO's card request: true only after
|
|
45
|
+
* syncRegistry() for an org the API serves the dark entry to.
|
|
46
|
+
*/
|
|
47
|
+
export function recognizesGmo(vault) {
|
|
48
|
+
if (!vault || typeof vault.isCardRequest !== 'function')
|
|
49
|
+
return false;
|
|
50
|
+
try {
|
|
51
|
+
return vault.isCardRequest(GMO_TOKEN_URLS.production, 'POST') || vault.isCardRequest(GMO_TOKEN_URLS.sandbox, 'POST');
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* GMO token v1's card request: a GET (or, with no method, a URL a route matcher is asked about)
|
|
59
|
+
* to /ext/api/getToken on either v1 host, in any case or with a trailing dot, since the servers
|
|
60
|
+
* behind it need not care.
|
|
61
|
+
*/
|
|
62
|
+
export function isGmoTokenV1Request(rawUrl, method) {
|
|
63
|
+
if (method !== undefined && method.toUpperCase() !== 'GET')
|
|
64
|
+
return false;
|
|
65
|
+
let url;
|
|
66
|
+
try {
|
|
67
|
+
url = new URL(rawUrl);
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
if (url.protocol !== 'https:')
|
|
73
|
+
return false;
|
|
74
|
+
const host = url.hostname.toLowerCase().replace(/\.$/, '');
|
|
75
|
+
return GMO_TOKEN_V1_HOSTS.includes(host) && url.pathname.toLowerCase() === GMO_TOKEN_V1_PATH;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Whether a POST the registry recognized on a GMO token host is anything but mp-token.js's
|
|
79
|
+
* SHARED_PK getToken for one token: null when the guard accepts it (it pauses for approval), else
|
|
80
|
+
* the reason it is aborted. A guard that throws refuses.
|
|
81
|
+
*/
|
|
82
|
+
export function gmoRequestRefusal(request) {
|
|
83
|
+
try {
|
|
84
|
+
return isGmoSharedPkRequest({ url: request.url, method: request.method.toUpperCase(), headers: request.headers ?? {}, body: request.body })
|
|
85
|
+
? null : 'unsupported_gmo_request';
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return 'unsupported_gmo_request';
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* The shop a GMO token request names (encryptionParameters.apiKey), as part of that request's
|
|
93
|
+
* identity. GMO mints a token for that one shop, so a retry that names another shop is a new
|
|
94
|
+
* question and never takes the first request's approval. Undefined when the URL is not a GMO token
|
|
95
|
+
* host; null when the body names no shop that can be read.
|
|
96
|
+
*/
|
|
97
|
+
export function gmoRequestShop(url, body) {
|
|
98
|
+
if (!isGmoTokenHost(url))
|
|
99
|
+
return undefined;
|
|
100
|
+
try {
|
|
101
|
+
const shop = JSON.parse(body)?.encryptionParameters?.apiKey;
|
|
102
|
+
return typeof shop === 'string' ? shop : null;
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* The only answer the page may receive for an approved GMO request: status 200, and GMO's body
|
|
110
|
+
* reduced to the five fields mp-token.js reads with exactly one 64-hex token
|
|
111
|
+
* (sanitizeGmoTokenResponse), under a JSON content type. Null for anything else, including
|
|
112
|
+
* several tokens, which one approval never pays for.
|
|
113
|
+
*/
|
|
114
|
+
export function gmoTokenAnswer(status, body) {
|
|
115
|
+
if (status !== 200)
|
|
116
|
+
return null;
|
|
117
|
+
const sanitized = sanitizeGmoTokenResponse(body);
|
|
118
|
+
return sanitized ? { status: 200, headers: { 'content-type': 'application/json' }, body: sanitized } : null;
|
|
119
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
export { Agentcard, Agentcard as VaultClient, CheckoutModule } from './agentcard.js';
|
|
2
2
|
export type { CheckoutAttachOptions } from './agentcard.js';
|
|
3
|
-
export { CardEncryptedError, UnsupportedModeError, PreparationRequiredError, ApprovalTimeoutError, ApprovalDeclinedError, AmountMismatchError, PresetRefusedError, PRESET_REFUSAL_REASONS, IntentNotConfirmableError, ProcessorRefusedError, CheckoutApiError, CheckoutAuthError, redactUrl, SUPPORTED_MODES, PaymentOutcomeUnknownError, CheckoutCancelledError, CheckoutPreparationError, AdyenTestPlatformRefusedError, MerchantTotalError, } from './client.js';
|
|
4
|
-
export type {
|
|
3
|
+
export { CardEncryptedError, UnsupportedModeError, UnsupportedCapabilityError, PreparationRequiredError, AmountRequiredError, ApprovalTimeoutError, ApprovalDeclinedError, AmountMismatchError, PresetRefusedError, PRESET_REFUSAL_REASONS, IntentNotConfirmableError, ProcessorRefusedError, CheckoutApiError, CheckoutAuthError, redactUrl, SUPPORTED_MODES, SUPPORTED_CAPABILITIES, PaymentOutcomeUnknownError, CheckoutCancelledError, CheckoutPreparationError, AdyenTestPlatformRefusedError, MerchantTotalError, PlaceholderCardError, } from './client.js';
|
|
4
|
+
export type { GmoUnsupportedReason } from './gmo.js';
|
|
5
|
+
export type { PausedRequest, ReplayResponse, TokenReplay, CseReplay, MerchantHostedReplay, HostedFormReplay, AmountAuthority, AuthorizeInput, VaultClientOptions, AgentcardOptions, AdyenTestPlatformRefusal, MerchantTotalRefusal, PrepareCheckoutOptions, PrepareCheckoutInput, PreparedCheckout, RazorpayProcessorError, RuntimeCancelReason, ExecutionMetadata, PlaceholderCard, } from './client.js';
|
|
6
|
+
export type { MicroformField, MicroformSidecar } from './cybersource-flex.js';
|
|
5
7
|
export { attachToCdp, attachToPlaywright, corsHeadersFor, corsDecision, withCorsHeaders } from './cdp.js';
|
|
6
8
|
export { CheckoutAttachmentError } from './attachment.js';
|
|
7
9
|
export type { CdpLike, AttachOptions, CorsOutcome } from './cdp.js';
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// The one client and its modules. `VaultClient` is the client's older name and
|
|
2
2
|
// stays importable for one release; it constructs the same object.
|
|
3
3
|
export { Agentcard, Agentcard as VaultClient, CheckoutModule } from './agentcard.js';
|
|
4
|
-
export { CardEncryptedError, UnsupportedModeError, PreparationRequiredError, ApprovalTimeoutError, ApprovalDeclinedError, AmountMismatchError, PresetRefusedError, PRESET_REFUSAL_REASONS, IntentNotConfirmableError, ProcessorRefusedError, CheckoutApiError, CheckoutAuthError, redactUrl, SUPPORTED_MODES, PaymentOutcomeUnknownError, CheckoutCancelledError, CheckoutPreparationError, AdyenTestPlatformRefusedError, MerchantTotalError, } from './client.js';
|
|
4
|
+
export { CardEncryptedError, UnsupportedModeError, UnsupportedCapabilityError, PreparationRequiredError, AmountRequiredError, ApprovalTimeoutError, ApprovalDeclinedError, AmountMismatchError, PresetRefusedError, PRESET_REFUSAL_REASONS, IntentNotConfirmableError, ProcessorRefusedError, CheckoutApiError, CheckoutAuthError, redactUrl, SUPPORTED_MODES, SUPPORTED_CAPABILITIES, PaymentOutcomeUnknownError, CheckoutCancelledError, CheckoutPreparationError, AdyenTestPlatformRefusedError, MerchantTotalError, PlaceholderCardError, } from './client.js';
|
|
5
5
|
export { attachToCdp, attachToPlaywright, corsHeadersFor, corsDecision, withCorsHeaders } from './cdp.js';
|
|
6
6
|
export { CheckoutAttachmentError } from './attachment.js';
|
|
7
7
|
export { substituteEncryptedFields, SubstitutionError } from './substitute.js';
|
package/dist/lifecycle.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { CheckoutPreparationError, type PrepareCheckoutOptions, type PreparedCheckout, type ReplayResponse } from './client.js';
|
|
2
2
|
import type { CheckoutMode } from './registry.js';
|
|
3
3
|
import type { Substitutions } from './substitute.js';
|
|
4
|
+
import type { GmoUnsupportedReason } from './gmo.js';
|
|
4
5
|
/** The application's resolver confirmed the payment for this checkout authorization. */
|
|
5
6
|
export interface MerchantPaymentConfirmation {
|
|
6
7
|
kind: 'merchant_payment';
|
|
@@ -183,10 +184,14 @@ export declare class CheckoutLifecycle implements CheckoutController {
|
|
|
183
184
|
/**
|
|
184
185
|
* A card request this SDK cannot pay was aborted. `reason`: an unrecognized
|
|
185
186
|
* declared payment endpoint (the default), a merchant profile Agentcard has not
|
|
186
|
-
* turned on (merchant_profile_observe),
|
|
187
|
-
* finish (merchant_request_unsupported)
|
|
187
|
+
* turned on (merchant_profile_observe), a card request the profile cannot
|
|
188
|
+
* finish (merchant_request_unsupported), a recognized processor's request in
|
|
189
|
+
* a form its gate refuses (GMO's unsupported_gmo_request and
|
|
190
|
+
* unsupported_gmo_token_v1), or a CyberSource Flex request that is not a
|
|
191
|
+
* reviewed Microform v2 card field's (microform_unsupported,
|
|
192
|
+
* cybersource-flex.ts).
|
|
188
193
|
*/
|
|
189
|
-
unsupported(reason?: 'unrecognized_payment_endpoint' | 'merchant_profile_observe' | 'merchant_request_unsupported'): void;
|
|
194
|
+
unsupported(reason?: 'unrecognized_payment_endpoint' | 'merchant_profile_observe' | 'merchant_request_unsupported' | GmoUnsupportedReason | 'microform_unsupported'): void;
|
|
190
195
|
/**
|
|
191
196
|
* A card request that only a prepared checkout pays (an Adyen merchant
|
|
192
197
|
* profile's, or a Fiserv card capture) arrived with no preparation on this
|
package/dist/lifecycle.js
CHANGED
|
@@ -132,8 +132,12 @@ export class CheckoutLifecycle {
|
|
|
132
132
|
/**
|
|
133
133
|
* A card request this SDK cannot pay was aborted. `reason`: an unrecognized
|
|
134
134
|
* declared payment endpoint (the default), a merchant profile Agentcard has not
|
|
135
|
-
* turned on (merchant_profile_observe),
|
|
136
|
-
* finish (merchant_request_unsupported)
|
|
135
|
+
* turned on (merchant_profile_observe), a card request the profile cannot
|
|
136
|
+
* finish (merchant_request_unsupported), a recognized processor's request in
|
|
137
|
+
* a form its gate refuses (GMO's unsupported_gmo_request and
|
|
138
|
+
* unsupported_gmo_token_v1), or a CyberSource Flex request that is not a
|
|
139
|
+
* reviewed Microform v2 card field's (microform_unsupported,
|
|
140
|
+
* cybersource-flex.ts).
|
|
137
141
|
*/
|
|
138
142
|
unsupported(reason = 'unrecognized_payment_endpoint') {
|
|
139
143
|
this.held = true;
|
package/dist/pre-claim.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { MercadoCheckoutGate } from './mercado-checkout.js';
|
|
|
3
3
|
import type { CheckoutLifecycle } from './lifecycle.js';
|
|
4
4
|
import { type MerchantProfile } from './merchant-hosted.js';
|
|
5
5
|
import type { MerchantHandoffWatch } from './merchant-handoff.js';
|
|
6
|
+
import { type CybersourceFlexDecision, type CybersourceFlexPause, type FlexRequest } from './cybersource-flex.js';
|
|
6
7
|
/** The native Stripe step the gate claimed, or null when none was: exactly what StripeCheckoutGate.claim returns. */
|
|
7
8
|
type StripeStep = ReturnType<StripeCheckoutGate['claim']>;
|
|
8
9
|
/** A synthetic response a gate fulfills locally. The effect applies CORS and encoding. */
|
|
@@ -17,7 +18,8 @@ type PreClaimEvent = {
|
|
|
17
18
|
detail?: unknown;
|
|
18
19
|
};
|
|
19
20
|
/** How the request was resolved. continue/answer/abort are already performed by the
|
|
20
|
-
* time the decision is returned; only pause hands work back to the adapter
|
|
21
|
+
* time the decision is returned; only pause hands work back to the adapter, with the
|
|
22
|
+
* CyberSource Flex sidecar when the Flex gate paused it. */
|
|
21
23
|
export type PreClaimDecision = {
|
|
22
24
|
kind: 'continue';
|
|
23
25
|
} | {
|
|
@@ -27,6 +29,7 @@ export type PreClaimDecision = {
|
|
|
27
29
|
} | {
|
|
28
30
|
kind: 'pause';
|
|
29
31
|
stripeStep: StripeStep;
|
|
32
|
+
cybersourceFlex?: CybersourceFlexPause;
|
|
30
33
|
};
|
|
31
34
|
/** The adapter mechanics a gate performs. Each is awaited where the inline code
|
|
32
35
|
* awaited it; none swallow their own transport failure (a gate adds a .catch
|
|
@@ -94,6 +97,14 @@ export interface PreClaimContext {
|
|
|
94
97
|
stripeStep: StripeStep;
|
|
95
98
|
/** The merchant-hosted hand-off this attachment made, if any (merchant-handoff.ts). */
|
|
96
99
|
merchantHandoff?: Pick<MerchantHandoffWatch, 'retried'>;
|
|
100
|
+
/**
|
|
101
|
+
* The adapter's reader of the Microform field iframe that sent a request (cybersource-flex.ts):
|
|
102
|
+
* CDP judges from the committed frame URLs it recorded, Playwright from request.frame().url().
|
|
103
|
+
* Absent, no CyberSource Flex request can pause: each one the registry recognizes is refused.
|
|
104
|
+
*/
|
|
105
|
+
cybersourceFlex?: {
|
|
106
|
+
judge(request: FlexRequest): CybersourceFlexDecision | Promise<CybersourceFlexDecision>;
|
|
107
|
+
};
|
|
97
108
|
}
|
|
98
109
|
/**
|
|
99
110
|
* The URL an event may name for a request. For an armed merchant profile's
|
package/dist/pre-claim.js
CHANGED
|
@@ -3,9 +3,12 @@
|
|
|
3
3
|
// Before a paused request is claimed for the vault, a small set of processor
|
|
4
4
|
// gates inspect it: Mercado Pago's native Checkout Pro configuration and
|
|
5
5
|
// association, Braintree's shared /graphql endpoint, native Stripe Checkout,
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
6
|
+
// Fiserv's card capture, GMO's CreateToken.json, which also carries requests
|
|
7
|
+
// the vault can never pay, and CyberSource Flex Microform's field iframes (whose
|
|
8
|
+
// capture context rides into the pause). The first three used to be written
|
|
9
|
+
// inline in Fetch.requestPaused and again in the page.route handler, so a
|
|
10
|
+
// decision could drift between the two adapters and a new family had to be
|
|
11
|
+
// added in both places.
|
|
9
12
|
//
|
|
10
13
|
// dispatchPreClaim runs the gates in order and resolves the request to one of:
|
|
11
14
|
// - continue: let the request through untouched, or with a body the gate
|
|
@@ -38,8 +41,10 @@
|
|
|
38
41
|
import { PaymentOutcomeUnknownError, redactUrl } from './client.js';
|
|
39
42
|
import { classifyBraintreeRequest } from './braintree.js';
|
|
40
43
|
import { StripeCheckoutClaimConflictError, stripeCheckoutReadinessError } from './stripe-checkout.js';
|
|
44
|
+
import { gmoRequestRefusal, isGmoTokenHost, isGmoTokenV1Request, recognizesGmo } from './gmo.js';
|
|
41
45
|
import { classifyProfileRequest, merchantBodyKeyPathSha256, profileTemplatedUrl } from './merchant-hosted.js';
|
|
42
46
|
import { isFiservCaptureHost, isFiservPausableBody } from './fiserv.js';
|
|
47
|
+
import { CYBERSOURCE_FLEX_PSP, isCybersourceFlexHost } from './cybersource-flex.js';
|
|
43
48
|
/**
|
|
44
49
|
* The URL an event may name for a request. For an armed merchant profile's
|
|
45
50
|
* endpoint or a sibling of it: the endpoint origin, the path TEMPLATE and the
|
|
@@ -104,10 +109,15 @@ async function mercadoContinuation(ctx) {
|
|
|
104
109
|
// a Braintree POST is classified the same as an empty one, so both adapters
|
|
105
110
|
// reach the same verdict. The configuration continue swallows a transport
|
|
106
111
|
// failure, as the inline CDP path did (the Playwright path never reaches a
|
|
107
|
-
// failing route here).
|
|
112
|
+
// failing route here). The body is read only for a Braintree host:
|
|
113
|
+
// classifyBraintreeRequest answers undefined for any other host before it looks
|
|
114
|
+
// at a body, so another processor's request is never read here, and a body read
|
|
115
|
+
// that throws (Playwright's postData() can) stays with the gate that owns it.
|
|
108
116
|
const braintreePreClaim = (ctx) => {
|
|
109
|
-
const { url, method
|
|
110
|
-
|
|
117
|
+
const { url, method } = ctx.request;
|
|
118
|
+
if (method.toUpperCase() !== 'POST' || classifyBraintreeRequest(url, method, null) === undefined)
|
|
119
|
+
return undefined;
|
|
120
|
+
const braintree = classifyBraintreeRequest(url, method, ctx.request.body);
|
|
111
121
|
if (braintree === 'configuration')
|
|
112
122
|
return braintreeContinue(ctx);
|
|
113
123
|
if (braintree === 'invalid')
|
|
@@ -311,10 +321,13 @@ async function merchantHostedUnsupported(ctx, profile, url, category, reason) {
|
|
|
311
321
|
// Synchronous until it must continue or abort, like every gate. Exported for the
|
|
312
322
|
// gate registry's tests.
|
|
313
323
|
export const fiservPreClaim = (ctx) => {
|
|
314
|
-
const { url, method
|
|
324
|
+
const { url, method } = ctx.request;
|
|
315
325
|
if (String(method).toUpperCase() !== 'POST' || !isFiservCaptureHost(url) || !ctx.vault.isCardRequest(url, method))
|
|
316
326
|
return undefined;
|
|
317
|
-
|
|
327
|
+
// The body is read only here, on a capture host, since reading it may throw: another processor's
|
|
328
|
+
// request whose body the adapter cannot read then reaches the gate that owns it (GMO's aborts
|
|
329
|
+
// that request alone) or the arbiter, as it did before this gate joined the list.
|
|
330
|
+
if (!isFiservPausableBody(ctx.request.body))
|
|
318
331
|
return fiservContinue(ctx);
|
|
319
332
|
const idle = ctx.attachmentReady() && !ctx.stripeAttachmentBusy() && !ctx.interceptionAborted() && !ctx.terminal()
|
|
320
333
|
&& !ctx.lifecycle.isBlocked() && !ctx.awaitingApproval();
|
|
@@ -333,6 +346,119 @@ async function fiservPreparationRequired(ctx) {
|
|
|
333
346
|
await ctx.effects.abort();
|
|
334
347
|
return { kind: 'abort' };
|
|
335
348
|
}
|
|
349
|
+
// GMO token v2 and v1 (gmo.ts). GMO's CreateToken.json also carries requests the vault can never
|
|
350
|
+
// pay, so a POST the registry recognizes on a GMO token host is judged here, before the terminal
|
|
351
|
+
// arbiter would pause it, by the whole-request guard the API runs at create:
|
|
352
|
+
// - mp-token.js's SHARED_PK getToken for one token defers, and the arbiter pauses it;
|
|
353
|
+
// - anything else (UNIQUE_PK, GMO Elements, several tokens, a shop id of the other
|
|
354
|
+
// environment's shape, another serialization) aborts as an unsupported checkout,
|
|
355
|
+
// `unsupported_checkout` with reason `unsupported_gmo_request`, with no claim, create or
|
|
356
|
+
// prompt. The attachment then reads `unsupported` and holds: the merchant's configuration
|
|
357
|
+
// decides that shape, so the page's next request would be the same.
|
|
358
|
+
// GMO token v1's JSONP GET to /ext/api/getToken aborts the same way (`unsupported_gmo_token_v1`),
|
|
359
|
+
// so the agent's placeholder is never tokenized silently. Nothing is decided without the registry:
|
|
360
|
+
// an SDK the API did not serve GMO (a build without the capability, or an org Agentcard has not
|
|
361
|
+
// enabled) recognizes neither, so the gate defers and every GMO request continues as before. The
|
|
362
|
+
// preflight OPTIONS and every other method on those URLs continue through the arbiter.
|
|
363
|
+
// A body the adapter could not read says nothing about the page's configuration, so that request
|
|
364
|
+
// alone is aborted with a `blocked` event, `unreadable_gmo_request`, and the attachment is not held.
|
|
365
|
+
// A body or headers whose read throws (Playwright's postData() can) is that same unread request:
|
|
366
|
+
// it is aborted here rather than rejecting the route handler with the request left undecided.
|
|
367
|
+
// Synchronous until the abort, so a card request pauses with no await. A guard that throws
|
|
368
|
+
// refuses the request rather than letting it reach a prompt.
|
|
369
|
+
const gmoPreClaim = (ctx) => {
|
|
370
|
+
const { url, method } = ctx.request;
|
|
371
|
+
if (method.toUpperCase() === 'POST' && isGmoTokenHost(url) && ctx.vault.isCardRequest(url, method)) {
|
|
372
|
+
let body;
|
|
373
|
+
let headers;
|
|
374
|
+
try {
|
|
375
|
+
body = ctx.request.body;
|
|
376
|
+
headers = ctx.request.headers;
|
|
377
|
+
}
|
|
378
|
+
catch {
|
|
379
|
+
return gmoUnreadable(ctx);
|
|
380
|
+
}
|
|
381
|
+
if (body === null)
|
|
382
|
+
return gmoUnreadable(ctx);
|
|
383
|
+
const reason = gmoRequestRefusal({ url, method, headers, body });
|
|
384
|
+
return reason === null ? undefined : gmoUnsupported(ctx, reason);
|
|
385
|
+
}
|
|
386
|
+
if (isGmoTokenV1Request(url, method) && recognizesGmo(ctx.vault))
|
|
387
|
+
return gmoUnsupported(ctx, 'unsupported_gmo_token_v1');
|
|
388
|
+
return undefined;
|
|
389
|
+
};
|
|
390
|
+
async function gmoUnreadable(ctx) {
|
|
391
|
+
ctx.onEvent?.({ type: 'blocked', detail: 'unreadable_gmo_request' });
|
|
392
|
+
await ctx.effects.abort();
|
|
393
|
+
return { kind: 'abort' };
|
|
394
|
+
}
|
|
395
|
+
async function gmoUnsupported(ctx, reason) {
|
|
396
|
+
const { url, method } = ctx.request;
|
|
397
|
+
ctx.preparationGate.invalidate('unsupported_checkout');
|
|
398
|
+
ctx.lifecycle.unsupported(reason);
|
|
399
|
+
ctx.onEvent?.({ type: 'unsupported_checkout', detail: { url: redactUrl(url), method, reason } });
|
|
400
|
+
await ctx.effects.abort();
|
|
401
|
+
return { kind: 'abort' };
|
|
402
|
+
}
|
|
403
|
+
// CyberSource Flex Microform (cybersource-flex.ts). A POST to a Flex host that the registry
|
|
404
|
+
// recognizes is this gate's to judge before the terminal arbiter, which would pause every one of
|
|
405
|
+
// them: the same tokens URL carries Microform v0.x and Flex API direct traffic, and only the
|
|
406
|
+
// field iframe's URL fragment says which card field sent it and under which capture context.
|
|
407
|
+
// - a check (eCheck) Microform: continue untouched, it carries no card;
|
|
408
|
+
// - not a field iframe's sealed card, a frame read and found to be no Microform field, an
|
|
409
|
+
// unreviewed version, or fields the device cannot rebuild: abort as unsupported, before any
|
|
410
|
+
// authorization, and hold the attachment (the page's next request would be judged the same way);
|
|
411
|
+
// - a capture context that does not verify, has expired, names another URL, or did not seal
|
|
412
|
+
// this body, a body the adapter could not read, or a frame it could not read: abort this
|
|
413
|
+
// request only, since the page's next request can pass (a freshly minted context, a frame
|
|
414
|
+
// read on the next try);
|
|
415
|
+
// - otherwise pause, carrying the sidecar the create sends and the request's retry shape.
|
|
416
|
+
// Nothing is decided without the registry: an SDK that did not sync with the capability, or whose
|
|
417
|
+
// org Agentcard has not enabled for CyberSource Flex (the API withholds the recognizer), never
|
|
418
|
+
// recognizes a Flex host, so the gate defers and the request continues as before. Synchronous
|
|
419
|
+
// once the context's verification settled (the adapters start it when the field iframe loads).
|
|
420
|
+
const FLEX_UNREADABLE = { kind: 'refuse', reason: 'microform_frame_unread' };
|
|
421
|
+
const cybersourceFlexPreClaim = (ctx) => {
|
|
422
|
+
const { url, method } = ctx.request;
|
|
423
|
+
if (method.toUpperCase() !== 'POST' || !isCybersourceFlexHost(url) || !ctx.vault.isCardRequest(url, method))
|
|
424
|
+
return undefined;
|
|
425
|
+
let decision;
|
|
426
|
+
try {
|
|
427
|
+
decision = ctx.cybersourceFlex ? ctx.cybersourceFlex.judge(ctx.request) : FLEX_UNREADABLE;
|
|
428
|
+
}
|
|
429
|
+
catch {
|
|
430
|
+
decision = FLEX_UNREADABLE;
|
|
431
|
+
}
|
|
432
|
+
return decision instanceof Promise
|
|
433
|
+
? decision.then((settled) => cybersourceFlexResolve(ctx, settled), () => cybersourceFlexResolve(ctx, FLEX_UNREADABLE))
|
|
434
|
+
: cybersourceFlexResolve(ctx, decision);
|
|
435
|
+
};
|
|
436
|
+
function cybersourceFlexResolve(ctx, decision) {
|
|
437
|
+
if (decision.kind === 'pause')
|
|
438
|
+
return { kind: 'pause', stripeStep: ctx.stripeStep, cybersourceFlex: decision.flex };
|
|
439
|
+
if (decision.kind === 'continue')
|
|
440
|
+
return cybersourceFlexContinue(ctx);
|
|
441
|
+
if (decision.kind === 'unsupported')
|
|
442
|
+
return cybersourceFlexUnsupported(ctx, decision.reason);
|
|
443
|
+
return cybersourceFlexRefuse(ctx, decision.reason);
|
|
444
|
+
}
|
|
445
|
+
async function cybersourceFlexContinue(ctx) {
|
|
446
|
+
await ctx.effects.continueRequest().catch(() => { });
|
|
447
|
+
return { kind: 'continue' };
|
|
448
|
+
}
|
|
449
|
+
async function cybersourceFlexUnsupported(ctx, reason) {
|
|
450
|
+
const { url, method } = ctx.request;
|
|
451
|
+
ctx.preparationGate.invalidate('unsupported_checkout');
|
|
452
|
+
ctx.lifecycle.unsupported('microform_unsupported');
|
|
453
|
+
ctx.onEvent?.({ type: 'unsupported_checkout', detail: { url: redactUrl(url), method, processor: CYBERSOURCE_FLEX_PSP, reason } });
|
|
454
|
+
await ctx.effects.abort();
|
|
455
|
+
return { kind: 'abort' };
|
|
456
|
+
}
|
|
457
|
+
async function cybersourceFlexRefuse(ctx, reason) {
|
|
458
|
+
ctx.onEvent?.({ type: 'blocked', detail: reason });
|
|
459
|
+
await ctx.effects.abort();
|
|
460
|
+
return { kind: 'abort' };
|
|
461
|
+
}
|
|
336
462
|
// The terminal arbiter, always last. A request that no gate claimed and that is
|
|
337
463
|
// neither a native Stripe step nor a recognized card request continues, unless
|
|
338
464
|
// it matches a declared payment endpoint we do not support (then it aborts as an
|
|
@@ -366,7 +492,7 @@ async function unsupportedContinue(ctx) {
|
|
|
366
492
|
* arbiter runs after all of them and is not part of this list. A gate appended
|
|
367
493
|
* after Stripe is never offered a step Stripe claimed: Stripe answers, aborts or
|
|
368
494
|
* pauses each one itself. */
|
|
369
|
-
export const PSP_PRE_CLAIM_GATES = [mercadoPreClaim, braintreePreClaim, stripePreClaim, merchantHostedPreClaim, fiservPreClaim];
|
|
495
|
+
export const PSP_PRE_CLAIM_GATES = [mercadoPreClaim, braintreePreClaim, stripePreClaim, merchantHostedPreClaim, fiservPreClaim, gmoPreClaim, cybersourceFlexPreClaim];
|
|
370
496
|
/** Run each gate in order; the first to return a decision wins. If none does,
|
|
371
497
|
* the terminal arbiter decides between continue, abort (unsupported) and pause.
|
|
372
498
|
* Returns synchronously while every gate defers synchronously (an ordinary card
|
|
@@ -2293,6 +2293,64 @@
|
|
|
2293
2293
|
"hostname_pattern": "^p01\\.mul-pay\\.jp$",
|
|
2294
2294
|
"pathname_pattern": "^\\/link\\/"
|
|
2295
2295
|
},
|
|
2296
|
+
{
|
|
2297
|
+
"id": "cybersource-flex-microform-script",
|
|
2298
|
+
"psp": "cybersource_flex",
|
|
2299
|
+
"kinds": [
|
|
2300
|
+
"script"
|
|
2301
|
+
],
|
|
2302
|
+
"origin": "https://flex.cybersource.com",
|
|
2303
|
+
"path_pattern": "/microform/bundle/v2{,.:minor.:patch}/flex-microform.min.js",
|
|
2304
|
+
"sources": [
|
|
2305
|
+
{
|
|
2306
|
+
"kind": "primary_source",
|
|
2307
|
+
"reference": "https://flex.cybersource.com/microform/bundle/v2.12.1/flex-microform.min.js",
|
|
2308
|
+
"reviewed_on": "2026-09-23"
|
|
2309
|
+
},
|
|
2310
|
+
{
|
|
2311
|
+
"kind": "primary_source",
|
|
2312
|
+
"reference": "https://flex.cybersource.com/microform/bundle/v2.12.1/iframe.min.js",
|
|
2313
|
+
"reviewed_on": "2026-09-23"
|
|
2314
|
+
},
|
|
2315
|
+
{
|
|
2316
|
+
"kind": "official_documentation",
|
|
2317
|
+
"reference": "https://developer.cybersource.com/docs/cybs/en-us/digital-accept-flex-api/developer/ctv/rest/flex-api/microform-integ-v2/microform-integ-getting-started-v2/creating-server-side-context-v2.html",
|
|
2318
|
+
"reviewed_on": "2026-09-23"
|
|
2319
|
+
}
|
|
2320
|
+
],
|
|
2321
|
+
"hostname_pattern": "^flex\\.cybersource\\.com$",
|
|
2322
|
+
"pathname_pattern": "^\\/microform\\/bundle\\/v2(?:\\.[0-9]+\\.[0-9]+)?\\/flex-microform\\.min\\.js$"
|
|
2323
|
+
},
|
|
2324
|
+
{
|
|
2325
|
+
"id": "cybersource-flex-microform-field",
|
|
2326
|
+
"psp": "cybersource_flex",
|
|
2327
|
+
"kinds": [
|
|
2328
|
+
"frame",
|
|
2329
|
+
"iframe",
|
|
2330
|
+
"document"
|
|
2331
|
+
],
|
|
2332
|
+
"origin": "https://flex.cybersource.com",
|
|
2333
|
+
"path_pattern": "/microform/bundle/v:version/iframe.html",
|
|
2334
|
+
"sources": [
|
|
2335
|
+
{
|
|
2336
|
+
"kind": "primary_source",
|
|
2337
|
+
"reference": "https://flex.cybersource.com/microform/bundle/v2.12.1/flex-microform.min.js",
|
|
2338
|
+
"reviewed_on": "2026-09-23"
|
|
2339
|
+
},
|
|
2340
|
+
{
|
|
2341
|
+
"kind": "primary_source",
|
|
2342
|
+
"reference": "https://flex.cybersource.com/microform/bundle/v2.12.1/iframe.min.js",
|
|
2343
|
+
"reviewed_on": "2026-09-23"
|
|
2344
|
+
},
|
|
2345
|
+
{
|
|
2346
|
+
"kind": "official_documentation",
|
|
2347
|
+
"reference": "https://developer.cybersource.com/docs/cybs/en-us/digital-accept-flex-api/developer/ctv/rest/flex-api/microform-integ-v2/microform-integ-getting-started-v2/creating-server-side-context-v2.html",
|
|
2348
|
+
"reviewed_on": "2026-09-23"
|
|
2349
|
+
}
|
|
2350
|
+
],
|
|
2351
|
+
"hostname_pattern": "^flex\\.cybersource\\.com$",
|
|
2352
|
+
"pathname_pattern": "^\\/microform\\/bundle\\/v2\\.[0-9]+\\.[0-9]+\\/iframe\\.html$"
|
|
2353
|
+
},
|
|
2296
2354
|
{
|
|
2297
2355
|
"id": "gmo-mp-token-script-test",
|
|
2298
2356
|
"psp": "gmo_pg",
|
|
@@ -2383,6 +2441,64 @@
|
|
|
2383
2441
|
"hostname_pattern": "^pt01\\.mul-pay\\.jp$",
|
|
2384
2442
|
"pathname_pattern": "^\\/link\\/"
|
|
2385
2443
|
},
|
|
2444
|
+
{
|
|
2445
|
+
"id": "cybersource-flex-microform-script-test",
|
|
2446
|
+
"psp": "cybersource_flex",
|
|
2447
|
+
"kinds": [
|
|
2448
|
+
"script"
|
|
2449
|
+
],
|
|
2450
|
+
"origin": "https://testflex.cybersource.com",
|
|
2451
|
+
"path_pattern": "/microform/bundle/v2{,.:minor.:patch}/flex-microform.min.js",
|
|
2452
|
+
"sources": [
|
|
2453
|
+
{
|
|
2454
|
+
"kind": "primary_source",
|
|
2455
|
+
"reference": "https://flex.cybersource.com/microform/bundle/v2.12.1/flex-microform.min.js",
|
|
2456
|
+
"reviewed_on": "2026-09-23"
|
|
2457
|
+
},
|
|
2458
|
+
{
|
|
2459
|
+
"kind": "primary_source",
|
|
2460
|
+
"reference": "https://flex.cybersource.com/microform/bundle/v2.12.1/iframe.min.js",
|
|
2461
|
+
"reviewed_on": "2026-09-23"
|
|
2462
|
+
},
|
|
2463
|
+
{
|
|
2464
|
+
"kind": "official_documentation",
|
|
2465
|
+
"reference": "https://developer.cybersource.com/docs/cybs/en-us/digital-accept-flex-api/developer/ctv/rest/flex-api/microform-integ-v2/microform-integ-getting-started-v2/creating-server-side-context-v2.html",
|
|
2466
|
+
"reviewed_on": "2026-09-23"
|
|
2467
|
+
}
|
|
2468
|
+
],
|
|
2469
|
+
"hostname_pattern": "^testflex\\.cybersource\\.com$",
|
|
2470
|
+
"pathname_pattern": "^\\/microform\\/bundle\\/v2(?:\\.[0-9]+\\.[0-9]+)?\\/flex-microform\\.min\\.js$"
|
|
2471
|
+
},
|
|
2472
|
+
{
|
|
2473
|
+
"id": "cybersource-flex-microform-field-test",
|
|
2474
|
+
"psp": "cybersource_flex",
|
|
2475
|
+
"kinds": [
|
|
2476
|
+
"frame",
|
|
2477
|
+
"iframe",
|
|
2478
|
+
"document"
|
|
2479
|
+
],
|
|
2480
|
+
"origin": "https://testflex.cybersource.com",
|
|
2481
|
+
"path_pattern": "/microform/bundle/v:version/iframe.html",
|
|
2482
|
+
"sources": [
|
|
2483
|
+
{
|
|
2484
|
+
"kind": "primary_source",
|
|
2485
|
+
"reference": "https://flex.cybersource.com/microform/bundle/v2.12.1/flex-microform.min.js",
|
|
2486
|
+
"reviewed_on": "2026-09-23"
|
|
2487
|
+
},
|
|
2488
|
+
{
|
|
2489
|
+
"kind": "primary_source",
|
|
2490
|
+
"reference": "https://flex.cybersource.com/microform/bundle/v2.12.1/iframe.min.js",
|
|
2491
|
+
"reviewed_on": "2026-09-23"
|
|
2492
|
+
},
|
|
2493
|
+
{
|
|
2494
|
+
"kind": "official_documentation",
|
|
2495
|
+
"reference": "https://developer.cybersource.com/docs/cybs/en-us/digital-accept-flex-api/developer/ctv/rest/flex-api/microform-integ-v2/microform-integ-getting-started-v2/creating-server-side-context-v2.html",
|
|
2496
|
+
"reviewed_on": "2026-09-23"
|
|
2497
|
+
}
|
|
2498
|
+
],
|
|
2499
|
+
"hostname_pattern": "^testflex\\.cybersource\\.com$",
|
|
2500
|
+
"pathname_pattern": "^\\/microform\\/bundle\\/v2\\.[0-9]+\\.[0-9]+\\/iframe\\.html$"
|
|
2501
|
+
},
|
|
2386
2502
|
{
|
|
2387
2503
|
"id": "square-web-sdk-sandbox",
|
|
2388
2504
|
"psp": "square",
|
|
@@ -473,10 +473,14 @@
|
|
|
473
473
|
"gmo-token-v1-script",
|
|
474
474
|
"gmo-elements-card-frame",
|
|
475
475
|
"gmo-link-hosted-page",
|
|
476
|
+
"cybersource-flex-microform-script",
|
|
477
|
+
"cybersource-flex-microform-field",
|
|
476
478
|
"gmo-mp-token-script-test",
|
|
477
479
|
"gmo-token-v1-script-test",
|
|
478
480
|
"gmo-elements-card-frame-test",
|
|
479
481
|
"gmo-link-hosted-page-test",
|
|
482
|
+
"cybersource-flex-microform-script-test",
|
|
483
|
+
"cybersource-flex-microform-field-test",
|
|
480
484
|
"square-web-sdk-sandbox",
|
|
481
485
|
"paysafe-js-test",
|
|
482
486
|
"worldpay-checkout-sdk-try",
|
|
@@ -1010,10 +1014,14 @@
|
|
|
1010
1014
|
"gmo-token-v1-script",
|
|
1011
1015
|
"gmo-elements-card-frame",
|
|
1012
1016
|
"gmo-link-hosted-page",
|
|
1017
|
+
"cybersource-flex-microform-script",
|
|
1018
|
+
"cybersource-flex-microform-field",
|
|
1013
1019
|
"gmo-mp-token-script-test",
|
|
1014
1020
|
"gmo-token-v1-script-test",
|
|
1015
1021
|
"gmo-elements-card-frame-test",
|
|
1016
1022
|
"gmo-link-hosted-page-test",
|
|
1023
|
+
"cybersource-flex-microform-script-test",
|
|
1024
|
+
"cybersource-flex-microform-field-test",
|
|
1017
1025
|
"square-web-sdk-sandbox",
|
|
1018
1026
|
"paysafe-js-test",
|
|
1019
1027
|
"worldpay-checkout-sdk-try",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Generated from @agent-cards/payment-core. Do not edit.
|
|
2
|
-
// source-sha256:
|
|
2
|
+
// source-sha256: 3a36f98936b5a93687dd4a052d1d4513935a093736b19475f023b5a0847c6b4a
|
|
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';
|
|
@@ -86,12 +86,26 @@ RULES.push({ id: 'gmo-mp-token-script', psp: 'gmo_pg', kinds: ['script'], hostna
|
|
|
86
86
|
variant_unverified: 'GMO Elements takes the card in GMO\'s own iframes and encrypts it under a merchant-registered key; it is not admitted.' }, { id: 'gmo-link-hosted-page', psp: 'gmo_pg', kinds: ['document', 'frame', 'iframe', 'form'], hostname: /^p01\.mul-pay\.jp$/, pathname: /^\/link\//, origin: 'https://p01.mul-pay.jp', path_pattern: '/link/*',
|
|
87
87
|
sources: [{ kind: 'official_documentation', reference: 'https://docs.gmo-pg.com/mulpay/docs/developer-support/test-environment/overview', reviewed_on: '2026-09-25' }],
|
|
88
88
|
variant_unverified: 'A GMO Link-type payment page takes the card on GMO\'s own hosted page; it is not admitted.' });
|
|
89
|
+
// CyberSource Flex Microform v2 (dark: its processor declares a capability, so the bundled
|
|
90
|
+
// catalog does not list it and these signals stay unknown until a client opts in). The loader
|
|
91
|
+
// is served as /microform/bundle/v2/ and v2.x.y/; each card field is its own iframe document.
|
|
92
|
+
// Sources: the reviewed v2.12.1 bundles (loader sha256 32151372...32f6, field iframe 8429ebae...8327).
|
|
93
|
+
const cybersourceSources = [
|
|
94
|
+
{ kind: 'primary_source', reference: 'https://flex.cybersource.com/microform/bundle/v2.12.1/flex-microform.min.js', reviewed_on: '2026-09-23' },
|
|
95
|
+
{ kind: 'primary_source', reference: 'https://flex.cybersource.com/microform/bundle/v2.12.1/iframe.min.js', reviewed_on: '2026-09-23' },
|
|
96
|
+
{ kind: 'official_documentation', reference: 'https://developer.cybersource.com/docs/cybs/en-us/digital-accept-flex-api/developer/ctv/rest/flex-api/microform-integ-v2/microform-integ-getting-started-v2/creating-server-side-context-v2.html', reviewed_on: '2026-09-23' },
|
|
97
|
+
];
|
|
98
|
+
RULES.push({ id: 'cybersource-flex-microform-script', psp: 'cybersource_flex', kinds: ['script'], hostname: /^flex\.cybersource\.com$/, pathname: /^\/microform\/bundle\/v2(?:\.[0-9]+\.[0-9]+)?\/flex-microform\.min\.js$/, origin: 'https://flex.cybersource.com', path_pattern: '/microform/bundle/v2{,.:minor.:patch}/flex-microform.min.js',
|
|
99
|
+
sources: cybersourceSources }, { id: 'cybersource-flex-microform-field', psp: 'cybersource_flex', kinds: ['frame', 'iframe', 'document'], hostname: /^flex\.cybersource\.com$/, pathname: /^\/microform\/bundle\/v2\.[0-9]+\.[0-9]+\/iframe\.html$/, origin: 'https://flex.cybersource.com', path_pattern: '/microform/bundle/v:version/iframe.html',
|
|
100
|
+
sources: cybersourceSources });
|
|
89
101
|
// Keep sandbox evidence truthful instead of labelling it with a production origin.
|
|
90
102
|
for (const [baseId, suffix, hostname, origin] of [
|
|
91
103
|
['gmo-mp-token-script', 'test', /^stg\.static\.mul-pay\.jp$/, 'https://stg.static.mul-pay.jp'],
|
|
92
104
|
['gmo-token-v1-script', 'test', /^stg\.static\.mul-pay\.jp$/, 'https://stg.static.mul-pay.jp'],
|
|
93
105
|
['gmo-elements-card-frame', 'test', /^stg\.static\.mul-pay\.jp$/, 'https://stg.static.mul-pay.jp'],
|
|
94
106
|
['gmo-link-hosted-page', 'test', /^pt01\.mul-pay\.jp$/, 'https://pt01.mul-pay.jp'],
|
|
107
|
+
['cybersource-flex-microform-script', 'test', /^testflex\.cybersource\.com$/, 'https://testflex.cybersource.com'],
|
|
108
|
+
['cybersource-flex-microform-field', 'test', /^testflex\.cybersource\.com$/, 'https://testflex.cybersource.com'],
|
|
95
109
|
['square-web-sdk', 'sandbox', /^sandbox\.web\.squarecdn\.com$/, 'https://sandbox.web.squarecdn.com'],
|
|
96
110
|
['paysafe-js', 'test', /^hosted\.test\.paysafe\.com$/, 'https://hosted.test.paysafe.com'],
|
|
97
111
|
['worldpay-checkout-sdk', 'try', /^try\.access\.worldpay\.com$/, 'https://try.access.worldpay.com'],
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type PreparationProcessor = 'square' | 'braintree' | 'worldpay' | 'bambora' | 'mercado_pago' | 'recurly' | 'spreedly' | 'adyen' | 'checkout_com' | 'paysafe' | 'fiserv';
|
|
1
|
+
export type PreparationProcessor = 'square' | 'braintree' | 'worldpay' | 'bambora' | 'mercado_pago' | 'recurly' | 'spreedly' | 'adyen' | 'checkout_com' | 'paysafe' | 'fiserv' | 'cybersource_flex';
|
|
2
2
|
export type PreparationEnvironment = 'production' | 'sandbox' | 'shared';
|
|
3
3
|
/**
|
|
4
4
|
* How the approved card reaches the processor: the device's own request (token), or
|
|
@@ -10,7 +10,9 @@ export declare function preparationMode(psp: string): PreparationMode;
|
|
|
10
10
|
/**
|
|
11
11
|
* Shared endpoint processors cannot attest test/live mode from their URL or key prefix.
|
|
12
12
|
* Adyen can: test and live are separate hosts and key prefixes. Fiserv's are separate
|
|
13
|
-
* hosts too: connect (production) and connect-cert (sandbox).
|
|
13
|
+
* hosts too: connect (production) and connect-cert (sandbox). So are CyberSource
|
|
14
|
+
* Flex's: flex.cybersource.com is live, testflex.cybersource.com is test, and each has
|
|
15
|
+
* its own signing keys.
|
|
14
16
|
*/
|
|
15
17
|
export declare function validPreparationEnvironment(psp: string, environment: string): boolean;
|
|
16
18
|
export declare function preparationEndpoint(psp: PreparationProcessor, environment: PreparationEnvironment): string;
|