@agent-cards/sdk 0.23.15 → 0.23.17

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
@@ -2,6 +2,8 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ - Finish a Worldpay eProtect checkout that your code resumes itself. With `attachToCdp(…, { pauseOnly: true })`, you create the authorization, read it, and call `controller.resume(read)`. The read carries the card registration as Agentcard stored it, bare JSON, and earlier releases handed exactly that to the merchant's paused registration script. Worldpay's script reads its answer only through the callback the request named, so it never received the registration: the page waited until the merchant's timeout, and the checkout read `outcome_unknown` with reason `merchant_request_aborted` after the cardholder had approved. The SDK now answers the resumed registration as it answers one it created itself, with the registration inside the request's own callback under Worldpay's script type. The SDK never hands the page a read that is not this request's registration, such as one already inside a callback or another request's answer: `resume` rejects with `PaymentOutcomeUnknownError`, reason `eprotect_registration_unconfirmed`, and the paused request fails. A checkout whose authorization the SDK creates was already answered this way and does not change. No API or Vault release is needed.
6
+
5
7
  - Refuse a sandbox declaration whose endpoint is on agentcard.com, Agentcard's own domain, as one on agentcard.sh is already refused. A `sandboxMerchants` entry on `VaultClient` whose endpoint is agentcard.com or any host under it makes the constructor throw:
6
8
 
7
9
  ```text
@@ -14,6 +16,8 @@
14
16
 
15
17
  - 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
18
 
19
+ - 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.
20
+
17
21
  - 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
22
  - 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
23
  - 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.
@@ -139,6 +143,8 @@
139
143
 
140
144
  - Pay a Wix checkout whose card goes to Wix's own tokenizer, from Agentcard's own account only for now (dark launch): Agentcard turns it on for another company once it checks that the site instance Wix's card frame sends belongs to the reviewed store. Every Wix checkout mounts Wix Cashier's card frame, and for Wix Payments and classic Stripe on Wix that frame posts the card to `https://cashier-pci.wixapps.net/_api/payment-gateway-web/tokenize/v2/tokens`. Wix's payment widget fails the payment 30 seconds after it asks the frame for a token, too soon for an approval after Pay, so the SDK pays a Wix checkout only through `prepare({ psp: 'wix_payments', environment: 'production' })`, at a store Agentcard reviewed (ParaHouse Magazine, Psalms & Potions and Alexandra Hagel today), with `amount` and `currency`, the total the cardholder approves: the request names none. Wix has no test environment, so a test client's `prepare()` fails with `live_host_on_sandbox_row`. The sync now also asks for `capabilities=wix_payments_tokenize`. Once the cardholder approves, the frame's request pauses, the cardholder's device sends the card through the checkout relay, and the frame receives Wix's token. The frame sends its card request once more under a fresh site instance after Wix answers 401 or 403: the SDK refuses that second request in the browser and never answers it from the first approval. The SDK fails a paused request the cardholder's device has not sent 20 seconds after the pause, of the 30 seconds Wix waits, with reason `wix_payments_send_window_closed`, as it fails a prepared Secure Acceptance token create, and the device sends nothing past its own earlier boundary.
141
145
 
146
+ - Keep a GoPay card form's token out of your events and error messages. GoPay's card frame sends the card to its own URL, `https://secure.gopay.com/gp-card-comm/h/<token>?lang=..&ver=..&SG=<signature>`, and that token, with the signature in the query, opens that payment's card form to anyone who holds it. `redactUrl`, every event and every error message now show it as `{token}` on GoPay's card frame hosts, as in `https://secure.gopay.com/gp-card-comm/h/{token}`, and drop the query as before. The SDK does not pause a GoPay payment yet. No API or Vault release is needed.
147
+
142
148
  ## 0.23.0
143
149
 
