@agent-cards/sdk 0.23.19 → 0.23.20

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.
Files changed (42) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/PREFLIGHT.md +2 -0
  3. package/README.md +34 -4
  4. package/dist/amadeus.d.ts +4 -2
  5. package/dist/amadeus.js +16 -3
  6. package/dist/buy.d.ts +84 -2
  7. package/dist/buy.js +16 -1
  8. package/dist/card-endpoint-facts.d.ts +2 -1
  9. package/dist/card-endpoint-facts.js +18 -9
  10. package/dist/card-endpoint.d.ts +20 -4
  11. package/dist/card-endpoint.js +38 -4
  12. package/dist/card-fields.generated.js +483 -17
  13. package/dist/cdp.d.ts +29 -0
  14. package/dist/cdp.js +302 -18
  15. package/dist/client.d.ts +30 -4
  16. package/dist/client.js +128 -13
  17. package/dist/hipay.generated.d.ts +56 -0
  18. package/dist/hipay.generated.js +389 -0
  19. package/dist/hold.d.ts +180 -0
  20. package/dist/hold.js +264 -0
  21. package/dist/index.d.ts +3 -1
  22. package/dist/index.js +1 -0
  23. package/dist/lifecycle.d.ts +10 -0
  24. package/dist/lifecycle.js +21 -0
  25. package/dist/merchant-card-endpoints.generated.js +102 -11
  26. package/dist/paddle-vgs.generated.d.ts +3 -2
  27. package/dist/paddle-vgs.generated.js +9 -5
  28. package/dist/pre-claim.d.ts +14 -0
  29. package/dist/pre-claim.js +76 -3
  30. package/dist/prepared-processor.d.ts +6 -2
  31. package/dist/prepared-processor.js +18 -2
  32. package/dist/primer.generated.js +510 -44
  33. package/dist/quickpay.d.ts +44 -0
  34. package/dist/quickpay.js +65 -0
  35. package/dist/stripe-checkout.generated.js +124 -2
  36. package/dist/twoc2p.d.ts +54 -0
  37. package/dist/twoc2p.generated.d.ts +33 -0
  38. package/dist/twoc2p.generated.js +1145 -0
  39. package/dist/twoc2p.js +85 -0
  40. package/dist/voice.d.ts +16 -13
  41. package/dist/voice.js +13 -10
  42. package/package.json +3 -3
@@ -46,7 +46,9 @@
46
46
  // that sends the typed card again outside the card request is aborted in every status
47
47
  // (cardEndpointResendFor). And the merchant's own record of the order, which its page
48
48
  // reads from the endpoint origin, is recorded read-only (card-endpoint-facts.ts) and sent
49
- // with the create, so the agent's amount is held to the merchant's total.
49
+ // with the create, so the agent's amount is held to the merchant's total. D-EDGE's card
50
+ // frame is read the same way from the payment hub around it, whose booking record says
51
+ // what the card pays now and whether the hotel charges it later.
50
52
  //
51
53
  // The endpoint URL (it carries cart, booking and instance ids), the paused body, the
52
54
  // session and the answer are cardholder data even with no real card in them: no
