@agent-cards/sdk 0.23.13 → 0.23.15
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 +39 -0
- package/PREFLIGHT.md +3 -1
- package/README.md +54 -13
- package/dist/adyen-merchant-hosted.generated.js +2 -2
- package/dist/amadeus.d.ts +5 -2
- package/dist/amadeus.js +17 -3
- package/dist/card-fields.generated.js +924 -3
- package/dist/cdp.js +83 -19
- package/dist/client.d.ts +97 -1
- package/dist/client.js +235 -16
- package/dist/creditguard.generated.d.ts +100 -2
- package/dist/creditguard.generated.js +333 -3
- package/dist/datatrans.generated.d.ts +19 -4
- package/dist/datatrans.generated.js +15 -3
- package/dist/ebanx.d.ts +107 -0
- package/dist/ebanx.generated.d.ts +78 -0
- package/dist/ebanx.generated.js +577 -0
- package/dist/ebanx.js +159 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/lifecycle.d.ts +32 -5
- package/dist/lifecycle.js +40 -5
- package/dist/paddle-tokenex.d.ts +56 -0
- package/dist/paddle-tokenex.generated.d.ts +67 -0
- package/dist/paddle-tokenex.generated.js +951 -0
- package/dist/paddle-tokenex.js +95 -0
- package/dist/paypal-card-forms.d.ts +73 -0
- package/dist/paypal-card-forms.js +126 -0
- package/dist/pre-claim.d.ts +39 -1
- package/dist/pre-claim.js +348 -18
- package/dist/preparation.d.ts +13 -0
- package/dist/preparation.js +22 -0
- package/dist/prepared-processor.d.ts +5 -1
- package/dist/prepared-processor.js +17 -2
- package/dist/primer.generated.js +960 -39
- package/dist/redsys.d.ts +42 -0
- package/dist/redsys.js +68 -0
- package/dist/stripe-checkout.generated.js +494 -9
- package/dist/wix-payments.generated.d.ts +42 -0
- package/dist/wix-payments.generated.js +241 -0
- package/package.json +8 -5
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// Paddle TokenEx, the card leg of a Paddle checkout whose frame names the tokenization provider "tokenex",
|
|
2
|
+
// as the SDK sees it (payment-core paddle-tokenex.js has the request's shape, the device encryption and the
|
|
3
|
+
// substitution). Paddle's frame RSA-encrypts the card number and the CVV in the page itself, each on its
|
|
4
|
+
// own, under the account-level TokenEx public key the checkout serves, and carries both inside one request:
|
|
5
|
+
// POST https://checkout-service.paddle.com/checkout/<id>/pay (Paddle Classic)
|
|
6
|
+
// POST https://checkout-service.paddle.com/transaction-checkout/<id>/pay (Paddle Billing)
|
|
7
|
+
// (sandbox-checkout-service.paddle.com in test). The agent's page encrypts a placeholder card, so the /pay
|
|
8
|
+
// names the placeholder's ciphertexts and the placeholder's first six, last four, expiry and brand. This
|
|
9
|
+
// build holds that /pay and writes over them the approved card's own: the two ciphertexts the cardholder's
|
|
10
|
+
// device produced under the key payment-core pins (never a key from a row, a request or a page) and the
|
|
11
|
+
// five metadata facts the device read from the real card. Every other byte goes as the frame wrote it
|
|
12
|
+
// (mode cse), so the full card number never reaches the agent's runtime.
|
|
13
|
+
//
|
|
14
|
+
// The generic Adyen swap writes only the named ciphertext path, not the five metadata facts a sibling of
|
|
15
|
+
// tokenex_card, so this lane is dispatched by psp to substitutePaddleTokenex instead, exactly as Shiji STS
|
|
16
|
+
// is dispatched for its own body root. A production checkout-service refuses the Vault's cross-origin /pay
|
|
17
|
+
// (403 at Cloudflare), so the device cannot send /pay itself and the lane rides in the agent's page.
|
|
18
|
+
//
|
|
19
|
+
// The registry entry ships dark (capability paddle_tokenex_pay). This build declares the capability on
|
|
20
|
+
// syncRegistry, and the API serves the recognizer only to an org Agentcard enabled for paddle_tokenex, so
|
|
21
|
+
// for every other org nothing here fires: isCardRequest never recognizes a TokenEx /pay and Paddle's
|
|
22
|
+
// requests go through untouched. Autopilot never pays this processor: the API, the authority and the
|
|
23
|
+
// enclave refuse it.
|
|
24
|
+
import { PADDLE_TOKENEX_FIELDS, PADDLE_TOKENEX_FACT_KEYS, paddleTokenexPayTarget, substitutePaddleTokenex } from './paddle-tokenex.generated.js';
|
|
25
|
+
/** The PSP id the API and the recognizer name this lane, re-exported so the client dispatches by it. */
|
|
26
|
+
export { PADDLE_TOKENEX_PSP } from './paddle-tokenex.generated.js';
|
|
27
|
+
/** The dark-launch capability a build declares when it fills a Paddle TokenEx /pay with the device's card. */
|
|
28
|
+
export const PADDLE_TOKENEX_CAPABILITY = 'paddle_tokenex_pay';
|
|
29
|
+
/** The holder the two ciphertexts are served at (the frame's tokenex_card), named once so both checks share it. */
|
|
30
|
+
const SERVED_AT = 'data.payment_method_data.card.tokenex_card';
|
|
31
|
+
const CIPHERTEXT_FIELDS = PADDLE_TOKENEX_FIELDS;
|
|
32
|
+
const FACT_KEYS = PADDLE_TOKENEX_FACT_KEYS;
|
|
33
|
+
const STRING_FACTS = ['card_first_six', 'card_last_four', 'card_brand'];
|
|
34
|
+
const NUMBER_FACTS = ['expiry_month', 'expiry_year'];
|
|
35
|
+
/**
|
|
36
|
+
* Whether an approved Paddle TokenEx authorization's served substitution is one this SDK can continue: JSON
|
|
37
|
+
* at the frame's tokenex_card holder, no sibling to remove, and exactly the two ciphertext fields, each a
|
|
38
|
+
* non-empty string and distinct from the other. substitutePaddleTokenex checks each against the pinned key
|
|
39
|
+
* for the /pay's environment; this is the shape gate the client runs before it acts.
|
|
40
|
+
*/
|
|
41
|
+
export function isPaddleTokenexServedSubstitution(sub) {
|
|
42
|
+
if (!sub || typeof sub !== 'object' || Array.isArray(sub))
|
|
43
|
+
return false;
|
|
44
|
+
const { encoding, at, fields, remove } = sub;
|
|
45
|
+
if (encoding !== 'json' || at !== SERVED_AT || !fields || typeof fields !== 'object' || Array.isArray(fields))
|
|
46
|
+
return false;
|
|
47
|
+
if (remove !== undefined && !(Array.isArray(remove) && remove.length === 0))
|
|
48
|
+
return false;
|
|
49
|
+
const named = fields;
|
|
50
|
+
const names = Object.keys(named);
|
|
51
|
+
if (names.length !== CIPHERTEXT_FIELDS.length || !CIPHERTEXT_FIELDS.every((name) => typeof named[name] === 'string' && named[name].length > 0))
|
|
52
|
+
return false;
|
|
53
|
+
return named.encrypted_card_number !== named.encrypted_cvv;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Whether the API's `paddle_tokenex_facts` beside an approved set is the five facts this SDK can write over
|
|
57
|
+
* the placeholder's: exactly the five keys, the three strings as strings and the two expiry parts as
|
|
58
|
+
* numbers. paddleTokenexSubstitutionOf checks the digits, range and network at the swap; this is the shape
|
|
59
|
+
* gate the client runs before it acts, so a malformed approval is refused before anything is written.
|
|
60
|
+
*/
|
|
61
|
+
export function isPaddleTokenexServedFacts(value) {
|
|
62
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
63
|
+
return false;
|
|
64
|
+
const named = value;
|
|
65
|
+
const names = Object.keys(named);
|
|
66
|
+
if (names.length !== FACT_KEYS.length || !FACT_KEYS.every((name) => name in named))
|
|
67
|
+
return false;
|
|
68
|
+
return STRING_FACTS.every((name) => typeof named[name] === 'string' && named[name].length > 0)
|
|
69
|
+
&& NUMBER_FACTS.every((name) => typeof named[name] === 'number' && Number.isInteger(named[name]));
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* The continuation of an approved Paddle TokenEx /pay: the paused body with the device's two ciphertexts
|
|
73
|
+
* written over the placeholder's at tokenex_card and the five facts over the placeholder's at metadata
|
|
74
|
+
* (payment-core substitutePaddleTokenex, which refuses a ciphertext that is not one under the pinned key
|
|
75
|
+
* for the /pay's environment, or one already in the paused body).
|
|
76
|
+
*
|
|
77
|
+
* Only into `approved`, the paused /pay the approval was created from: `url` and `body` must equal it byte
|
|
78
|
+
* for byte. The account-level TokenEx key is the same for every checkout of that seller, so the device's
|
|
79
|
+
* ciphertext could be decrypted in any later /pay of the same shape; binding it to the one request keeps
|
|
80
|
+
* this lane from ever submitting one checkout's ciphertext to another.
|
|
81
|
+
*
|
|
82
|
+
* Null when neither URL is a TokenEx /pay, so every other processor keeps the generic swap. Throws for any
|
|
83
|
+
* other body or URL, and for a substitution or facts the shape gates refuse, in each case before anything
|
|
84
|
+
* continues.
|
|
85
|
+
*/
|
|
86
|
+
export function paddleTokenexTokenContinuation(url, body, sub, facts, approved) {
|
|
87
|
+
if (paddleTokenexPayTarget(url) === null && paddleTokenexPayTarget(approved.url) === null)
|
|
88
|
+
return null;
|
|
89
|
+
if (url !== approved.url || body !== approved.body)
|
|
90
|
+
throw new Error('Refusing to substitute: the paused request is not the Paddle TokenEx /pay the cardholder approved.');
|
|
91
|
+
if (!isPaddleTokenexServedSubstitution(sub) || !isPaddleTokenexServedFacts(facts))
|
|
92
|
+
throw new Error('Refusing to substitute: the Paddle TokenEx approval is not two ciphertexts and five card facts.');
|
|
93
|
+
const substitution = { encrypted_card_number: sub.fields.encrypted_card_number, encrypted_cvv: sub.fields.encrypted_cvv, ...facts };
|
|
94
|
+
return { body: substitutePaddleTokenex(url, body, substitution) };
|
|
95
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PayPal's Card Fields and PayPal's guest card form, which this SDK refuses for every company until a
|
|
3
|
+
* synced recognizer takes the request.
|
|
4
|
+
*
|
|
5
|
+
* Read 2026-10-15 from PayPal's public bundles and card-free page reads (WooCommerce PayPal Payments
|
|
6
|
+
* 4.1.3 checkouts on PayPal JS SDK 5.0.582, card-field client 1.270.0; web-sdk v6 6.68.0):
|
|
7
|
+
*
|
|
8
|
+
* Card Fields v5 (components=card-fields): each field is a frame on www.paypal.com/smart/card-field,
|
|
9
|
+
* and at submit the number frame sends the typed card as plaintext JSON, a same-origin XHR:
|
|
10
|
+
* POST https://www.paypal.com/v2/checkout/orders/<order id>/confirm-payment-source
|
|
11
|
+
* {"payment_source":{"card":{"number","expiry":"YYYY-MM","security_code","name"?,"billing_address"?}}}
|
|
12
|
+
* Card Fields v6 (web-sdk v6): the same request, sent to api-m.paypal.com.
|
|
13
|
+
* Card Fields saving a card with no purchase: POST https://www.paypal.com/graphql?UpdateVaultSetupToken,
|
|
14
|
+
* the card at variables.paymentSource.card.
|
|
15
|
+
* PayPal's guest card form, behind the black "Debit or Credit Card" button: PayPal's checkout page
|
|
16
|
+
* sends the card as POST https://www.paypal.com/graphql?OnboardGuestMutation, the number at
|
|
17
|
+
* variables.card.cardNumber.
|
|
18
|
+
* PayPal's sandbox serves each on www.sandbox.paypal.com and api-m.sandbox.paypal.com.
|
|
19
|
+
*
|
|
20
|
+
* An SDK without this guard let the agent's placeholder card reach PayPal there, and PayPal declined it.
|
|
21
|
+
* Both adapters arm these paths whatever the synced registry serves, and the pre-claim gate
|
|
22
|
+
* (paypalCardFormsPreClaim, pre-claim.ts) judges each POST:
|
|
23
|
+
* - a Card Fields confirm whose body carries a number at payment_source.card.number aborts, reason
|
|
24
|
+
* `unsupported_paypal_card_fields`, unless the synced registry recognizes it as a card request: an
|
|
25
|
+
* org Agentcard turned PayPal Card Fields on for pauses and pays that confirm through the recognizer,
|
|
26
|
+
* which judges the body itself;
|
|
27
|
+
* - a GraphQL operation carrying a card aborts whatever the registry serves, since no recognizer pays
|
|
28
|
+
* one: the guest form's card as `unsupported_paypal_guest_checkout`, a card saved with no purchase as
|
|
29
|
+
* `unsupported_paypal_card_fields`;
|
|
30
|
+
* - a body with no card (a PayPal wallet confirm, a saved card, every other GraphQL operation the
|
|
31
|
+
* buttons send) continues untouched;
|
|
32
|
+
* - a confirm the adapter could not read aborts that request alone, since nothing proves it carries no
|
|
33
|
+
* card. A GraphQL post it could not read aborts only when its query names one of the two card
|
|
34
|
+
* operations: PayPal's buttons send many others, and failing them would break PayPal's own wallet.
|
|
35
|
+
* Each abort holds the attachment as every unsupported refusal does: the page's next submit would carry
|
|
36
|
+
* the card again, so another way to pay needs a new attachment.
|
|
37
|
+
*
|
|
38
|
+
* A guest form PayPal opens in a popup window runs in another page, which an attachment covers only when
|
|
39
|
+
* the agent attaches the SDK to that page as well. PayPal's BIN lookup (/v2/payments/find-bin-details)
|
|
40
|
+
* reads the first digits the agent types and pays nothing; neither adapter intercepts it.
|
|
41
|
+
*/
|
|
42
|
+
import { paypalHostedFieldsBody } from './paypal-hosted-fields.js';
|
|
43
|
+
export declare const PAYPAL_CARD_FIELDS_REASON: "unsupported_paypal_card_fields";
|
|
44
|
+
export declare const PAYPAL_GUEST_CHECKOUT_REASON: "unsupported_paypal_guest_checkout";
|
|
45
|
+
export type PaypalCardFormReason = typeof PAYPAL_CARD_FIELDS_REASON | typeof PAYPAL_GUEST_CHECKOUT_REASON;
|
|
46
|
+
/** The hosts Card Fields sends its confirm to: v5 on www, v6 on api-m, live and sandbox. */
|
|
47
|
+
export declare const PAYPAL_CARD_FIELDS_HOSTS: readonly string[];
|
|
48
|
+
/** The hosts of PayPal's own pages, whose GraphQL endpoint takes the guest form's card and a card saved with no purchase. */
|
|
49
|
+
export declare const PAYPAL_GRAPHQL_HOSTS: readonly string[];
|
|
50
|
+
/**
|
|
51
|
+
* CDP Fetch patterns, armed on every attachment: the confirm on its four hosts and GraphQL on PayPal's
|
|
52
|
+
* two page hosts. Chrome sends the canonical URL, whose host is lower case, and the trailing `*` keeps a
|
|
53
|
+
* query or a trailing slash paused. Nothing else on www.paypal.com is armed.
|
|
54
|
+
*/
|
|
55
|
+
export declare const PAYPAL_CARD_FORM_PATTERNS: readonly string[];
|
|
56
|
+
/** Whether this URL is the Card Fields confirm on one of its four hosts (https, standard port, no credentials). */
|
|
57
|
+
export declare function isPaypalCardFieldsConfirm(url: string): boolean;
|
|
58
|
+
/** Whether this URL is GraphQL on one of PayPal's two page hosts. */
|
|
59
|
+
export declare function isPaypalGraphql(url: string): boolean;
|
|
60
|
+
/** Whether this URL is any request the guard judges, for the Playwright route's predicate. */
|
|
61
|
+
export declare function isPaypalCardFormUrl(url: string): boolean;
|
|
62
|
+
/** Whether a GraphQL URL's query names one of the two card operations (`/graphql?OnboardGuestMutation`). */
|
|
63
|
+
export declare function paypalGraphqlNamesCardOperation(url: string): boolean;
|
|
64
|
+
/**
|
|
65
|
+
* What a GraphQL post carries, read as PayPal reads it (the last of a repeated key wins in both), for one
|
|
66
|
+
* operation or a batch of them: 'guest_card' when an operation's variables.card.cardNumber holds anything
|
|
67
|
+
* but null or an empty string, 'saved_card' when an operation's variables.paymentSource.card is an object,
|
|
68
|
+
* 'no_card' for any other JSON object or array of them, and 'unreadable' for a body the adapter could not
|
|
69
|
+
* read (null), an empty one, or one that is neither.
|
|
70
|
+
*/
|
|
71
|
+
export declare function paypalGraphqlCard(body: string | null): 'guest_card' | 'saved_card' | 'no_card' | 'unreadable';
|
|
72
|
+
/** What a Card Fields confirm carries: its body is the Orders v2 shape Hosted Fields also sends. */
|
|
73
|
+
export declare const paypalCardFieldsBody: typeof paypalHostedFieldsBody;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PayPal's Card Fields and PayPal's guest card form, which this SDK refuses for every company until a
|
|
3
|
+
* synced recognizer takes the request.
|
|
4
|
+
*
|
|
5
|
+
* Read 2026-10-15 from PayPal's public bundles and card-free page reads (WooCommerce PayPal Payments
|
|
6
|
+
* 4.1.3 checkouts on PayPal JS SDK 5.0.582, card-field client 1.270.0; web-sdk v6 6.68.0):
|
|
7
|
+
*
|
|
8
|
+
* Card Fields v5 (components=card-fields): each field is a frame on www.paypal.com/smart/card-field,
|
|
9
|
+
* and at submit the number frame sends the typed card as plaintext JSON, a same-origin XHR:
|
|
10
|
+
* POST https://www.paypal.com/v2/checkout/orders/<order id>/confirm-payment-source
|
|
11
|
+
* {"payment_source":{"card":{"number","expiry":"YYYY-MM","security_code","name"?,"billing_address"?}}}
|
|
12
|
+
* Card Fields v6 (web-sdk v6): the same request, sent to api-m.paypal.com.
|
|
13
|
+
* Card Fields saving a card with no purchase: POST https://www.paypal.com/graphql?UpdateVaultSetupToken,
|
|
14
|
+
* the card at variables.paymentSource.card.
|
|
15
|
+
* PayPal's guest card form, behind the black "Debit or Credit Card" button: PayPal's checkout page
|
|
16
|
+
* sends the card as POST https://www.paypal.com/graphql?OnboardGuestMutation, the number at
|
|
17
|
+
* variables.card.cardNumber.
|
|
18
|
+
* PayPal's sandbox serves each on www.sandbox.paypal.com and api-m.sandbox.paypal.com.
|
|
19
|
+
*
|
|
20
|
+
* An SDK without this guard let the agent's placeholder card reach PayPal there, and PayPal declined it.
|
|
21
|
+
* Both adapters arm these paths whatever the synced registry serves, and the pre-claim gate
|
|
22
|
+
* (paypalCardFormsPreClaim, pre-claim.ts) judges each POST:
|
|
23
|
+
* - a Card Fields confirm whose body carries a number at payment_source.card.number aborts, reason
|
|
24
|
+
* `unsupported_paypal_card_fields`, unless the synced registry recognizes it as a card request: an
|
|
25
|
+
* org Agentcard turned PayPal Card Fields on for pauses and pays that confirm through the recognizer,
|
|
26
|
+
* which judges the body itself;
|
|
27
|
+
* - a GraphQL operation carrying a card aborts whatever the registry serves, since no recognizer pays
|
|
28
|
+
* one: the guest form's card as `unsupported_paypal_guest_checkout`, a card saved with no purchase as
|
|
29
|
+
* `unsupported_paypal_card_fields`;
|
|
30
|
+
* - a body with no card (a PayPal wallet confirm, a saved card, every other GraphQL operation the
|
|
31
|
+
* buttons send) continues untouched;
|
|
32
|
+
* - a confirm the adapter could not read aborts that request alone, since nothing proves it carries no
|
|
33
|
+
* card. A GraphQL post it could not read aborts only when its query names one of the two card
|
|
34
|
+
* operations: PayPal's buttons send many others, and failing them would break PayPal's own wallet.
|
|
35
|
+
* Each abort holds the attachment as every unsupported refusal does: the page's next submit would carry
|
|
36
|
+
* the card again, so another way to pay needs a new attachment.
|
|
37
|
+
*
|
|
38
|
+
* A guest form PayPal opens in a popup window runs in another page, which an attachment covers only when
|
|
39
|
+
* the agent attaches the SDK to that page as well. PayPal's BIN lookup (/v2/payments/find-bin-details)
|
|
40
|
+
* reads the first digits the agent types and pays nothing; neither adapter intercepts it.
|
|
41
|
+
*/
|
|
42
|
+
import { paypalHostedFieldsBody } from './paypal-hosted-fields.js';
|
|
43
|
+
export const PAYPAL_CARD_FIELDS_REASON = 'unsupported_paypal_card_fields';
|
|
44
|
+
export const PAYPAL_GUEST_CHECKOUT_REASON = 'unsupported_paypal_guest_checkout';
|
|
45
|
+
/** The hosts Card Fields sends its confirm to: v5 on www, v6 on api-m, live and sandbox. */
|
|
46
|
+
export const PAYPAL_CARD_FIELDS_HOSTS = Object.freeze(['www.paypal.com', 'www.sandbox.paypal.com',
|
|
47
|
+
'api-m.paypal.com', 'api-m.sandbox.paypal.com']);
|
|
48
|
+
/** The hosts of PayPal's own pages, whose GraphQL endpoint takes the guest form's card and a card saved with no purchase. */
|
|
49
|
+
export const PAYPAL_GRAPHQL_HOSTS = Object.freeze(['www.paypal.com', 'www.sandbox.paypal.com']);
|
|
50
|
+
const CONFIRM_PATH = /^\/v2\/checkout\/orders\/[^/]+\/confirm-payment-source\/?$/;
|
|
51
|
+
const GRAPHQL_PATH = /^\/graphql\/?$/;
|
|
52
|
+
/** The two GraphQL operations that carry a card, as PayPal's clients name them in the query string. */
|
|
53
|
+
const CARD_OPERATIONS = ['OnboardGuestMutation', 'UpdateVaultSetupToken'];
|
|
54
|
+
/**
|
|
55
|
+
* CDP Fetch patterns, armed on every attachment: the confirm on its four hosts and GraphQL on PayPal's
|
|
56
|
+
* two page hosts. Chrome sends the canonical URL, whose host is lower case, and the trailing `*` keeps a
|
|
57
|
+
* query or a trailing slash paused. Nothing else on www.paypal.com is armed.
|
|
58
|
+
*/
|
|
59
|
+
export const PAYPAL_CARD_FORM_PATTERNS = Object.freeze([
|
|
60
|
+
...PAYPAL_CARD_FIELDS_HOSTS.map((host) => `https://${host}/v2/checkout/orders/*/confirm-payment-source*`),
|
|
61
|
+
...PAYPAL_GRAPHQL_HOSTS.map((host) => `https://${host}/graphql*`),
|
|
62
|
+
]);
|
|
63
|
+
function paypalUrl(url, hosts, path) {
|
|
64
|
+
let parsed;
|
|
65
|
+
try {
|
|
66
|
+
parsed = new URL(url);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
return parsed.protocol === 'https:' && !parsed.port && !parsed.username && !parsed.password
|
|
72
|
+
&& hosts.includes(parsed.hostname.toLowerCase()) && path.test(parsed.pathname) ? parsed : null;
|
|
73
|
+
}
|
|
74
|
+
/** Whether this URL is the Card Fields confirm on one of its four hosts (https, standard port, no credentials). */
|
|
75
|
+
export function isPaypalCardFieldsConfirm(url) {
|
|
76
|
+
return paypalUrl(url, PAYPAL_CARD_FIELDS_HOSTS, CONFIRM_PATH) !== null;
|
|
77
|
+
}
|
|
78
|
+
/** Whether this URL is GraphQL on one of PayPal's two page hosts. */
|
|
79
|
+
export function isPaypalGraphql(url) {
|
|
80
|
+
return paypalUrl(url, PAYPAL_GRAPHQL_HOSTS, GRAPHQL_PATH) !== null;
|
|
81
|
+
}
|
|
82
|
+
/** Whether this URL is any request the guard judges, for the Playwright route's predicate. */
|
|
83
|
+
export function isPaypalCardFormUrl(url) {
|
|
84
|
+
return isPaypalCardFieldsConfirm(url) || isPaypalGraphql(url);
|
|
85
|
+
}
|
|
86
|
+
/** Whether a GraphQL URL's query names one of the two card operations (`/graphql?OnboardGuestMutation`). */
|
|
87
|
+
export function paypalGraphqlNamesCardOperation(url) {
|
|
88
|
+
const parsed = paypalUrl(url, PAYPAL_GRAPHQL_HOSTS, GRAPHQL_PATH);
|
|
89
|
+
return parsed !== null && CARD_OPERATIONS.some((name) => parsed.searchParams.has(name));
|
|
90
|
+
}
|
|
91
|
+
const record = (value) => !!value && typeof value === 'object' && !Array.isArray(value);
|
|
92
|
+
const present = (value) => value !== undefined && value !== null && value !== '';
|
|
93
|
+
/**
|
|
94
|
+
* What a GraphQL post carries, read as PayPal reads it (the last of a repeated key wins in both), for one
|
|
95
|
+
* operation or a batch of them: 'guest_card' when an operation's variables.card.cardNumber holds anything
|
|
96
|
+
* but null or an empty string, 'saved_card' when an operation's variables.paymentSource.card is an object,
|
|
97
|
+
* 'no_card' for any other JSON object or array of them, and 'unreadable' for a body the adapter could not
|
|
98
|
+
* read (null), an empty one, or one that is neither.
|
|
99
|
+
*/
|
|
100
|
+
export function paypalGraphqlCard(body) {
|
|
101
|
+
if (typeof body !== 'string' || body === '')
|
|
102
|
+
return 'unreadable';
|
|
103
|
+
let parsed;
|
|
104
|
+
try {
|
|
105
|
+
parsed = JSON.parse(body);
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
return 'unreadable';
|
|
109
|
+
}
|
|
110
|
+
const operations = Array.isArray(parsed) ? parsed : [parsed];
|
|
111
|
+
if (operations.length === 0 || !operations.every(record))
|
|
112
|
+
return 'unreadable';
|
|
113
|
+
let carried = 'no_card';
|
|
114
|
+
for (const operation of operations) {
|
|
115
|
+
const variables = operation.variables;
|
|
116
|
+
if (!record(variables))
|
|
117
|
+
continue;
|
|
118
|
+
if (record(variables.card) && present(variables.card.cardNumber))
|
|
119
|
+
return 'guest_card';
|
|
120
|
+
if (record(variables.paymentSource) && record(variables.paymentSource.card))
|
|
121
|
+
carried = 'saved_card';
|
|
122
|
+
}
|
|
123
|
+
return carried;
|
|
124
|
+
}
|
|
125
|
+
/** What a Card Fields confirm carries: its body is the Orders v2 shape Hosted Fields also sends. */
|
|
126
|
+
export const paypalCardFieldsBody = paypalHostedFieldsBody;
|
package/dist/pre-claim.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ import { type PayrailsSessionCapture, type PayrailsSidecar } from './payrails.js
|
|
|
14
14
|
import { type VerifoneProfile } from './verifone.js';
|
|
15
15
|
import { type WorldlineMyCheckoutProducts } from './worldline-mycheckout.js';
|
|
16
16
|
import { type PaddleVgsPayGate } from './paddle-vgs-pay.js';
|
|
17
|
+
import { type EbanxFollowUps } from './ebanx.js';
|
|
17
18
|
/** The native Stripe step the gate claimed, or null when none was: exactly what StripeCheckoutGate.claim returns. */
|
|
18
19
|
type StripeStep = ReturnType<StripeCheckoutGate['claim']>;
|
|
19
20
|
/** A synthetic response a gate fulfills locally. The effect applies CORS and encoding. */
|
|
@@ -98,6 +99,20 @@ export interface PreClaimContext {
|
|
|
98
99
|
verifoneProfileOf?(url: string): VerifoneProfile | null;
|
|
99
100
|
cardOnFilePolicy?(url: string, method?: string): string | null;
|
|
100
101
|
withoutCard?(url: string, body: string | null | undefined): 'continue' | 'refuse' | null;
|
|
102
|
+
/** VaultClient.sendEbanxFollowUp: a send an approved EBANX token request covers, from the cardholder's device. */
|
|
103
|
+
sendEbanxFollowUp?(authorizationId: string, request: {
|
|
104
|
+
url: string;
|
|
105
|
+
method: 'POST';
|
|
106
|
+
headers: Record<string, string>;
|
|
107
|
+
body: string;
|
|
108
|
+
}, options?: {
|
|
109
|
+
signal?: AbortSignal;
|
|
110
|
+
until?: number;
|
|
111
|
+
}): Promise<{
|
|
112
|
+
status: number;
|
|
113
|
+
headers: Record<string, string>;
|
|
114
|
+
body: string;
|
|
115
|
+
}>;
|
|
101
116
|
};
|
|
102
117
|
guards: {
|
|
103
118
|
matches(url: string, method?: string): boolean;
|
|
@@ -117,11 +132,15 @@ export interface PreClaimContext {
|
|
|
117
132
|
eprotect?: EprotectGate;
|
|
118
133
|
readDocumentUrl: () => Promise<string>;
|
|
119
134
|
lifecycle: CheckoutLifecycle;
|
|
120
|
-
/**
|
|
135
|
+
/**
|
|
136
|
+
* isEngaged and observeUnprepared are called only for an armed merchant profile's card request or a Fiserv card capture.
|
|
137
|
+
* creditguardStanding, only for a request on a CreditGuard PPS host (PreparationGate.creditguardStanding); absent reads as 'none'.
|
|
138
|
+
*/
|
|
121
139
|
preparationGate: {
|
|
122
140
|
invalidate(reason: string): void;
|
|
123
141
|
isEngaged(): boolean;
|
|
124
142
|
observeUnprepared(): void;
|
|
143
|
+
creditguardStanding?(txId: string): 'none' | 'ready' | 'refuse';
|
|
125
144
|
};
|
|
126
145
|
effects: PreClaimEffects;
|
|
127
146
|
onEvent?: (event: PreClaimEvent) => void;
|
|
@@ -196,6 +215,12 @@ export interface PreClaimContext {
|
|
|
196
215
|
* checkout services are not this gate's.
|
|
197
216
|
*/
|
|
198
217
|
paddleVgsPay?: PaddleVgsPayGate;
|
|
218
|
+
/**
|
|
219
|
+
* The attachment's approved EBANX token request and the sends claimed under it (ebanx.ts EbanxFollowUps).
|
|
220
|
+
* Absent, or holding no approval whose read named a window, and every EBANX 3-D Secure call and card confirm
|
|
221
|
+
* is refused, as before the approval covered them.
|
|
222
|
+
*/
|
|
223
|
+
ebanx?: EbanxFollowUps;
|
|
199
224
|
}
|
|
200
225
|
/**
|
|
201
226
|
* The URL an event may name for a request. For an armed merchant profile's
|
|
@@ -214,11 +239,24 @@ export type PreClaimGate = (ctx: PreClaimContext) => PreClaimDecision | undefine
|
|
|
214
239
|
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";
|
|
215
240
|
export declare const verifonePreClaim: PreClaimGate;
|
|
216
241
|
export declare const fiservPreClaim: PreClaimGate;
|
|
242
|
+
/**
|
|
243
|
+
* Whether an adapter must hand this request to the pre-claim gates as a CreditGuard page's own call
|
|
244
|
+
* beside its submit: a companion endpoint (payment-core creditguardCompanionCall, as loosely as a
|
|
245
|
+
* request could spell one) while this build's registry serves CreditGuard. The CDP adapter pauses
|
|
246
|
+
* them already through the recognizer's host-wide URL patterns; attachToPlaywright's route predicate,
|
|
247
|
+
* which otherwise sees only the submit, asks this.
|
|
248
|
+
*/
|
|
249
|
+
export declare function isArmedCreditguardCall(vault: {
|
|
250
|
+
recognizesProcessor?(psp: string): boolean;
|
|
251
|
+
} | undefined, url: string): boolean;
|
|
217
252
|
export declare const ekashuPreClaim: PreClaimGate;
|
|
253
|
+
export declare const redsysPreClaim: PreClaimGate;
|
|
218
254
|
export declare const paypalHostedFieldsPreClaim: PreClaimGate;
|
|
255
|
+
export declare const paypalCardFormsPreClaim: PreClaimGate;
|
|
219
256
|
export declare const cybersourceSecureAcceptancePreClaim: PreClaimGate;
|
|
220
257
|
export declare const worldlineMyCheckoutPreClaim: PreClaimGate;
|
|
221
258
|
export declare const paddleVgsPayPreClaim: PreClaimGate;
|
|
259
|
+
export declare const ebanxPreClaim: PreClaimGate;
|
|
222
260
|
/** The processor gates, in order. A new family adds one entry here; the terminal
|
|
223
261
|
* arbiter runs after all of them and is not part of this list. A gate appended
|
|
224
262
|
* after Stripe is never offered a step Stripe claimed: Stripe answers, aborts or
|