@agent-cards/sdk 0.23.1 → 0.23.2

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 CHANGED
@@ -6,6 +6,8 @@
6
6
 
7
7
  - Abort the requests in which IHG's pay page sends the typed card outside its reviewed card request, in every status, as `card_endpoint_refused` with reason `card_resend`. The page posts the same booking to IHG's enrollment service while its pre-ticked "Enroll for free" box stays ticked, posts it on other paths for more than one room, a travel agent or Business Rewards, and at a hotel that asks for 3-D Secure first posts the number to two 3-D Secure calls. The SDK let each of these reach IHG with the agent's dummy card. A booking with the box unticked reaches IHG's reviewed card request, which the adapters refuse as before while IHG is in `observe`.
8
8
 
9
+ - Read IHG's booking at a hotel that asks for no security code as IHG's reviewed card request. At the two US hotels a live check visited, the pay page shows no security code field and sends `cvvNumber: {token: ""}`. The adapters read that as a card in a body IHG's profile did not review and refused it with reason `unrecognized_payment_endpoint`, so the booking could never pause for the cardholder. They now refuse it with reason `merchant_card_endpoint_not_enabled`, naming IHG's profile, while IHG is in `observe`, and once Agentcard enables IHG it pauses and asks the cardholder like any other IHG booking. A security code the hotel asks for is still read as three or four digits, and any other value there is refused as before.
10
+
9
11
  ## 0.23.0
10
12
 
11
13
  ### Upgrading from 0.22.0
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
2
  // Generated from @agent-cards/payment-core. Do not edit.
3
- // artifact-sha256: a2baaac410b5aaa629b3d5031136f88645c7b45c67c3bbc154cad72de216a04e
3
+ // artifact-sha256: c6a711b5dc964dbeb45863780001d99b79090f919b282fed9ae6fc06b4839681
4
4
  // src/cybersource-flex-rules.js
5
5
  var CYBERSOURCE_FLEX_RULES_SOURCE = Object.freeze({ version: "2.12.1", sha256: "8429ebae83e9745cd53ad8ff0d9ba69bee0087c1435ed0695a25444bed418327" });
