@agent-cards/sdk 0.23.9 → 0.23.10
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 +40 -0
- package/PREFLIGHT.md +7 -5
- package/README.md +181 -92
- package/dist/aci.d.ts +7 -5
- package/dist/aci.generated.d.ts +2 -1
- package/dist/aci.generated.js +14 -4
- package/dist/aci.js +28 -7
- package/dist/amadeus-checkout.generated.js +2 -2
- package/dist/builtin-registry.generated.js +1 -1
- package/dist/card-fields.generated.js +163 -9
- package/dist/cdp.js +79 -34
- package/dist/client.d.ts +61 -31
- package/dist/client.js +99 -42
- package/dist/creditguard.generated.d.ts +1 -1
- package/dist/creditguard.generated.js +1 -3
- package/dist/cse-body.d.ts +7 -6
- package/dist/cse-body.js +8 -7
- package/dist/datatrans.generated.js +8 -5
- package/dist/elavon-converge.d.ts +1 -1
- package/dist/elavon-converge.generated.js +7 -4
- package/dist/elavon-converge.js +4 -3
- package/dist/fiserv.d.ts +9 -5
- package/dist/fiserv.generated.d.ts +3 -3
- package/dist/fiserv.generated.js +50 -20
- package/dist/fiserv.js +10 -6
- package/dist/payrails.d.ts +78 -18
- package/dist/payrails.generated.d.ts +12 -2
- package/dist/payrails.generated.js +213 -18
- package/dist/payrails.js +165 -44
- package/dist/pre-claim.js +51 -29
- package/dist/preflight-capabilities.generated.d.ts +0 -106
- package/dist/preflight-capabilities.generated.js +0 -153
- package/dist/preflight-catalog.json +61 -181
- package/dist/preflight-schemas.json +6 -6
- package/dist/preflight.generated.d.ts +0 -106
- package/dist/preflight.generated.js +27 -15
- package/dist/preparation.d.ts +2 -0
- package/dist/preparation.js +4 -2
- package/dist/prepared-processor.d.ts +19 -5
- package/dist/prepared-processor.js +21 -5
- package/dist/primer.generated.d.ts +5 -1
- package/dist/primer.generated.js +200 -33
- package/dist/registry.d.ts +18 -12
- package/dist/registry.js +11 -8
- package/dist/shiji-sts.d.ts +24 -22
- package/dist/shiji-sts.generated.d.ts +1 -1
- package/dist/shiji-sts.generated.js +12 -8
- package/dist/shiji-sts.js +49 -46
- package/dist/stripe-checkout.generated.js +146 -49
- package/dist/verifone.generated.js +192 -17
- package/dist/verifone.js +1 -1
- package/dist/wspay.d.ts +17 -16
- package/dist/wspay.generated.d.ts +6 -1
- package/dist/wspay.generated.js +13 -3
- package/dist/wspay.js +9 -11
- package/examples/preflight/kernel-native/README.md +1 -1
- package/examples/preflight/kernel-native/inventory.json +1 -19
- 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: db732bdbb517b37ea27d05debafb7659bb456f686edd0c90d78b2fbdb993d68d
|
|
4
4
|
// src/deep-freeze.js
|
|
5
5
|
function deepFreeze(value) {
|
|
6
6
|
if (value && typeof value === "object" && !Object.isFrozen(value)) {
|
|
@@ -415,18 +415,44 @@ var VERIFONE_MERCHANT_PROFILES = /* @__PURE__ */ deepFreeze([
|
|
|
415
415
|
// employee variants (featureConfig verifoneCCEnabled, verifonePLCCEnabled,
|
|
416
416
|
// verifoneEmployeeCCEnabled, verifoneEmployeePLCCEnabled; live from late 2023, still on
|
|
417
417
|
// 2026-09-19). Checkout is www.containerstore.com/checkout?fulfillmentMethod=STANDARD|PICKUP,
|
|
418
|
-
// on the legacy app behind PerimeterX.
|
|
419
|
-
//
|
|
420
|
-
//
|
|
421
|
-
//
|
|
422
|
-
//
|
|
418
|
+
// on the legacy app behind PerimeterX.
|
|
419
|
+
//
|
|
420
|
+
// The card request, read from TCS's own CheckoutV2 build 3.340.1.16022 (its public source
|
|
421
|
+
// map: CheckoutForm and the checkout service) and its live guest checkout on 2026-10-10:
|
|
422
|
+
// Place Order encrypts the card once with verifone.js, and axios posts the order once, as
|
|
423
|
+
// JSON, to /checkout/api/submit, with the new card last in paymentMethods after any gift
|
|
424
|
+
// card, as {defaultWallet, cardNumber (masked but its last four), encryptedCard, type
|
|
425
|
+
// 'CREDIT_CARD', cardType}. A saved card is type 'COF' with a walletId, TCS's own card
|
|
426
|
+
// 'TCS_CREDIT_CARD'; defaultWallet saves the card to the shopper's wallet, and
|
|
427
|
+
// popTermsAndConditionsAccepted (the form's popEnroll box) enrolls them in TCS's loyalty
|
|
428
|
+
// program, Organized Insider (once POP!). A gift card's balance check posts its own blob to
|
|
429
|
+
// /checkout/api/gift-card, which aborts like any request off the leg.
|
|
430
|
+
//
|
|
431
|
+
// The body names no amount (TCS's total is only in its cart response), and the key the page
|
|
432
|
+
// encrypts under, its verifoneEncryptionKey, is not pinned (verifone-keys.js). So the profile
|
|
433
|
+
// stays in observe: the leg's requests abort as unreviewed until a person pins the key and the
|
|
434
|
+
// merchant's total has a reviewed source.
|
|
423
435
|
id: "containerstore_checkout",
|
|
424
436
|
merchant: "The Container Store",
|
|
425
437
|
processor: "verifone",
|
|
426
438
|
status: "observe",
|
|
427
439
|
environment: "production",
|
|
428
440
|
origins: [{ checkout: "https://www.containerstore.com", endpoint: "https://www.containerstore.com" }],
|
|
429
|
-
legs: [
|
|
441
|
+
legs: [{
|
|
442
|
+
name: "card",
|
|
443
|
+
method: "POST",
|
|
444
|
+
path: "/checkout/api/submit",
|
|
445
|
+
query: {},
|
|
446
|
+
requires: [{ path: ["paymentMethods", 0, "type"], equals: "CREDIT_CARD" }],
|
|
447
|
+
refuse: [
|
|
448
|
+
{ path: ["paymentMethods", 1], when: "present" },
|
|
449
|
+
{ path: ["paymentMethods", 0, "defaultWallet"], when: "true" },
|
|
450
|
+
{ path: ["paymentMethods", 0, "walletId"], when: "present" },
|
|
451
|
+
{ path: ["popTermsAndConditionsAccepted"], when: "true" }
|
|
452
|
+
],
|
|
453
|
+
holder: ["paymentMethods", 0],
|
|
454
|
+
field: "encryptedCard"
|
|
455
|
+
}],
|
|
430
456
|
keyPin: null,
|
|
431
457
|
amount: null
|
|
432
458
|
}
|
|
@@ -652,8 +678,143 @@ function decodeBase64(text) {
|
|
|
652
678
|
}
|
|
653
679
|
return encodeBase64(out) === text ? out : null;
|
|
654
680
|
}
|
|
681
|
+
// src/secp256k1.js
|
|
682
|
+
var P = (1n << 256n) - (1n << 32n) - 977n;
|
|
683
|
+
var N = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n;
|
|
684
|
+
var G = Object.freeze({
|
|
685
|
+
x: 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798n,
|
|
686
|
+
y: 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8n
|
|
687
|
+
});
|
|
688
|
+
var BYTES = 32;
|
|
689
|
+
var MAX_DRAWS = 16;
|
|
690
|
+
var mod = (a) => {
|
|
691
|
+
const r = a % P;
|
|
692
|
+
return r < 0n ? r + P : r;
|
|
693
|
+
};
|
|
694
|
+
function toBigInt(bytes) {
|
|
695
|
+
let hex2 = "0";
|
|
696
|
+
for (let i = 0; i < bytes.length; i++)
|
|
697
|
+
hex2 += (bytes[i] < 16 ? "0" : "") + bytes[i].toString(16);
|
|
698
|
+
return BigInt(`0x${hex2}`);
|
|
699
|
+
}
|
|
700
|
+
function toBytes(value) {
|
|
701
|
+
const hex2 = value.toString(16).padStart(BYTES * 2, "0");
|
|
702
|
+
const out = new Uint8Array(BYTES);
|
|
703
|
+
for (let i = 0; i < BYTES; i++)
|
|
704
|
+
out[i] = parseInt(hex2.slice(2 * i, 2 * i + 2), 16);
|
|
705
|
+
return out;
|
|
706
|
+
}
|
|
707
|
+
function decodePoint(bytes) {
|
|
708
|
+
if (!(bytes instanceof Uint8Array) || bytes.length !== 1 + 2 * BYTES || bytes[0] !== 4)
|
|
709
|
+
return null;
|
|
710
|
+
const x = toBigInt(bytes.subarray(1, 1 + BYTES));
|
|
711
|
+
const y = toBigInt(bytes.subarray(1 + BYTES));
|
|
712
|
+
if (x >= P || y >= P)
|
|
713
|
+
return null;
|
|
714
|
+
return mod(y * y) === mod(x * x * x + 7n) ? { x, y } : null;
|
|
715
|
+
}
|
|
716
|
+
function isSecp256k1Point(bytes) {
|
|
717
|
+
return decodePoint(bytes) !== null;
|
|
718
|
+
}
|
|
719
|
+
var INFINITY = Object.freeze({ X: 0n, Y: 1n, Z: 0n });
|
|
720
|
+
function double(p) {
|
|
721
|
+
if (p.Z === 0n || p.Y === 0n)
|
|
722
|
+
return INFINITY;
|
|
723
|
+
const a = mod(p.X * p.X);
|
|
724
|
+
const b = mod(p.Y * p.Y);
|
|
725
|
+
const c = mod(b * b);
|
|
726
|
+
const d = mod(2n * (mod((p.X + b) * (p.X + b)) - a - c));
|
|
727
|
+
const e = mod(3n * a);
|
|
728
|
+
const X = mod(e * e - 2n * d);
|
|
729
|
+
return { X, Y: mod(e * (d - X) - 8n * c), Z: mod(2n * p.Y * p.Z) };
|
|
730
|
+
}
|
|
731
|
+
function add(p, q) {
|
|
732
|
+
if (p.Z === 0n)
|
|
733
|
+
return q;
|
|
734
|
+
if (q.Z === 0n)
|
|
735
|
+
return p;
|
|
736
|
+
const z1z1 = mod(p.Z * p.Z);
|
|
737
|
+
const z2z2 = mod(q.Z * q.Z);
|
|
738
|
+
const u1 = mod(p.X * z2z2);
|
|
739
|
+
const u2 = mod(q.X * z1z1);
|
|
740
|
+
const s1 = mod(p.Y * q.Z * z2z2);
|
|
741
|
+
const s2 = mod(q.Y * p.Z * z1z1);
|
|
742
|
+
const h = mod(u2 - u1);
|
|
743
|
+
const r = mod(2n * (s2 - s1));
|
|
744
|
+
if (h === 0n)
|
|
745
|
+
return r === 0n ? double(p) : INFINITY;
|
|
746
|
+
const i = mod(4n * h * h);
|
|
747
|
+
const j = mod(h * i);
|
|
748
|
+
const v = mod(u1 * i);
|
|
749
|
+
const X = mod(r * r - j - 2n * v);
|
|
750
|
+
return { X, Y: mod(r * (v - X) - 2n * s1 * j), Z: mod((mod((p.Z + q.Z) * (p.Z + q.Z)) - z1z1 - z2z2) * h) };
|
|
751
|
+
}
|
|
752
|
+
function power(base, exponent) {
|
|
753
|
+
let result = 1n;
|
|
754
|
+
let square = mod(base);
|
|
755
|
+
for (let rest = exponent; rest > 0n; rest >>= 1n) {
|
|
756
|
+
if (rest & 1n)
|
|
757
|
+
result = mod(result * square);
|
|
758
|
+
square = mod(square * square);
|
|
759
|
+
}
|
|
760
|
+
return result;
|
|
761
|
+
}
|
|
762
|
+
function multiply(k, point) {
|
|
763
|
+
let r0 = INFINITY;
|
|
764
|
+
let r1 = { X: point.x, Y: point.y, Z: 1n };
|
|
765
|
+
for (let i = 255; i >= 0; i--) {
|
|
766
|
+
if (k >> BigInt(i) & 1n) {
|
|
767
|
+
r0 = add(r0, r1);
|
|
768
|
+
r1 = double(r1);
|
|
769
|
+
}
|
|
770
|
+
else {
|
|
771
|
+
r1 = add(r0, r1);
|
|
772
|
+
r0 = double(r0);
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
if (r0.Z === 0n)
|
|
776
|
+
return null;
|
|
777
|
+
const inverse = power(r0.Z, P - 2n);
|
|
778
|
+
const inverse2 = mod(inverse * inverse);
|
|
779
|
+
return { x: mod(r0.X * inverse2), y: mod(r0.Y * inverse2 * inverse) };
|
|
780
|
+
}
|
|
781
|
+
function ephemeralScalar(random) {
|
|
782
|
+
if (!random || typeof random.getRandomValues !== "function")
|
|
783
|
+
throw new Error("Refusing to encrypt: no random source.");
|
|
784
|
+
const draw = new Uint8Array(BYTES);
|
|
785
|
+
try {
|
|
786
|
+
for (let round = 0; round < MAX_DRAWS; round++) {
|
|
787
|
+
random.getRandomValues(draw);
|
|
788
|
+
const k = toBigInt(draw);
|
|
789
|
+
if (k > 0n && k < N)
|
|
790
|
+
return k;
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
finally {
|
|
794
|
+
draw.fill(0);
|
|
795
|
+
}
|
|
796
|
+
throw new Error("Refusing to encrypt: the random source drew no usable key.");
|
|
797
|
+
}
|
|
798
|
+
function secp256k1Agreement(recipient, random) {
|
|
799
|
+
const q = decodePoint(recipient);
|
|
800
|
+
if (!q)
|
|
801
|
+
throw new Error("Refusing to encrypt: the key is not a point on secp256k1.");
|
|
802
|
+
const k = ephemeralScalar(random);
|
|
803
|
+
const v = multiply(k, G);
|
|
804
|
+
const s = multiply(k, q);
|
|
805
|
+
if (!v || !s)
|
|
806
|
+
throw new Error("Refusing to encrypt: the key agreement reached the point at infinity.");
|
|
807
|
+
const ephemeralPoint = new Uint8Array(1 + 2 * BYTES);
|
|
808
|
+
ephemeralPoint[0] = 4;
|
|
809
|
+
ephemeralPoint.set(toBytes(v.x), 1);
|
|
810
|
+
ephemeralPoint.set(toBytes(v.y), 1 + BYTES);
|
|
811
|
+
return { ephemeralPoint, sharedSecret: toBytes(s.x) };
|
|
812
|
+
}
|
|
655
813
|
// src/verifone-pgp.js
|
|
656
|
-
var
|
|
814
|
+
var CURVE_OIDS = Object.freeze({
|
|
815
|
+
"P-256": Object.freeze([42, 134, 72, 206, 61, 3, 1, 7]),
|
|
816
|
+
secp256k1: Object.freeze([43, 129, 4, 0, 10])
|
|
817
|
+
});
|
|
657
818
|
var ALGORITHM_ECDH = 18;
|
|
658
819
|
var ENCRYPTING_ALGORITHMS = Object.freeze([1, 2, 16, 18]);
|
|
659
820
|
var KNOWN_SYMMETRIC = Object.freeze([2, 3, 4, 7, 8, 9, 10]);
|
|
@@ -863,7 +1024,8 @@ function keyPacket(body) {
|
|
|
863
1024
|
function ecdhFields(fields) {
|
|
864
1025
|
const oidLength = fields[0];
|
|
865
1026
|
const oid = fields.subarray(1, 1 + oidLength);
|
|
866
|
-
|
|
1027
|
+
const curve = sameBytes(oid, CURVE_OIDS["P-256"]) ? "P-256" : sameBytes(oid, CURVE_OIDS.secp256k1) ? "secp256k1" : null;
|
|
1028
|
+
if (!curve)
|
|
867
1029
|
return { refusal: "verifone_key_curve_unsupported" };
|
|
868
1030
|
let at = 1 + oidLength;
|
|
869
1031
|
const bits = fields[at] << 8 | fields[at + 1];
|
|
@@ -871,12 +1033,14 @@ function ecdhFields(fields) {
|
|
|
871
1033
|
at += 2 + point.length;
|
|
872
1034
|
if (bits !== 515 || point.length !== 65 || point[0] !== 4)
|
|
873
1035
|
return { refusal: "verifone_key_malformed" };
|
|
1036
|
+
if (curve === "secp256k1" && !isSecp256k1Point(point))
|
|
1037
|
+
return { refusal: "verifone_key_malformed" };
|
|
874
1038
|
const kdf = fields.subarray(at, at + 1 + fields[at]);
|
|
875
1039
|
if (kdf.length !== 4 || kdf[0] !== 3 || kdf[1] !== 1 || at + 4 !== fields.length)
|
|
876
1040
|
return { refusal: "verifone_key_malformed" };
|
|
877
1041
|
if (!KDF_HASHES[kdf[2]] || !AES[kdf[3]])
|
|
878
1042
|
return { refusal: "verifone_key_kdf_unsupported" };
|
|
879
|
-
return { point: Uint8Array.from(point), kdfHash: kdf[2], kekAlgorithm: kdf[3] };
|
|
1043
|
+
return { curve, point: Uint8Array.from(point), kdfHash: kdf[2], kekAlgorithm: kdf[3] };
|
|
880
1044
|
}
|
|
881
1045
|
async function fingerprintOf(body, subtle) {
|
|
882
1046
|
return new Uint8Array(await subtle.digest("SHA-1", concat(Uint8Array.of(153), u16(body.length), body)));
|
|
@@ -962,6 +1126,7 @@ async function readVerifonePublicKey(publicKeyBase64, facilities) {
|
|
|
962
1126
|
primaryFingerprint: hex(primaryFingerprint),
|
|
963
1127
|
encryptionSubkeyId: hex(fingerprint.subarray(12, 20)),
|
|
964
1128
|
encryptionFingerprint: fingerprint,
|
|
1129
|
+
curve: ecdh.curve,
|
|
965
1130
|
point: ecdh.point,
|
|
966
1131
|
kdfHash: ecdh.kdfHash,
|
|
967
1132
|
kekAlgorithm: ecdh.kekAlgorithm,
|
|
@@ -999,21 +1164,31 @@ ${MESSAGE_END}\r
|
|
|
999
1164
|
`;
|
|
1000
1165
|
return encodeBase64(asciiBytes(armored));
|
|
1001
1166
|
}
|
|
1167
|
+
async function agree(curve, point, crypto) {
|
|
1168
|
+
if (curve === "secp256k1") {
|
|
1169
|
+
const { ephemeralPoint: ephemeralPoint2, sharedSecret } = secp256k1Agreement(point, crypto);
|
|
1170
|
+
return { ephemeralPoint: ephemeralPoint2, shared: sharedSecret };
|
|
1171
|
+
}
|
|
1172
|
+
const subtle = crypto.subtle;
|
|
1173
|
+
const ephemeral = await subtle.generateKey({ name: "ECDH", namedCurve: "P-256" }, true, ["deriveBits"]);
|
|
1174
|
+
const ephemeralPoint = new Uint8Array(await subtle.exportKey("raw", ephemeral.publicKey));
|
|
1175
|
+
const recipient = await subtle.importKey("raw", point, { name: "ECDH", namedCurve: "P-256" }, false, []);
|
|
1176
|
+
const shared = new Uint8Array(await subtle.deriveBits({ name: "ECDH", public: recipient }, ephemeral.privateKey, 256));
|
|
1177
|
+
return { ephemeralPoint, shared };
|
|
1178
|
+
}
|
|
1002
1179
|
async function verifoneEncryptText(key, text, facilities) {
|
|
1003
1180
|
const crypto = facilities?.crypto;
|
|
1004
1181
|
const subtle = crypto?.subtle;
|
|
1005
1182
|
if (!subtle || typeof crypto.getRandomValues !== "function")
|
|
1006
1183
|
throw new Error("Refusing to encrypt: no WebCrypto.");
|
|
1007
|
-
|
|
1184
|
+
const oid = key && Object.prototype.hasOwnProperty.call(CURVE_OIDS, key.curve) ? CURVE_OIDS[key.curve] : null;
|
|
1185
|
+
if (!key || key.refusal || !oid || !(key.point instanceof Uint8Array) || !AES[key.sessionCipher] || !AES[key.kekAlgorithm] || !KDF_HASHES[key.kdfHash]) {
|
|
1008
1186
|
throw new Error("Refusing to encrypt: the Verifone key is not one this codec reads.");
|
|
1009
1187
|
}
|
|
1010
1188
|
if (!Number.isSafeInteger(facilities.nowMs) || facilities.nowMs < 0)
|
|
1011
1189
|
throw new Error("Refusing to encrypt: no clock.");
|
|
1012
|
-
const
|
|
1013
|
-
const
|
|
1014
|
-
const recipient = await subtle.importKey("raw", key.point, { name: "ECDH", namedCurve: "P-256" }, false, []);
|
|
1015
|
-
const shared = new Uint8Array(await subtle.deriveBits({ name: "ECDH", public: recipient }, ephemeral.privateKey, 256));
|
|
1016
|
-
const param = concat(Uint8Array.of(P256_OID.length), Uint8Array.from(P256_OID), Uint8Array.of(ALGORITHM_ECDH, 3, 1, key.kdfHash, key.kekAlgorithm), asciiBytes("Anonymous Sender "), key.encryptionFingerprint);
|
|
1190
|
+
const { ephemeralPoint, shared } = await agree(key.curve, key.point, crypto);
|
|
1191
|
+
const param = concat(Uint8Array.of(oid.length), Uint8Array.from(oid), Uint8Array.of(ALGORITHM_ECDH, 3, 1, key.kdfHash, key.kekAlgorithm), asciiBytes("Anonymous Sender "), key.encryptionFingerprint);
|
|
1017
1192
|
const derived = new Uint8Array(await subtle.digest(KDF_HASHES[key.kdfHash], concat(u32(1), shared, param)));
|
|
1018
1193
|
const kek = await subtle.importKey("raw", derived.subarray(0, AES[key.kekAlgorithm]), "AES-KW", false, ["wrapKey"]);
|
|
1019
1194
|
const sessionKey = crypto.getRandomValues(new Uint8Array(AES[key.sessionCipher]));
|
|
@@ -1142,7 +1317,7 @@ function verifoneClockSkewRefusal(deviceNowMs, serverNowMs) {
|
|
|
1142
1317
|
}
|
|
1143
1318
|
var KEY_REFUSALS = Object.freeze({
|
|
1144
1319
|
verifone_key_unpinned: "Refusing to encrypt: Agentcard has not pinned this Verifone key.",
|
|
1145
|
-
verifone_key_curve_unsupported: "Refusing to encrypt: the Verifone key is
|
|
1320
|
+
verifone_key_curve_unsupported: "Refusing to encrypt: the Verifone key is on neither NIST P-256 nor secp256k1.",
|
|
1146
1321
|
verifone_key_expired: "Refusing to encrypt: this Verifone key has expired.",
|
|
1147
1322
|
verifone_key_revoked: "Refusing to encrypt: this Verifone key was revoked."
|
|
1148
1323
|
});
|
package/dist/verifone.js
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* key paths, never a value) and aborts it, so the agent's placeholder card never
|
|
19
19
|
* reaches the merchant and nothing is charged; 'enabled' lets a prepared checkout
|
|
20
20
|
* pay the reviewed leg. A profile is 'enabled' only when the API and this build both
|
|
21
|
-
* say so. The Container Store ships in 'observe',
|
|
21
|
+
* say so. The Container Store ships in 'observe', its card request reviewed and no key pinned.
|
|
22
22
|
*/
|
|
23
23
|
import * as generated from './verifone.generated.js';
|
|
24
24
|
import { sha256Hex as sharedSha256Hex } from './adyen-merchant-hosted.generated.js';
|
package/dist/wspay.d.ts
CHANGED
|
@@ -4,27 +4,28 @@ export declare const WSPAY_PSP = "wspay";
|
|
|
4
4
|
export declare const WSPAY_CAPABILITY = "wspay_confirm";
|
|
5
5
|
/**
|
|
6
6
|
* Why the SDK refuses a WSPay request before anything is claimed, created or prompted:
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
7
|
+
* `unsupported_wspay_payment_method`, not the card frame's new-card confirm. That covers a
|
|
8
|
+
* saved_card or temp_card_id body (no new card to fill), a card-shaped object the page built
|
|
9
|
+
* into the transaction, another URL shape on the host, or headers the frame does not send. The
|
|
10
|
+
* cardholder's device could never fill it, and the API refuses the same requests at create
|
|
11
|
+
* (invalid_wspay_request), so a refusal here only saves the round trip.
|
|
12
|
+
*
|
|
13
|
+
* A sound confirm that asks WSPay to keep the card on file (tokenize_pan true) pauses like a
|
|
14
|
+
* one-time one: the approval that follows asks the cardholder whether the merchant may keep the
|
|
15
|
+
* card. The API offers it for that approval only as a hotel's EUR 1.00 card guarantee paid with a
|
|
16
|
+
* card the cardholder stored, and refuses any other at create (wspay_keep_on_file_unsupported,
|
|
17
|
+
* card_not_stored).
|
|
16
18
|
*/
|
|
17
|
-
export type WspayRefusalReason = 'unsupported_wspay_payment_method'
|
|
19
|
+
export type WspayRefusalReason = 'unsupported_wspay_payment_method';
|
|
18
20
|
/** True when the URL's host is one of WSPay's two Components hosts. */
|
|
19
21
|
export declare function isWspayHost(url: string): boolean;
|
|
20
22
|
/**
|
|
21
23
|
* The pause decision for a POST the registry recognized on a WSPay host. Null when it is the
|
|
22
|
-
* card frame's confirm of a new card
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* the cardholder.
|
|
24
|
+
* card frame's confirm of a new card, which pauses for approval; otherwise the reason it is
|
|
25
|
+
* refused. It judges the whole request (the exact URL, the frame's content type, Accept and
|
|
26
|
+
* WP3-v2-Client authorization, and a body of the frame's own keys bound to the URL's
|
|
27
|
+
* client_secret) with payment-core's wspayConfirmRefusal, the check the API runs at create.
|
|
28
|
+
* It passes keep-on-file consent because the approval that follows asks the cardholder for it.
|
|
28
29
|
*/
|
|
29
30
|
export declare function wspayRefusal(request: {
|
|
30
31
|
url: string;
|
|
@@ -6,6 +6,11 @@ declare function isWspayNewCardBody(body: any, clientSecret: any, options: any):
|
|
|
6
6
|
declare function classifyWspayRequest(url: any, method: any, body: any, options: any): "card" | "unsupported" | null;
|
|
7
7
|
declare function isWspayConfirmRequest(request: any, options: any): any;
|
|
8
8
|
declare function wspayStoredCredentialRequested(body: any): boolean | null;
|
|
9
|
+
declare var WSPAY_GUARANTEE: Readonly<{
|
|
10
|
+
amount: 100;
|
|
11
|
+
currency: "eur";
|
|
12
|
+
}>;
|
|
13
|
+
declare function wspayKeepOnFileRefusal(body: any, amount: any, currency: any): "keep_on_file" | null;
|
|
9
14
|
declare function wspayConfirmRefusal(request: any, options: any): "unsupported" | "keep_on_file" | null;
|
|
10
15
|
declare function wspayRefusalMessage(reason: any): string;
|
|
11
16
|
declare function injectWspayCard(body: any, card: any, options: any): {
|
|
@@ -38,4 +43,4 @@ declare function wspayFacts(status: any, text2: any): {
|
|
|
38
43
|
outcome: string;
|
|
39
44
|
refusalCode: any;
|
|
40
45
|
};
|
|
41
|
-
export { WSPAY_CONFIRM_HOSTS, WSPAY_TEST_HOST, classifyWspayRequest, injectWspayCard, isWspayConfirmRequest, isWspayConfirmUrl, isWspayNewCardBody, sanitizeWspayResponse, wspayConfirmClientSecret, wspayConfirmRefusal, wspayFacts, wspayRefusalMessage, wspayResponseOutcome, wspayStoredCredentialRequested };
|
|
46
|
+
export { WSPAY_CONFIRM_HOSTS, WSPAY_GUARANTEE, WSPAY_TEST_HOST, classifyWspayRequest, injectWspayCard, isWspayConfirmRequest, isWspayConfirmUrl, isWspayNewCardBody, sanitizeWspayResponse, wspayConfirmClientSecret, wspayConfirmRefusal, wspayFacts, wspayKeepOnFileRefusal, wspayRefusalMessage, wspayResponseOutcome, wspayStoredCredentialRequested };
|
package/dist/wspay.generated.js
CHANGED
|
@@ -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: 9ba65916c5dc5ee3ca830d630cafbde62d537e61991c33c80f1520ac93ef0b0d
|
|
4
4
|
// src/wspay.js
|
|
5
5
|
var WSPAY_CONFIRM_HOSTS = Object.freeze(["proxy.wspay.biz", "proxy-test.wspay.biz"]);
|
|
6
6
|
var WSPAY_TEST_HOST = "proxy-test.wspay.biz";
|
|
@@ -224,6 +224,12 @@ function wspayStoredCredentialRequested(body) {
|
|
|
224
224
|
const value = confirmBody(body);
|
|
225
225
|
return value === null ? null : value.payment_method.data.tokenize_pan === true;
|
|
226
226
|
}
|
|
227
|
+
var WSPAY_GUARANTEE = Object.freeze({ amount: 100, currency: "eur" });
|
|
228
|
+
function wspayKeepOnFileRefusal(body, amount, currency) {
|
|
229
|
+
if (wspayStoredCredentialRequested(body) !== true)
|
|
230
|
+
return null;
|
|
231
|
+
return amount === WSPAY_GUARANTEE.amount && typeof currency === "string" && currency.toLowerCase() === WSPAY_GUARANTEE.currency ? null : "keep_on_file";
|
|
232
|
+
}
|
|
227
233
|
function wspayConfirmRefusal(request, options) {
|
|
228
234
|
if (!isWspayConfirmRequest(request, { keepOnFile: true }))
|
|
229
235
|
return "unsupported";
|
|
@@ -358,7 +364,11 @@ function sanitizeWspayResponse(text2, options) {
|
|
|
358
364
|
if (pm !== null && pm !== void 0) {
|
|
359
365
|
if (!keysWithin(pm, ["type", "data"]) || pm.type !== "card" || !keysWithin(data, ["brand", "issuer", "masked", "expiration_date", "token"]) || !opaqueId(data.token) || owns(data, "brand") && !opaqueId(data.brand, 32) || owns(data, "issuer") && !opaqueId(data.issuer, 64) || owns(data, "expiration_date") && !yymm(data.expiration_date) || owns(data, "masked") && !exact(/^[0-9]{0,6}[-* xX]{4,16}[0-9]{4}$/, data.masked))
|
|
360
366
|
return fail();
|
|
361
|
-
|
|
367
|
+
const card = {};
|
|
368
|
+
for (const key of ["brand", "issuer", "token"])
|
|
369
|
+
if (owns(data, key))
|
|
370
|
+
card[key] = data[key];
|
|
371
|
+
safe.payment_method = { type: "card", data: card };
|
|
362
372
|
}
|
|
363
373
|
}
|
|
364
374
|
return JSON.stringify({ status: "approved", action_required: null, payment_result: safe });
|
|
@@ -367,4 +377,4 @@ function wspayFacts(status, text2) {
|
|
|
367
377
|
const verdict = wspayResponseOutcome(status, text2);
|
|
368
378
|
return { outcome: verdict.outcome, refusalCode: verdict.outcome === "refused" ? verdict.code : null };
|
|
369
379
|
}
|
|
370
|
-
export { WSPAY_CONFIRM_HOSTS, WSPAY_TEST_HOST, classifyWspayRequest, injectWspayCard, isWspayConfirmRequest, isWspayConfirmUrl, isWspayNewCardBody, sanitizeWspayResponse, wspayConfirmClientSecret, wspayConfirmRefusal, wspayFacts, wspayRefusalMessage, wspayResponseOutcome, wspayStoredCredentialRequested };
|
|
380
|
+
export { WSPAY_CONFIRM_HOSTS, WSPAY_GUARANTEE, WSPAY_TEST_HOST, classifyWspayRequest, injectWspayCard, isWspayConfirmRequest, isWspayConfirmUrl, isWspayNewCardBody, sanitizeWspayResponse, wspayConfirmClientSecret, wspayConfirmRefusal, wspayFacts, wspayKeepOnFileRefusal, wspayRefusalMessage, wspayResponseOutcome, wspayStoredCredentialRequested };
|
package/dist/wspay.js
CHANGED
|
@@ -28,19 +28,17 @@ export function isWspayHost(url) {
|
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
30
30
|
* The pause decision for a POST the registry recognized on a WSPay host. Null when it is the
|
|
31
|
-
* card frame's confirm of a new card
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* the cardholder.
|
|
31
|
+
* card frame's confirm of a new card, which pauses for approval; otherwise the reason it is
|
|
32
|
+
* refused. It judges the whole request (the exact URL, the frame's content type, Accept and
|
|
33
|
+
* WP3-v2-Client authorization, and a body of the frame's own keys bound to the URL's
|
|
34
|
+
* client_secret) with payment-core's wspayConfirmRefusal, the check the API runs at create.
|
|
35
|
+
* It passes keep-on-file consent because the approval that follows asks the cardholder for it.
|
|
37
36
|
*/
|
|
38
37
|
export function wspayRefusal(request) {
|
|
39
|
-
//
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
return refusal === 'keep_on_file' ? 'wspay_keep_on_file_unsupported' : 'unsupported_wspay_payment_method';
|
|
38
|
+
// Keep-on-file consent (the second argument): the Vault's approval asks the cardholder whether
|
|
39
|
+
// the merchant may keep the card, and the API admits such a confirm only as a card guarantee.
|
|
40
|
+
const refusal = wspayConfirmRefusal({ url: request.url, method: 'POST', headers: request.headers ?? {}, body: request.body ?? '' }, { keepOnFile: true });
|
|
41
|
+
return refusal === null ? null : 'unsupported_wspay_payment_method';
|
|
44
42
|
}
|
|
45
43
|
/**
|
|
46
44
|
* Whether an approved answer handed to a WSPay confirm is WSPay's 3-D Secure step: HTTP 200 with
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
You can detect a checkout's PSP before entering card details with `@agent-cards/sdk`. Kernel native support needs a separate profile for the native adapter that actually runs the checkout. The direct SDK's coverage does not establish Kernel's native coverage.
|
|
4
4
|
|
|
5
|
-
No qualified native profile accompanies this kit. The inventory covers all
|
|
5
|
+
No qualified native profile accompanies this kit. The inventory covers all 24 PSPs in the checkout catalog and reports `unknown` for every native runtime status. Kernel's pinned documentation lists Stripe, Shopify, Square, Recurly, and Razorpay. The other processors are unestablished, rather than explicitly unsupported. See the endpoint constraints and source hashes in [documented-adapters.json](./documented-adapters.json).
|
|
6
6
|
|
|
7
7
|
## Use the detector now
|
|
8
8
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema_version": 1,
|
|
3
3
|
"catalog_version": "2026-09-15.1",
|
|
4
|
-
"catalog_sha256": "
|
|
4
|
+
"catalog_sha256": "47dd1bc5a749224f66980b42b758f9a19d9ac849e3a8d5230075226a4870fde5",
|
|
5
5
|
"baseline_version": "kernel-native-docs-2026-09-11.1",
|
|
6
6
|
"baseline_sha256": "d86722f49633d8223fccae54cd3d485df4375aee06aa156a273cc689b7c8507c",
|
|
7
7
|
"native_build": null,
|
|
@@ -202,15 +202,6 @@
|
|
|
202
202
|
"Native runtime evidence is missing."
|
|
203
203
|
]
|
|
204
204
|
},
|
|
205
|
-
{
|
|
206
|
-
"psp": "moneris",
|
|
207
|
-
"mode": "token",
|
|
208
|
-
"documentation": "not_documented",
|
|
209
|
-
"status": "unknown",
|
|
210
|
-
"limitations": [
|
|
211
|
-
"No adapter declaration was found in the pinned documentation. Native runtime evidence is missing."
|
|
212
|
-
]
|
|
213
|
-
},
|
|
214
205
|
{
|
|
215
206
|
"psp": "bambora",
|
|
216
207
|
"mode": "token",
|
|
@@ -228,15 +219,6 @@
|
|
|
228
219
|
"limitations": [
|
|
229
220
|
"No adapter declaration was found in the pinned documentation. Native runtime evidence is missing."
|
|
230
221
|
]
|
|
231
|
-
},
|
|
232
|
-
{
|
|
233
|
-
"psp": "gravy",
|
|
234
|
-
"mode": "token",
|
|
235
|
-
"documentation": "not_documented",
|
|
236
|
-
"status": "unknown",
|
|
237
|
-
"limitations": [
|
|
238
|
-
"No adapter declaration was found in the pinned documentation. Native runtime evidence is missing."
|
|
239
|
-
]
|
|
240
222
|
}
|
|
241
223
|
]
|
|
242
224
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-cards/sdk",
|
|
3
|
-
"version": "0.23.
|
|
3
|
+
"version": "0.23.10",
|
|
4
4
|
"description": "Agentcard's SDK: one client, Agentcard, with two modules. checkout pauses a browser purchase and pays it with the person's own card; voice connects a person to your product once and approves a purchase by voice inside it. Card data never enters your process.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"_comment_build": "The public SDK keeps zero runtime dependencies. Its build vendors deterministic metadata and substitution artifacts from the internal payment core, and the voice streaming door from packages/voice/src/core (the phone package, @agent-cards/voice, ships it to phones); TypeScript remains pinned.",
|
|
28
28
|
"build": "node ../payment-core/scripts/build.mjs && node scripts/generate-payment-core.mjs && node scripts/generate-voice-stream.mjs && npx -y -p typescript@5.9.3 tsc && node scripts/generate-preflight-contract.mjs",
|
|
29
29
|
"prepublishOnly": "pnpm build",
|
|
30
|
-
"test": "node test.mjs && node --test lifecycle.test.mjs merchant-abort.test.mjs preparation.test.mjs braintree.test.mjs pre-claim.test.mjs ekashu.test.mjs paypal-hosted-fields.test.mjs cybersource-secure-acceptance.test.mjs autopilot.test.mjs stripe-checkout.test.mjs stripe-setup.test.mjs stripe-legacy-checkout.test.mjs payment-core.test.mjs prepared-processor.test.mjs merchant-hosted.test.mjs merchant-total.test.mjs sandbox-declaration.test.mjs minimum-delay.test.mjs paysafe.test.mjs payu.test.mjs attachment.test.mjs worker-targets.test.mjs mercado-checkout.test.mjs mercado-polling.test.mjs amadeus.test.mjs pelecard.test.mjs aci.test.mjs primer.test.mjs payrails.test.mjs elavon-converge.test.mjs voice.test.mjs agentcard.test.mjs buy.test.mjs readme.test.mjs gmo.test.mjs cybersource-flex.test.mjs juspay-gate.test.mjs card-endpoint.test.mjs card-endpoint-fastspring.test.mjs card-endpoint-navigation.test.mjs merchant-session-probe.test.mjs datatrans.test.mjs authorize-net-dpm.test.mjs creditguard.test.mjs eprotect.test.mjs wspay.test.mjs shiji-sts.test.mjs worldline-mycheckout.test.mjs verifone.test.mjs && node --test preflight-package.test.mjs preflight-collector.test.mjs && node --test kernel-native-qualification.test.mjs && node --test ../vault/scripts/recurly-validation/watch-duty-sdk-result.test.mjs",
|
|
31
|
-
"test:browser": "node browser.test.mjs && node stripe-browser.test.mjs && node preparation-browser.test.mjs && node checkout-com-browser.test.mjs && node paysafe-preparation-browser.test.mjs && node owned-shop-browser.test.mjs && node spreedly-browser.test.mjs && node worker-browser.test.mjs && node amadeus-browser.test.mjs && node adyen-merchant-hosted-browser.test.mjs && node adyen-merchant-frames-browser.test.mjs && node fiserv-browser.test.mjs && node gmo-browser.test.mjs && node cybersource-flex-browser.test.mjs && node juspay-browser.test.mjs && node card-endpoint-browser.test.mjs && node datatrans-browser.test.mjs && node authorize-net-dpm-browser.test.mjs && node pelecard-browser.test.mjs && node aci-browser.test.mjs && node creditguard-browser.test.mjs && node primer-browser.test.mjs && node payrails-browser.test.mjs && node elavon-converge-browser.test.mjs && node eprotect-browser.test.mjs && node wspay-browser.test.mjs && node shiji-sts-browser.test.mjs && node worldline-mycheckout-browser.test.mjs && node paypal-hosted-fields-browser.test.mjs && node cybersource-secure-acceptance-browser.test.mjs",
|
|
30
|
+
"test": "node test.mjs && node --test lifecycle.test.mjs merchant-abort.test.mjs preparation.test.mjs braintree.test.mjs pre-claim.test.mjs ekashu.test.mjs paypal-hosted-fields.test.mjs cybersource-secure-acceptance.test.mjs autopilot.test.mjs stripe-checkout.test.mjs stripe-setup.test.mjs stripe-legacy-checkout.test.mjs payment-core.test.mjs prepared-processor.test.mjs merchant-hosted.test.mjs merchant-total.test.mjs sandbox-declaration.test.mjs minimum-delay.test.mjs paysafe.test.mjs payu.test.mjs attachment.test.mjs worker-targets.test.mjs mercado-checkout.test.mjs mercado-polling.test.mjs amadeus.test.mjs pelecard.test.mjs aci.test.mjs primer.test.mjs payrails.test.mjs elavon-converge.test.mjs voice.test.mjs agentcard.test.mjs buy.test.mjs readme.test.mjs gmo.test.mjs cybersource-flex.test.mjs juspay-gate.test.mjs card-endpoint.test.mjs card-endpoint-fastspring.test.mjs card-endpoint-navigation.test.mjs merchant-session-probe.test.mjs datatrans.test.mjs authorize-net-dpm.test.mjs creditguard.test.mjs eprotect.test.mjs wspay.test.mjs shiji-sts.test.mjs worldline-mycheckout.test.mjs verifone.test.mjs gravy.test.mjs && node --test preflight-package.test.mjs preflight-collector.test.mjs && node --test kernel-native-qualification.test.mjs && node --test ../vault/scripts/recurly-validation/watch-duty-sdk-result.test.mjs",
|
|
31
|
+
"test:browser": "node browser.test.mjs && node stripe-browser.test.mjs && node preparation-browser.test.mjs && node checkout-com-browser.test.mjs && node paysafe-preparation-browser.test.mjs && node owned-shop-browser.test.mjs && node spreedly-browser.test.mjs && node worker-browser.test.mjs && node amadeus-browser.test.mjs && node adyen-merchant-hosted-browser.test.mjs && node adyen-merchant-frames-browser.test.mjs && node fiserv-browser.test.mjs && node gmo-browser.test.mjs && node cybersource-flex-browser.test.mjs && node juspay-browser.test.mjs && node card-endpoint-browser.test.mjs && node datatrans-browser.test.mjs && node authorize-net-dpm-browser.test.mjs && node pelecard-browser.test.mjs && node aci-browser.test.mjs && node creditguard-browser.test.mjs && node primer-browser.test.mjs && node payrails-browser.test.mjs && node elavon-converge-browser.test.mjs && node eprotect-browser.test.mjs && node wspay-browser.test.mjs && node shiji-sts-browser.test.mjs && node worldline-mycheckout-browser.test.mjs && node paypal-hosted-fields-browser.test.mjs && node cybersource-secure-acceptance-browser.test.mjs && node gravy-browser.test.mjs",
|
|
32
32
|
"check:payment-core": "node scripts/generate-payment-core.mjs --check",
|
|
33
33
|
"check:voice-stream": "node scripts/generate-voice-stream.mjs --check",
|
|
34
34
|
"test:preflight": "node --test preflight-package.test.mjs preflight-collector.test.mjs kernel-native-qualification.test.mjs",
|