144
150
  ### Upgrading from 0.22.0
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: 0fcc0e758acec92fba9d21092bcb3704b8a73ec864647ea194ca44eba57cb96d
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,230 @@ 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
+ }
1445
+ // src/gopay.js
1446
+ var GOPAY_PSP = "gopay";
1447
+ var GOPAY_CARD_FORM_HOSTS = /* @__PURE__ */ Object.freeze({ "secure.gopay.com": "production", "secure.sandbox.gopay.com": "test" });
1448
+ var GOPAY_CARD_FORM_PATH = "/gp-card-comm/h/";
1449
+ var BODY_LIMIT7 = 1024;
1450
+ var ROOT_KEYS4 = /* @__PURE__ */ Object.freeze(["SG", "cardData", "type"]);
1451
+ var CARD_KEYS6 = /* @__PURE__ */ Object.freeze(["cardNumber", "cvc", "expiration"]);
1452
+ var TOKEN2 = /^[0-9A-Fa-f]{16,1024}$/;
1453
+ var SIGNATURE = /^[0-9A-Fa-f]{64}$/;
1454
+ var LANGUAGE = /^[a-z]{2}(?:-[A-Za-z]{2})?$/;
1455
+ var VERSION = /^[A-Za-z0-9]{1,16}$/;
1456
+ var QUERY_NAMES = /* @__PURE__ */ Object.freeze(["lang", "ver", "SG"]);
1457
+ var CARD_NUMBER7 = /^[0-9]{16}$/;
1458
+ var CODE = /^[0-9]{3}$/;
1459
+ var EXPIRATION = /^[0-9]{2}(?:0[1-9]|1[0-2])$/;
1460
+ var CARD_PAYMENT = "PAYMENT_CARD";
1461
+ var record8 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
1462
+ var sameKeys4 = (value, keys) => {
1463
+ const own2 = Object.keys(value);
1464
+ return own2.length === keys.length && own2.every((key, at) => key === keys[at]);
1465
+ };
1466
+ var refuse11 = (code) => Object.freeze({ verdict: "refuse", code });
1467
+ var CARD10 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
1468
+ function luhn(digits) {
1469
+ let sum = 0;
1470
+ for (let at = 0; at < digits.length; at += 1) {
1471
+ let digit = Number(digits[digits.length - 1 - at]);
1472
+ if (at % 2 === 1) {
1473
+ digit *= 2;
1474
+ if (digit > 9)
1475
+ digit -= 9;
1476
+ }
1477
+ sum += digit;
1478
+ }
1479
+ return sum % 10 === 0;
1480
+ }
1481
+ function gopayCardFormUrl(url) {
1482
+ if (typeof url !== "string" || url.length > 2048 || url.includes("#"))
1483
+ return null;
1484
+ let parsed;
1485
+ try {
1486
+ parsed = new URL(url);
1487
+ }
1488
+ catch {
1489
+ return null;
1490
+ }
1491
+ if (parsed.href !== url || parsed.protocol !== "https:" || parsed.port || parsed.username || parsed.password)
1492
+ return null;
1493
+ const environment = Object.prototype.hasOwnProperty.call(GOPAY_CARD_FORM_HOSTS, parsed.hostname) ? GOPAY_CARD_FORM_HOSTS[parsed.hostname] : null;
1494
+ if (environment === null || !parsed.pathname.startsWith(GOPAY_CARD_FORM_PATH))
1495
+ return null;
1496
+ if (!TOKEN2.test(parsed.pathname.slice(GOPAY_CARD_FORM_PATH.length)))
1497
+ return null;
1498
+ const names = [...parsed.searchParams.keys()];
1499
+ if (names.some((name) => !QUERY_NAMES.includes(name)) || new Set(names).size !== names.length)
1500
+ return null;
1501
+ const signature = parsed.searchParams.get("SG");
1502
+ const language = parsed.searchParams.get("lang");
1503
+ const version = parsed.searchParams.get("ver");
1504
+ if (signature === null || !SIGNATURE.test(signature) || language !== null && !LANGUAGE.test(language) || version !== null && !VERSION.test(version))
1505
+ return null;
1506
+ return Object.freeze({ host: parsed.hostname, environment, signature });
1507
+ }
1508
+ function readBody4(body) {
1509
+ if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT7)
1510
+ return null;
1511
+ let value;
1512
+ try {
1513
+ value = JSON.parse(body);
1514
+ if (!record8(value) || JSON.stringify(value) !== body)
1515
+ return null;
1516
+ }
1517
+ catch {
1518
+ return null;
1519
+ }
1520
+ return value;
1521
+ }
1522
+ function gopayBodyVerdict(body, url) {
1523
+ let target;
1524
+ if (url !== void 0) {
1525
+ target = gopayCardFormUrl(url);
1526
+ if (target === null)
1527
+ return refuse11("gopay_url_refused");
1528
+ }
1529
+ const value = readBody4(body);
1530
+ if (value === null || !sameKeys4(value, ROOT_KEYS4) || !record8(value.cardData) || !sameKeys4(value.cardData, CARD_KEYS6)) {
1531
+ return refuse11("gopay_body_unsupported");
1532
+ }
1533
+ const card = value.cardData;
1534
+ if (typeof value.SG !== "string" || !SIGNATURE.test(value.SG) || typeof card.cardNumber !== "string" || !CARD_NUMBER7.test(card.cardNumber) || !luhn(card.cardNumber) || typeof card.cvc !== "string" || !CODE.test(card.cvc) || typeof card.expiration !== "string" || !EXPIRATION.test(card.expiration) || typeof value.type !== "string") {
1535
+ return refuse11("gopay_body_unsupported");
1536
+ }
1537
+ if (value.type !== CARD_PAYMENT)
1538
+ return refuse11("gopay_card_saving_refused");
1539
+ if (target !== void 0 && value.SG !== target.signature)
1540
+ return refuse11("gopay_signature_mismatch");
1541
+ return CARD10;
1542
+ }
1314
1543
  // src/card-fields.js
