@agent-cards/sdk 0.23.15 → 0.23.16

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
@@ -14,6 +14,8 @@
14
14
 
15
15
  - Pause Redsys's hosted payment page (the TPV Virtual redirect most Spanish banks give their merchants) for the cardholder's device. The sync now also asks for `capabilities=redsys_hosted_payment_page`, and the API serves Redsys's recognizer only for a company Agentcard turned Redsys on for. The SDK pauses the merchant's signed entry form to `sis.redsys.es/sis/realizarPago` (or `/sis/realizarPago/utf-8`), which carries no card, as a `hosted_form` authorization, and answers the paused navigation with the `submitted_on_device` page once the cardholder's device has paid it. Every other post your browser makes to Redsys, its card page's own post, its older page's 3-D Secure card lookup, InSite's card post and any post to Redsys's test platform, carries the card your agent typed or opens a page that asks for one: the SDK fails it and reads `unsupported` with reason `processor_card_page`. Your events and error messages name Redsys's session id, the `;jsessionid=` part of its paths, as `{session}`. Matching API and Vault releases are required. Redsys stays off for every company Agentcard has not turned it on for.
16
16
 
17
+ - Keep a PayMongo checkout's session id out of your events and error messages. PayMongo's hosted checkout sends the card to its own page URL, `https://checkout.paymongo.com/<session>`, with no auth header and no cookie, so the session id is the only credential that request needs: anyone who holds it can open the checkout, its amount and its merchant, and pay it. `redactUrl`, every event and every error message now show it as `{session}` on that host, as in `https://checkout.paymongo.com/{session}`. The SDK does not pause a PayMongo payment yet. No API or Vault release is needed.
18
+
17
19
  - Pay a Paddle checkout whose card method names TokenEx, from Agentcard's own account only for now (dark launch): Agentcard turns it on for another company once it has confirmed that a card encrypted for one Paddle checkout cannot pay another. On such a checkout, Paddle's frame RSA-encrypts the card number and the CVV in the page itself, each on its own, under the account's TokenEx key, and posts them to `https://checkout-service.paddle.com/<checkout>/pay` (`https://sandbox-checkout-service.paddle.com/<checkout>/pay` in test) with the placeholder's first six and last four digits, expiry and brand. The SDK now pauses that `/pay`, and once the cardholder approves, the cardholder's device encrypts the real card under the key the SDK pins for that checkout's environment and the SDK writes the two ciphertexts and those five facts over the placeholder's, changing nothing else in the request. The full card number never reaches the agent's page. The sync now also asks for `capabilities=paddle_tokenex_pay`. The ciphertext goes only into the `/pay` the approval was created from, byte for byte, because the account's TokenEx key would decrypt it in any later `/pay` of that seller. A `/pay` that names no TokenEx card (PayPal, a wallet, a saved card) carries none of the cardholder's cards and continues untouched, and the SDK refuses a `/pay` that is not the frame's shape with `paddle_tokenex_pay_unsupported` before anything is sent. No live payment has gone through this route yet. A payment also needs the matching API and Vault releases.
18
20
  - Pay a Lyra payment form (PayZen, Systempay or Sogecommerce) for a company Agentcard turned Lyra on for (dark launch): the SDK declares `lyra_krypton_payment`, pauses the form's card payment and hands the form Lyra's answer with the payment id its 3-D Secure step needs.
19
21
  - Keep a Lyra payment's session id out of your events and error messages. Lyra's Krypton payment form (PayZen, Systempay, Sogecommerce, Lyra Collect) sends its payment to `/api-payment/V4/Charge/Public/ProcessPayment/2;jsessionid=<id>` on the brand's API host, and that id, with the form token the page holds, continues the payment on Lyra's side. `redactUrl`, every event and every error message show it as `{session}`, as in `https://api.systempay.fr/api-payment/V4/Charge/Public/ProcessPayment/2;jsessionid={session}`. Lyra stays dark for every company Agentcard has not turned it on for, and no API or Vault release is needed.
package/LICENSE CHANGED
@@ -35,4 +35,4 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35
35
  IMPLIED. IN NO EVENT SHALL AGENTCARD CORPORATION BE LIABLE FOR ANY CLAIM,
36
36
  DAMAGES OR OTHER LIABILITY ARISING FROM THE SOFTWARE OR ITS USE.
37
37
 
38
- Questions: legal@agentcard.sh
38
+ Questions: legal@agentcard.com
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
2
  // Generated from @agent-cards/payment-core. Do not edit.
3
- // artifact-sha256: d16bc471bdb814eb3e7b9da3834c9cbb5b1db7089ce91d3bbfb2215f81c1958d
3
+ // artifact-sha256: e4858832550c43f6e3cbef0c64facb820d7ae9b5118a2c8c4fcadb429c94b2b0
4
4
  // src/card-number-key.js
5
5
  var CARD_NUMBER_KEY = /^(number|card_number|cardnumber|cardNum|card_num|pan)$/i;
6
6
  // src/json-path.js
@@ -357,8 +357,8 @@ var CONTROL = /[\u0000-\u001f\u007f]/;
357
357
  var cardLikeName = (name) => (name.match(/[0-9]/g) ?? []).length >= 12;
358
358
  var record3 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
359
359
  var sameKeys = (value, keys) => {
360
- const own = Object.keys(value);
361
- return own.length === keys.length && own.every((key, at) => key === keys[at]);
360
+ const own2 = Object.keys(value);
361
+ return own2.length === keys.length && own2.every((key, at) => key === keys[at]);
362
362
  };
363
363
  var refuse4 = (code) => Object.freeze({ verdict: "refuse", code });
364
364
  var CARD4 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
@@ -425,6 +425,9 @@ var PAYFAST_BODY_KEYS = /* @__PURE__ */ Object.freeze([
425
425
  "captcha_version",
426
426
  "captcha_action"
427
427
  ]);
428
+ var CAPTCHA_ANSWER = "g-recaptcha-response";
429
+ var UNANSWERED_KEYS = /* @__PURE__ */ Object.freeze(PAYFAST_BODY_KEYS.filter((key) => key !== CAPTCHA_ANSWER));
430
+ var UNANSWERED_VERSIONS = /* @__PURE__ */ Object.freeze(["v0", "v1"]);
428
431
  var BODY_LIMIT3 = 8192;
429
432
  var URL_LIMIT = 256;
430
433
  var PAY_PATH = /^\/eng\/method\/CreditCard\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\/pay$/;
@@ -487,18 +490,20 @@ function cardNetwork(number) {
487
490
  return "mastercard";
488
491
  return AMEX.test(number) ? "amex" : null;
489
492
  }
