@agent-cards/sdk 0.20.0 → 0.22.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 +51 -0
- package/PREFLIGHT.md +34 -0
- package/README.md +1217 -15
- package/dist/aci.d.ts +173 -0
- package/dist/aci.generated.d.ts +87 -0
- package/dist/aci.generated.js +306 -0
- package/dist/aci.js +371 -0
- package/dist/adyen-merchant-hosted.generated.d.ts +3 -3
- package/dist/adyen-merchant-hosted.generated.js +283 -49
- package/dist/agentcard.d.ts +9 -2
- package/dist/agentcard.js +4 -2
- package/dist/amadeus-checkout.generated.d.ts +57 -0
- package/dist/amadeus-checkout.generated.js +549 -0
- package/dist/amadeus.d.ts +41 -0
- package/dist/amadeus.js +81 -0
- package/dist/builtin-registry.generated.js +1 -1
- package/dist/card-endpoint.d.ts +177 -0
- package/dist/card-endpoint.js +286 -0
- package/dist/card-fields.generated.d.ts +5 -3
- package/dist/card-fields.generated.js +284 -7
- package/dist/cdp.d.ts +6 -1
- package/dist/cdp.js +983 -147
- package/dist/client.d.ts +493 -13
- package/dist/client.js +1100 -82
- package/dist/creditguard.generated.d.ts +79 -0
- package/dist/creditguard.generated.js +662 -0
- package/dist/cse-body.js +11 -1
- 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/datatrans.d.ts +96 -0
- package/dist/datatrans.generated.d.ts +64 -0
- package/dist/datatrans.generated.js +426 -0
- package/dist/datatrans.js +178 -0
- package/dist/elavon-converge.d.ts +37 -0
- package/dist/elavon-converge.generated.d.ts +49 -0
- package/dist/elavon-converge.generated.js +439 -0
- package/dist/elavon-converge.js +84 -0
- package/dist/eprotect.d.ts +152 -0
- package/dist/eprotect.generated.d.ts +77 -0
- package/dist/eprotect.generated.js +498 -0
- package/dist/eprotect.js +222 -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/hosted-form.d.ts +3 -2
- package/dist/hosted-form.js +3 -2
- package/dist/index.d.ts +19 -3
- package/dist/index.js +6 -1
- package/dist/juspay-gate.d.ts +82 -0
- package/dist/juspay-gate.js +126 -0
- package/dist/juspay.generated.d.ts +89 -0
- package/dist/juspay.generated.js +705 -0
- package/dist/lifecycle.d.ts +62 -6
- package/dist/lifecycle.js +123 -8
- package/dist/merchant-card-endpoints.generated.d.ts +63 -0
- package/dist/merchant-card-endpoints.generated.js +1103 -0
- package/dist/merchant-hosted.d.ts +4 -1
- package/dist/merchant-hosted.js +5 -2
- package/dist/merchant-session-probe.d.ts +48 -0
- package/dist/merchant-session-probe.js +53 -0
- package/dist/merchant-session.generated.d.ts +69 -0
- package/dist/merchant-session.generated.js +919 -0
- package/dist/payrails.d.ts +133 -0
- package/dist/payrails.generated.d.ts +73 -0
- package/dist/payrails.generated.js +596 -0
- package/dist/payrails.js +305 -0
- package/dist/pelecard.d.ts +32 -0
- package/dist/pelecard.generated.d.ts +32 -0
- package/dist/pelecard.generated.js +283 -0
- package/dist/pelecard.js +42 -0
- package/dist/pre-claim.d.ts +84 -3
- package/dist/pre-claim.js +987 -9
- package/dist/preflight-catalog.json +2310 -263
- package/dist/preflight-schemas.json +187 -6
- package/dist/preflight.generated.d.ts +1 -1
- package/dist/preflight.generated.js +247 -4
- package/dist/preparation.d.ts +5 -2
- package/dist/preparation.js +36 -10
- package/dist/prepared-processor.d.ts +86 -5
- package/dist/prepared-processor.js +157 -6
- package/dist/primer.d.ts +53 -0
- package/dist/primer.generated.d.ts +38 -0
- package/dist/primer.generated.js +624 -0
- package/dist/primer.js +82 -0
- package/dist/registry.d.ts +114 -12
- package/dist/registry.js +85 -11
- package/dist/shiji-sts.d.ts +144 -0
- package/dist/shiji-sts.generated.d.ts +72 -0
- package/dist/shiji-sts.generated.js +913 -0
- package/dist/shiji-sts.js +222 -0
- package/dist/stripe-checkout.generated.d.ts +1 -1
- package/dist/stripe-checkout.generated.js +735 -10
- package/dist/stripe-setup.d.ts +16 -0
- package/dist/stripe-setup.js +61 -0
- package/dist/substitutions.generated.js +187 -29
- package/dist/verifone.d.ts +68 -0
- package/dist/verifone.generated.d.ts +51 -0
- package/dist/verifone.generated.js +1401 -0
- package/dist/verifone.js +119 -0
- package/dist/voice-types.d.ts +27 -0
- package/dist/voice.d.ts +6 -1
- package/dist/voice.js +6 -1
- package/dist/wspay.d.ts +41 -0
- package/dist/wspay.generated.d.ts +41 -0
- package/dist/wspay.generated.js +370 -0
- package/dist/wspay.js +65 -0
- package/examples/preflight/kernel-native/inventory.json +1 -1
- package/package.json +3 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
2
|
// Generated from @agent-cards/payment-core. Do not edit.
|
|
3
|
-
// artifact-sha256:
|
|
3
|
+
// artifact-sha256: 83b01fa41dce013a97e4daf34de13d53978f6ef972e0328c67b3380f057b4e17
|
|
4
4
|
// src/deep-freeze.js
|
|
5
5
|
function deepFreeze(value) {
|
|
6
6
|
if (value && typeof value === "object" && !Object.isFrozen(value)) {
|
|
@@ -48,6 +48,28 @@ function pathsOverlap(a, b) {
|
|
|
48
48
|
return false;
|
|
49
49
|
return true;
|
|
50
50
|
}
|
|
51
|
+
function sameKeyIgnoringCase(key, step) {
|
|
52
|
+
return !FORBIDDEN_KEYS.has(key) && (key.toLowerCase() === step.toLowerCase() || key.toUpperCase() === step.toUpperCase());
|
|
53
|
+
}
|
|
54
|
+
function valuesIgnoringCase(root, path) {
|
|
55
|
+
let nodes = [root];
|
|
56
|
+
for (const step of path) {
|
|
57
|
+
const next = [];
|
|
58
|
+
for (const node of nodes) {
|
|
59
|
+
if (typeof step === "number") {
|
|
60
|
+
if (Array.isArray(node) && Number.isSafeInteger(step) && step >= 0 && step < node.length)
|
|
61
|
+
next.push(node[step]);
|
|
62
|
+
}
|
|
63
|
+
else if (isPlainObject(node)) {
|
|
64
|
+
for (const key of Object.keys(node))
|
|
65
|
+
if (sameKeyIgnoringCase(key, step))
|
|
66
|
+
next.push(node[key]);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
nodes = next;
|
|
70
|
+
}
|
|
71
|
+
return nodes;
|
|
72
|
+
}
|
|
51
73
|
function describePath(path) {
|
|
52
74
|
return path.length ? path.map((step) => typeof step === "number" ? `[${step}]` : `.${step}`).join("").replace(/^\./, "") : "(root)";
|
|
53
75
|
}
|
|
@@ -713,6 +735,55 @@ function adyenAmount(value) {
|
|
|
713
735
|
const currency = typeof value.currency === "string" && /^[A-Za-z]{3}$/.test(value.currency) ? value.currency.toUpperCase() : null;
|
|
714
736
|
return minor === null || !currency ? null : { minor, currency };
|
|
715
737
|
}
|
|
738
|
+
var BODY_AMOUNT_MEMBERS = ["value", "currency", "format", "unit"];
|
|
739
|
+
function merchantBodyAmountRefusal(profile) {
|
|
740
|
+
if (!isPlainObject(profile))
|
|
741
|
+
return "the profile is not an object";
|
|
742
|
+
const amount = profile.amount;
|
|
743
|
+
if (amount === null)
|
|
744
|
+
return null;
|
|
745
|
+
if (Array.isArray(amount))
|
|
746
|
+
return pathRefusal(amount, "the body amount");
|
|
747
|
+
const members = membersRefusal(amount, BODY_AMOUNT_MEMBERS, BODY_AMOUNT_MEMBERS, "the body amount");
|
|
748
|
+
if (members)
|
|
749
|
+
return members;
|
|
750
|
+
const paths = pathRefusal(amount.value, "the body amount's value") ?? pathRefusal(amount.currency, "the body amount's currency");
|
|
751
|
+
if (paths)
|
|
752
|
+
return paths;
|
|
753
|
+
if (pathsOverlap(amount.value, amount.currency))
|
|
754
|
+
return "the body amount's value and currency are read at the same place";
|
|
755
|
+
if (!FORMATS.includes(amount.format))
|
|
756
|
+
return `the body amount's format is not one of ${FORMATS.join(", ")}`;
|
|
757
|
+
if (!["major", "minor"].includes(amount.unit))
|
|
758
|
+
return "the body amount's unit is not major or minor";
|
|
759
|
+
if (amount.format !== "number" && amount.unit !== "major")
|
|
760
|
+
return "a decimal body amount is in major units";
|
|
761
|
+
return null;
|
|
762
|
+
}
|
|
763
|
+
function readMerchantBodyAmount(profile, body) {
|
|
764
|
+
const refusal = merchantBodyAmountRefusal(profile);
|
|
765
|
+
if (refusal)
|
|
766
|
+
throw new Error(`Refusing to pay: ${profile?.merchant ?? "this merchant"}'s body amount is not a reviewed declaration: ${refusal}.`);
|
|
767
|
+
const amount = profile.amount;
|
|
768
|
+
if (amount === null)
|
|
769
|
+
return { kind: "unnamed" };
|
|
770
|
+
if (Array.isArray(amount)) {
|
|
771
|
+
const at = jsonAt(body, amount);
|
|
772
|
+
if (!at.found)
|
|
773
|
+
return { kind: "absent" };
|
|
774
|
+
const named = adyenAmount(at.value);
|
|
775
|
+
return named ? { kind: "amount", amountCents: named.minor, currency: named.currency } : { kind: "unreadable" };
|
|
776
|
+
}
|
|
777
|
+
const value = jsonAt(body, amount.value);
|
|
778
|
+
if (!value.found)
|
|
779
|
+
return { kind: "absent" };
|
|
780
|
+
const currency = jsonAt(body, amount.currency);
|
|
781
|
+
if (!currency.found || typeof currency.value !== "string" || !/^[A-Za-z]{3}$/.test(currency.value))
|
|
782
|
+
return { kind: "unreadable" };
|
|
783
|
+
const code = currency.value.toUpperCase();
|
|
784
|
+
const minor = totalMinor(value.value, amount.format, amount.unit, code);
|
|
785
|
+
return minor === null ? { kind: "unreadable" } : { kind: "amount", amountCents: minor, currency: code };
|
|
786
|
+
}
|
|
716
787
|
function readMerchantAmount(profile, input) {
|
|
717
788
|
const stage = isPlainObject(profile) ? profile.amountSource : void 0;
|
|
718
789
|
if (!isPlainObject(stage))
|
|
@@ -776,18 +847,15 @@ function readMerchantAmount(profile, input) {
|
|
|
776
847
|
return fail("stale", `the card request was built from another ${merchant} response than the latest one (${describePath(rule.card)})`);
|
|
777
848
|
}
|
|
778
849
|
}
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
return fail("mismatch", `${merchant}'s card request asks for ${named.minor} ${named.currency}, but its own total is ${reading.amountCents} ${reading.currency}`);
|
|
789
|
-
}
|
|
790
|
-
}
|
|
850
|
+
if (merchantBodyAmountRefusal(profile) !== null)
|
|
851
|
+
return fail("unreviewed", `${merchant}'s body amount is not a reviewed declaration`);
|
|
852
|
+
const named = readMerchantBodyAmount(profile, ctx.body);
|
|
853
|
+
const bodyAmount = named.kind === "unnamed" ? "none" : named.kind === "absent" ? "absent" : "equal";
|
|
854
|
+
if (named.kind === "unreadable") {
|
|
855
|
+
return fail("unreadable", `the amount in ${merchant}'s card request is not the ${Array.isArray(profile.amount) ? "{value, currency}" : "amount"} Agentcard reviewed`);
|
|
856
|
+
}
|
|
857
|
+
if (named.kind === "amount" && (named.currency !== reading.currency || named.amountCents !== reading.amountCents)) {
|
|
858
|
+
return fail("mismatch", `${merchant}'s card request asks for ${named.amountCents} ${named.currency}, but its own total is ${reading.amountCents} ${reading.currency}`);
|
|
791
859
|
}
|
|
792
860
|
return {
|
|
793
861
|
ok: true,
|
|
@@ -1307,6 +1375,154 @@ var MERCHANT_HOSTED_PROFILES = /* @__PURE__ */ deepFreeze([
|
|
|
1307
1375
|
clientKey: "live_YJLFKT47JJG2RI7QIYX6HTKKDEDOEGOH",
|
|
1308
1376
|
publicKeySha256: "da33611149dff3ab715be8671c0550bb8aec6112983b2473db9ee7afb829c110"
|
|
1309
1377
|
}
|
|
1378
|
+
},
|
|
1379
|
+
{
|
|
1380
|
+
// Read Sep 25, 2026, from public code only: the WooCommerce plugin super-payments 1.40.1 and
|
|
1381
|
+
// cdn.superpayments.com/js/v2/payment.webcomponents.script.js as it stood on Sep 19.
|
|
1382
|
+
// WePrescribe's page runs Super's <super-checkout> component, which picks the card leg per
|
|
1383
|
+
// checkout session: ADYEN, under Super's own Adyen account (adyen-web 6.36.0 in Super's frame
|
|
1384
|
+
// web-checkout.superpayments.com/adyen-card-host, which hands state.data to the page by
|
|
1385
|
+
// postMessage), or STRIPE, a Payment Element the stripe definition already pays. On the ADYEN
|
|
1386
|
+
// leg handleAdyenSubmit posts, with the session's Bearer token, {amount (the gross, minor
|
|
1387
|
+
// units), currency, fundingMethod: {amount (the card's net share), type CARD, providerArgs:
|
|
1388
|
+
// {type ADYEN, paymentMethod: {type CARD, the four JWEs, holderName, postalCode},
|
|
1389
|
+
// browserInfo}}, rewardsToUse} from the page to api.superpayments.com. The card is charged
|
|
1390
|
+
// fundingMethod.amount, so that is what the agent's amount must equal. No brand rides in the
|
|
1391
|
+
// body. A saved card sends type SAVED_CARD with storedPaymentMethodId and no JWEs. Super's
|
|
1392
|
+
// save-card component posts ciphertext to client.superpayments.com/setup-intent/confirm,
|
|
1393
|
+
// which the WooCommerce checkout never calls. Public key read from checkoutshopper-live.adyen.com
|
|
1394
|
+
// on 2026-09-25 and again on 2026-09-30 (UTC), unchanged. The path carries the checkout
|
|
1395
|
+
// session id, which no preparation can name before the card request exists, so the review
|
|
1396
|
+
// rules hold this profile in observe. A HAR still has to confirm the leg Super picks for a
|
|
1397
|
+
// WePrescribe order and the body that leg posts.
|
|
1398
|
+
id: "super_payments_checkout",
|
|
1399
|
+
merchant: "Super Payments",
|
|
1400
|
+
status: "observe",
|
|
1401
|
+
origins: [{ checkout: "https://weprescribe.co.uk", endpoint: "https://api.superpayments.com" }],
|
|
1402
|
+
method: "POST",
|
|
1403
|
+
path: "/v3/checkout-sessions/:checkoutSessionId/payment",
|
|
1404
|
+
query: {},
|
|
1405
|
+
requires: [
|
|
1406
|
+
{ path: ["fundingMethod", "type"], equals: "CARD" },
|
|
1407
|
+
{ path: ["fundingMethod", "providerArgs", "type"], equals: "ADYEN" }
|
|
1408
|
+
],
|
|
1409
|
+
holder: ["fundingMethod", "providerArgs", "paymentMethod"],
|
|
1410
|
+
holderType: "CARD",
|
|
1411
|
+
fields: {
|
|
1412
|
+
encryptedCardNumber: "encryptedCardNumber",
|
|
1413
|
+
encryptedExpiryMonth: "encryptedExpiryMonth",
|
|
1414
|
+
encryptedExpiryYear: "encryptedExpiryYear",
|
|
1415
|
+
encryptedSecurityCode: "encryptedSecurityCode"
|
|
1416
|
+
},
|
|
1417
|
+
remove: [],
|
|
1418
|
+
refuse: [
|
|
1419
|
+
{ path: ["fundingMethod", "providerArgs", "paymentMethod", "storedPaymentMethodId"], when: "present" }
|
|
1420
|
+
],
|
|
1421
|
+
amount: { value: ["fundingMethod", "amount"], currency: ["currency"], format: "number", unit: "minor" },
|
|
1422
|
+
otherCardRequests: [{ origin: "https://client.superpayments.com", path: "/setup-intent/confirm" }],
|
|
1423
|
+
adyen: {
|
|
1424
|
+
environment: "live",
|
|
1425
|
+
clientKey: "live_5MO5NXLPV5HPFJZWKYBAGA5RRMHEYWSD",
|
|
1426
|
+
publicKeySha256: "b1cd67db43491625b433c9b864beea8a0f0351378bcd3e9e1e0f19e3aad38fcf"
|
|
1427
|
+
}
|
|
1428
|
+
},
|
|
1429
|
+
{
|
|
1430
|
+
// Read Sep 25, 2026, from public code only.
|
|
1431
|
+
// www.corepoweryoga.com asks its API for a hosted payment page (the card-free POST
|
|
1432
|
+
// api2.corepoweryoga.com/stored-payment answers hosted_payment_uri) and frames it: Zenoti
|
|
1433
|
+
// Payments, Zenoti's Adyen platform, at corepoweryoga.zenoti.com/OnlinePayments/AdyentHPP.aspx,
|
|
1434
|
+
// a cross-origin frame running adyen-web v6 Drop-in in the Advanced flow. Its makePayment
|
|
1435
|
+
// (fintech-cdn.zenoti.com .../AdyentHPP.js, SHA-256 95e14da8...5df39) posts {processorId,
|
|
1436
|
+
// subscriberId, transactionSource, paymentRequest: {paymentMethod: adyen-web's
|
|
1437
|
+
// state.data.paymentMethod, type: that method's type, reference, BrowserInformation,
|
|
1438
|
+
// shopperLocale, signature, channel, amount: {currency, value}, brand: onBrand's code for the
|
|
1439
|
+
// typed card, FirstRecurringCharge}} to AdyentHPP.aspx/ProcessTransaction on the frame's own
|
|
1440
|
+
// origin, and Zenoti's server calls Adyen /payments. The pair names the top page, the checkout
|
|
1441
|
+
// the SDK prepares on. paymentRequest.brand describes the agent's dummy, so the approved card's
|
|
1442
|
+
// brand is written there, beside the holder, and adyen-web's own brand at the holder is dropped.
|
|
1443
|
+
// This request saves the card on file: CorePower then charges the stored card on its server
|
|
1444
|
+
// (api2.corepoweryoga.com/purchase-invoice-cc-on-file) and memberships bill it monthly. The
|
|
1445
|
+
// client key and environment arrive with the frame's per-session token, which only a signed-in
|
|
1446
|
+
// shopper's page reads, so the key is a draft until a HAR pins it.
|
|
1447
|
+
id: "zenoti_corepoweryoga_hpp",
|
|
1448
|
+
merchant: "CorePower Yoga",
|
|
1449
|
+
status: "observe",
|
|
1450
|
+
origins: [{ checkout: "https://www.corepoweryoga.com", endpoint: "https://corepoweryoga.zenoti.com" }],
|
|
1451
|
+
method: "POST",
|
|
1452
|
+
path: "/OnlinePayments/AdyentHPP.aspx/ProcessTransaction",
|
|
1453
|
+
query: {},
|
|
1454
|
+
requires: [{ path: ["paymentRequest", "type"], equals: "scheme" }],
|
|
1455
|
+
holder: ["paymentRequest", "paymentMethod"],
|
|
1456
|
+
fields: {
|
|
1457
|
+
encryptedCardNumber: "encryptedCardNumber",
|
|
1458
|
+
encryptedExpiryMonth: "encryptedExpiryMonth",
|
|
1459
|
+
encryptedExpiryYear: "encryptedExpiryYear",
|
|
1460
|
+
encryptedSecurityCode: "encryptedSecurityCode"
|
|
1461
|
+
},
|
|
1462
|
+
remove: ["brand"],
|
|
1463
|
+
refuse: [
|
|
1464
|
+
{ path: ["paymentRequest", "storePaymentMethod"], when: "true" },
|
|
1465
|
+
{ path: ["paymentRequest", "paymentMethod", "storedPaymentMethodId"], when: "present" },
|
|
1466
|
+
{ path: ["paymentRequest", "paymentMethod", "recurringDetailReference"], when: "present" }
|
|
1467
|
+
],
|
|
1468
|
+
amount: ["paymentRequest", "amount"],
|
|
1469
|
+
facts: [
|
|
1470
|
+
// adyen-web's brand codes, as onBrand reports them.
|
|
1471
|
+
{
|
|
1472
|
+
path: ["paymentRequest", "brand"],
|
|
1473
|
+
fact: "brand",
|
|
1474
|
+
map: { visa: "visa", mastercard: "mc", amex: "amex", discover: "discover", diners: "diners", jcb: "jcb" }
|
|
1475
|
+
}
|
|
1476
|
+
],
|
|
1477
|
+
adyen: { environment: "live", clientKey: null, publicKeySha256: null }
|
|
1478
|
+
},
|
|
1479
|
+
{
|
|
1480
|
+
// Read Sep 25, 2026, from public code only: the Cathay Payment Page bundle on
|
|
1481
|
+
// payment.cathaypacific.com (main.14d368386ca2a9041a823b758307b3c2.js, adyen-web 5.71.5
|
|
1482
|
+
// securedfields, environment live), where flight bookings and manage-booking pay. The page
|
|
1483
|
+
// builds one outgoing request: amount and currency from the booking (a decimal
|
|
1484
|
+
// number in major units; the cash part when miles pay the rest), the four JWEs at its root as
|
|
1485
|
+
// encrypted_card_number, encrypted_expiry_month, encrypted_expiry_year and
|
|
1486
|
+
// encrypted_security_code, raw_card_bin (the typed card's BIN, as adyen-web's issuerBin or
|
|
1487
|
+
// binValue reports it), store_a_card, pay_with_stored_card, stored_card_token and
|
|
1488
|
+
// pay_with_adyen_web true. signAndAuthorise posts {sign_request: that request, hpp_signature}
|
|
1489
|
+
// to /cpp-paypage/v1/public/sign (header signapi: authorise, or its discount, currency, split,
|
|
1490
|
+
// full-miles or bank-form variant), then a copy made before signing, plus the returned
|
|
1491
|
+
// cpp_signature, to /cpp-paypage/v1/miles-plus-cash-authorise, which charges it. The signature
|
|
1492
|
+
// covers the JWEs, so the card request is the signing step and the charge is its then request.
|
|
1493
|
+
// raw_card_bin describes the dummy, so the approved card's BIN6 is written there, never more
|
|
1494
|
+
// (adyen-web can report eight digits). The client key comes from document.cppData per
|
|
1495
|
+
// session, so the key is a draft until a HAR pins it. The page's other card form sends a card
|
|
1496
|
+
// alias (alias_card_number) in place of the JWEs, and a refuse rule below turns it away.
|
|
1497
|
+
id: "cathay_cpp_sign",
|
|
1498
|
+
merchant: "Cathay Pacific",
|
|
1499
|
+
status: "observe",
|
|
1500
|
+
origins: [{ checkout: "https://payment.cathaypacific.com", endpoint: "https://api.cathaypacific.com" }],
|
|
1501
|
+
method: "POST",
|
|
1502
|
+
path: "/cpp-paypage/v1/public/sign",
|
|
1503
|
+
query: {},
|
|
1504
|
+
requires: [
|
|
1505
|
+
{ path: ["sign_request", "pay_with_adyen_web"], equals: true },
|
|
1506
|
+
{ path: ["sign_request", "pay_with_stored_card"], equals: false },
|
|
1507
|
+
{ path: ["sign_request", "stored_card_token"], equals: "" }
|
|
1508
|
+
],
|
|
1509
|
+
holder: ["sign_request"],
|
|
1510
|
+
fields: {
|
|
1511
|
+
encryptedCardNumber: "encrypted_card_number",
|
|
1512
|
+
encryptedExpiryMonth: "encrypted_expiry_month",
|
|
1513
|
+
encryptedExpiryYear: "encrypted_expiry_year",
|
|
1514
|
+
encryptedSecurityCode: "encrypted_security_code"
|
|
1515
|
+
},
|
|
1516
|
+
remove: [],
|
|
1517
|
+
refuse: [
|
|
1518
|
+
{ path: ["sign_request", "store_a_card"], when: "true" },
|
|
1519
|
+
{ path: ["sign_request", "stored_card_id"], when: "present" },
|
|
1520
|
+
{ path: ["sign_request", "alias_card_number"], when: "present" }
|
|
1521
|
+
],
|
|
1522
|
+
amount: { value: ["sign_request", "amount"], currency: ["sign_request", "currency"], format: "number", unit: "major" },
|
|
1523
|
+
facts: [{ path: ["sign_request", "raw_card_bin"], fact: "bin6" }],
|
|
1524
|
+
then: { method: "POST", path: "/cpp-paypage/v1/miles-plus-cash-authorise", query: {}, holder: [] },
|
|
1525
|
+
adyen: { environment: "live", clientKey: null, publicKeySha256: null }
|
|
1310
1526
|
}
|
|
1311
1527
|
]);
|
|
1312
1528
|
function adyenKeyHost(environment) {
|
|
@@ -1352,9 +1568,11 @@ var IPV4_HOST = /^\d{1,3}(?:\.\d{1,3}){3}$/;
|
|
|
1352
1568
|
function underDomain(hostname, domain) {
|
|
1353
1569
|
return hostname === domain || hostname.endsWith(`.${domain}`);
|
|
1354
1570
|
}
|
|
1571
|
+
var TWO_LABEL_SUFFIXES = /* @__PURE__ */ new Set(["co.uk", "org.uk", "ac.uk", "com.au", "net.au", "co.nz", "co.jp", "com.hk", "com.sg", "co.in"]);
|
|
1355
1572
|
function reviewedDomain(hostname) {
|
|
1356
1573
|
const labels = hostname.split(".");
|
|
1357
|
-
|
|
1574
|
+
const kept = TWO_LABEL_SUFFIXES.has(labels.slice(-2).join(".")) ? 3 : 2;
|
|
1575
|
+
return labels.length > kept ? labels.slice(1).join(".") : hostname;
|
|
1358
1576
|
}
|
|
1359
1577
|
function declaredEndpointRefusal(endpoint) {
|
|
1360
1578
|
let url;
|
|
@@ -1380,28 +1598,6 @@ function declaredEndpointRefusal(endpoint) {
|
|
|
1380
1598
|
return `${url.hostname} belongs to a merchant Agentcard reviewed, so it cannot be declared`;
|
|
1381
1599
|
return null;
|
|
1382
1600
|
}
|
|
1383
|
-
function sameKeyIgnoringCase(key, step) {
|
|
1384
|
-
return !FORBIDDEN_KEYS.has(key) && (key.toLowerCase() === step.toLowerCase() || key.toUpperCase() === step.toUpperCase());
|
|
1385
|
-
}
|
|
1386
|
-
function valuesIgnoringCase(root, path) {
|
|
1387
|
-
let nodes = [root];
|
|
1388
|
-
for (const step of path) {
|
|
1389
|
-
const next = [];
|
|
1390
|
-
for (const node of nodes) {
|
|
1391
|
-
if (typeof step === "number") {
|
|
1392
|
-
if (Array.isArray(node) && Number.isSafeInteger(step) && step >= 0 && step < node.length)
|
|
1393
|
-
next.push(node[step]);
|
|
1394
|
-
}
|
|
1395
|
-
else if (isPlainObject(node)) {
|
|
1396
|
-
for (const key of Object.keys(node))
|
|
1397
|
-
if (sameKeyIgnoringCase(key, step))
|
|
1398
|
-
next.push(node[key]);
|
|
1399
|
-
}
|
|
1400
|
-
}
|
|
1401
|
-
nodes = next;
|
|
1402
|
-
}
|
|
1403
|
-
return nodes;
|
|
1404
|
-
}
|
|
1405
1601
|
function merchantBodyRefusal(profile, body) {
|
|
1406
1602
|
const p = merchantProfileRecognizerById(typeof profile === "string" ? profile : profile?.id);
|
|
1407
1603
|
if (!p)
|
|
@@ -1639,6 +1835,10 @@ function reviewedProfile(profileId) {
|
|
|
1639
1835
|
throw new Error("Refusing to pay: unknown merchant profile.");
|
|
1640
1836
|
return profile;
|
|
1641
1837
|
}
|
|
1838
|
+
function otherCardRequestOf(profile, url) {
|
|
1839
|
+
const others = Array.isArray(profile.otherCardRequests) ? profile.otherCardRequests : [];
|
|
1840
|
+
return others.find((other) => other.origin === url.origin && pathMatchesTemplate(other.path, url.pathname));
|
|
1841
|
+
}
|
|
1642
1842
|
function merchantProfileUrlRelation(profileId, rawUrl) {
|
|
1643
1843
|
const profile = reviewedProfile(profileId);
|
|
1644
1844
|
if (typeof rawUrl !== "string")
|
|
@@ -1654,9 +1854,12 @@ function merchantProfileUrlRelation(profileId, rawUrl) {
|
|
|
1654
1854
|
}
|
|
1655
1855
|
if (url.protocol !== "https:" || url.port || url.username || url.password)
|
|
1656
1856
|
return null;
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1857
|
+
const onEndpoint = profile.origins.some((pair) => pair.endpoint === url.origin);
|
|
1858
|
+
if (onEndpoint && pathMatchesTemplate(profile.path, url.pathname))
|
|
1859
|
+
return "sibling";
|
|
1860
|
+
if (onEndpoint && isPlainObject(profile.then) && pathMatchesTemplate(profile.then.path, url.pathname))
|
|
1861
|
+
return "then";
|
|
1862
|
+
return otherCardRequestOf(profile, url) ? "other" : null;
|
|
1660
1863
|
}
|
|
1661
1864
|
var JWE_AT = /ey[A-Za-z0-9_-]{1,126}\.[A-Za-z0-9_-]{342}\.[A-Za-z0-9_-]{16}\.[A-Za-z0-9_-]{1,1024}\.[A-Za-z0-9_-]{22}/y;
|
|
1662
1865
|
var LEGACY_BLOB = /adyenjs_0_1_\d{1,4}(?:\$|%24)/i;
|
|
@@ -1738,15 +1941,30 @@ function holderRefusal(profile, parsed) {
|
|
|
1738
1941
|
if (new Set(values).size !== values.length)
|
|
1739
1942
|
return "two encrypted card fields in the paused body are the same";
|
|
1740
1943
|
const type = holder.value.type;
|
|
1741
|
-
if (type !== void 0 && type !== "scheme")
|
|
1944
|
+
if (type !== void 0 && type !== (profile.holderType ?? "scheme"))
|
|
1742
1945
|
return "the paused body pays with something other than a card";
|
|
1743
1946
|
return null;
|
|
1744
1947
|
}
|
|
1745
1948
|
function amountRefusal(profile, parsed) {
|
|
1746
1949
|
const priced = isPlainObject(profile.amountSource);
|
|
1747
|
-
if (
|
|
1950
|
+
if (profile.amount === null || profile.amount === void 0) {
|
|
1748
1951
|
return priced ? null : `${profile.merchant}'s card request names no amount, so it cannot be checked against the amount the cardholder approves`;
|
|
1749
1952
|
}
|
|
1953
|
+
if (!Array.isArray(profile.amount)) {
|
|
1954
|
+
let read;
|
|
1955
|
+
try {
|
|
1956
|
+
read = readMerchantBodyAmount(profile, parsed);
|
|
1957
|
+
}
|
|
1958
|
+
catch {
|
|
1959
|
+
read = { kind: "unreadable" };
|
|
1960
|
+
}
|
|
1961
|
+
if (read.kind === "amount")
|
|
1962
|
+
return null;
|
|
1963
|
+
if (read.kind === "absent") {
|
|
1964
|
+
return priced ? null : `the paused body names no amount where ${profile.merchant}'s card request holds it, so it cannot be checked against the amount the cardholder approves`;
|
|
1965
|
+
}
|
|
1966
|
+
return `the amount where ${profile.merchant}'s card request holds it is not the amount Agentcard reviewed, so it cannot be checked`;
|
|
1967
|
+
}
|
|
1750
1968
|
const at = jsonAt(parsed, profile.amount);
|
|
1751
1969
|
if (!at.found) {
|
|
1752
1970
|
return priced ? null : `the paused body names no amount where ${profile.merchant}'s card request holds it, so it cannot be checked against the amount the cardholder approves`;
|
|
@@ -1774,9 +1992,12 @@ function classifyMerchantRequest(profileId, rawUrl, method, body) {
|
|
|
1774
1992
|
const relation = merchantProfileUrlRelation(profile.id, rawUrl);
|
|
1775
1993
|
if (!relation || !carriesAdyenCardCiphertext(body))
|
|
1776
1994
|
return PASS;
|
|
1777
|
-
if (relation === "sibling") {
|
|
1995
|
+
if (relation === "sibling" || relation === "other") {
|
|
1778
1996
|
return abort(`the paused request sends a card to ${profile.merchant} somewhere other than the card request Agentcard reviewed`);
|
|
1779
1997
|
}
|
|
1998
|
+
if (relation === "then") {
|
|
1999
|
+
return abort(`the paused request sends ${profile.merchant}'s card again, to the request after the card request Agentcard reviewed, and Agentcard does not write the card there yet`);
|
|
2000
|
+
}
|
|
1780
2001
|
if (typeof method !== "string" || method.toUpperCase() !== profile.method) {
|
|
1781
2002
|
return abort(`the paused request sends a card to ${profile.merchant} as ${String(method).toUpperCase()}, not as the ${profile.method} Agentcard reviewed`);
|
|
1782
2003
|
}
|
|
@@ -1816,16 +2037,23 @@ function declaredTemplatedUrl(endpoint) {
|
|
|
1816
2037
|
}
|
|
1817
2038
|
function merchantProfileTemplatedUrl(profileId, rawUrl) {
|
|
1818
2039
|
const profile = reviewedProfile(profileId);
|
|
1819
|
-
let
|
|
2040
|
+
let url = null;
|
|
1820
2041
|
try {
|
|
1821
|
-
|
|
2042
|
+
url = new URL(rawUrl);
|
|
1822
2043
|
}
|
|
1823
2044
|
catch {
|
|
1824
|
-
|
|
2045
|
+
url = null;
|
|
2046
|
+
}
|
|
2047
|
+
const origin = url ? url.origin : null;
|
|
2048
|
+
const relation = url ? merchantProfileUrlRelation(profile.id, rawUrl) : null;
|
|
2049
|
+
if (relation === "other") {
|
|
2050
|
+
const other = otherCardRequestOf(profile, url);
|
|
2051
|
+
return `${other.origin}${other.path}`;
|
|
1825
2052
|
}
|
|
1826
2053
|
const pair = profile.origins.find((candidate) => candidate.endpoint === origin) ?? profile.origins[0];
|
|
1827
|
-
const
|
|
1828
|
-
|
|
2054
|
+
const request = relation === "then" ? profile.then : profile;
|
|
2055
|
+
const query = Object.entries(request.query).map(([key, value]) => `${key}=${value}`).join("&");
|
|
2056
|
+
return `${pair.endpoint}${request.path}${query ? `?${query}` : ""}`;
|
|
1829
2057
|
}
|
|
1830
2058
|
function keyPaths(root, out) {
|
|
1831
2059
|
const stack = [[root, ""]];
|
|
@@ -1858,10 +2086,16 @@ function merchantBodyKeyPathSha256(body) {
|
|
|
1858
2086
|
return sha256Hex([...paths].sort().join("\n"));
|
|
1859
2087
|
}
|
|
1860
2088
|
var globEscape = (text) => text.replace(/[*?\\]/g, (char) => `\\${char}`);
|
|
2089
|
+
var templateGlob = (template) => template.split("/").map((segment) => segment.startsWith(":") ? "*" : globEscape(segment)).join("/");
|
|
1861
2090
|
function merchantProfileUrlGlobs(profileId) {
|
|
1862
2091
|
const profile = reviewedProfile(profileId);
|
|
1863
|
-
const
|
|
1864
|
-
|
|
2092
|
+
const endpoints = profile.origins.map((pair) => pair.endpoint);
|
|
2093
|
+
const others = Array.isArray(profile.otherCardRequests) ? profile.otherCardRequests : [];
|
|
2094
|
+
return [... /* @__PURE__ */new Set([
|
|
2095
|
+
...endpoints.map((origin) => `${origin}${templateGlob(profile.path)}*`),
|
|
2096
|
+
...isPlainObject(profile.then) ? endpoints.map((origin) => `${origin}${templateGlob(profile.then.path)}*`) : [],
|
|
2097
|
+
...others.map((other) => `${other.origin}${templateGlob(other.path)}*`)
|
|
2098
|
+
])];
|
|
1865
2099
|
}
|
|
1866
2100
|
function declaredUrlGlobs(endpoint) {
|
|
1867
2101
|
const url = new URL(endpoint);
|
package/dist/agentcard.d.ts
CHANGED
|
@@ -46,14 +46,21 @@ export declare class CheckoutModule {
|
|
|
46
46
|
headers: Record<string, string>;
|
|
47
47
|
body: string;
|
|
48
48
|
}): ReturnType<VaultClient['checkStripeContinuation']>;
|
|
49
|
+
/** Asks the API whether a Stripe card save may continue with the payment method an approval produced. */
|
|
50
|
+
checkStripeSetupContinuation(authorizationId: string, request: {
|
|
51
|
+
url: string;
|
|
52
|
+
method: string;
|
|
53
|
+
headers: Record<string, string>;
|
|
54
|
+
body: string;
|
|
55
|
+
}): ReturnType<VaultClient['checkStripeSetupContinuation']>;
|
|
49
56
|
/** True when this request is a card request a recogniser claims. */
|
|
50
57
|
isCardRequest(url: string, method?: string): boolean;
|
|
51
58
|
/** The recogniser that claims a card request, or null. */
|
|
52
59
|
recognizerOf(url: string, method?: string): Recognizer | null;
|
|
53
60
|
/** How the card would reach the processor on this request, or null when nothing recognises it. */
|
|
54
61
|
checkoutModeOf(url: string, method?: string): CheckoutMode | null;
|
|
55
|
-
/** What happens to a recognised request whose body carries no card. */
|
|
56
|
-
withoutCard(url: string, body: string | null | undefined): 'continue' | 'refuse' | null;
|
|
62
|
+
/** What happens to a recognised request whose body carries no card, given the requests this attachment already handed the card to. */
|
|
63
|
+
withoutCard(url: string, body: string | null | undefined, handedTo?: readonly string[]): 'continue' | 'refuse' | null;
|
|
57
64
|
/** The URL patterns a raw CDP connection hands `Fetch.enable`, for the current recognisers. */
|
|
58
65
|
cardUrlPatterns(): string[];
|
|
59
66
|
/** The recognisers: the served or built-in list plus yours (`register`, `list`, `find`). */
|
package/dist/agentcard.js
CHANGED
|
@@ -42,14 +42,16 @@ export class CheckoutModule {
|
|
|
42
42
|
cancelAuthorization(authorizationId, reason) { return this.client.cancelAuthorization(authorizationId, reason); }
|
|
43
43
|
/** Asks the API whether a Stripe confirmation that pays with an approved token may continue. */
|
|
44
44
|
checkStripeContinuation(authorizationId, request) { return this.client.checkStripeContinuation(authorizationId, request); }
|
|
45
|
+
/** Asks the API whether a Stripe card save may continue with the payment method an approval produced. */
|
|
46
|
+
checkStripeSetupContinuation(authorizationId, request) { return this.client.checkStripeSetupContinuation(authorizationId, request); }
|
|
45
47
|
/** True when this request is a card request a recogniser claims. */
|
|
46
48
|
isCardRequest(url, method = 'POST') { return this.client.isCardRequest(url, method); }
|
|
47
49
|
/** The recogniser that claims a card request, or null. */
|
|
48
50
|
recognizerOf(url, method = 'POST') { return this.client.recognizerOf(url, method); }
|
|
49
51
|
/** How the card would reach the processor on this request, or null when nothing recognises it. */
|
|
50
52
|
checkoutModeOf(url, method = 'POST') { return this.client.checkoutModeOf(url, method); }
|
|
51
|
-
/** What happens to a recognised request whose body carries no card. */
|
|
52
|
-
withoutCard(url, body) { return this.client.withoutCard(url, body); }
|
|
53
|
+
/** What happens to a recognised request whose body carries no card, given the requests this attachment already handed the card to. */
|
|
54
|
+
withoutCard(url, body, handedTo = []) { return this.client.withoutCard(url, body, handedTo); }
|
|
53
55
|
/** The URL patterns a raw CDP connection hands `Fetch.enable`, for the current recognisers. */
|
|
54
56
|
cardUrlPatterns() { return this.client.cardUrlPatterns(); }
|
|
55
57
|
/** The recognisers: the served or built-in list plus yours (`register`, `list`, `find`). */
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
declare var AMADEUS_CARD_MOPID: RegExp;
|
|
2
|
+
declare function amadeusBodyKind(body: any): "card" | "other";
|
|
3
|
+
declare var AMADEUS_CHECKOUT_PSP: string;
|
|
4
|
+
declare var AMADEUS_CHECKOUT_CAPABILITY: string;
|
|
5
|
+
declare var AMADEUS_CARD_URLS: Readonly<{
|
|
6
|
+
production: Readonly<{
|
|
7
|
+
sdk: readonly string[];
|
|
8
|
+
dcp: readonly string[];
|
|
9
|
+
}>;
|
|
10
|
+
sandbox: Readonly<{
|
|
11
|
+
sdk: readonly string[];
|
|
12
|
+
dcp: readonly never[];
|
|
13
|
+
}>;
|
|
14
|
+
}>;
|
|
15
|
+
declare var AMADEUS_MERCHANT_EXPIRY_POLICIES: readonly string[];
|
|
16
|
+
declare var AMADEUS_MERCHANT_EXPIRY_POLICY: string;
|
|
17
|
+
declare var AMADEUS_REFUSAL_REASONS: readonly string[];
|
|
18
|
+
declare function readAmadeusBody(body: any): any;
|
|
19
|
+
declare function amadeusCardUrl(url: any): {
|
|
20
|
+
path: string;
|
|
21
|
+
environment: string;
|
|
22
|
+
} | null;
|
|
23
|
+
declare function isAmadeusCardUrl(url: any, method?: string): boolean;
|
|
24
|
+
declare function amadeusEnvironment(url: any): string | undefined;
|
|
25
|
+
declare function amadeusPreparationUrls(environment: any): any[];
|
|
26
|
+
declare function amadeusSdkHostRefusal(headers: any, approvedHost: any): "header_binding" | null;
|
|
27
|
+
declare var AMADEUS_DCP_REVIEWED_KEYS: readonly string[];
|
|
28
|
+
declare function isAmadeusDcpConfig(config: any): boolean;
|
|
29
|
+
declare function amadeusVendorFor(number: any): "visa" | "mastercard" | "amex" | null;
|
|
30
|
+
declare function amadeusRequestRefusal(request: any, card: any, options?: {}): any;
|
|
31
|
+
declare function amadeusRefusalMessage(reason: any): any;
|
|
32
|
+
declare function isPreparedAmadeusRequest(url: any, method: any, body: any, environment: any, headers: any, options?: {}): boolean;
|
|
33
|
+
declare function injectAmadeusCard(body: any, card: any, options?: {}): {
|
|
34
|
+
body: string;
|
|
35
|
+
where: any[];
|
|
36
|
+
};
|
|
37
|
+
declare function amadeusResponseOutcome(status: any, body: any, { url, card }?: {}): {
|
|
38
|
+
outcome: string;
|
|
39
|
+
reason: string;
|
|
40
|
+
feeApplied?: undefined;
|
|
41
|
+
code?: undefined;
|
|
42
|
+
} | {
|
|
43
|
+
outcome: string;
|
|
44
|
+
feeApplied: boolean;
|
|
45
|
+
reason?: undefined;
|
|
46
|
+
code?: undefined;
|
|
47
|
+
} | {
|
|
48
|
+
outcome: string;
|
|
49
|
+
code: any;
|
|
50
|
+
reason?: undefined;
|
|
51
|
+
feeApplied?: undefined;
|
|
52
|
+
};
|
|
53
|
+
declare function sanitizeAmadeusResponse(body: any, url: any, card: any): string;
|
|
54
|
+
declare function amadeusFacts(body: any): {
|
|
55
|
+
refusalCode: any;
|
|
56
|
+
};
|
|
57
|
+
export { AMADEUS_CARD_MOPID, AMADEUS_CARD_URLS, AMADEUS_CHECKOUT_CAPABILITY, AMADEUS_CHECKOUT_PSP, AMADEUS_DCP_REVIEWED_KEYS, AMADEUS_MERCHANT_EXPIRY_POLICIES, AMADEUS_MERCHANT_EXPIRY_POLICY, AMADEUS_REFUSAL_REASONS, amadeusBodyKind, amadeusCardUrl, amadeusEnvironment, amadeusFacts, amadeusPreparationUrls, amadeusRefusalMessage, amadeusRequestRefusal, amadeusResponseOutcome, amadeusSdkHostRefusal, amadeusVendorFor, injectAmadeusCard, isAmadeusCardUrl, isAmadeusDcpConfig, isPreparedAmadeusRequest, readAmadeusBody, sanitizeAmadeusResponse };
|