@@ -121,9 +123,23 @@ const ROUTED_METHODS = [...new Set(PROFILES.flatMap((profile) => [profile.method
121
123
  export function cardEndpointRouted(url) {
122
124
  return ROUTED_METHODS.some((method) => cardEndpointFor(url, method) !== null || cardEndpointResendFor(url, method) !== null);
123
125
  }
124
- /** The origins of the profiles whose merchant keeps its own record of the order: the only responses card-endpoint-facts.ts records. */
126
+ /**
127
+ * The origins the record of each profile whose merchant keeps one comes from (its facts.origin, else its
128
+ * endpoint): the only responses card-endpoint-facts.ts records.
129
+ */
125
130
  export function cardEndpointFactsOrigins() {
126
- return [...new Set(PROFILES.filter((profile) => profile.facts).map((profile) => profile.endpoint))];
131
+ return [...new Set(PROFILES.filter((profile) => profile.facts).map((profile) => profile.facts.origin ?? profile.endpoint))];
132
+ }
133
+ /**
134
+ * The `:name` segment of a card path template a URL path gives, when the path has the template's
135
+ * shape (as many segments, every literal one equal); else null.
136
+ */
137
+ function boundSegment(template, segments, name) {
138
+ const want = template.split('/');
139
+ if (want.length !== segments.length || !want.every((part, i) => (part.startsWith(':') ? segments[i] !== '' : part === segments[i])))
140
+ return null;
141
+ const at = want.indexOf(`:${name}`);
142
+ return at < 1 ? null : segments[at];
127
143
  }
128
144
  /**
129
145
  * The checkout session a request on the endpoint of a profile with facts belongs to: the
@@ -133,6 +149,12 @@ export function cardEndpointFactsOrigins() {
133
149
  * request. card-endpoint-facts.ts counts what it keeps, and what a checkout lost, by it.
134
150
  * When the paths of two profiles on one origin both fit, the shorter session is the one:
135
151
  * every request on a card request's session then gets the card request's own.
152
+ *
153
+ * For a profile whose record comes from its own origin (D-EDGE's payment hub beside the card
154
+ * frame), a request on that origin belongs to the session its last path segment names, the
155
+ * session id every hub URL ends in, and the profile's card request to the session its bind
156
+ * value names, both written on that origin ('https://pay.secure-hotel-booking.com/<id>'): the
157
+ * card post and the hub's own calls are one checkout, as payment-core's role rules read them.
136
158
  */
137
159
  export function cardEndpointFactsSession(url) {
138
160
  let parsed;
@@ -143,9 +165,21 @@ export function cardEndpointFactsSession(url) {
143
165
  return null;
144
166
  }
145
167
  const segments = parsed.pathname.split('/');
168
+ for (const profile of PROFILES) {
169
+ const origin = profile.facts?.origin;
170
+ if (!origin)
171
+ continue;
172
+ if (parsed.origin === origin) {
173
+ const last = segments[segments.length - 1];
174
+ return last ? `${origin}/${last}` : null;
175
+ }
176
+ const bound = parsed.origin === profile.endpoint ? boundSegment(profile.path, segments, profile.facts.bind) : null;
177
+ if (bound)
178
+ return `${origin}/${bound}`;
179
+ }
146
180
  let shortest = null;
147
181
  for (const profile of PROFILES) {
148
- if (!profile.facts || profile.endpoint !== parsed.origin)
182
+ if (!profile.facts || profile.facts.origin || profile.endpoint !== parsed.origin)
149
183
  continue;
150
184
  const template = profile.path.split('/');
151
185
  const at = template.indexOf(`:${profile.facts.bind}`);
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
2
  // Generated from @agent-cards/payment-core. Do not edit.
3
- // artifact-sha256: d59cc35c7ffec2b7a8aa6b52e65fd0a6a22465f4e60812b87ec23256ea9e8885
3
+ // artifact-sha256: 7e485110ac882bd8e19be7369be8487a532ae7dc93bde3bf660fecb1851f500e
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
@@ -101,8 +101,8 @@ function parseConvergeBody(body) {
101
101
  return parsed;
102
102
  }
103
103
  function convergeAmountCents(value) {
104
- const text2 = typeof value === "number" && Number.isFinite(value) ? String(value) : value;
105
- const m = typeof text2 === "string" ? AMOUNT.exec(text2) : null;
104
+ const text3 = typeof value === "number" && Number.isFinite(value) ? String(value) : value;
105
+ const m = typeof text3 === "string" ? AMOUNT.exec(text3) : null;
106
106
  if (!m)
107
107
  return null;
108
108
  const cents = Number(m[1]) * 100 + Number(((m[2] ?? "") + "00").slice(0, 2));
@@ -582,9 +582,9 @@ var K = /* @__PURE__ */ new Uint32Array([
582
582
  3329325298
583
583
  ]);
584
584
  var rotr = (x, n) => x >>> n | x << 32 - n;
585
- function utf8(text2) {
585
+ function utf8(text3) {
586
586
  const out = [];
587
- for (const char of text2) {
587
+ for (const char of text3) {
588
588
  let cp = char.codePointAt(0);
589
589
  if (cp >= 55296 && cp <= 57343)
590
590
  cp = 65533;
@@ -1368,14 +1368,14 @@ function readJson2(body) {
1368
1368
  catch {
1369
1369
  return { parsed: null, exact: false };
1370
1370
  }
1371
- let exact = false;
1371
+ let exact2 = false;
1372
1372
  try {
1373
- exact = body.length <= BODY_LIMIT6 && JSON.stringify(parsed) === body;
1373
+ exact2 = body.length <= BODY_LIMIT6 && JSON.stringify(parsed) === body;
1374
1374
  }
1375
1375
  catch {
1376
- exact = false;
1376
+ exact2 = false;
1377
1377
  }
1378
- return { parsed, exact };
1378
+ return { parsed, exact: exact2 };
1379
1379
  }
1380
1380
  function billingValue(value) {
1381
1381
  if (value === UNDEFINED)
@@ -1430,14 +1430,14 @@ function attachType(parsed) {
1430
1430
  return typeof type === "string" ? type : null;
1431
1431
  }
1432
1432
  function paymongoBodyVerdict(body, session) {
1433
- const { parsed, exact } = readJson2(body);
1433
+ const { parsed, exact: exact2 } = readJson2(body);
1434
1434
  const type = parsed === null ? null : attachType(parsed);
1435
1435
  if (type !== "card") {
1436
1436
  if (parsed === null)
1437
1437
  return body === void 0 || body === null || body === "" ? CONTINUE4 : refuse10("paymongo_body_unsupported");
1438
1438
  return namesCardValue(parsed) ? refuse10("paymongo_body_unsupported") : CONTINUE4;
1439
1439
  }
1440
- if (!exact)
1440
+ if (!exact2)
1441
1441
  return refuse10("paymongo_body_unsupported");
1442
1442
  const code = judgeCardAttach(parsed, session);
1443
1443
  return code === null ? CARD9 : refuse10(code);
@@ -1658,6 +1658,9 @@ function payrexxGateVerdict(url, body) {
1658
1658
  const verdict = payrexxBodyVerdict(body);
1659
1659
  return verdict.verdict === "card" && target.pspId !== PAYREXX_PAY_PSP_ID ? refuse12("payrexx_other_provider") : verdict;
1660
1660
  }
1661
+ var PAYREXX_FOLLOW_UP_WINDOW_MS = 15 * 60 * 1e3;
1662
+ var PAYREXX_FOLLOW_UP_IDLE_MS = 60 * 1e3;
1663
+ var PAYREXX_FOLLOW_UP_CHALLENGE_MS = 11 * 60 * 1e3;
1661
1664
  // src/komoju.js
1662
1665
  var KOMOJU_PSP = "komoju";
1663
1666
  var KOMOJU_HOST = "komoju.com";
@@ -2091,7 +2094,7 @@ var luhn2 = (digits) => {
2091
2094
  return sum % 10 === 0;
2092
2095
  };
2093
2096
  var ANY_NETWORK = /^[2-6][0-9]{12,18}$/;
2094
- var holdsCardShape = (text2, shape = NETWORK) => (text2.match(/[0-9]{13,}/g) ?? []).some((run) => run.length > 19 || shape.test(run) && luhn2(run));
2097
+ var holdsCardShape = (text3, shape = NETWORK) => (text3.match(/[0-9]{13,}/g) ?? []).some((run) => run.length > 19 || shape.test(run) && luhn2(run));
2095
2098
  var phone = (value) => typeof value === "string" && PHONE.test(value) && (value.match(/[0-9]/g) ?? []).length >= 6 && (value.match(/[0-9]/g) ?? []).length <= 15;
2096
2099
  var refuse16 = (code) => Object.freeze({ verdict: "refuse", code });
2097
2100
  var CARD15 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
@@ -2319,13 +2322,13 @@ var printable = (value) => [...value].every((ch) => ch.charCodeAt(0) >= 32 && ch
2319
2322
  function typed(value, limit = 256) {
2320
2323
  return typeof value === "string" && value.length >= 1 && value.length <= limit && !PAN_LIKE4.test(value) && printable(value);
2321
2324
  }
2322
- function decodeBase64(text2) {
2323
- if (typeof text2 !== "string" || !BASE643.test(text2) || text2.length % 4 !== 0)
2325
+ function decodeBase64(text3) {
2326
+ if (typeof text3 !== "string" || !BASE643.test(text3) || text3.length % 4 !== 0)
2324
2327
  return null;
2325
2328
  let bits = 0;
2326
2329
  let value = 0;
2327
2330
  let out = "";
2328
- for (const ch of text2.replace(/=+$/, "")) {
2331
+ for (const ch of text3.replace(/=+$/, "")) {
2329
2332
  value = (value << 6 | BASE64_ALPHABET.indexOf(ch)) & 16777215;
2330
2333
  bits += 6;
2331
2334
  if (bits >= 8) {
@@ -2335,8 +2338,8 @@ function decodeBase64(text2) {
2335
2338
  }
2336
2339
  return out;
2337
2340
  }
2338
- function soundDevice(text2) {
2339
- const json = decodeBase64(text2);
2341
+ function soundDevice(text3) {
2342
+ const json = decodeBase64(text3);
2340
2343
  if (json === null)
2341
2344
  return false;
2342
2345
  let value;
@@ -2450,6 +2453,451 @@ function sumupBodyVerdict(body, url) {
2450
2453
  return refuse17("sumup_card_saving_refused");
2451
2454
  return CARD16;
2452
2455
  }
2456
+ // src/twoc2p-secure-pay.js
2457
+ var SALTED = /* @__PURE__ */ Object.freeze([83, 97, 108, 116, 101, 100, 95, 95]);
2458
+ var B64 = /^[A-Za-z0-9+/]+={0,2}$/;
2459
+ var FIELD_LIMIT = 1024;
2460
+ function decodeCanonical(text3) {
2461
+ if (typeof text3 !== "string" || text3.length === 0 || text3.length % 4 !== 0 || !B64.test(text3))
2462
+ return null;
2463
+ let binary;
2464
+ try {
2465
+ binary = atob(text3);
2466
+ }
2467
+ catch {
2468
+ return null;
2469
+ }
2470
+ if (btoa(binary) !== text3)
2471
+ return null;
2472
+ return Uint8Array.from(binary, (char) => char.charCodeAt(0));
2473
+ }
2474
+ function twoC2pSecurePayParts(value) {
2475
+ if (typeof value !== "string" || value.length > FIELD_LIMIT || !/^[0-9a-f]{4}/.test(value))
2476
+ return null;
2477
+ const length = parseInt(value.slice(0, 4), 16);
2478
+ if (length < 4 || 4 + length >= value.length)
2479
+ return null;
2480
+ const rsaText = value.slice(4, 4 + length);
2481
+ const rsa = decodeCanonical(rsaText);
2482
+ const cipher = decodeCanonical(value.slice(4 + length));
2483
+ if (!rsa || !cipher || cipher.length < 32 || cipher.length > 80 || cipher.length % 16 !== 0)
2484
+ return null;
2485
+ if (!SALTED.every((byte, at) => cipher[at] === byte))
2486
+ return null;
2487
+ return { rsaText, rsa, salt: cipher.slice(8, 16), blocks: (cipher.length - 16) / 16 };
2488
+ }
2489
+ function isTwoC2pPageField(value, keyBytes) {
2490
+ const parts = twoC2pSecurePayParts(value);
2491
+ if (!parts || !Number.isInteger(keyBytes) || keyBytes < 128)
2492
+ return false;
2493
+ const expected = Math.ceil(keyBytes / 3) * 4;
2494
+ return parts.rsaText.length === expected && (parts.rsa.length === keyBytes || parts.rsa.length === keyBytes - 1);
2495
+ }
2496
+ // src/twoc2p-keys.js
2497
+ var TWOC2P_KEYS = /* @__PURE__ */ Object.freeze({
2498
+ production: Object.freeze({
2499
+ spki: "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC/1ljsxI+r6qQraTFrHfWNrV41vxumBF+4ILAG3WsN6HEBQU2wSUv/IyQmZkiys1ilOb+OOuQTH8OXMnqQg9E4epyePW3L7IeOieSbIIDeSX6UpTWmT/Fs7moWZkN8RpuCV0u87n3AY2tQbtcSqwEKi2sxzWLFwscoGn6N5yVIpQIDAQAB",
2500
+ sha256: "bb8f27929ce140c6ef0ec9c4a20d7ca0b83376bc35a501985dc40d16669384fe",
2501
+ script: Object.freeze({ url: "https://t.2c2p.com/SecurePayment/api/my2c2p.1.7.6.min.js", sha256: "4a745a37765a2e28e299d64f6ea5811aab27b176da61db6f840fa85d6a47e763" })
2502
+ }),
2503
+ sandbox: Object.freeze({
2504
+ spki: "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDKakJC+2MSZikKoPzlNqXvJCuWNLhejg3gMRePSetYNNgnhyqFwwAR7t7i/B2QFZoixSYc2/23cJz0jA5O+q+Cu3fycqKlf1L9966+X3B9nyHe2eKQZr8KrcS/8+sEKcd0pLATY4AleW1iktuN+2oghrDKuv+aDNztWcOy+PTofwIDAQAB",
2505
+ sha256: "7f80c07f1d72db28ede10dae942940657c72dfa789836c9fdf283cba6feff2e6",
2506
+ script: Object.freeze({ url: "https://demo2.2c2p.com/2C2PFrontEnd/SecurePayment/api/my2c2p.1.7.6.min.js", sha256: "435723d92bfefb00607a56851967e0b745d52b8d49443de5f0000f0583fde5cc" })
2507
+ })
2508
+ });
2509
+ function twoC2pKey(environment2) {
2510
+ if (environment2 !== "production" && environment2 !== "sandbox")
2511
+ return null;
2512
+ return TWOC2P_KEYS[environment2] ?? null;
2513
+ }
2514
+ function twoC2pKeyBytes(environment2) {
2515
+ const key = twoC2pKey(environment2);
2516
+ if (!key)
2517
+ return null;
2518
+ try {
2519
+ return parseRsaPublicKey(key).size;
2520
+ }
2521
+ catch {
2522
+ return null;
2523
+ }
2524
+ }
2525
+ // src/twoc2p.js
2526
+ var TWOC2P_PSP = "twoc2p";
2527
+ var TWOC2P_FIELD = "securePayToken";
2528
+ var TWOC2P_REVIEWED_BUILDS = /* @__PURE__ */ Object.freeze(["4.1", "4.2", "4.3", "4.4", "4.5"]);
2529
+ var record12 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
2530
+ var refuse18 = (code) => Object.freeze({ verdict: "refuse", code });
2531
+ var CARD17 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
2532
+ var CONTINUE8 = /* @__PURE__ */ Object.freeze({ verdict: "continue" });
2533
+ var PAYMENT_URL = /^https:\/\/(sandbox-)?pgwv4\.2c2p\.com\/payment\/(4\.[0-9]{1,2})\/Payment$/;
2534
+ function twoC2pPaymentTarget(url) {
2535
+ const match = typeof url === "string" ? PAYMENT_URL.exec(url) : null;
2536
+ if (!match)
2537
+ return null;
2538
+ return Object.freeze({ environment: match[1] ? "sandbox" : "production", version: match[2], reviewed: TWOC2P_REVIEWED_BUILDS.includes(match[2]) });
2539
+ }
2540
+ function twoC2pPaymentCarriesCard(body) {
2541
+ if (typeof body !== "string")
2542
+ return true;
2543
+ try {
2544
+ return JSON.stringify(JSON.parse(body)).includes(`"${TWOC2P_FIELD}"`);
2545
+ }
2546
+ catch {
2547
+ return true;
2548
+ }
2549
+ }
2550
+ var ROOT_KEYS6 = /* @__PURE__ */ Object.freeze(["paymentToken", "clientIP", "locale", "responseReturnUrl", "clientID", "payment"]);
2551
+ var CODE_KEYS = /* @__PURE__ */ Object.freeze(["channelCode", "agentCode", "agentChannelCode"]);
2552
+ var DATA_KEYS2 = /* @__PURE__ */ Object.freeze([
2553
+ "name",
2554
+ "isIppChosen",
2555
+ "cardDetails",
2556
+ "loyaltyPoints",
2557
+ "fxRateID",
2558
+ "email",
2559
+ "mobileNo",
2560
+ "mobileNoPrefix",
2561
+ "customerNote",
2562
+ "paymentExpiry",
2563
+ "securePayToken",
2564
+ "cardTokenize",
2565
+ "accountTokenization",
2566
+ "token",
2567
+ "customerToken",
2568
+ "accountNo",
2569
+ "installmentPeriod",
2570
+ "interestType",
2571
+ "payLaterPeriod",
2572
+ "billingAddress1",
2573
+ "billingAddress2",
2574
+ "billingCity",
2575
+ "billingState",
2576
+ "billingCountryCode",
2577
+ "billingPostalCode",
2578
+ "riskInfo"
2579
+ ]);
2580
+ var RISK_KEYS = /* @__PURE__ */ Object.freeze(["customer_id", "shipping_method", "deviceSessionId", "customData"]);
2581
+ var BODY_LIMIT14 = 16384;
2582
+ var CONTROL6 = /[\u0000-\u001f\u007f]/;
2583
+ var CARD_LIKE = /(?:[0-9][ _.:/-]*){12,}/;
2584
+ var PAYMENT_TOKEN = /^[A-Za-z0-9+/]{16,1000}={0,2}$/;
2585
+ var UUID2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
2586
+ var IP = /^[0-9A-Fa-f.:]{2,45}$/;
2587
+ var LOCALE2 = /^[A-Za-z]{2,3}(?:[-_][A-Za-z0-9]{2,8})?$/;
2588
+ var AGENT = /^[A-Za-z0-9_]{1,32}$/;
2589
+ var RISK_TOKEN2 = /^[\x21-\x7e]{1,512}$/;
2590
+ var RETURN_URL = /^https:\/\/((?:sandbox-)?pgw-ui\.2c2p\.com)\/payment\/4\.[0-9]{1,2}(?:\/|\/index\.html)?#\/(?:info|mobile\/process)\/([A-Za-z0-9+/]{16,1000}={0,2})?$/;
2591
+ var PAGE_HOSTS = /* @__PURE__ */ Object.freeze({ production: "pgw-ui.2c2p.com", sandbox: "sandbox-pgw-ui.2c2p.com" });
2592
+ var returnUrlTaken = (value, paymentToken, environment2) => {
2593
+ if (value === void 0)
2594
+ return true;
2595
+ const match = typeof value === "string" ? RETURN_URL.exec(value) : null;
2596
+ return !!match && (match[2] === void 0 || match[2] === paymentToken) && (environment2 === void 0 || match[1] === PAGE_HOSTS[environment2]);
2597
+ };
2598
+ var inOrder2 = (value, order) => {
2599
+ let at = -1;
2600
+ for (const key of Object.keys(value)) {
2601
+ const next = order.indexOf(key);
2602
+ if (next <= at)
2603
+ return false;
2604
+ at = next;
2605
+ }
2606
+ return true;
2607
+ };
2608
+ var text2 = (value, limit) => typeof value === "string" && value.length <= limit && !CONTROL6.test(value) && !CARD_LIKE.test(value);
2609
+ var optionalText = (value, limit) => value === void 0 || text2(value, limit);
2610
+ function twoC2pBodyVerdict(body, keyBytes = 128, environment2 = void 0) {
2611
+ if (!twoC2pPaymentCarriesCard(body))
2612
+ return CONTINUE8;
2613
+ if (typeof body !== "string" || body.length > BODY_LIMIT14)
2614
+ return refuse18("twoc2p_body_unsupported");
2615
+ let value;
2616
+ try {
2617
+ value = JSON.parse(body);
2618
+ }
2619
+ catch {
2620
+ return refuse18("twoc2p_body_unsupported");
2621
+ }
2622
+ if (!record12(value) || JSON.stringify(value) !== body || !inOrder2(value, ROOT_KEYS6))
2623
+ return refuse18("twoc2p_body_unsupported");
2624
+ if (typeof value.paymentToken !== "string" || !PAYMENT_TOKEN.test(value.paymentToken) || value.clientIP !== void 0 && !(typeof value.clientIP === "string" && IP.test(value.clientIP)) || value.locale !== void 0 && !(typeof value.locale === "string" && LOCALE2.test(value.locale)) || !returnUrlTaken(value.responseReturnUrl, value.paymentToken, environment2) || value.clientID !== void 0 && !(typeof value.clientID === "string" && UUID2.test(value.clientID)))
2625
+ return refuse18("twoc2p_body_unsupported");
2626
+ const payment = value.payment;
2627
+ if (!record12(payment) || Object.keys(payment).join(",") !== "code,data")
2628
+ return refuse18("twoc2p_body_unsupported");
2629
+ const code = payment.code;
2630
+ const data = payment.data;
2631
+ if (!record12(code) || !record12(data))
2632
+ return refuse18("twoc2p_body_unsupported");
2633
+ if (Object.prototype.hasOwnProperty.call(code, "subChannelCode"))
2634
+ return refuse18("twoc2p_stored_card");
2635
+ if (code.channelCode === "IPP" || code.channelCode === "LIPP")
2636
+ return refuse18("twoc2p_installments");
2637
+ if (!inOrder2(code, CODE_KEYS) || code.channelCode === void 0)
2638
+ return refuse18("twoc2p_body_unsupported");
2639
+ if (code.channelCode !== "CC")
2640
+ return refuse18("twoc2p_channel_unsupported");
2641
+ if ([code.agentCode, code.agentChannelCode].some((part) => part !== void 0 && !(typeof part === "string" && AGENT.test(part))))
2642
+ return refuse18("twoc2p_body_unsupported");
2643
+ return dataVerdict(data, keyBytes, body);
2644
+ }
2645
+ function dataVerdict(data, keyBytes, body) {
2646
+ if (data.cardTokenize !== void 0 || data.accountTokenization !== void 0)
2647
+ return refuse18("twoc2p_keeps_card");
2648
+ if (data.token !== void 0 || data.customerToken !== void 0)
2649
+ return refuse18("twoc2p_stored_card");
2650
+ if (data.accountNo !== void 0)
2651
+ return refuse18("twoc2p_card_in_clear");
2652
+ const details = data.cardDetails;
2653
+ if (record12(details) && (details.cardNo !== void 0 || details.accountNo !== void 0))
2654
+ return refuse18("twoc2p_card_in_clear");
2655
+ if (record12(details) && Object.keys(details).some((key) => key !== "email"))
2656
+ return refuse18("twoc2p_stored_card");
2657
+ if (data.isIppChosen === true || data.installmentPeriod !== void 0 || data.interestType !== void 0 || data.payLaterPeriod !== void 0) {
2658
+ return refuse18("twoc2p_installments");
2659
+ }
2660
+ if (data.fxRateID !== void 0)
2661
+ return refuse18("twoc2p_currency_conversion");
2662
+ if (data.loyaltyPoints !== void 0 && !(Array.isArray(data.loyaltyPoints) && data.loyaltyPoints.length === 0)) {
2663
+ return refuse18("twoc2p_loyalty_redemption");
2664
+ }
2665
+ if (!inOrder2(data, DATA_KEYS2) || data.paymentExpiry !== void 0)
2666
+ return refuse18("twoc2p_body_unsupported");
2667
+ if (typeof data.securePayToken !== "string" || !isTwoC2pPageField(data.securePayToken, keyBytes))
2668
+ return refuse18("twoc2p_field_unreviewed");
2669
+ if (body.split(data.securePayToken).length !== 2)
2670
+ return refuse18("twoc2p_body_unsupported");
2671
+ if (data.isIppChosen !== void 0 && data.isIppChosen !== false)
2672
+ return refuse18("twoc2p_body_unsupported");
2673
+ if (details !== void 0 && !(record12(details) && (details.email === void 0 || text2(details.email, 254))))
2674
+ return refuse18("twoc2p_body_unsupported");
2675
+ if (!optionalText(data.name, 128) || !optionalText(data.email, 254) || !optionalText(data.customerNote, 255) || !(data.mobileNo === void 0 || typeof data.mobileNo === "string" && /^[0-9]{4,11}$/.test(data.mobileNo)) || !(data.mobileNoPrefix === void 0 || typeof data.mobileNoPrefix === "string" && /^\+?[0-9]{1,4}$/.test(data.mobileNoPrefix))) {
2676
+ return refuse18("twoc2p_body_unsupported");
2677
+ }
2678
+ for (const key of ["billingAddress1", "billingAddress2", "billingCity", "billingState", "billingPostalCode"]) {
2679
+ if (!optionalText(data[key], 128))
2680
+ return refuse18("twoc2p_body_unsupported");
2681
+ }
2682
+ if (data.billingCountryCode !== void 0 && !(typeof data.billingCountryCode === "string" && /^[A-Za-z]{2}$/.test(data.billingCountryCode))) {
2683
+ return refuse18("twoc2p_body_unsupported");
2684
+ }
2685
+ const risk = data.riskInfo;
2686
+ if (risk !== void 0 && risk !== null && !(record12(risk) && Object.keys(risk).join(",") === RISK_KEYS.join(",") && risk.customer_id === "" && risk.shipping_method === "" && typeof risk.deviceSessionId === "string" && RISK_TOKEN2.test(risk.deviceSessionId) && record12(risk.customData) && Object.keys(risk.customData).length === 0)) {
2687
+ return refuse18("twoc2p_body_unsupported");
2688
+ }
2689
+ return CARD17;
2690
+ }
2691
+ // src/hipay.js
2692
+ var HIPAY_PSP = "hipay";
2693
+ var HIPAY_TOKEN_URLS = /* @__PURE__ */ Object.freeze({
2694
+ production: "https://secure2-vault.hipay-tpp.com/rest/v2/token",
2695
+ sandbox: "https://stage-secure2-vault.hipay-tpp.com/rest/v2/token"
2696
+ });
2697
+ var BODY_LIMIT15 = 2048;
2698
+ var HOSTED_KEYS = /* @__PURE__ */ Object.freeze(["multi_use", "card_expiry_month", "card_expiry_year", "card_number", "card_holder", "cvc"]);
2699
+ var HOSTED_KEYS_NO_HOLDER = /* @__PURE__ */ Object.freeze(["multi_use", "card_expiry_month", "card_expiry_year", "card_number", "cvc"]);
2700
+ var DIRECT_KEYS = /* @__PURE__ */ Object.freeze(["card_expiry_month", "card_expiry_year", "card_number", "card_holder", "cvc", "multi_use"]);
2701
+ var DIRECT_KEYS_NO_HOLDER = /* @__PURE__ */ Object.freeze(["card_expiry_month", "card_expiry_year", "card_number", "cvc", "multi_use"]);
2702
+ var CARD_SHAPES = /* @__PURE__ */ Object.freeze([HOSTED_KEYS, HOSTED_KEYS_NO_HOLDER, DIRECT_KEYS, DIRECT_KEYS_NO_HOLDER]);
2703
+ var NUMBER_ONLY_KEYS = /* @__PURE__ */ Object.freeze(["multi_use", "card_expiry_month", "card_expiry_year", "card_number"]);
2704
+ var CARD_NUMBER10 = /^[0-9]{12,19}$/;
2705
+ var SECURITY_CODE12 = /^[0-9]{3,4}$/;
2706
+ var MONTH8 = /^(?:0[1-9]|1[0-2])$/;
2707
+ var YEAR8 = /^20[0-9]{2}$/;
2708
+ var TEXT_LIMIT3 = 256;
2709
+ var CONTROL7 = /[\u0000-\u001f\u007f]/;
2710
+ var record13 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
2711
+ var sameKeys7 = (value, keys) => {
2712
+ const own3 = Object.keys(value);
2713
+ return own3.length === keys.length && own3.every((key, at) => key === keys[at]);
2714
+ };
2715
+ var plainText3 = (value) => typeof value === "string" && value.length <= TEXT_LIMIT3 && !CONTROL7.test(value) && (value.match(/[0-9]/g) ?? []).length < 12;
2716
+ var refuse19 = (code) => Object.freeze({ verdict: "refuse", code });
2717
+ var CARD18 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
2718
+ function hipayTokenEnvironment(url) {
2719
+ if (url === HIPAY_TOKEN_URLS.production)
2720
+ return "production";
2721
+ if (url === HIPAY_TOKEN_URLS.sandbox)
2722
+ return "sandbox";
2723
+ return null;
2724
+ }
2725
+ function isHipayTokenUrl(url) {
2726
+ return hipayTokenEnvironment(url) !== null;
2727
+ }
2728
+ function readBody9(body) {
2729
+ if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT15)
2730
+ return null;
2731
+ let value;
2732
+ try {
2733
+ value = JSON.parse(body);
2734
+ if (!record13(value) || JSON.stringify(value) !== body)
2735
+ return null;
2736
+ }
2737
+ catch {
2738
+ return null;
2739
+ }
2740
+ return value;
2741
+ }
2742
+ function hipayBodyVerdict(body) {
2743
+ const value = readBody9(body);
2744
+ if (value === null)
2745
+ return refuse19("hipay_body_unsupported");
2746
+ if (sameKeys7(value, NUMBER_ONLY_KEYS))
2747
+ return refuse19("hipay_number_only");
2748
+ if (!CARD_SHAPES.some((keys) => sameKeys7(value, keys)))
2749
+ return refuse19("hipay_body_unsupported");
2750
+ if (typeof value.card_number !== "string" || !CARD_NUMBER10.test(value.card_number) || typeof value.cvc !== "string" || !SECURITY_CODE12.test(value.cvc) || typeof value.card_expiry_month !== "string" || !MONTH8.test(value.card_expiry_month) || typeof value.card_expiry_year !== "string" || !YEAR8.test(value.card_expiry_year) || "card_holder" in value && !plainText3(value.card_holder)) {
2751
+ return refuse19("hipay_body_unsupported");
2752
+ }
2753
+ if (value.multi_use === 1)
2754
+ return refuse19("hipay_keeps_card");
2755
+ return value.multi_use === 0 ? CARD18 : refuse19("hipay_body_unsupported");
2756
+ }
2757
+ // src/amazon-payment-services.js
2758
+ var APS_PSP = "amazon_payment_services";
2759
+ var APS_HOSTS = /* @__PURE__ */ Object.freeze({ "checkout.payfort.com": "production", "sbcheckout.payfort.com": "sandbox" });
2760
+ var APS_TOKENIZATION_PATH = "/FortAPI/paymentPage";
2761
+ var APS_SIGNED_FIELDS = /* @__PURE__ */ Object.freeze([
2762
+ "service_command",
2763
+ "access_code",
2764
+ "merchant_identifier",
2765
+ "merchant_reference",
2766
+ "language",
2767
+ "return_url",
2768
+ "signature"
2769
+ ]);
2770
+ var APS_CARD_FIELDS = /* @__PURE__ */ Object.freeze(["card_number", "expiry_date", "card_security_code"]);
2771
+ var APS_OPTIONAL_FIELDS = /* @__PURE__ */ Object.freeze(["card_holder_name", "remember_me"]);
2772
+ var URL_LIMIT7 = 2048;
2773
+ var BODY_LIMIT16 = 32 * 1024;
2774
+ var exact = (pattern, value) => typeof value === "string" && pattern.exec(value)?.[0] === value;
2775
+ var controlFree = (value, max) => typeof value === "string" && value.length <= max && !/[\u0000-\u001f\u007f]/.test(value);
2776
+ var SHAPES = /* @__PURE__ */ new Map([
2777
+ ["service_command", (v) => v === "TOKENIZATION"],
2778
+ ["access_code", (v) => exact(/^[A-Za-z0-9]{1,20}$/, v)],
2779
+ ["merchant_identifier", (v) => exact(/^[A-Za-z0-9]{1,20}$/, v)],
2780
+ ["merchant_reference", (v) => exact(/^[A-Za-z0-9._-]{1,40}$/, v)],
2781
+ ["language", (v) => v === "en" || v === "ar"],
2782
+ // Hex SHA-256 (APS's default), SHA-512, or the 40 characters of the SHA-1 APS calls SHA-128.
2783
+ ["signature", (v) => exact(/^(?:[0-9A-Fa-f]{40}|[0-9A-Fa-f]{64}|[0-9A-Fa-f]{128})$/, v)],
2784
+ ["card_number", (v) => exact(/^[0-9]{12,19}$/, v)],
2785
+ ["expiry_date", (v) => exact(/^[0-9]{2}(?:0[1-9]|1[0-2])$/, v)],
2786
+ ["card_security_code", (v) => exact(/^[0-9]{3,4}$/, v)],
2787
+ ["card_holder_name", (v) => controlFree(v, 255)],
2788
+ ["remember_me", (v) => v === "YES" || v === "NO"]
2789
+ ]);
2790
+ function apsTokenizationUrl(url) {
2791
+ if (typeof url !== "string" || url.length > URL_LIMIT7 || url.includes("?") || url.includes("#"))
2792
+ return null;
2793
+ let parsed;
2794
+ try {
2795
+ parsed = new URL(url);
2796
+ }
2797
+ catch {
2798
+ return null;
2799
+ }
2800
+ if (parsed.href !== url || parsed.protocol !== "https:" || parsed.port || parsed.username || parsed.password || parsed.pathname !== APS_TOKENIZATION_PATH || !Object.prototype.hasOwnProperty.call(APS_HOSTS, parsed.hostname))
2801
+ return null;
2802
+ return Object.freeze({ host: parsed.hostname, environment: APS_HOSTS[parsed.hostname] });
2803
+ }
2804
+ function formEncode2(value) {
2805
+ let encoded;
2806
+ try {
2807
+ encoded = encodeURIComponent(value);
2808
+ }
2809
+ catch {
2810
+ return null;
2811
+ }
2812
+ return encoded.replace(/[!'()~]/g, (ch) => `%${ch.charCodeAt(0).toString(16).toUpperCase()}`).replace(/%20/g, "+");
2813
+ }
2814
+ function formDecode(raw) {
2815
+ if (!/^(?:[A-Za-z0-9*._+-]|%[0-9A-F]{2})*$/.test(raw))
2816
+ return null;
2817
+ let value;
2818
+ try {
2819
+ value = decodeURIComponent(raw.replace(/\+/g, "%20"));
2820
+ }
2821
+ catch {
2822
+ return null;
2823
+ }
2824
+ return formEncode2(value) === raw ? value : null;
2825
+ }
2826
+ function parseForm(body) {
2827
+ if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT16)
2828
+ return null;
2829
+ const pairs = [];
2830
+ const values = /* @__PURE__ */ new Map();
2831
+ for (const chunk of body.split("&")) {
2832
+ const separator = chunk.indexOf("=");
2833
+ if (separator < 1)
2834
+ return null;
2835
+ const rawName = chunk.slice(0, separator), raw = chunk.slice(separator + 1);
2836
+ const name = formDecode(rawName), value = formDecode(raw);
2837
+ if (name === null || value === null || values.has(name))
2838
+ return null;
2839
+ pairs.push({ name, rawName, raw, value });
2840
+ values.set(name, value);
2841
+ }
2842
+ return { pairs, values };
2843
+ }
2844
+ function returnUrlAdmitted(value) {
2845
+ if (typeof value !== "string" || value.length > 400 || value.includes("#") || /[\u0000- \u007f]/.test(value))
2846
+ return false;
2847
+ let parsed;
2848
+ try {
2849
+ parsed = new URL(value);
2850
+ }
2851
+ catch {
2852
+ return false;
2853
+ }
2854
+ return parsed.protocol === "https:" && !parsed.username && !parsed.password && parsed.href === value;
2855
+ }
2856
+ function apsBodyRefusal(body) {
2857
+ const form = parseForm(body);
2858
+ if (!form)
2859
+ return "aps_body_unsupported";
2860
+ const has = (name) => form.values.has(name);
2861
+ if (has("token_name"))
2862
+ return "aps_saved_card_refused";
2863
+ if ([...form.values.keys()].some((name) => /^merchant_extra[1-5]?$|^agreement_id$|^recurring_/.test(name)))
2864
+ return "aps_recurring_refused";
2865
+ if (has("service_command") && form.values.get("service_command") !== "TOKENIZATION")
2866
+ return "aps_service_command_refused";
2867
+ const allowed = /* @__PURE__ */ new Set([...APS_SIGNED_FIELDS, ...APS_CARD_FIELDS, ...APS_OPTIONAL_FIELDS]);
2868
+ if (form.pairs.some(({ name }) => !allowed.has(name)))
2869
+ return "aps_body_unsupported";
2870
+ if (!returnUrlAdmitted(form.values.get("return_url")))
2871
+ return "aps_return_url_refused";
2872
+ for (const name of [...APS_SIGNED_FIELDS, ...APS_CARD_FIELDS]) {
2873
+ if (name !== "return_url" && !SHAPES.get(name)(form.values.get(name)))
2874
+ return "aps_body_unsupported";
2875
+ }
2876
+ for (const name of APS_OPTIONAL_FIELDS) {
2877
+ if (has(name) && !SHAPES.get(name)(form.values.get(name)))
2878
+ return "aps_body_unsupported";
2879
+ }
2880
+ return null;
2881
+ }
2882
+ function apsBodyVerdict(body, url) {
2883
+ if (url !== void 0 && !apsTokenizationUrl(url))
2884
+ return { verdict: "refuse", code: "aps_url_refused" };
2885
+ const form = parseForm(body);
2886
+ const names = form ? [...form.values.keys()] : typeof body === "string" ? body.split("&").map((chunk) => {
2887
+ try {
2888
+ return decodeURIComponent(chunk.split("=")[0].replace(/\+/g, " "));
2889
+ }
2890
+ catch {
2891
+ return APS_CARD_FIELDS[0];
2892
+ }
2893
+ }) : [APS_CARD_FIELDS[0]];
2894
+ const mentionsCard = !form && typeof body === "string" && APS_CARD_FIELDS.some((name) => body.toLowerCase().includes(name) || body.replace(/%([0-9A-Fa-f]{2})/g, (_, hex) => String.fromCharCode(parseInt(hex, 16))).toLowerCase().includes(name));
2895
+ if (!mentionsCard && !names.some((name) => APS_CARD_FIELDS.includes(name.trim().toLowerCase())))
2896
+ return { verdict: "continue" };
2897
+ const code = apsBodyRefusal(body);
2898
+ return code ? { verdict: "refuse", code } : { verdict: "card" };
2899
+ }
2900
+ var ANSWER_LIMIT = 64 * 1024;
2453
2901
  // src/card-fields.js
2454
2902
  function processorGate(recognizer, url, body) {
2455
2903
  if (recognizer && recognizer.psp === LYRA_PSP)
@@ -2461,6 +2909,11 @@ function processorGate(recognizer, url, body) {
2461
2909
  }
2462
2910
  if (recognizer && recognizer.psp === KOMOJU_PSP)
2463
2911
  return komojuBodyVerdict(body, url);
2912
+ if (recognizer && recognizer.psp === HIPAY_PSP) {
2913
+ if (url !== void 0 && !isHipayTokenUrl(url))
2914
+ return { verdict: "refuse", code: "hipay_url_refused" };
2915
+ return hipayBodyVerdict(body);
2916
+ }
2464
2917
  if (recognizer && recognizer.psp === PADDLE_VGS_PSP) {
2465
2918
  if (url !== void 0 && !isPaddleVgsCardsUrl(url))
2466
2919
  return { verdict: "refuse", code: "paddle_vgs_url_refused" };
@@ -2482,6 +2935,19 @@ function processorGate(recognizer, url, body) {
2482
2935
  return { verdict: "refuse", code: "pay_nl_url_refused" };
2483
2936
  return payNlBodyVerdict(body);
2484
2937
  }
2938
+ if (recognizer && recognizer.psp === TWOC2P_PSP) {
2939
+ if (url === void 0)
2940
+ return twoC2pBodyVerdict(body);
2941
+ const target = twoC2pPaymentTarget(url);
2942
+ if (target === null)
2943
+ return { verdict: "refuse", code: "twoc2p_url_refused" };
2944
+ if (!target.reviewed)
2945
+ return twoC2pPaymentCarriesCard(body) ? { verdict: "refuse", code: "twoc2p_build_unreviewed" } : { verdict: "continue" };
2946
+ const keyBytes = twoC2pKeyBytes(target.environment);
2947
+ return keyBytes === null ? { verdict: "refuse", code: "twoc2p_field_unreviewed" } : twoC2pBodyVerdict(body, keyBytes, target.environment);
2948
+ }
2949
+ if (recognizer && recognizer.psp === APS_PSP)
2950
+ return apsBodyVerdict(body, url);
2485
2951
  if (recognizer && recognizer.psp === PADDLE_TOKENEX_PSP) {
2486
2952
  const target = url !== void 0 ? paddleTokenexPayTarget(url) : null;
2487
2953
  if (url !== void 0 && target === null)