493
+ var namesKeys = (pairs, keys) => pairs.length === keys.length && pairs.every(([key], at) => key === keys[at]);
490
494
  function judgeBody(body) {
491
495
  const pairs = readForm(body);
492
496
  if (pairs === null)
493
497
  return { code: "payfast_body_unsupported", pairs: null };
494
498
  if (pairs.some(([key]) => key === "cc_key"))
495
499
  return { code: "payfast_saved_card", pairs: null };
496
- if (pairs.length !== PAYFAST_BODY_KEYS.length || !pairs.every(([key], at) => key === PAYFAST_BODY_KEYS[at])) {
500
+ const answered = namesKeys(pairs, PAYFAST_BODY_KEYS);
501
+ if (!answered && !namesKeys(pairs, UNANSWERED_KEYS))
497
502
  return { code: "payfast_body_unsupported", pairs: null };
498
- }
499
503
  const value = Object.fromEntries(pairs);
500
- const answer = value["g-recaptcha-response"];
501
- if (cardNetwork(value.card_number) === null || !SECURITY_CODE3.test(value.cvv) || !MONTH.test(value.expiry_month) || !YEAR.test(value.expiry_year) || value.cardholder_name.length > HOLDER_LIMIT || !HOLDER.test(value.cardholder_name) || !(answer === "" || SOLVED_CAPTCHA2.test(answer)) || !CAPTCHA_VERSIONS.includes(value.captcha_version) || value.captcha_action !== "checkout") {
504
+ const answer = value[CAPTCHA_ANSWER];
505
+ const captcha = answered ? answer === "" || SOLVED_CAPTCHA2.test(answer) : UNANSWERED_VERSIONS.includes(value.captcha_version);
506
+ if (cardNetwork(value.card_number) === null || !SECURITY_CODE3.test(value.cvv) || !MONTH.test(value.expiry_month) || !YEAR.test(value.expiry_year) || value.cardholder_name.length > HOLDER_LIMIT || !HOLDER.test(value.cardholder_name) || !captcha || !CAPTCHA_VERSIONS.includes(value.captcha_version) || value.captcha_action !== "checkout") {
502
507
  return { code: "payfast_body_unsupported", pairs: null };
503
508
  }
504
509
  if (value.consent_check === "1")
@@ -762,8 +767,8 @@ var PADDLE_TOKENEX_PSP = "paddle_tokenex";
762
767
  var PADDLE_TOKENEX_FACT_KEYS = /* @__PURE__ */ Object.freeze(["card_first_six", "card_last_four", "expiry_month", "expiry_year", "card_brand"]);
763
768
  var record4 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
764
769
  var sameKeys2 = (value, keys) => {
765
- const own = Object.keys(value);
766
- return own.length === keys.length && own.every((key, at) => key === keys[at]);
770
+ const own2 = Object.keys(value);
771
+ return own2.length === keys.length && own2.every((key, at) => key === keys[at]);
767
772
  };
768
773
  var refuse7 = (code) => Object.freeze({ verdict: "refuse", code });
769
774
  var CARD6 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
@@ -1252,8 +1257,8 @@ var TEXT_LIMIT = 256;
1252
1257
  var CONTROL4 = /[\u0000-\u001f\u007f]/;
1253
1258
  var record6 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
1254
1259
  var sameKeys3 = (value, keys) => {
1255
- const own = Object.keys(value);
1256
- return own.length === keys.length && own.every((key, at) => key === keys[at]);
1260
+ const own2 = Object.keys(value);
1261
+ return own2.length === keys.length && own2.every((key, at) => key === keys[at]);
1257
1262
  };
1258
1263
  var plainText = (value) => typeof value === "string" && value.length <= TEXT_LIMIT && !CONTROL4.test(value) && (value.match(/[0-9]/g) ?? []).length < 12;
1259
1264
  var refuse9 = (code) => Object.freeze({ verdict: "refuse", code });
@@ -1311,6 +1316,132 @@ var WIX_PAYMENTS_MERCHANT_PINS = /* @__PURE__ */ Object.freeze([
1311
1316
  pin3({ id: "psalms_and_potions", merchant: "Psalms & Potions", origins: ["https://www.psalmsandpotions.com"] }),
1312
1317
  pin3({ id: "alexandra_hagel", merchant: "Alexandra Hagel, LLC", origins: ["https://www.alexandrahagel.com"] })
1313
1318
  ]);
1319
+ // src/paymongo.js
1320
+ var PAYMONGO_PSP = "paymongo";
1321
+ var PAYMONGO_CHECKOUT_HOST = "checkout.paymongo.com";
1322
+ var PAYMONGO_ATTRIBUTE_KEYS = /* @__PURE__ */ Object.freeze(["payment_method_type", "details", "billing", "return_url"]);
1323
+ var PAYMONGO_CARD_KEYS = /* @__PURE__ */ Object.freeze(["card_number", "exp_month", "exp_year", "cvc"]);
1324
+ var PAYMONGO_BILLING_KEYS = /* @__PURE__ */ Object.freeze(["name", "email", "phone", "address"]);
1325
+ var PAYMONGO_ADDRESS_KEYS = /* @__PURE__ */ Object.freeze(["line1", "line2", "city", "state", "country", "postal_code"]);
1326
+ var CLICK_TO_PAY_KEYS = /* @__PURE__ */ Object.freeze(["merchant_transaction_id", "correlation_id", "x_src_cx_flow_id"]);
1327
+ var URL_LIMIT2 = 128;
1328
+ var BODY_LIMIT6 = 16384;
1329
+ var ORIGIN = `https://${PAYMONGO_CHECKOUT_HOST}/`;
1330
+ var SESSION2 = /^[A-Za-z0-9]{24}$/;
1331
+ var CHECKOUT_PATH = /^\/(?:cs_)?([A-Za-z0-9]{24})$/;
1332
+ var NUMBER = /^[0-9]{12,19}$/;
1333
+ var SECURITY_CODE6 = /^[0-9]{3,4}$/;
1334
+ var TEXT = /^[^\x00-\x1f\x7f]{1,256}$/;
1335
+ var UNDEFINED = "$undefined";
1336
+ var CARD_MEMBER = /^(?:card_?number|pan|cvc|cvv)$/i;
1337
+ var record7 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
1338
+ var own = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
1339
+ var keysAre = (value, keys) => {
1340
+ const names = Object.keys(value);
1341
+ return names.length === keys.length && names.every((name, at) => name === keys[at]);
1342
+ };
1343
+ var refuse10 = (code) => Object.freeze({ verdict: "refuse", code });
1344
+ var CARD9 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
1345
+ var CONTINUE4 = /* @__PURE__ */ Object.freeze({ verdict: "continue" });
1346
+ function paymongoCheckoutSession(url) {
1347
+ if (typeof url !== "string" || url.length > URL_LIMIT2 || url.includes("?") || url.includes("#"))
1348
+ return null;
1349
+ let parsed;
1350
+ try {
1351
+ parsed = new URL(url);
1352
+ }
1353
+ catch {
1354
+ return null;
1355
+ }
1356
+ if (parsed.href !== url || parsed.protocol !== "https:" || parsed.port || parsed.username || parsed.password || parsed.hostname !== PAYMONGO_CHECKOUT_HOST)
1357
+ return null;
1358
+ const match = CHECKOUT_PATH.exec(parsed.pathname);
1359
+ return match ? match[1] : null;
1360
+ }
1361
+ function readJson2(body) {
1362
+ if (typeof body !== "string" || body === "")
1363
+ return { parsed: null, exact: false };
1364
+ let parsed;
1365
+ try {
1366
+ parsed = JSON.parse(body);
1367
+ }
1368
+ catch {
1369
+ return { parsed: null, exact: false };
1370
+ }
1371
+ let exact = false;
1372
+ try {
1373
+ exact = body.length <= BODY_LIMIT6 && JSON.stringify(parsed) === body;
1374
+ }
1375
+ catch {
1376
+ exact = false;
1377
+ }
1378
+ return { parsed, exact };
1379
+ }
1380
+ function billingValue(value) {
1381
+ if (value === UNDEFINED)
1382
+ return true;
1383
+ if (typeof value !== "string" || !TEXT.test(value))
1384
+ return false;
1385
+ return value[0] !== "$" || value.startsWith("$$");
1386
+ }
1387
+ function judgeCardAttach(args, session) {
1388
+ if (args.length !== 3 || typeof args[0] !== "string" || !args[0].startsWith("cs_") || !SESSION2.test(args[0].slice(3))) {
1389
+ return "paymongo_body_unsupported";
1390
+ }
1391
+ const id = args[0].slice(3);
1392
+ const attributes = args[1].data.attributes;
1393
+ const details = attributes.details;
1394
+ if (record7(details) && CLICK_TO_PAY_KEYS.some((key) => own(details, key)))
1395
+ return "paymongo_click_to_pay";
1396
+ if (!keysAre(args[1], ["data"]) || !keysAre(args[1].data, ["attributes"]) || !keysAre(attributes, PAYMONGO_ATTRIBUTE_KEYS) || !record7(details) || !keysAre(details, PAYMONGO_CARD_KEYS))
1397
+ return "paymongo_body_unsupported";
1398
+ if (typeof details.card_number !== "string" || !NUMBER.test(details.card_number) || !Number.isSafeInteger(details.exp_month) || details.exp_month < 1 || details.exp_month > 12 || !Number.isSafeInteger(details.exp_year) || details.exp_year < 0 || details.exp_year > 99 || typeof details.cvc !== "string" || !SECURITY_CODE6.test(details.cvc))
1399
+ return "paymongo_body_unsupported";
1400
+ const billing = attributes.billing;
1401
+ if (!record7(billing) || !keysAre(billing, PAYMONGO_BILLING_KEYS) || !record7(billing.address) || !keysAre(billing.address, PAYMONGO_ADDRESS_KEYS))
1402
+ return "paymongo_body_unsupported";
1403
+ if (billing.name === UNDEFINED || !billingValue(billing.name) || !billingValue(billing.email) || !billingValue(billing.phone) || !PAYMONGO_ADDRESS_KEYS.every((key) => billingValue(billing.address[key])))
1404
+ return "paymongo_body_unsupported";
1405
+ const third = args[2];
1406
+ if (!record7(third) || !keysAre(third, ["viewerAccept"]) || !billingValue(third.viewerAccept))
1407
+ return "paymongo_body_unsupported";
1408
+ if (attributes.return_url !== `${ORIGIN}${id}` || session !== void 0 && session !== id)
1409
+ return "paymongo_session_mismatch";
1410
+ return null;
1411
+ }
1412
+ function namesCardValue(parsed) {
1413
+ const pending = parsed !== null && typeof parsed === "object" ? [parsed] : [];
1414
+ while (pending.length > 0) {
1415
+ const node = pending.pop();
1416
+ for (const key of Object.keys(node)) {
1417
+ if (!Array.isArray(node) && CARD_MEMBER.test(key))
1418
+ return true;
1419
+ const value = node[key];
1420
+ if (value !== null && typeof value === "object")
1421
+ pending.push(value);
1422
+ }
1423
+ }
1424
+ return false;
1425
+ }
1426
+ function attachType(parsed) {
1427
+ if (!Array.isArray(parsed) || parsed.length < 2 || !record7(parsed[1]) || !record7(parsed[1].data) || !record7(parsed[1].data.attributes))
1428
+ return null;
1429
+ const type = parsed[1].data.attributes.payment_method_type;
1430
+ return typeof type === "string" ? type : null;
1431
+ }
1432
+ function paymongoBodyVerdict(body, session) {
1433
+ const { parsed, exact } = readJson2(body);
1434
+ const type = parsed === null ? null : attachType(parsed);
1435
+ if (type !== "card") {
1436
+ if (parsed === null)
1437
+ return body === void 0 || body === null || body === "" ? CONTINUE4 : refuse10("paymongo_body_unsupported");
1438
+ return namesCardValue(parsed) ? refuse10("paymongo_body_unsupported") : CONTINUE4;
1439
+ }
1440
+ if (!exact)
1441
+ return refuse10("paymongo_body_unsupported");
1442
+ const code = judgeCardAttach(parsed, session);
1443
+ return code === null ? CARD9 : refuse10(code);
1444
+ }
1314
1445
  // src/card-fields.js
1315
1446
  function processorGate(recognizer, url, body) {
1316
1447
  if (recognizer && recognizer.psp === LYRA_PSP)
@@ -1336,6 +1467,12 @@ function processorGate(recognizer, url, body) {
1336
1467
  return { verdict: "refuse", code: "paddle_tokenex_pay_unsupported" };
1337
1468
  return paddleTokenexBodyVerdict(body, target ? target.line : void 0);
1338
1469
  }
1470
+ if (recognizer && recognizer.psp === PAYMONGO_PSP) {
1471
+ const session = url !== void 0 ? paymongoCheckoutSession(url) : void 0;
1472
+ if (url !== void 0 && session === null)
1473
+ return { verdict: "refuse", code: "paymongo_url_refused" };
1474
+ return paymongoBodyVerdict(body, session);
1475
+ }
1339
1476
  if (recognizer && recognizer.psp === GRAVY_PSP)
1340
1477
  return gravyBodyVerdict(body);
1341
1478
  if (recognizer && recognizer.psp === MONERIS_PSP) {
@@ -1453,7 +1590,7 @@ function splitCardLeg(recognizer, body) {
1453
1590
  const absorb = list(split.absorb);
1454
1591
  const pass = list(split.pass);
1455
1592
  const sibling = list(split.siblingKeys);
1456
- const own = [];
1593
+ const own2 = [];
1457
1594
  const seen = /* @__PURE__ */ new Set();
1458
1595
  for (const chunk of body.split("&")) {
1459
1596
  const eq = chunk.indexOf("=");
@@ -1470,13 +1607,13 @@ function splitCardLeg(recognizer, body) {
1470
1607
  return null;
1471
1608
  seen.add(key);
1472
1609
  if (!sibling.includes(key))
1473
- own.push(key);
1610
+ own2.push(key);
1474
1611
  }
1475
- if (own.length === 0)
1612
+ if (own2.length === 0)
1476
1613
  return null;
1477
- if (own.every((key) => absorb.includes(key)))
1614
+ if (own2.every((key) => absorb.includes(key)))
1478
1615
  return "absorb";
1479
- if (own.every((key) => pass.includes(key)))
1616
+ if (own2.every((key) => pass.includes(key)))
1480
1617
  return "pass";
1481
1618
  return null;
1482
1619
  }
package/dist/client.d.ts CHANGED
@@ -1174,6 +1174,7 @@ export declare class CheckoutAuthError extends Error {
1174
1174
  * On Lyra's API hosts the form token's session id reads `{session}`.
1175
1175
  * On PayPal's hosts an order id reads `{order}`:
1176
1176
  * https://www.paypal.com/v2/checkout/orders/{order}/confirm-payment-source.
1177
+ * On PayMongo's checkout host the session id reads `{session}`: https://checkout.paymongo.com/{session}.
1177
1178
  * A string that is not a URL keeps the part before any `?` or `#`, with the
1178
1179
  * same segments masked.
1179
1180
  */
package/dist/client.js CHANGED
@@ -1102,6 +1102,19 @@ const LYRA_SESSION = /;jsessionid=[^/;?#]*/gi;
1102
1102
  function maskLyraSession(path) {
1103
1103
  return path.replace(LYRA_SESSION, ';jsessionid={session}');
1104
1104
  }
1105
+ /**
1106
+ * PayMongo's hosted checkout sends its card form's attach to its own page URL,
1107
+ * https://checkout.paymongo.com/<session> (payment-core paymongo.js), and the session id is the only
1108
+ * credential there, no cookies: with it anyone can open that checkout, its amount and its merchant, and
1109
+ * pay it. Every route of the host is a session page, so on it any run of 24 or more letters and digits,
1110
+ * with or without its cs_ prefix, in any case, after an escaped slash or with any character
1111
+ * percent-encoded (a path keeps %36 where it means 6), reads {session}.
1112
+ */
1113
+ const PAYMONGO_CHECKOUT_HOST = /^checkout\.paymongo\.com\.?$/i;
1114
+ const PAYMONGO_SESSION = /(?:cs_)?(?:[A-Za-z0-9]|%[0-9A-Fa-f]{2}){24,}/gi;
1115
+ function maskPaymongoSession(path) {
1116
+ return path.replace(PAYMONGO_SESSION, '{session}');
1117
+ }
1105
1118
  /**
1106
1119
  * The processors whose card request carries its own credential in the URL path, with the hosts
1107
1120
  * that send it, the text that names those hosts in a string that is not a URL, and the mask. The
@@ -1141,6 +1154,7 @@ const PATH_CREDENTIALS = [
1141
1154
  { host: REDSYS_HOST, named: /redsys\.es/i, mask: maskRedsysSession },
1142
1155
  { host: LYRA_HOST, named: /(?:payzen\.eu|systempay\.fr|societegenerale\.eu|lyra\.com)/i, mask: maskLyraSession },
1143
1156
  { host: PAYPAL_HOST, named: /paypal\.com/i, mask: maskPaypalOrder },
1157
+ { host: PAYMONGO_CHECKOUT_HOST, named: /checkout\.paymongo\.com/i, mask: maskPaymongoSession },
1144
1158
  ];
1145
1159
  /**
1146
1160
  * A URL as it may appear in an error message: origin + path only. A paused
@@ -1163,6 +1177,7 @@ const PATH_CREDENTIALS = [
1163
1177
  * On Lyra's API hosts the form token's session id reads `{session}`.
1164
1178
  * On PayPal's hosts an order id reads `{order}`:
1165
1179
  * https://www.paypal.com/v2/checkout/orders/{order}/confirm-payment-source.
1180
+ * On PayMongo's checkout host the session id reads `{session}`: https://checkout.paymongo.com/{session}.
1166
1181
  * A string that is not a URL keeps the part before any `?` or `#`, with the
1167
1182
  * same segments masked.
1168
1183
  */
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
2
  // Generated from @agent-cards/payment-core. Do not edit.
3
- // artifact-sha256: 1d05273d23008e96c38c3be306ab215212b654fc275b96cf11e6452dee60c0d7
3
+ // artifact-sha256: 833d97716c57df725c942d14494012032a87b561ac7734676fe9dcb1d6be4819
4
4
  // src/card-number-key.js
5
5
  var CARD_NUMBER_KEY = /^(number|card_number|cardnumber|cardNum|card_num|pan)$/i;
6
6
  // src/json-path.js
@@ -365,8 +365,8 @@ var CONTROL = /[\u0000-\u001f\u007f]/;
365
365
  var cardLikeName = (name) => (name.match(/[0-9]/g) ?? []).length >= 12;
366
366
  var record3 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
367
367
  var sameKeys = (value, keys) => {
368
- const own = Object.keys(value);
369
- return own.length === keys.length && own.every((key, at) => key === keys[at]);
368
+ const own2 = Object.keys(value);
369
+ return own2.length === keys.length && own2.every((key, at) => key === keys[at]);
370
370
  };
371
371
  var refuse4 = (code) => Object.freeze({ verdict: "refuse", code });
372
372
  var CARD4 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
@@ -433,6 +433,9 @@ var PAYFAST_BODY_KEYS = /* @__PURE__ */ Object.freeze([
433
433
  "captcha_version",
434
434
  "captcha_action"
435
435
  ]);
436
+ var CAPTCHA_ANSWER = "g-recaptcha-response";
437
+ var UNANSWERED_KEYS = /* @__PURE__ */ Object.freeze(PAYFAST_BODY_KEYS.filter((key) => key !== CAPTCHA_ANSWER));
438
+ var UNANSWERED_VERSIONS = /* @__PURE__ */ Object.freeze(["v0", "v1"]);
436
439
  var BODY_LIMIT3 = 8192;
437
440
  var URL_LIMIT = 256;
438
441
  var PAY_PATH = /^\/eng\/method\/CreditCard\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\/pay$/;
@@ -495,18 +498,20 @@ function cardNetwork(number) {
495
498
  return "mastercard";
496
499
  return AMEX.test(number) ? "amex" : null;
497
500
  }
501
+ var namesKeys = (pairs, keys) => pairs.length === keys.length && pairs.every(([key], at) => key === keys[at]);
498
502
  function judgeBody(body) {
499
503
  const pairs = readForm(body);
500
504
  if (pairs === null)
501
505
  return { code: "payfast_body_unsupported", pairs: null };
502
506
  if (pairs.some(([key]) => key === "cc_key"))
503
507
  return { code: "payfast_saved_card", pairs: null };
504
- if (pairs.length !== PAYFAST_BODY_KEYS.length || !pairs.every(([key], at) => key === PAYFAST_BODY_KEYS[at])) {
508
+ const answered = namesKeys(pairs, PAYFAST_BODY_KEYS);
509
+ if (!answered && !namesKeys(pairs, UNANSWERED_KEYS))
505
510
  return { code: "payfast_body_unsupported", pairs: null };
506
- }
507
511
  const value = Object.fromEntries(pairs);
508
- const answer = value["g-recaptcha-response"];
509
- if (cardNetwork(value.card_number) === null || !SECURITY_CODE3.test(value.cvv) || !MONTH.test(value.expiry_month) || !YEAR.test(value.expiry_year) || value.cardholder_name.length > HOLDER_LIMIT || !HOLDER.test(value.cardholder_name) || !(answer === "" || SOLVED_CAPTCHA2.test(answer)) || !CAPTCHA_VERSIONS.includes(value.captcha_version) || value.captcha_action !== "checkout") {
512
+ const answer = value[CAPTCHA_ANSWER];
513
+ const captcha = answered ? answer === "" || SOLVED_CAPTCHA2.test(answer) : UNANSWERED_VERSIONS.includes(value.captcha_version);
514
+ if (cardNetwork(value.card_number) === null || !SECURITY_CODE3.test(value.cvv) || !MONTH.test(value.expiry_month) || !YEAR.test(value.expiry_year) || value.cardholder_name.length > HOLDER_LIMIT || !HOLDER.test(value.cardholder_name) || !captcha || !CAPTCHA_VERSIONS.includes(value.captcha_version) || value.captcha_action !== "checkout") {
510
515
  return { code: "payfast_body_unsupported", pairs: null };
511
516
  }
512
517
  if (value.consent_check === "1")
@@ -770,8 +775,8 @@ var PADDLE_TOKENEX_PSP = "paddle_tokenex";
770
775
  var PADDLE_TOKENEX_FACT_KEYS = /* @__PURE__ */ Object.freeze(["card_first_six", "card_last_four", "expiry_month", "expiry_year", "card_brand"]);
771
776
  var record4 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
772
777
  var sameKeys2 = (value, keys) => {
773
- const own = Object.keys(value);
774
- return own.length === keys.length && own.every((key, at) => key === keys[at]);
778
+ const own2 = Object.keys(value);
779
+ return own2.length === keys.length && own2.every((key, at) => key === keys[at]);
775
780
  };
776
781
  var refuse7 = (code) => Object.freeze({ verdict: "refuse", code });
777
782
  var CARD6 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
@@ -1260,8 +1265,8 @@ var TEXT_LIMIT = 256;
1260
1265
  var CONTROL4 = /[\u0000-\u001f\u007f]/;
1261
1266
  var record6 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
1262
1267
  var sameKeys3 = (value, keys) => {
1263
- const own = Object.keys(value);
1264
- return own.length === keys.length && own.every((key, at) => key === keys[at]);
1268
+ const own2 = Object.keys(value);
1269
+ return own2.length === keys.length && own2.every((key, at) => key === keys[at]);
1265
1270
  };
1266
1271
  var plainText = (value) => typeof value === "string" && value.length <= TEXT_LIMIT && !CONTROL4.test(value) && (value.match(/[0-9]/g) ?? []).length < 12;
1267
1272
  var refuse9 = (code) => Object.freeze({ verdict: "refuse", code });
@@ -1319,6 +1324,132 @@ var WIX_PAYMENTS_MERCHANT_PINS = /* @__PURE__ */ Object.freeze([
1319
1324
  pin3({ id: "psalms_and_potions", merchant: "Psalms & Potions", origins: ["https://www.psalmsandpotions.com"] }),
1320
1325
  pin3({ id: "alexandra_hagel", merchant: "Alexandra Hagel, LLC", origins: ["https://www.alexandrahagel.com"] })
1321
1326
  ]);
1327
+ // src/paymongo.js
1328
+ var PAYMONGO_PSP = "paymongo";
1329
+ var PAYMONGO_CHECKOUT_HOST = "checkout.paymongo.com";
1330
+ var PAYMONGO_ATTRIBUTE_KEYS = /* @__PURE__ */ Object.freeze(["payment_method_type", "details", "billing", "return_url"]);
1331
+ var PAYMONGO_CARD_KEYS = /* @__PURE__ */ Object.freeze(["card_number", "exp_month", "exp_year", "cvc"]);
1332
+ var PAYMONGO_BILLING_KEYS = /* @__PURE__ */ Object.freeze(["name", "email", "phone", "address"]);
1333
+ var PAYMONGO_ADDRESS_KEYS = /* @__PURE__ */ Object.freeze(["line1", "line2", "city", "state", "country", "postal_code"]);
1334
+ var CLICK_TO_PAY_KEYS = /* @__PURE__ */ Object.freeze(["merchant_transaction_id", "correlation_id", "x_src_cx_flow_id"]);
1335
+ var URL_LIMIT2 = 128;
1336
+ var BODY_LIMIT6 = 16384;
1337
+ var ORIGIN = `https://${PAYMONGO_CHECKOUT_HOST}/`;
1338
+ var SESSION2 = /^[A-Za-z0-9]{24}$/;
1339
+ var CHECKOUT_PATH = /^\/(?:cs_)?([A-Za-z0-9]{24})$/;
1340
+ var NUMBER = /^[0-9]{12,19}$/;
1341
+ var SECURITY_CODE6 = /^[0-9]{3,4}$/;
1342
+ var TEXT = /^[^\x00-\x1f\x7f]{1,256}$/;
1343
+ var UNDEFINED = "$undefined";
1344
+ var CARD_MEMBER = /^(?:card_?number|pan|cvc|cvv)$/i;
1345
+ var record7 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
1346
+ var own = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
1347
+ var keysAre = (value, keys) => {
1348
+ const names = Object.keys(value);
1349
+ return names.length === keys.length && names.every((name, at) => name === keys[at]);
1350
+ };
1351
+ var refuse10 = (code) => Object.freeze({ verdict: "refuse", code });
1352
+ var CARD9 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
1353
+ var CONTINUE4 = /* @__PURE__ */ Object.freeze({ verdict: "continue" });
1354
+ function paymongoCheckoutSession(url) {
1355
+ if (typeof url !== "string" || url.length > URL_LIMIT2 || url.includes("?") || url.includes("#"))
1356
+ return null;
1357
+ let parsed;
1358
+ try {
1359
+ parsed = new URL(url);
1360
+ }
1361
+ catch {
1362
+ return null;
1363
+ }
1364
+ if (parsed.href !== url || parsed.protocol !== "https:" || parsed.port || parsed.username || parsed.password || parsed.hostname !== PAYMONGO_CHECKOUT_HOST)
1365
+ return null;
1366
+ const match = CHECKOUT_PATH.exec(parsed.pathname);
1367
+ return match ? match[1] : null;
1368
+ }
1369
+ function readJson2(body) {
1370
+ if (typeof body !== "string" || body === "")
1371
+ return { parsed: null, exact: false };
1372
+ let parsed;
1373
+ try {
1374
+ parsed = JSON.parse(body);
1375
+ }
1376
+ catch {
1377
+ return { parsed: null, exact: false };
1378
+ }
1379
+ let exact2 = false;
1380
+ try {
1381
+ exact2 = body.length <= BODY_LIMIT6 && JSON.stringify(parsed) === body;
1382
+ }
1383
+ catch {
1384
+ exact2 = false;
1385
+ }
1386
+ return { parsed, exact: exact2 };
1387
+ }
1388
+ function billingValue(value) {
1389
+ if (value === UNDEFINED)
1390
+ return true;
1391
+ if (typeof value !== "string" || !TEXT.test(value))
1392
+ return false;
1393
+ return value[0] !== "$" || value.startsWith("$$");
1394
+ }
1395
+ function judgeCardAttach(args, session) {
1396
+ if (args.length !== 3 || typeof args[0] !== "string" || !args[0].startsWith("cs_") || !SESSION2.test(args[0].slice(3))) {
1397
+ return "paymongo_body_unsupported";
1398
+ }
1399
+ const id = args[0].slice(3);
1400
+ const attributes = args[1].data.attributes;
1401
+ const details = attributes.details;
1402
+ if (record7(details) && CLICK_TO_PAY_KEYS.some((key) => own(details, key)))
1403
+ return "paymongo_click_to_pay";
1404
+ if (!keysAre(args[1], ["data"]) || !keysAre(args[1].data, ["attributes"]) || !keysAre(attributes, PAYMONGO_ATTRIBUTE_KEYS) || !record7(details) || !keysAre(details, PAYMONGO_CARD_KEYS))
1405
+ return "paymongo_body_unsupported";
1406
+ if (typeof details.card_number !== "string" || !NUMBER.test(details.card_number) || !Number.isSafeInteger(details.exp_month) || details.exp_month < 1 || details.exp_month > 12 || !Number.isSafeInteger(details.exp_year) || details.exp_year < 0 || details.exp_year > 99 || typeof details.cvc !== "string" || !SECURITY_CODE6.test(details.cvc))
1407
+ return "paymongo_body_unsupported";
1408
+ const billing = attributes.billing;
1409
+ if (!record7(billing) || !keysAre(billing, PAYMONGO_BILLING_KEYS) || !record7(billing.address) || !keysAre(billing.address, PAYMONGO_ADDRESS_KEYS))
1410
+ return "paymongo_body_unsupported";
1411
+ if (billing.name === UNDEFINED || !billingValue(billing.name) || !billingValue(billing.email) || !billingValue(billing.phone) || !PAYMONGO_ADDRESS_KEYS.every((key) => billingValue(billing.address[key])))
1412
+ return "paymongo_body_unsupported";
1413
+ const third = args[2];
1414
+ if (!record7(third) || !keysAre(third, ["viewerAccept"]) || !billingValue(third.viewerAccept))
1415
+ return "paymongo_body_unsupported";
1416
+ if (attributes.return_url !== `${ORIGIN}${id}` || session !== void 0 && session !== id)
1417
+ return "paymongo_session_mismatch";
1418
+ return null;
1419
+ }
1420
+ function namesCardValue(parsed) {
1421
+ const pending = parsed !== null && typeof parsed === "object" ? [parsed] : [];
1422
+ while (pending.length > 0) {
1423
+ const node = pending.pop();
1424
+ for (const key of Object.keys(node)) {
1425
+ if (!Array.isArray(node) && CARD_MEMBER.test(key))
1426
+ return true;
1427
+ const value = node[key];
1428
+ if (value !== null && typeof value === "object")
1429
+ pending.push(value);
1430
+ }
1431
+ }
1432
+ return false;
1433
+ }
1434
+ function attachType(parsed) {
1435
+ if (!Array.isArray(parsed) || parsed.length < 2 || !record7(parsed[1]) || !record7(parsed[1].data) || !record7(parsed[1].data.attributes))
1436
+ return null;
1437
+ const type = parsed[1].data.attributes.payment_method_type;
1438
+ return typeof type === "string" ? type : null;
1439
+ }
1440
+ function paymongoBodyVerdict(body, session) {
1441
+ const { parsed, exact: exact2 } = readJson2(body);
1442
+ const type = parsed === null ? null : attachType(parsed);
1443
+ if (type !== "card") {
1444
+ if (parsed === null)
1445
+ return body === void 0 || body === null || body === "" ? CONTINUE4 : refuse10("paymongo_body_unsupported");
1446
+ return namesCardValue(parsed) ? refuse10("paymongo_body_unsupported") : CONTINUE4;
1447
+ }
1448
+ if (!exact2)
1449
+ return refuse10("paymongo_body_unsupported");
1450
+ const code = judgeCardAttach(parsed, session);
1451
+ return code === null ? CARD9 : refuse10(code);
1452
+ }
1322
1453
  // src/card-fields.js
1323
1454
  function processorGate(recognizer, url, body) {
1324
1455
  if (recognizer && recognizer.psp === LYRA_PSP)
@@ -1344,6 +1475,12 @@ function processorGate(recognizer, url, body) {
1344
1475
  return { verdict: "refuse", code: "paddle_tokenex_pay_unsupported" };
1345
1476
  return paddleTokenexBodyVerdict(body, target ? target.line : void 0);
1346
1477
  }
1478
+ if (recognizer && recognizer.psp === PAYMONGO_PSP) {
1479
+ const session = url !== void 0 ? paymongoCheckoutSession(url) : void 0;
1480
+ if (url !== void 0 && session === null)
1481
+ return { verdict: "refuse", code: "paymongo_url_refused" };
1482
+ return paymongoBodyVerdict(body, session);
1483
+ }
1347
1484
  if (recognizer && recognizer.psp === GRAVY_PSP)
1348
1485
  return gravyBodyVerdict(body);
1349
1486
  if (recognizer && recognizer.psp === MONERIS_PSP) {
@@ -1464,12 +1601,12 @@ var KEEP_ON_FILE_REFUSAL = "Refusing to pay: this Primer payment would keep the
1464
1601
  var UNSUPPORTED_SDK_REFUSAL = "Refusing to pay: this checkout uses a Primer SDK Agentcard does not support yet. Nothing was sent.";
1465
1602
  var NETWORK_MISMATCH_REFUSAL = "Refusing to pay: this Primer payment names a card network that is not your card's. Nothing was sent.";
1466
1603
  var FILL_REFUSAL = "Could not fill the card fields for Primer. Nothing was sent.";
1467
- var BODY_LIMIT6 = 16384;
1604
+ var BODY_LIMIT7 = 16384;
1468
1605
  var RESPONSE_LIMIT = 32768;
1469
1606
  var ROOT_KEYS4 = ["paymentInstrument", "userDescription", "tokenType", "paymentFlow"];
1470
1607
  var INSTRUMENT_KEYS = ["number", "cvv", "expirationMonth", "expirationYear", "cardholderName", "preferredNetwork"];
1471
1608
  var REQUIRED_INSTRUMENT_KEYS = ["number", "cvv", "expirationMonth", "expirationYear"];
1472
- var record7 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
1609
+ var record8 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
1473
1610
  var owns5 = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
1474
1611
  var exact = (pattern, value) => typeof value === "string" && pattern.exec(value)?.[0] === value;
1475
1612
  var text2 = (value, max) => typeof value === "string" && value.length <= max && !/[\u0000-\u001f\u007f]/.test(value);
@@ -1492,7 +1629,7 @@ function isPrimerTokenizeUrl(url, method = "POST") {
1492
1629
  return parsed.href === url && parsed.protocol === "https:" && !parsed.port && !parsed.username && !parsed.password && !parsed.search && !parsed.hash && PRIMER_PCI_HOSTS.includes(parsed.hostname) && parsed.pathname === PRIMER_TOKENIZE_PATH;
1493
1630
  }
1494
1631
  function judgeBody2(body) {
1495
- if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT6)
1632
+ if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT7)
1496
1633
  return null;
1497
1634
  let value;
1498
1635
  try {
@@ -1501,12 +1638,12 @@ function judgeBody2(body) {
1501
1638
  catch {
1502
1639
  return null;
1503
1640
  }
1504
- if (!record7(value) || !roundTrips(value, body))
1641
+ if (!record8(value) || !roundTrips(value, body))
1505
1642
  return null;
1506
1643
  if (!Object.keys(value).every((key) => ROOT_KEYS4.includes(key)) || !owns5(value, "paymentInstrument"))
1507
1644
  return null;
1508
1645
  const instrument = value.paymentInstrument;
1509
- if (!record7(instrument) || !Object.keys(instrument).every((key) => INSTRUMENT_KEYS.includes(key)) || !REQUIRED_INSTRUMENT_KEYS.every((key) => owns5(instrument, key)))
1646
+ if (!record8(instrument) || !Object.keys(instrument).every((key) => INSTRUMENT_KEYS.includes(key)) || !REQUIRED_INSTRUMENT_KEYS.every((key) => owns5(instrument, key)))
1510
1647
  return null;
1511
1648
  if (!digits(instrument.number, 12, 19) || !digits(instrument.cvv, 3, 4) || !exact(MONTH3, instrument.expirationMonth) || !exact(YEAR3, instrument.expirationYear))
1512
1649
  return null;
@@ -1534,7 +1671,7 @@ var CLIENT_TOKEN = /^[A-Za-z0-9._~+/=-]{16,4096}$/;
1534
1671
  var REQUEST_ID = /^[A-Za-z0-9-]{1,64}$/;
1535
1672
  var API_VERSION = /^2\.[0-9]{1,2}$/;
1536
1673
  function readHeaders(headers) {
1537
- if (!record7(headers))
1674
+ if (!record8(headers))
1538
1675
  return null;
1539
1676
  const folded = /* @__PURE__ */ new Map();
1540
1677
  for (const [name, value] of Object.entries(headers)) {
@@ -1581,7 +1718,7 @@ function onTokenizePath(url) {
1581
1718
  }
1582
1719
  }
1583
1720
  function primerTokenizeRefusal(request) {
1584
- if (!record7(request) || request.method !== "POST" || !isPrimerTokenizeUrl(request.url))
1721
+ if (!record8(request) || request.method !== "POST" || !isPrimerTokenizeUrl(request.url))
1585
1722
  return "unsupported";
1586
1723
  return headersRefusal(request.headers) ?? primerBodyRefusal(request.body);
1587
1724
  }
@@ -1596,7 +1733,7 @@ function primerCardOnFileRefusal(url, options, policy = PRIMER_SESSION_CARD_ON_F
1596
1733
  return "unsupported";
1597
1734
  if (new URL(url).hostname !== LIVE_PCI_HOST)
1598
1735
  return null;
1599
- return primerCardOnFileDisclosure(url, policy) && record7(options) && options.keepOnFile === true ? null : "keep_on_file";
1736
+ return primerCardOnFileDisclosure(url, policy) && record8(options) && options.keepOnFile === true ? null : "keep_on_file";
1600
1737
  }
1601
1738
  function primerRefusalMessage(reason) {
1602
1739
  if (reason === "keep_on_file")
@@ -1680,7 +1817,7 @@ function readAnswer(body) {
1680
1817
  return null;
1681
1818
  try {
1682
1819
  const value = JSON.parse(body);
1683
- return record7(value) ? value : null;
1820
+ return record8(value) ? value : null;
1684
1821
  }
1685
1822
  catch {
1686
1823
  return null;
@@ -1689,16 +1826,16 @@ function readAnswer(body) {
1689
1826
  var tokenValue = (value) => exact(TOKEN2, value) && !panLike(value);
1690
1827
  var optional = (value, key, check) => !owns5(value, key) || value[key] === null || check(value[key]);
1691
1828
  function cardDetails(data) {
1692
- if (!record7(data) || !exact(/^[0-9]{4}$/, data.last4Digits))
1829
+ if (!record8(data) || !exact(/^[0-9]{4}$/, data.last4Digits))
1693
1830
  return null;
1694
- if (!optional(data, "first6Digits", (v) => exact(/^[0-9]{6}$/, v)) || !optional(data, "expirationMonth", (v) => exact(RESPONSE_MONTH, v)) || !optional(data, "expirationYear", (v) => exact(RESPONSE_YEAR, v)) || !optional(data, "cardholderName", (v) => plain(v, 256)) || !optional(data, "network", (v) => exact(NETWORK_NAME, v)) || !optional(data, "isNetworkTokenized", (v) => typeof v === "boolean") || !optional(data, "binData", record7))
1831
+ if (!optional(data, "first6Digits", (v) => exact(/^[0-9]{6}$/, v)) || !optional(data, "expirationMonth", (v) => exact(RESPONSE_MONTH, v)) || !optional(data, "expirationYear", (v) => exact(RESPONSE_YEAR, v)) || !optional(data, "cardholderName", (v) => plain(v, 256)) || !optional(data, "network", (v) => exact(NETWORK_NAME, v)) || !optional(data, "isNetworkTokenized", (v) => typeof v === "boolean") || !optional(data, "binData", record8))
1695
1832
  return null;
1696
1833
  const safe = { last4Digits: data.last4Digits };
1697
1834
  for (const key of ["first6Digits", "expirationMonth", "expirationYear", "cardholderName", "network", "isNetworkTokenized"]) {
1698
1835
  if (owns5(data, key) && data[key] !== null)
1699
1836
  safe[key] = data[key];
1700
1837
  }
1701
- if (record7(data.binData)) {
1838
+ if (record8(data.binData)) {
1702
1839
  const bin = {};
1703
1840
  for (const key of BIN_KEYS) {
1704
1841
  if (!owns5(data.binData, key) || data.binData[key] === null)
@@ -1714,7 +1851,7 @@ function cardDetails(data) {
1714
1851
  function threeDsSummary(value) {
1715
1852
  if (value === void 0 || value === null)
1716
1853
  return null;
1717
- if (!record7(value) || !exact(CODE, value.responseCode) || !optional(value, "reasonCode", (v) => exact(CODE, v)) || !optional(value, "reasonText", (v) => plain(v, 256)) || !optional(value, "protocolVersion", (v) => v === "" || exact(PROTOCOL, v)) || !optional(value, "challengeIssued", (v) => typeof v === "boolean"))
1854
+ if (!record8(value) || !exact(CODE, value.responseCode) || !optional(value, "reasonCode", (v) => exact(CODE, v)) || !optional(value, "reasonText", (v) => plain(v, 256)) || !optional(value, "protocolVersion", (v) => v === "" || exact(PROTOCOL, v)) || !optional(value, "challengeIssued", (v) => typeof v === "boolean"))
1718
1855
  return void 0;
1719
1856
  const safe = { responseCode: value.responseCode };
1720
1857
  for (const key of ["reasonCode", "reasonText", "protocolVersion", "challengeIssued"]) {
@@ -1742,7 +1879,7 @@ function rebuildToken(value) {
1742
1879
  }
1743
1880
  function primerErrorId(body) {
1744
1881
  const value = readAnswer(body);
1745
- const id = value && record7(value.error) ? value.error.errorId : null;
1882
+ const id = value && record8(value.error) ? value.error.errorId : null;
1746
1883
  return exact(ERROR_ID, id) && !panLike(id) ? id : null;
1747
1884
  }
1748
1885
  function matchesCard(details, card) {
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
2
  // Generated from @agent-cards/payment-core. Do not edit.
3
- // artifact-sha256: ce4887768a0ee59bbca5f329bce47a2831a24b06d7bea1d5517335f7afad75e0
3
+ // artifact-sha256: 3e73afac7d2a16c36e81a7ddca5ea143be4880e056cb31558d31d3d4d72d84b1
4
4
  // src/deep-freeze.js
5
5
  function deepFreeze(value) {
6
6
  if (value && typeof value === "object" && !Object.isFrozen(value)) {
@@ -1685,6 +1685,36 @@ var PROCESSOR_DEFINITIONS = deepFreeze([
1685
1685
  preparationRequired: true,
1686
1686
  encoding: "json",
1687
1687
  passthroughHeaders: ["^authorization$", "^x-wix-client-artifact-id$", "^commonconfig$", "^x-wix-brand$", "^consent-policy$", "^x-wix-linguist$"]
1688
+ },
1689
+ {
1690
+ psp: "paymongo",
1691
+ // PayMongo's hosted checkout (Philippines) at checkout.paymongo.com/<session>, which every PayMongo
1692
+ // payment link, Storefront page, Shopify hosted app, WooCommerce hosted plugin and Checkout Session
1693
+ // API opens. The card form's Pay click runs the page's Next.js Server Action attachCheckout: a POST
1694
+ // to the page's own URL under its Next-Action id, Accept text/x-component, the body React's
1695
+ // encodeReply writes as text/plain: [session, {data: {attributes: {payment_method_type: "card",
1696
+ // details: {card_number, exp_month, exp_year, cvc}, billing, return_url}}}, {viewerAccept}].
1697
+ // Unencrypted. The request names no amount: the session bound its line items (always PHP) when the
1698
+ // merchant created it. paymongo.js holds the rule the pause decision reads: the exact URL, the Server
1699
+ // Action's headers, and the card form's attach for that URL's session, key by key, with a Click to Pay
1700
+ // attach and any other card shape refused. Every other action of the page (polling, fees, another
1701
+ // method's attach) carries no card on the same URL and continues untouched (passWithoutCard). Next
1702
+ // refuses an action whose Origin names another host, and the page answers no other origin's preflight,
1703
+ // so the card leaves only through the checkout relay. 3-D Secure follows the answer on
1704
+ // secure-authentication.paymongo.com with no card. Test mode and live mode share the host (a session's
1705
+ // livemode, not its host, separates them), so no sandbox host is marked.
1706
+ // Ships dark: served only to a client that declares `paymongo_checkout_pay`, gated off for every org
1707
+ // until an operator lists one (`paymongo:<org>`), and autopilot never sends this request
1708
+ // (autopilot.js DEVICE_REPLAY_REFUSED_OPERATIONS).
1709
+ capability: "paymongo_checkout_pay",
1710
+ match: "checkout\\.paymongo\\.com/(?:cs_)?[A-Za-z0-9]{24}",
1711
+ hosts: ["^checkout\\.paymongo\\.com$"],
1712
+ encoding: "json",
1713
+ // Next answers a Server Action only under its id, renders with the page's router state, and the page
1714
+ // reads the answer only as an RSC stream. Origin, Referer and cookies never ride (none is needed).
1715
+ passthroughHeaders: ["^next-action$", "^next-router-state-tree$", "^accept$"],
1716
+ jsonCardFields: [[1, "data", "attributes", "details", "card_number"]],
1717
+ passWithoutCard: "checkout\\.paymongo\\.com/(?:cs_)?[A-Za-z0-9]{24}"
1688
1718
  }
1689
1719
  ]);
1690
1720
  var PSP_RECOGNIZERS = deepFreeze(PROCESSOR_DEFINITIONS.map(({ compose, encryptedCardFields, deviceSteps, deviceEncrypt, ...definition }) => definition));
@@ -1807,6 +1837,19 @@ var PAYFAST_PAY_HOSTS = /* @__PURE__ */ Object.freeze({
1807
1837
  production: Object.freeze(["payment.payfast.io", "www.payfast.co.za"]),
1808
1838
  sandbox: Object.freeze(["sandbox.payfast.co.za"])
1809
1839
  });
1840
+ var PAYFAST_BODY_KEYS = /* @__PURE__ */ Object.freeze([
1841
+ "card_number",
1842
+ "cardholder_name",
1843
+ "consent_check",
1844
+ "cvv",
1845
+ "expiry_month",
1846
+ "expiry_year",
1847
+ "g-recaptcha-response",
1848
+ "captcha_version",
1849
+ "captcha_action"
1850
+ ]);
1851
+ var CAPTCHA_ANSWER = "g-recaptcha-response";
1852
+ var UNANSWERED_KEYS = /* @__PURE__ */ Object.freeze(PAYFAST_BODY_KEYS.filter((key) => key !== CAPTCHA_ANSWER));
1810
1853
  // src/rsa-pkcs1v15.js
1811
1854
  var TYPED_ARRAY = Object.getPrototypeOf(Uint8Array.prototype);
1812
1855
  var typedArrayName = Object.getOwnPropertyDescriptor(TYPED_ARRAY, Symbol.toStringTag).get;
@@ -1849,6 +1892,9 @@ var WIX_PAYMENTS_MERCHANT_PINS = /* @__PURE__ */ Object.freeze([
1849
1892
  pin3({ id: "psalms_and_potions", merchant: "Psalms & Potions", origins: ["https://www.psalmsandpotions.com"] }),
1850
1893
  pin3({ id: "alexandra_hagel", merchant: "Alexandra Hagel, LLC", origins: ["https://www.alexandrahagel.com"] })
1851
1894
  ]);
1895
+ // src/paymongo.js
1896
+ var PAYMONGO_CHECKOUT_HOST = "checkout.paymongo.com";
1897
+ var ORIGIN = `https://${PAYMONGO_CHECKOUT_HOST}/`;
1852
1898
  // src/cybersource-secure-acceptance.js
1853
1899
  var SA_BODY_LIMIT = 32 * 1024;
1854
1900
  var SA_REPLY_LIMIT = 64 * 1024;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-cards/sdk",
3
- "version": "0.23.15",
3
+ "version": "0.23.16",
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",