1315
1544
  function processorGate(recognizer, url, body) {
1316
1545
  if (recognizer && recognizer.psp === LYRA_PSP)
@@ -1336,6 +1565,14 @@ function processorGate(recognizer, url, body) {
1336
1565
  return { verdict: "refuse", code: "paddle_tokenex_pay_unsupported" };
1337
1566
  return paddleTokenexBodyVerdict(body, target ? target.line : void 0);
1338
1567
  }
1568
+ if (recognizer && recognizer.psp === PAYMONGO_PSP) {
1569
+ const session = url !== void 0 ? paymongoCheckoutSession(url) : void 0;
1570
+ if (url !== void 0 && session === null)
1571
+ return { verdict: "refuse", code: "paymongo_url_refused" };
1572
+ return paymongoBodyVerdict(body, session);
1573
+ }
1574
+ if (recognizer && recognizer.psp === GOPAY_PSP)
1575
+ return gopayBodyVerdict(body, url);
1339
1576
  if (recognizer && recognizer.psp === GRAVY_PSP)
1340
1577
  return gravyBodyVerdict(body);
1341
1578
  if (recognizer && recognizer.psp === MONERIS_PSP) {
@@ -1453,7 +1690,7 @@ function splitCardLeg(recognizer, body) {
1453
1690
  const absorb = list(split.absorb);
1454
1691
  const pass = list(split.pass);
1455
1692
  const sibling = list(split.siblingKeys);
1456
- const own = [];
1693
+ const own2 = [];
1457
1694
  const seen = /* @__PURE__ */ new Set();
1458
1695
  for (const chunk of body.split("&")) {
1459
1696
  const eq = chunk.indexOf("=");
@@ -1470,13 +1707,13 @@ function splitCardLeg(recognizer, body) {
1470
1707
  return null;
1471
1708
  seen.add(key);
1472
1709
  if (!sibling.includes(key))
1473
- own.push(key);
1710
+ own2.push(key);
1474
1711
  }
1475
- if (own.length === 0)
1712
+ if (own2.length === 0)
1476
1713
  return null;
1477
- if (own.every((key) => absorb.includes(key)))
1714
+ if (own2.every((key) => absorb.includes(key)))
1478
1715
  return "absorb";
1479
- if (own.every((key) => pass.includes(key)))
1716
+ if (own2.every((key) => pass.includes(key)))
1480
1717
  return "pass";
1481
1718
  return null;
1482
1719
  }
package/dist/cdp.js CHANGED
@@ -7,7 +7,7 @@ import { MercadoCheckoutGate } from './mercado-checkout.js';
7
7
  import { MERCADO_CHECKOUT_PATTERN } from './mercado-checkout.generated.js';
8
8
  import { JuspayCheckoutGate } from './juspay-gate.js';
9
9
  import { ACI_CHECKOUT_REUSED, AciGate, playwrightReplacesNavigationBody } from './aci.js';
10
- import { EprotectGate } from './eprotect.js';
10
+ import { EprotectGate, classifyEprotectRequest, eprotectScriptAnswer } from './eprotect.js';
11
11
  import { dispatchPreClaim, eventUrl, isArmedCreditguardCall } from './pre-claim.js';
12
12
  import { GMO_TOKEN_V1_PATTERNS, gmoRequestShop, isGmoTokenV1Request, recognizesGmo } from './gmo.js';
13
13
  import { isPaddleVgsCardsUrl } from './paddle-vgs.generated.js';
@@ -1549,6 +1549,23 @@ function replayOf(result, timeoutMs) {
1549
1549
  return { mode: 'token', authorizationId, status: response.status, headers: { ...response.headers }, body: response.body, amountVerified: null,
1550
1550
  ...(result.processor_context !== undefined ? { processorContext: result.processor_context } : {}), ...execution };
1551
1551
  }
1552
+ /**
1553
+ * Worldpay eProtect's registration, resumed by the business. The read carries the registration as the API
1554
+ * stored it, bare JSON, and the paused request is the vendor's JSONP <script>, which runs its answer and reads
1555
+ * the registration only through the callback the paused URL named. So it gets the answer authorize() gives on
1556
+ * the create path (client.ts): the registration inside that callback, under Worldpay's script type, and only a
1557
+ * registration payment-core's judge accepts for that URL. A read in any other mode never answers it either. The
1558
+ * paused URL alone decides, whatever recognizer claimed it. Any other request's replay passes as it came, and a
1559
+ * create's replay never comes here, so no answer is wrapped twice.
1560
+ */
1561
+ function eprotectResumedReplay(replay, request) {
1562
+ if (classifyEprotectRequest(request.url, request.method)?.kind !== 'registration')
1563
+ return replay;
1564
+ const answer = replay.mode === 'token' ? eprotectScriptAnswer(request.url, replay) : null;
1565
+ if (replay.mode !== 'token' || !answer)
1566
+ throw new PaymentOutcomeUnknownError(replay.authorizationId, 'eprotect_registration_unconfirmed');
1567
+ return { ...replay, status: answer.status, headers: answer.headers, body: answer.body };
1568
+ }
1552
1569
  /** The recogniser that claimed a paused request, by processor name, so a caller never re-matches the URL; null on a duck-typed vault without the read. */
1553
1570
  function recognizerNameOf(opts, url, method) {
1554
1571
  const read = opts.vault.recognizerOf;
@@ -2763,7 +2780,7 @@ export async function attachToCdp(cdp, pageSessionId, opts) {
2763
2780
  // through controller.resume; the replay it hands back goes down the same delivery path as a create's.
2764
2781
  const pause = opts.pauseOnly ? pauseForBusiness(opts, lifecycle, attempt.signal, { url: request.url, method: request.method, headers: request.headers ?? {}, body }, pageOrigin) : null;
2765
2782
  businessPause = pause;
2766
- const replay = pause ? await pause.replay : await opts.vault.authorize({
2783
+ const replay = pause ? eprotectResumedReplay(await pause.replay, request) : await opts.vault.authorize({
2767
2784
  user: opts.user,
2768
2785
  merchant: opts.merchant,
2769
2786
  amount: opts.amount,
package/dist/client.d.ts CHANGED
@@ -1174,6 +1174,8 @@ 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}.
1178
+ * On GoPay's card frame hosts the card form's token reads `{token}`: https://secure.gopay.com/gp-card-comm/h/{token}.
1177
1179
  * A string that is not a URL keeps the part before any `?` or `#`, with the
1178
1180
  * same segments masked.
1179
1181
  */
package/dist/client.js CHANGED
@@ -1102,6 +1102,31 @@ 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
+ }
1118
+ /**
1119
+ * GoPay's card frame posts the card to its own URL,
1120
+ * https://secure.gopay.com/gp-card-comm/h/<hex token>?lang=..&ver=..&SG=<64 hex> (payment-core gopay.js). The
1121
+ * token names that payment's card form, and with the SG, which redactUrl drops with the query, anyone who holds
1122
+ * the URL can open the form and post a card to it. On GoPay's two card frame hosts the segment after /h/, in any
1123
+ * case or after an escaped slash, reads {token}: https://secure.gopay.com/gp-card-comm/h/{token}.
1124
+ */
1125
+ const GOPAY_CARD_FORM_HOST = /^secure(?:\.sandbox)?\.gopay\.com\.?$/i;
1126
+ const GOPAY_CARD_FORM_TOKEN = /(\/h(?:\/|%2f))[^/?#]*/gi;
1127
+ function maskGopayToken(path) {
1128
+ return path.replace(GOPAY_CARD_FORM_TOKEN, '$1{token}');
1129
+ }
1105
1130
  /**
1106
1131
  * The processors whose card request carries its own credential in the URL path, with the hosts
1107
1132
  * that send it, the text that names those hosts in a string that is not a URL, and the mask. The
@@ -1141,6 +1166,8 @@ const PATH_CREDENTIALS = [
1141
1166
  { host: REDSYS_HOST, named: /redsys\.es/i, mask: maskRedsysSession },
1142
1167
  { host: LYRA_HOST, named: /(?:payzen\.eu|systempay\.fr|societegenerale\.eu|lyra\.com)/i, mask: maskLyraSession },
1143
1168
  { host: PAYPAL_HOST, named: /paypal\.com/i, mask: maskPaypalOrder },
1169
+ { host: PAYMONGO_CHECKOUT_HOST, named: /checkout\.paymongo\.com/i, mask: maskPaymongoSession },
1170
+ { host: GOPAY_CARD_FORM_HOST, named: /secure(?:\.sandbox)?\.gopay\.com/i, mask: maskGopayToken },
1144
1171
  ];
1145
1172
  /**
1146
1173
  * A URL as it may appear in an error message: origin + path only. A paused
@@ -1163,6 +1190,8 @@ const PATH_CREDENTIALS = [
1163
1190
  * On Lyra's API hosts the form token's session id reads `{session}`.
1164
1191
  * On PayPal's hosts an order id reads `{order}`:
1165
1192
  * https://www.paypal.com/v2/checkout/orders/{order}/confirm-payment-source.
1193
+ * On PayMongo's checkout host the session id reads `{session}`: https://checkout.paymongo.com/{session}.
1194
+ * On GoPay's card frame hosts the card form's token reads `{token}`: https://secure.gopay.com/gp-card-comm/h/{token}.
1166
1195
  * A string that is not a URL keeps the part before any `?` or `#`, with the
1167
1196
  * same segments masked.
1168
1197
  */
@@ -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: c3b720efaa20837c1bf50cc511610282f324867e9fe5538ac155b2ff79f2d9b4
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,230 @@ 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
+ }
1453
+ // src/gopay.js
1454
+ var GOPAY_PSP = "gopay";
1455
+ var GOPAY_CARD_FORM_HOSTS = /* @__PURE__ */ Object.freeze({ "secure.gopay.com": "production", "secure.sandbox.gopay.com": "test" });
1456
+ var GOPAY_CARD_FORM_PATH = "/gp-card-comm/h/";
1457
+ var BODY_LIMIT7 = 1024;
1458
+ var ROOT_KEYS4 = /* @__PURE__ */ Object.freeze(["SG", "cardData", "type"]);
1459
+ var CARD_KEYS6 = /* @__PURE__ */ Object.freeze(["cardNumber", "cvc", "expiration"]);
1460
+ var TOKEN2 = /^[0-9A-Fa-f]{16,1024}$/;
1461
+ var SIGNATURE = /^[0-9A-Fa-f]{64}$/;
1462
+ var LANGUAGE = /^[a-z]{2}(?:-[A-Za-z]{2})?$/;
1463
+ var VERSION = /^[A-Za-z0-9]{1,16}$/;
1464
+ var QUERY_NAMES = /* @__PURE__ */ Object.freeze(["lang", "ver", "SG"]);
1465
+ var CARD_NUMBER7 = /^[0-9]{16}$/;
1466
+ var CODE = /^[0-9]{3}$/;
1467
+ var EXPIRATION = /^[0-9]{2}(?:0[1-9]|1[0-2])$/;
1468
+ var CARD_PAYMENT = "PAYMENT_CARD";
1469
+ var record8 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
1470
+ var sameKeys4 = (value, keys) => {
1471
+ const own2 = Object.keys(value);
1472
+ return own2.length === keys.length && own2.every((key, at) => key === keys[at]);
1473
+ };
1474
+ var refuse11 = (code) => Object.freeze({ verdict: "refuse", code });
1475
+ var CARD10 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
1476
+ function luhn(digits2) {
1477
+ let sum = 0;
1478
+ for (let at = 0; at < digits2.length; at += 1) {
1479
+ let digit = Number(digits2[digits2.length - 1 - at]);
1480
+ if (at % 2 === 1) {
1481
+ digit *= 2;
1482
+ if (digit > 9)
1483
+ digit -= 9;
1484
+ }
1485
+ sum += digit;
1486
+ }
1487
+ return sum % 10 === 0;
1488
+ }
1489
+ function gopayCardFormUrl(url) {
1490
+ if (typeof url !== "string" || url.length > 2048 || url.includes("#"))
1491
+ return null;
1492
+ let parsed;
1493
+ try {
1494
+ parsed = new URL(url);
1495
+ }
1496
+ catch {
1497
+ return null;
1498
+ }
1499
+ if (parsed.href !== url || parsed.protocol !== "https:" || parsed.port || parsed.username || parsed.password)
1500
+ return null;
1501
+ const environment = Object.prototype.hasOwnProperty.call(GOPAY_CARD_FORM_HOSTS, parsed.hostname) ? GOPAY_CARD_FORM_HOSTS[parsed.hostname] : null;
1502
+ if (environment === null || !parsed.pathname.startsWith(GOPAY_CARD_FORM_PATH))
1503
+ return null;
1504
+ if (!TOKEN2.test(parsed.pathname.slice(GOPAY_CARD_FORM_PATH.length)))
1505
+ return null;
1506
+ const names = [...parsed.searchParams.keys()];
1507
+ if (names.some((name) => !QUERY_NAMES.includes(name)) || new Set(names).size !== names.length)
1508
+ return null;
1509
+ const signature = parsed.searchParams.get("SG");
1510
+ const language = parsed.searchParams.get("lang");
1511
+ const version = parsed.searchParams.get("ver");
1512
+ if (signature === null || !SIGNATURE.test(signature) || language !== null && !LANGUAGE.test(language) || version !== null && !VERSION.test(version))
1513
+ return null;
1514
+ return Object.freeze({ host: parsed.hostname, environment, signature });
1515
+ }
1516
+ function readBody4(body) {
1517
+ if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT7)
1518
+ return null;
1519
+ let value;
1520
+ try {
1521
+ value = JSON.parse(body);
1522
+ if (!record8(value) || JSON.stringify(value) !== body)
1523
+ return null;
1524
+ }
1525
+ catch {
1526
+ return null;
1527
+ }
1528
+ return value;
1529
+ }
1530
+ function gopayBodyVerdict(body, url) {
1531
+ let target;
1532
+ if (url !== void 0) {
1533
+ target = gopayCardFormUrl(url);
1534
+ if (target === null)
1535
+ return refuse11("gopay_url_refused");
1536
+ }
1537
+ const value = readBody4(body);
1538
+ if (value === null || !sameKeys4(value, ROOT_KEYS4) || !record8(value.cardData) || !sameKeys4(value.cardData, CARD_KEYS6)) {
1539
+ return refuse11("gopay_body_unsupported");
1540
+ }
1541
+ const card = value.cardData;
1542
+ if (typeof value.SG !== "string" || !SIGNATURE.test(value.SG) || typeof card.cardNumber !== "string" || !CARD_NUMBER7.test(card.cardNumber) || !luhn(card.cardNumber) || typeof card.cvc !== "string" || !CODE.test(card.cvc) || typeof card.expiration !== "string" || !EXPIRATION.test(card.expiration) || typeof value.type !== "string") {
1543
+ return refuse11("gopay_body_unsupported");
1544
+ }
1545
+ if (value.type !== CARD_PAYMENT)
1546
+ return refuse11("gopay_card_saving_refused");
1547
+ if (target !== void 0 && value.SG !== target.signature)
1548
+ return refuse11("gopay_signature_mismatch");
1549
+ return CARD10;
1550
+ }
1322
1551
  // src/card-fields.js
1323
1552
  function processorGate(recognizer, url, body) {
1324
1553
  if (recognizer && recognizer.psp === LYRA_PSP)
@@ -1344,6 +1573,14 @@ function processorGate(recognizer, url, body) {
1344
1573
  return { verdict: "refuse", code: "paddle_tokenex_pay_unsupported" };
1345
1574
  return paddleTokenexBodyVerdict(body, target ? target.line : void 0);
1346
1575
  }
1576
+ if (recognizer && recognizer.psp === PAYMONGO_PSP) {
1577
+ const session = url !== void 0 ? paymongoCheckoutSession(url) : void 0;
1578
+ if (url !== void 0 && session === null)
1579
+ return { verdict: "refuse", code: "paymongo_url_refused" };
1580
+ return paymongoBodyVerdict(body, session);
1581
+ }
1582
+ if (recognizer && recognizer.psp === GOPAY_PSP)
1583
+ return gopayBodyVerdict(body, url);
1347
1584
  if (recognizer && recognizer.psp === GRAVY_PSP)
1348
1585
  return gravyBodyVerdict(body);
1349
1586
  if (recognizer && recognizer.psp === MONERIS_PSP) {
@@ -1464,12 +1701,12 @@ var KEEP_ON_FILE_REFUSAL = "Refusing to pay: this Primer payment would keep the
1464
1701
  var UNSUPPORTED_SDK_REFUSAL = "Refusing to pay: this checkout uses a Primer SDK Agentcard does not support yet. Nothing was sent.";
1465
1702
  var NETWORK_MISMATCH_REFUSAL = "Refusing to pay: this Primer payment names a card network that is not your card's. Nothing was sent.";
1466
1703
  var FILL_REFUSAL = "Could not fill the card fields for Primer. Nothing was sent.";
1467
- var BODY_LIMIT6 = 16384;
1704
+ var BODY_LIMIT8 = 16384;
1468
1705
  var RESPONSE_LIMIT = 32768;
1469
- var ROOT_KEYS4 = ["paymentInstrument", "userDescription", "tokenType", "paymentFlow"];
1706
+ var ROOT_KEYS5 = ["paymentInstrument", "userDescription", "tokenType", "paymentFlow"];
1470
1707
  var INSTRUMENT_KEYS = ["number", "cvv", "expirationMonth", "expirationYear", "cardholderName", "preferredNetwork"];
1471
1708
  var REQUIRED_INSTRUMENT_KEYS = ["number", "cvv", "expirationMonth", "expirationYear"];
1472
- var record7 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
1709
+ var record9 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
1473
1710
  var owns5 = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
1474
1711
  var exact = (pattern, value) => typeof value === "string" && pattern.exec(value)?.[0] === value;
1475
1712
  var text2 = (value, max) => typeof value === "string" && value.length <= max && !/[\u0000-\u001f\u007f]/.test(value);
@@ -1492,7 +1729,7 @@ function isPrimerTokenizeUrl(url, method = "POST") {
1492
1729
  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
1730
  }
1494
1731
  function judgeBody2(body) {
1495
- if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT6)
1732
+ if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT8)
1496
1733
  return null;
1497
1734
  let value;
1498
1735
  try {
@@ -1501,12 +1738,12 @@ function judgeBody2(body) {
1501
1738
  catch {
1502
1739
  return null;
1503
1740
  }
1504
- if (!record7(value) || !roundTrips(value, body))
1741
+ if (!record9(value) || !roundTrips(value, body))
1505
1742
  return null;
1506
- if (!Object.keys(value).every((key) => ROOT_KEYS4.includes(key)) || !owns5(value, "paymentInstrument"))
1743
+ if (!Object.keys(value).every((key) => ROOT_KEYS5.includes(key)) || !owns5(value, "paymentInstrument"))
1507
1744
  return null;
1508
1745
  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)))
1746
+ if (!record9(instrument) || !Object.keys(instrument).every((key) => INSTRUMENT_KEYS.includes(key)) || !REQUIRED_INSTRUMENT_KEYS.every((key) => owns5(instrument, key)))
1510
1747
  return null;
1511
1748
  if (!digits(instrument.number, 12, 19) || !digits(instrument.cvv, 3, 4) || !exact(MONTH3, instrument.expirationMonth) || !exact(YEAR3, instrument.expirationYear))
1512
1749
  return null;
@@ -1534,7 +1771,7 @@ var CLIENT_TOKEN = /^[A-Za-z0-9._~+/=-]{16,4096}$/;
1534
1771
  var REQUEST_ID = /^[A-Za-z0-9-]{1,64}$/;
1535
1772
  var API_VERSION = /^2\.[0-9]{1,2}$/;
1536
1773
  function readHeaders(headers) {
1537
- if (!record7(headers))
1774
+ if (!record9(headers))
1538
1775
  return null;
1539
1776
  const folded = /* @__PURE__ */ new Map();
1540
1777
  for (const [name, value] of Object.entries(headers)) {
@@ -1581,7 +1818,7 @@ function onTokenizePath(url) {
1581
1818
  }
1582
1819
  }
1583
1820
  function primerTokenizeRefusal(request) {
1584
- if (!record7(request) || request.method !== "POST" || !isPrimerTokenizeUrl(request.url))
1821
+ if (!record9(request) || request.method !== "POST" || !isPrimerTokenizeUrl(request.url))
1585
1822
  return "unsupported";
1586
1823
  return headersRefusal(request.headers) ?? primerBodyRefusal(request.body);
1587
1824
  }
@@ -1596,7 +1833,7 @@ function primerCardOnFileRefusal(url, options, policy = PRIMER_SESSION_CARD_ON_F
1596
1833
  return "unsupported";
1597
1834
  if (new URL(url).hostname !== LIVE_PCI_HOST)
1598
1835
  return null;
1599
- return primerCardOnFileDisclosure(url, policy) && record7(options) && options.keepOnFile === true ? null : "keep_on_file";
1836
+ return primerCardOnFileDisclosure(url, policy) && record9(options) && options.keepOnFile === true ? null : "keep_on_file";
1600
1837
  }
1601
1838
  function primerRefusalMessage(reason) {
1602
1839
  if (reason === "keep_on_file")
@@ -1655,9 +1892,9 @@ function injectPrimerCard(body, card) {
1655
1892
  }
1656
1893
  return { body: JSON.stringify(judged.value), where };
1657
1894
  }
1658
- var TOKEN2 = /^[A-Za-z0-9_-]{8,256}$/;
1895
+ var TOKEN3 = /^[A-Za-z0-9_-]{8,256}$/;
1659
1896
  var ERROR_ID = /^[A-Za-z][A-Za-z0-9_.-]{0,63}$/;
1660
- var CODE = /^[A-Z][A-Z0-9_]{0,63}$/;
1897
+ var CODE2 = /^[A-Z][A-Z0-9_]{0,63}$/;
1661
1898
  var NETWORK_NAME = /^[A-Za-z][A-Za-z0-9 _-]{0,31}$/;
1662
1899
  var RESPONSE_MONTH = /^(?:0?[1-9]|1[0-2])$/;
1663
1900
  var RESPONSE_YEAR = /^(?:[0-9]{2}|20[0-9]{2})$/;
@@ -1680,25 +1917,25 @@ function readAnswer(body) {
1680
1917
  return null;
1681
1918
  try {
1682
1919
  const value = JSON.parse(body);
1683
- return record7(value) ? value : null;
1920
+ return record9(value) ? value : null;
1684
1921
  }
1685
1922
  catch {
1686
1923
  return null;
1687
1924
  }
1688
1925
  }
1689
- var tokenValue = (value) => exact(TOKEN2, value) && !panLike(value);
1926
+ var tokenValue = (value) => exact(TOKEN3, value) && !panLike(value);
1690
1927
  var optional = (value, key, check) => !owns5(value, key) || value[key] === null || check(value[key]);
1691
1928
  function cardDetails(data) {
1692
- if (!record7(data) || !exact(/^[0-9]{4}$/, data.last4Digits))
1929
+ if (!record9(data) || !exact(/^[0-9]{4}$/, data.last4Digits))
1693
1930
  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))
1931
+ 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", record9))
1695
1932
  return null;
1696
1933
  const safe = { last4Digits: data.last4Digits };
1697
1934
  for (const key of ["first6Digits", "expirationMonth", "expirationYear", "cardholderName", "network", "isNetworkTokenized"]) {
1698
1935
  if (owns5(data, key) && data[key] !== null)
1699
1936
  safe[key] = data[key];
1700
1937
  }
1701
- if (record7(data.binData)) {
1938
+ if (record9(data.binData)) {
1702
1939
  const bin = {};
1703
1940
  for (const key of BIN_KEYS) {
1704
1941
  if (!owns5(data.binData, key) || data.binData[key] === null)
@@ -1714,7 +1951,7 @@ function cardDetails(data) {
1714
1951
  function threeDsSummary(value) {
1715
1952
  if (value === void 0 || value === null)
1716
1953
  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"))
1954
+ if (!record9(value) || !exact(CODE2, value.responseCode) || !optional(value, "reasonCode", (v) => exact(CODE2, v)) || !optional(value, "reasonText", (v) => plain(v, 256)) || !optional(value, "protocolVersion", (v) => v === "" || exact(PROTOCOL, v)) || !optional(value, "challengeIssued", (v) => typeof v === "boolean"))
1718
1955
  return void 0;
1719
1956
  const safe = { responseCode: value.responseCode };
1720
1957
  for (const key of ["reasonCode", "reasonText", "protocolVersion", "challengeIssued"]) {
@@ -1742,7 +1979,7 @@ function rebuildToken(value) {
1742
1979
  }
1743
1980
  function primerErrorId(body) {
1744
1981
  const value = readAnswer(body);
1745
- const id = value && record7(value.error) ? value.error.errorId : null;
1982
+ const id = value && record9(value.error) ? value.error.errorId : null;
1746
1983
  return exact(ERROR_ID, id) && !panLike(id) ? id : null;
1747
1984
  }
1748
1985
  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: 7af6b8dae5c779ea1901a4deac135effd97b00ea0925db7a269c82330e110cc9
4
4
  // src/deep-freeze.js
5
5
  function deepFreeze(value) {
6
6
  if (value && typeof value === "object" && !Object.isFrozen(value)) {
@@ -1685,6 +1685,64 @@ 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}"
1718
+ },
1719
+ {
1720
+ psp: "gopay",
1721
+ // GoPay's payment gateway (Czech Republic and Slovakia), which a shop opens as a page or as an overlay frame
1722
+ // (embed.js). The gateway loads GoPay's card frame from https://secure.gopay.com/gp-card-comm/h/<hex
1723
+ // token>?lang=..&ver=..&SG=<64 hex>, and on Pay the frame posts the card as one JSON body to its own URL:
1724
+ // {"SG":<the URL's SG>,"cardData":{"cardNumber":<16 digits>,"cvc":<3 digits>,"expiration":<YYMM>},
1725
+ // "type":"PAYMENT_CARD"}, unencrypted. gopay.js holds the request rule the pause decision, the API's create
1726
+ // and the device all read: exactly a card frame URL, a JSON Content-Type, and the frame's body byte for byte,
1727
+ // with a body that names Click to Pay (the frame's "save the card" box) refused. The body names no amount
1728
+ // and no shop: the payment GoPay keeps on its side holds both, so a live request is taken only for a
1729
+ // checkout origin a reviewed pin lists. The frame's host answers no browser origin, so the card leaves the
1730
+ // cardholder's device only through the checkout relay. The answer tells the gateway only whether GoPay took
1731
+ // the card; the gateway then reads the payment's end from its own API and runs 3-D Secure by redirect.
1732
+ // secure.sandbox.gopay.com is GoPay's sandbox: pinned (S7) to test rows, which send only test cards.
1733
+ // Ships dark: served only to a client that declares `gopay_card_form`, gated off for every org until an
1734
+ // operator lists one (`gopay:<org>`), and autopilot never sends this request (autopilot.js
1735
+ // DEVICE_REPLAY_REFUSED_OPERATIONS). `(?![\w/.%-])` ends the path for a consumer that tests `match`
1736
+ // unanchored.
1737
+ capability: "gopay_card_form",
1738
+ match: "secure(?:\\.sandbox)?\\.gopay\\.com/gp-card-comm/h/[0-9A-Fa-f]{16,1024}(?![\\w/.%-])",
1739
+ hosts: ["^secure\\.gopay\\.com$", "^secure\\.sandbox\\.gopay\\.com$"],
1740
+ sandboxHosts: ["^secure\\.sandbox\\.gopay\\.com$"],
1741
+ hostEnvironmentPinned: true,
1742
+ encoding: "json",
1743
+ // The frame's own Accept rides as it sent it; origin, referer and cookies never do.
1744
+ passthroughHeaders: ["^accept$"],
1745
+ jsonCardFields: [["cardData", "cardNumber"]]
1688
1746
  }
1689
1747
  ]);
1690
1748
  var PSP_RECOGNIZERS = deepFreeze(PROCESSOR_DEFINITIONS.map(({ compose, encryptedCardFields, deviceSteps, deviceEncrypt, ...definition }) => definition));
@@ -1807,6 +1865,19 @@ var PAYFAST_PAY_HOSTS = /* @__PURE__ */ Object.freeze({
1807
1865
  production: Object.freeze(["payment.payfast.io", "www.payfast.co.za"]),
1808
1866
  sandbox: Object.freeze(["sandbox.payfast.co.za"])
1809
1867
  });
1868
+ var PAYFAST_BODY_KEYS = /* @__PURE__ */ Object.freeze([
1869
+ "card_number",
1870
+ "cardholder_name",
1871
+ "consent_check",
1872
+ "cvv",
1873
+ "expiry_month",
1874
+ "expiry_year",
1875
+ "g-recaptcha-response",
1876
+ "captcha_version",
1877
+ "captcha_action"
1878
+ ]);
1879
+ var CAPTCHA_ANSWER = "g-recaptcha-response";
1880
+ var UNANSWERED_KEYS = /* @__PURE__ */ Object.freeze(PAYFAST_BODY_KEYS.filter((key) => key !== CAPTCHA_ANSWER));
1810
1881
  // src/rsa-pkcs1v15.js
1811
1882
  var TYPED_ARRAY = Object.getPrototypeOf(Uint8Array.prototype);
1812
1883
  var typedArrayName = Object.getOwnPropertyDescriptor(TYPED_ARRAY, Symbol.toStringTag).get;
@@ -1849,6 +1920,9 @@ var WIX_PAYMENTS_MERCHANT_PINS = /* @__PURE__ */ Object.freeze([
1849
1920
  pin3({ id: "psalms_and_potions", merchant: "Psalms & Potions", origins: ["https://www.psalmsandpotions.com"] }),
1850
1921
  pin3({ id: "alexandra_hagel", merchant: "Alexandra Hagel, LLC", origins: ["https://www.alexandrahagel.com"] })
1851
1922
  ]);
1923
+ // src/paymongo.js
1924
+ var PAYMONGO_CHECKOUT_HOST = "checkout.paymongo.com";
1925
+ var ORIGIN = `https://${PAYMONGO_CHECKOUT_HOST}/`;
1852
1926
  // src/cybersource-secure-acceptance.js
1853
1927
  var SA_BODY_LIMIT = 32 * 1024;
1854
1928
  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.17",
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",