6
6
  var CYBERSOURCE_FLEX_RULES = [
@@ -631,9 +631,11 @@ async function transientTokenFacts(status, body, verified, card, { crypto } = {}
631
631
  if (!/^[0-9]{12,19}$/.test(number) || typeof masked !== "string" || masked.length > 19 || !masked.endsWith(number.slice(-4))) {
632
632
  return unconfirmed("last_four");
633
633
  }
634
- const bin = tokenCard.number.bin;
635
- if (typeof bin !== "string" || !/^[0-9]{6,8}$/.test(bin) || !number.startsWith(bin))
634
+ const { bin, prefix } = tokenCard.number;
635
+ const startsThisCard = (value, form) => typeof value === "string" && form.test(value) && number.startsWith(value);
636
+ if (bin === void 0 && prefix === void 0 || bin !== void 0 && !startsThisCard(bin, /^[0-9]{6,8}$/) || prefix !== void 0 && !startsThisCard(prefix, number.length >= 16 ? /^(?:[0-9]{6}|[0-9]{8})$/ : /^[0-9]{6}$/)) {
636
637
  return unconfirmed("bin");
638
+ }
637
639
  const month = tokenCard.expirationMonth?.value;
638
640
  const year = tokenCard.expirationYear?.value;
639
641
  const cardMonth = String(card?.month ?? "").padStart(2, "0");
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
2
  // Generated from @agent-cards/payment-core. Do not edit.
3
- // artifact-sha256: ed096050a26a3c26d7fc8167d1bfbeb05e120b392a9aa7a34a924514c56fc870
3
+ // artifact-sha256: d73edb25ace75651a72071180425f4e2b4717e5fd5504f2d2d336d70a55e0f64
4
4
  // src/json-path.js
5
5
  var FORBIDDEN_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
6
6
  function isPlainObject(v) {
@@ -1115,7 +1115,8 @@ var MERCHANT_CARD_ENDPOINT_PROFILES = /* @__PURE__ */ deepFreeze([
1115
1115
  evidence: [
1116
1116
  "IHG pay SPA pay-ng v14.144.1 (chunks 5PVRTMTV, 7U5FHKAZ and AO2OILHC, archive.org copies of Jul 24 and 27, 2026), read Sep 25, 2026; the Sep 5 Common Crawl copy of find-hotels v14.147.0 still sends checkout there.",
1117
1117
  'ReservationService.createReservation posts the first reservation, JSON with withCredentials, to https://apis.ihg.com/reservations/v3/hotels: {id, imageStatus "COMMIT", segments: [{payment: {paymentByPoints, paymentInformation: {paymentCard}, guaranteeType, billingAddress}, ...}], userProfiles, hotels}.',
1118
- "paymentCard (getPaymentInformation): {cardCode, expireDate `${expirationMonth}${expirationYear}` (MMYY), cardHolderName, cvvNumber: {token: <CVV>}, cardNumber: {token: <PAN, spaces stripped>}}, plus 3dsData after a PSD2 check.",
1118
+ 'paymentCard (getPaymentInformation): {cardCode, expireDate `${expirationMonth}${expirationYear}` (MMYY), cardHolderName, cvvNumber: {token: <CVV, or "" when the hotel asks for none>}, cardNumber: {token: <PAN, spaces stripped>}}, plus 3dsData after a PSD2 check.',
1119
+ `pay-ng v14.149.0, read live Oct 6, 2026 (live-checks-oct6/ihg): neither US hotel checked (AMAEH, AMARS) shows a security code field, and the page writes cvvNumber {token: ""} for each. The form asks for a code for points plus cash, and for a paid offer at Iberostar or at a hotel whose policy sets isCreditCardCVVRequired or isPaymentServiceInformationRequired; otherwise it keeps its code empty. So card.cvv is digits_if_asked, as Hilton's and SynXis' are: the rules leave an empty code empty and still read a code the hotel asks for as digits.`,
1119
1120
  "Headers: x-ihg-api-key (public client key), content-type application/json; charset=UTF-8, ihg-language, X-IHG-SSO-TOKEN, x-accept-currency (USD), IHG-SellSource, Forter-Token; interceptors add IHG-SessionId and IHG-TransactionId.",
1120
1121
  "Hotels that set isPaymentServiceInformationRequired first send the PAN to /payments/threedsecure/v1/token ({cardToken: <PAN>, cardType}) and /paymentSetup (card.token: <PAN>) and put the result in 3dsData, which is refused here; China UnionPay and PayPal set cupTokenId and paymentSource, also refused. Both 3-D Secure posts are in resends below.",
1121
1122
  'pay-ng v14.149.0, read live Oct 6, 2026 (live-checks-oct6/ihg): the pay page posts the same reservation body, card in the clear, to /channels/direct/quickEnroll/v8/hotelReservations while its pre-ticked "Enroll for free as you book" box stays ticked (/quickEnroll/v9/hotelReservations behind the shouldUseNewQuickEnrolV9 flag, /quickEnroll/v8/multiRoomReservation for a cart), and to /reservations/v3/hotels/rooms/fromCart for more than one room, /reservations/v3/hotels/rooms/agent/reservations for a travel agent and /reservations/v3/businessRewardReservations for Business Rewards. Each is in resends below, so the SDK aborts it in every status.'
@@ -1149,7 +1150,7 @@ var MERCHANT_CARD_ENDPOINT_PROFILES = /* @__PURE__ */ deepFreeze([
1149
1150
  },
1150
1151
  card: {
1151
1152
  pan: { at: ["segments", 0, "payment", "paymentInformation", "paymentCard", "cardNumber", "token"], format: "digits" },
1152
- cvv: { at: ["segments", 0, "payment", "paymentInformation", "paymentCard", "cvvNumber", "token"], format: "digits" },
1153
+ cvv: { at: ["segments", 0, "payment", "paymentInformation", "paymentCard", "cvvNumber", "token"], format: "digits_if_asked" },
1153
1154
  exp_month: null,
1154
1155
  exp_year: null,
1155
1156
  expiry: { at: ["segments", 0, "payment", "paymentInformation", "paymentCard", "expireDate"], format: "mmyy" },
@@ -2068,8 +2069,10 @@ var MERCHANT_CARD_ENDPOINT_PROFILES = /* @__PURE__ */ deepFreeze([
2068
2069
  evidence: [
2069
2070
  "HUMA Kotor Bay Hotel & Villas books through D-EDGE (secure-hotel-booking.com/d-edge/HUMA-Kotor-Bay-Hotel-Villas/J6UZ); D-EDGE's payment hub on pay.secure-hotel-booking.com (main.bundle.js, Last-Modified 2026-09-10) renders a CreditCard provider as an iframe at window.cardFrameUrl, card.secure-hotel-booking.com/<the session uuid>.",
2070
2071
  "The card frame, PciCardForm (archive.org 2026-07-06, 2026-07-23 and 2026-09-04), posts form action /validate/<session uuid>/Default natively, as a navigation of the iframe: hidden Id (the same uuid), CardNumber (maxlength 22), Month (1 to 12, no leading zero), Year (four digits), Cvv (maxlength 4) and CardHolderName. No processor SDK in the frame; D-EDGE charges from its own servers (WSPay for this hotel, by its terms).",
2071
- "The frame also posts the card's first 8 digits to /cardCss/<session uuid>/Default to pick the card logo, which carries no full card and is not this request.",
2072
- "secure-hotel-booking.com sits behind DataDome. The same card frame serves every D-EDGE hotel, so the profile names D-EDGE rather than one hotel; its currency is HUMA's."
2072
+ "The frame also posts the first 8 characters of CardNumber as the field holds them (7 digits and a space once it groups a Visa or Mastercard number) to /cardCss/<session uuid>/Default to pick the card logo, which carries no full card and is not this request.",
2073
+ "secure-hotel-booking.com sits behind DataDome. The same card frame serves every D-EDGE hotel, so the profile names D-EDGE rather than one hotel; its currency is HUMA's.",
2074
+ "HUMA's own payment step, read live Oct 6, 2026 (live-checks-oct6/huma_kotor_bay): the frame's cleanCardNumber rewrites CardNumber on every keypress and on blur into groups of four with one space between them for a Visa or Mastercard number (4242 4242 4242 4242; 4-6-5 for an Amex, 4-6-4 for a Diners), so the post carries the spaces. card.pan is grouped4: the rules take the number grouped in fours or as plain digits, and write the real number the way the placeholder was written.",
2075
+ "The same check read when HUMA charges: its Non Refundable rate charges the whole stay at this post (the hub shows Due to pay now and its button reads PAY), while its flexible rate only guarantees the booking with the card, which the hotel charges on a late cancellation or a no-show."
2073
2076
  ],
2074
2077
  har: null,
2075
2078
  checkout: "https://card.secure-hotel-booking.com",
@@ -2088,7 +2091,7 @@ var MERCHANT_CARD_ENDPOINT_PROFILES = /* @__PURE__ */ deepFreeze([
2088
2091
  required: []
2089
2092
  },
2090
2093
  card: {
2091
- pan: { at: "CardNumber", format: "digits" },
2094
+ pan: { at: "CardNumber", format: "grouped4" },
2092
2095
  cvv: { at: "Cvv", format: "digits" },
2093
2096
  exp_month: { at: "Month", format: "m" },
2094
2097
  exp_year: { at: "Year", format: "yyyy" },
@@ -2115,9 +2118,9 @@ var MERCHANT_CARD_ENDPOINT_PROFILES = /* @__PURE__ */ deepFreeze([
2115
2118
  pending: [
2116
2119
  "HUMA's own payment step: whether its pay hub offers this card frame or a WSPay redirect (a HAR of one real booking's payment step)",
2117
2120
  "which cookies the card post needs, with DataDome in front of the host",
2118
- "whether CardNumber is posted as digits or with the spaces the field allows",
2121
+ "whether D-EDGE takes a real Amex or Diners number grouped in fours, which grouped4 writes and the frame never does (it groups those 4-6-5 and 4-6-4)",
2119
2122
  "the answer to the card post (a redirect, a 3DS step or a page), and whether a 3DS step sends the card again",
2120
- "whether D-EDGE charges the card at this step or holds it for the hotel to charge later",
2123
+ GUARANTEE_RATES,
2121
2124
  "that the bootstrap path answers without a server error"
2122
2125
  ]
2123
2126
  },
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
2
  // Generated from @agent-cards/payment-core. Do not edit.
3
- // artifact-sha256: 622844dcc82d0276b966b1c6e6714d2cc6c3cbb0f854caeba0f92c0bfb041e1b
3
+ // artifact-sha256: b114efe706f6bfbca37bdf2a2044eb3f1e0215c03f4de228f25c9155de8c5629
4
4
  // src/deep-freeze.js
5
5
  function deepFreeze(value) {
6
6
  if (value && typeof value === "object" && !Object.isFrozen(value)) {
@@ -839,22 +839,41 @@ function attributesOf(text) {
839
839
  }
840
840
  return attributes;
841
841
  }
842
- function runsInline(attributes) {
843
- if (attributes.has("src"))
844
- return false;
842
+ var ROCKET_LOADER_ACTIVATOR = /^\/cdn-cgi\/scripts\/[0-9a-f]{8}\/cloudflare-static\/rocket-loader\.min\.js$/;
843
+ var ROCKET_LOADER_SETTINGS = /^([0-9a-f]{24}-)\|[0-9]+$/;
844
+ var ROCKET_LOADER_TYPE = /^([0-9a-f]{24}-)text\/javascript$/;
845
+ function scriptKind(attributes) {
845
846
  const type = attributes.has("type") ? attributes.get("type") || "text/javascript" : attributes.get("language") ? `text/${attributes.get("language")}` : "text/javascript";
846
847
  const typeString = type.replace(/^[\t\n\f\r ]+|[\t\n\f\r ]+$/g, "").toLowerCase();
847
848
  if (typeString === "module")
848
- return true;
849
- return JAVASCRIPT_TYPES.has(typeString) && !attributes.has("nomodule");
849
+ return "module";
850
+ return JAVASCRIPT_TYPES.has(typeString) && !attributes.has("nomodule") ? "classic" : null;
851
+ }
852
+ function runsInline(attributes, rocketLoaderNonces) {
853
+ if (attributes.has("src"))
854
+ return false;
855
+ const rewritten = ROCKET_LOADER_TYPE.exec(attributes.get("type") ?? "");
856
+ if (rewritten)
857
+ return rocketLoaderNonces.has(rewritten[1]) && !attributes.has("nomodule");
858
+ return scriptKind(attributes) !== null;
859
+ }
860
+ function rocketLoaderNoncesOf(scripts) {
861
+ const nonces = /* @__PURE__ */ new Set();
862
+ for (const attributes of scripts) {
863
+ const settings = ROCKET_LOADER_SETTINGS.exec(attributes.get("data-cf-settings") ?? "");
864
+ if (settings && ROCKET_LOADER_ACTIVATOR.test(attributes.get("src") ?? "") && scriptKind(attributes) === "classic" && attributes.has("defer") && !attributes.has("async"))
865
+ nonces.add(settings[1]);
866
+ }
867
+ return nonces;
850
868
  }
851
869
  function inlineScriptText(html) {
852
- const texts = [];
870
+ const scripts = [];
853
871
  for (const [, attributes, text] of html.matchAll(COMMENT_OR_SCRIPT)) {
854
- if (text !== void 0 && runsInline(attributesOf(attributes)))
855
- texts.push(text);
872
+ if (text !== void 0)
873
+ scripts.push({ attributes: attributesOf(attributes), text });
856
874
  }
857
- return texts.join("\n");
875
+ const nonces = rocketLoaderNoncesOf(scripts.map((script) => script.attributes));
876
+ return scripts.filter((script) => runsInline(script.attributes, nonces)).map((script) => script.text).join("\n");
858
877
  }
859
878
  function htmlReading(block, html) {
860
879
  const markup = html.replace(NON_MARKUP, "");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-cards/sdk",
3
- "version": "0.23.1",
3
+ "version": "0.23.2",
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",