@agent-cards/sdk 0.23.8 → 0.23.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/PREFLIGHT.md +7 -5
  3. package/README.md +181 -92
  4. package/dist/aci.d.ts +7 -5
  5. package/dist/aci.generated.d.ts +2 -1
  6. package/dist/aci.generated.js +14 -4
  7. package/dist/aci.js +28 -7
  8. package/dist/amadeus-checkout.generated.js +2 -2
  9. package/dist/builtin-registry.generated.js +1 -1
  10. package/dist/card-fields.generated.js +163 -9
  11. package/dist/cdp.js +79 -34
  12. package/dist/client.d.ts +61 -31
  13. package/dist/client.js +99 -42
  14. package/dist/creditguard.generated.d.ts +1 -1
  15. package/dist/creditguard.generated.js +1 -3
  16. package/dist/cse-body.d.ts +7 -6
  17. package/dist/cse-body.js +8 -7
  18. package/dist/cybersource-secure-acceptance.generated.js +4 -3
  19. package/dist/datatrans.generated.js +8 -5
  20. package/dist/elavon-converge.d.ts +1 -1
  21. package/dist/elavon-converge.generated.js +7 -4
  22. package/dist/elavon-converge.js +4 -3
  23. package/dist/fiserv.d.ts +9 -5
  24. package/dist/fiserv.generated.d.ts +3 -3
  25. package/dist/fiserv.generated.js +50 -20
  26. package/dist/fiserv.js +10 -6
  27. package/dist/payrails.d.ts +78 -18
  28. package/dist/payrails.generated.d.ts +12 -2
  29. package/dist/payrails.generated.js +213 -18
  30. package/dist/payrails.js +165 -44
  31. package/dist/pre-claim.js +51 -29
  32. package/dist/preflight-capabilities.generated.d.ts +0 -106
  33. package/dist/preflight-capabilities.generated.js +0 -153
  34. package/dist/preflight-catalog.json +61 -181
  35. package/dist/preflight-schemas.json +6 -6
  36. package/dist/preflight.generated.d.ts +0 -106
  37. package/dist/preflight.generated.js +27 -15
  38. package/dist/preparation.d.ts +2 -0
  39. package/dist/preparation.js +4 -2
  40. package/dist/prepared-processor.d.ts +19 -5
  41. package/dist/prepared-processor.js +21 -5
  42. package/dist/primer.generated.d.ts +5 -1
  43. package/dist/primer.generated.js +200 -33
  44. package/dist/registry.d.ts +18 -12
  45. package/dist/registry.js +11 -8
  46. package/dist/shiji-sts.d.ts +24 -22
  47. package/dist/shiji-sts.generated.d.ts +1 -1
  48. package/dist/shiji-sts.generated.js +12 -8
  49. package/dist/shiji-sts.js +49 -46
  50. package/dist/stripe-checkout.generated.js +146 -49
  51. package/dist/verifone.generated.js +192 -17
  52. package/dist/verifone.js +1 -1
  53. package/dist/wspay.d.ts +17 -16
  54. package/dist/wspay.generated.d.ts +6 -1
  55. package/dist/wspay.generated.js +13 -3
  56. package/dist/wspay.js +9 -11
  57. package/examples/preflight/kernel-native/README.md +1 -1
  58. package/examples/preflight/kernel-native/inventory.json +1 -19
  59. package/package.json +3 -3
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
2
  // Generated from @agent-cards/payment-core. Do not edit.
3
- // artifact-sha256: b5b6d696111cb2906b73f99dc9ed21cbf51580bd0799183694ed5147c8a10e66
3
+ // artifact-sha256: 624ca03645e28d72156188c850b3650fd0f5162b0366475e6a124657120f7f11
4
4
  // src/aci.js
5
5
  var ACI_HOSTS = Object.freeze(["eu-prod.oppwa.com", "oppwa.com", "eu-test.oppwa.com", "test.oppwa.com"]);
6
6
  var ACI_TEST_HOSTS = Object.freeze(["eu-test.oppwa.com", "test.oppwa.com"]);
@@ -22,6 +22,9 @@ var ACI_ABSORBED_FIELDS = Object.freeze(["card.cvv", "card.expiryMonth", "card.e
22
22
  var ACI_PASSED_FIELDS = Object.freeze(["card.holder"]);
23
23
  var ACI_SIBLING_KEYS = Object.freeze(["customParameters[SHOPPER_EndToEndIdentity]"]);
24
24
  var ACI_REMOVED_ON_CONTINUATION = Object.freeze(["card.expiryMonth", "card.expiryYear"]);
25
+ var ACI_FINGERPRINT_FIELD = "customer.browserFingerprint.value";
26
+ var FINGERPRINT_LENGTH = 4096;
27
+ var LEG_BODY_LIMIT = 16384;
25
28
  var END_TO_END = ACI_SIBLING_KEYS[0];
26
29
  var CHECKOUT_ID = /^[0-9A-F]{32}\.[a-z0-9]{1,16}-vm-tx[0-9]{1,3}$/i;
27
30
  var ENDPOINT_PATH = /^\/v1\/checkouts\/([^/]+?)(\/payment|\/registration)?$/;
@@ -76,7 +79,8 @@ function readAciForm(body, limit = 8192) {
76
79
  catch {
77
80
  return null;
78
81
  }
79
- if (!key || key.length > 128 || CONTROL.test(key) || CONTROL.test(value) || value.length > 2048 || seen.has(key))
82
+ const longest = key === ACI_FINGERPRINT_FIELD ? FINGERPRINT_LENGTH : 2048;
83
+ if (!key || key.length > 128 || CONTROL.test(key) || CONTROL.test(value) || value.length > longest || seen.has(key))
80
84
  return null;
81
85
  seen.add(key);
82
86
  pairs.push({ key, value, raw });
@@ -117,11 +121,13 @@ function classifyAciRequest(request) {
117
121
  return refuse(ACI_CARD_ON_FILE_REFUSED);
118
122
  if (endpoint.kind === "payment")
119
123
  return { leg: "continuation", ...at };
120
- const pairs = readAciForm(request.body);
124
+ const pairs = readAciForm(request.body, LEG_BODY_LIMIT);
121
125
  if (!pairs)
122
126
  return refuse(ACI_UNSUPPORTED_REQUEST);
123
127
  if (pairs.some(({ key }) => isAciCardOnFileKey(key)))
124
128
  return refuse(ACI_CARD_ON_FILE_REFUSED);
129
+ if (pairs.length === 1 && pairs[0].key === ACI_FINGERPRINT_FIELD)
130
+ return { leg: "pass", ...at };
125
131
  if (!pairs.every(({ key, value }) => validField(key, value)))
126
132
  return refuse(ACI_UNSUPPORTED_REQUEST);
127
133
  const own = pairs.map(({ key }) => key).filter((key) => key !== END_TO_END);
@@ -199,6 +205,7 @@ function aciPlaceholderBrandRefusal(templateBody, card) {
199
205
  var CONTINUATION_KEYS = /* @__PURE__ */ new Set([
200
206
  "paymentBrand",
201
207
  "shopperResultUrl",
208
+ "shopperResultTarget",
202
209
  "shopOrigin",
203
210
  "forceUtf8",
204
211
  "card.holder",
@@ -250,6 +257,9 @@ function prepareAciContinuation(request, context) {
250
257
  if (!pairs.every(({ key }) => continuationKey(key)))
251
258
  return refuse(ACI_UNSUPPORTED_REQUEST);
252
259
  const value = (key) => pairs.find((pair) => pair.key === key)?.value;
260
+ const target = value("shopperResultTarget");
261
+ if (target !== void 0 && target !== "_top")
262
+ return refuse(ACI_UNSUPPORTED_REQUEST);
253
263
  if (typeof brand !== "string" || !/^[A-Z]{2,16}$/.test(brand) || value("paymentBrand") !== brand)
254
264
  return refuse(ACI_BRAND_MISMATCH);
255
265
  if (!onOrigin(value("shopperResultUrl"), merchantOrigin))
@@ -303,4 +313,4 @@ function sanitizeAciResponse(text) {
303
313
  throw new Error("Refusing to store an unconfirmed ACI answer.");
304
314
  return JSON.stringify({ result: { code: ACI_CHECKOUT_UPDATED, description: "successfully updated checkout" } });
305
315
  }
306
- export { ACI_ABSORBED_FIELDS, ACI_BRAND_MISMATCH, ACI_CARD_FIELD, ACI_CARD_ON_FILE_REFUSED, ACI_CHECKOUT_UPDATED, ACI_EXPIRY_UNSTRIPPABLE, ACI_HOSTS, ACI_PASSED_FIELDS, ACI_REMOVED_ON_CONTINUATION, ACI_RESULT_URL_REFUSED, ACI_SIBLING_KEYS, ACI_TEST_HOSTS, ACI_TEST_PANS, ACI_UNSUPPORTED_REQUEST, aciBrandForNetwork, aciBrandOfCardLeg, aciCardBrand, aciEndpoint, aciEnvironment, aciFacts, aciHostEnvironment, aciPlaceholderBrandRefusal, aciResponseOutcome, classifyAciRequest, injectAciCard, isAciCardOnFileKey, isAciCardRequest, isPreparedAciRequest, prepareAciContinuation, readAciForm, sanitizeAciResponse };
316
+ export { ACI_ABSORBED_FIELDS, ACI_BRAND_MISMATCH, ACI_CARD_FIELD, ACI_CARD_ON_FILE_REFUSED, ACI_CHECKOUT_UPDATED, ACI_EXPIRY_UNSTRIPPABLE, ACI_FINGERPRINT_FIELD, ACI_HOSTS, ACI_PASSED_FIELDS, ACI_REMOVED_ON_CONTINUATION, ACI_RESULT_URL_REFUSED, ACI_SIBLING_KEYS, ACI_TEST_HOSTS, ACI_TEST_PANS, ACI_UNSUPPORTED_REQUEST, aciBrandForNetwork, aciBrandOfCardLeg, aciCardBrand, aciEndpoint, aciEnvironment, aciFacts, aciHostEnvironment, aciPlaceholderBrandRefusal, aciResponseOutcome, classifyAciRequest, injectAciCard, isAciCardOnFileKey, isAciCardRequest, isPreparedAciRequest, prepareAciContinuation, readAciForm, sanitizeAciResponse };
package/dist/aci.js CHANGED
@@ -12,7 +12,10 @@
12
12
  // - the page's own CVC and expiry requests carry the agent's placeholder values: they are held
13
13
  // and answered with the card-number request's answer once it lands, never forwarded, and
14
14
  // failed when it does not (or when no card-number request for their checkout ever begins);
15
- // - the holder request carries nothing secret and continues;
15
+ // - the holder request and the ReD Shield device fingerprint the widget posts on load carry
16
+ // nothing secret and continue;
17
+ // - a refused request fails the checkout's waiting CVC and expiry requests only when it is that
18
+ // checkout's card-number request: a refusal that names no card number leaves them waiting;
16
19
  // - a second card-number request on a checkout whose first one is running or was answered here
17
20
  // is refused: that answer put the real card on the checkout and may already have let /payment
18
21
  // through, and ACI warns that one checkout id reused can carry a second transaction;
@@ -22,7 +25,7 @@
22
25
  // It continues only as a frame navigation, which is how the widget's form posts it into its
23
26
  // hidden iframe, and a classic-mode body only on a browser shown to send the body the SDK
24
27
  // replaced on a navigation (Chromium; see playwrightReplacesNavigationBody).
25
- import { aciBrandOfCardLeg as brandOfCardLeg, aciEndpoint, classifyAciRequest, prepareAciContinuation, sanitizeAciResponse, } from './aci.generated.js';
28
+ import { ACI_CARD_FIELD, aciBrandOfCardLeg as brandOfCardLeg, aciEndpoint, classifyAciRequest, prepareAciContinuation, sanitizeAciResponse, } from './aci.generated.js';
26
29
  const classifyLeg = classifyAciRequest;
27
30
  const judgePayment = prepareAciContinuation;
28
31
  /** The processor id, as the registry and the API name it. */
@@ -164,6 +167,20 @@ export async function playwrightReplacesNavigationBody(page, probeMs = ACI_ENGIN
164
167
  }
165
168
  }
166
169
  const groupKey = (leg) => `${leg.host}/${leg.checkoutId}`;
170
+ /** Whether a form body has a card.number key, whatever else it carries and however it broke the rules. */
171
+ function namesCardNumber(body) {
172
+ if (typeof body !== 'string')
173
+ return false;
174
+ return body.split('&').some((pair) => {
175
+ const eq = pair.indexOf('=');
176
+ try {
177
+ return decodeURIComponent((eq < 0 ? pair : pair.slice(0, eq)).replace(/\+/g, ' ')) === ACI_CARD_FIELD;
178
+ }
179
+ catch {
180
+ return false;
181
+ }
182
+ });
183
+ }
167
184
  /**
168
185
  * One attachment's ACI state, keyed by checkout (host and checkout id). Every sibling and every
169
186
  * /payment submission is matched against a card-number request this attachment itself paused and
@@ -280,12 +297,16 @@ export class AciGate {
280
297
  this.prune();
281
298
  }
282
299
  /**
283
- * A request on this checkout was refused before any card-number request began (a card-number
284
- * request that asks ACI to keep the card, a leg the widget never sends): the siblings waiting for
285
- * one fail now, and so does every later sibling until a card-number request begins. A running or
286
- * answered card-number request keeps its siblings.
300
+ * A request on this checkout was refused. When it names the card number (a card-number request
301
+ * that asks ACI to keep the card, or carries a field the widget never sends with it) and no
302
+ * card-number request began, the siblings waiting for one fail now, and so does every later sibling
303
+ * until a card-number request begins. A refused request that names no card number, such as a
304
+ * fingerprint longer than ACI takes, says nothing about the card-number request a later Pay sends,
305
+ * so its siblings keep waiting for it. A running or answered card-number request keeps its siblings.
287
306
  */
288
- refused(leg) {
307
+ refused(leg, body) {
308
+ if (!namesCardNumber(body))
309
+ return;
289
310
  const key = groupKey(leg);
290
311
  const known = this.groups.get(key);
291
312
  if (known && known.state !== 'failed')
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
2
  // Generated from @agent-cards/payment-core. Do not edit.
3
- // artifact-sha256: bc8b9a0ad66eb321bec67650079b2d157a84f9f8de4ad79cc9006b937a9a5a58
3
+ // artifact-sha256: d537d04a5cd64f34af196a0f6cec7a7f5319bb396d94824131857a04632aab0a
4
4
  // src/amadeus-body.js
5
5
  var AMADEUS_CARD_MOPID = /^creditcard[0-9]*$/;
6
6
  var record = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
@@ -44,7 +44,7 @@ var AMADEUS_CARD_URLS = Object.freeze({
44
44
  })
45
45
  });
46
46
  var AMADEUS_MERCHANT_EXPIRY_POLICIES = Object.freeze(["refuse", "fill"]);
47
- var AMADEUS_MERCHANT_EXPIRY_POLICY = "refuse";
47
+ var AMADEUS_MERCHANT_EXPIRY_POLICY = "fill";
48
48
  var AMADEUS_REFUSAL_REASONS = Object.freeze([
49
49
  "unsupported",
50
50
  "card_on_file",
@@ -1 +1 @@
1
- export const BUILTIN_REGISTRY = [{ "psp": "spreedly", "match": /core\.spreedly\.com\/v1\/payment_methods\/restricted\.json/i, "hosts": ["^core\\.spreedly\\.com$"], "encoding": "json", "passthroughHeaders": [/^spreedly-environment-key$/i] }, { "psp": "shopify", "match": /(checkout\.pci\.shopifyinc\.com|deposit\.[a-z0-9-]+\.shopifycs\.com)\/sessions/i, "hosts": ["^checkout\\.pci\\.shopifyinc\\.com$", "^deposit\\.[a-z0-9-]+\\.shopifycs\\.com$"], "encoding": "json", "passthroughHeaders": [/^shopify-identification-signature$/i] }, { "psp": "stripe", "match": /api\.stripe\.com\/v1\/(payment_methods|tokens|sources|confirmation_tokens|setup_intents\/seti_\w+\/confirm|payment_intents\/pi_\w+\/confirm|payment_pages\/cs_(?:test|live)_\w+\/confirm)/i, "hosts": ["^api\\.stripe\\.com$"], "encoding": "form", "passthroughHeaders": [/^authorization$/i, /^stripe-version$/i, /^x-stripe-client-user-agent$/i], "cardFields": ["card[number]", "payment_method_data[card][number]"], "passWithoutCard": "api\\.stripe\\.com/v1/(sources|confirmation_tokens|payment_pages/cs_(?:test|live)_\\w+/confirm)" }, { "psp": "braintree", "match": /payments(\.sandbox)?\.braintree-api\.com\/graphql/i, "hosts": ["^payments\\.braintree-api\\.com$", "^payments\\.sandbox\\.braintree-api\\.com$"], "sandboxHosts": ["^payments\\.sandbox\\.braintree-api\\.com$"], "encoding": "json", "passthroughHeaders": [/^authorization$/i, /^braintree-version$/i] }, { "psp": "checkout_com", "match": /(api|card-acquisition-gateway)(\.sandbox)?\.checkout\.com\/tokens/i, "hosts": ["^api\\.checkout\\.com$", "^api\\.sandbox\\.checkout\\.com$", "^card-acquisition-gateway\\.checkout\\.com$", "^card-acquisition-gateway\\.sandbox\\.checkout\\.com$"], "sandboxHosts": ["^api\\.sandbox\\.checkout\\.com$", "^card-acquisition-gateway\\.sandbox\\.checkout\\.com$"], "encoding": "json", "passthroughHeaders": [/^authorization$/i] }, { "psp": "adyen", "match": /(checkoutshopper-(test|live(-[a-z]+)?)\.adyen\.com|([a-z0-9-]+\.)*adyenpayments\.com)\/checkoutshopper\/v1\/sessions\/[A-Za-z0-9_-]+\/payments/i, "hosts": ["^checkoutshopper-(test|live(-[a-z]+)?)\\.adyen\\.com$", "^([a-z0-9-]+\\.)*adyenpayments\\.com$"], "sandboxHosts": ["^checkoutshopper-test\\.adyen\\.com$"], "encoding": "json", "passthroughHeaders": [], "clientSideEncrypted": true, "mode": "cse" }, { "psp": "tranzila", "match": /(direct\.tranzila\.com\/process\/n\/|directng\.tranzila\.com\/process\/?)/i, "hosts": ["^direct\\.tranzila\\.com$", "^directng\\.tranzila\\.com$"], "encoding": "form", "passthroughHeaders": [], "mode": "hosted_form" }, { "psp": "square", "match": /pci-connect\.squareup(?:sandbox)?\.com\/v2\/card-nonce/i, "hosts": ["^pci-connect\\.squareup\\.com$", "^pci-connect\\.squareupsandbox\\.com$"], "sandboxHosts": ["^pci-connect\\.squareupsandbox\\.com$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "authorize_net", "match": /(api2|apitest)\.authorize\.net\/xml\/v1\/request\.api/i, "hosts": ["^api2\\.authorize\\.net$", "^apitest\\.authorize\\.net$"], "sandboxHosts": ["^apitest\\.authorize\\.net$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "worldpay", "match": /(try\.)?access\.worldpay\.com\/(sessions\/card|verifiedTokens\/sessions)/i, "hosts": ["^access\\.worldpay\\.com$", "^try\\.access\\.worldpay\\.com$"], "sandboxHosts": ["^try\\.access\\.worldpay\\.com$"], "encoding": "json", "passthroughHeaders": [/^accept$/i] }, { "psp": "nuvei", "match": /(secure|ppp-test)\.safecharge\.com\/ppp\/api\/v1\/(?:cardTokenization|clientPayment|websdk\/initPaymentWithCardTokenization)\.do/i, "hosts": ["^secure\\.safecharge\\.com$", "^ppp-test\\.safecharge\\.com$"], "sandboxHosts": ["^ppp-test\\.safecharge\\.com$"], "encoding": "json", "passthroughHeaders": [], "jsonCardFields": [["paymentOption", "card", "cardNumber"], ["cardData", "cardNumber"]], "passWithoutCard": "(?:secure|ppp-test)\\.safecharge\\.com/ppp/api/v1/(?:clientPayment|websdk/initPaymentWithCardTokenization)\\.do" }, { "psp": "airwallex", "match": /(checkout(\.sandbox)?\.airwallex\.com|pci-api(\.sandbox)?\.airwallex\.com)\/api\/v1\/pa\/(payment_intents\/[^/?#]+\/confirm|payment_consents\/[^/?#]+\/verify|payment_methods\/create)(\?|$)/i, "hosts": ["^checkout\\.airwallex\\.com$", "^checkout\\.sandbox\\.airwallex\\.com$", "^pci-api\\.airwallex\\.com$", "^pci-api\\.sandbox\\.airwallex\\.com$"], "sandboxHosts": ["^checkout\\.sandbox\\.airwallex\\.com$", "^pci-api\\.sandbox\\.airwallex\\.com$"], "encoding": "json", "passthroughHeaders": [/^client-secret$/i, /^authorization$/i, /^x-auth-token$/i, /^x-on-behalf-of$/i, /^x-api-version$/i] }, { "psp": "rapyd", "match": /(api|sandboxapi)\.rapyd\.net\/v1\/(?:hosted\/collect\/card\/[^/?#]+\/payment_method|checkout\/checkout_[A-Za-z0-9]+)(?:[?#]|$)/i, "hosts": ["^api\\.rapyd\\.net$", "^sandboxapi\\.rapyd\\.net$"], "sandboxHosts": ["^sandboxapi\\.rapyd\\.net$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "dlocal", "match": /ppmcc(-sandbox)?\.dlocal\.com\/cvault\/credit-card\/temporal/i, "hosts": ["^ppmcc\\.dlocal\\.com$", "^ppmcc-sandbox\\.dlocal\\.com$"], "sandboxHosts": ["^ppmcc-sandbox\\.dlocal\\.com$"], "encoding": "json", "passthroughHeaders": [/^x-fields-api-key$/i, /^x-uow$/i, /^x-dlocal-infrav2$/i] }, { "psp": "ebanx", "match": /(?:(?:customer-frontier|customer|api-local-latam|api|sandbox-local-latam|sandbox)\.ebanx\.com|(?:api-diamond|api|sandbox)\.ebanxpay\.com)\/ws\/token/i, "hosts": ["^customer\\.ebanx\\.com$", "^customer-frontier\\.ebanx\\.com$", "^api\\.ebanx\\.com$", "^sandbox\\.ebanx\\.com$", "^api-local-latam\\.ebanx\\.com$", "^sandbox-local-latam\\.ebanx\\.com$", "^api-diamond\\.ebanxpay\\.com$", "^api\\.ebanxpay\\.com$", "^sandbox\\.ebanxpay\\.com$"], "sandboxHosts": ["^sandbox\\.ebanx\\.com$", "^sandbox-local-latam\\.ebanx\\.com$", "^sandbox\\.ebanxpay\\.com$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "mercado_pago", "match": /api\.mercadopago\.com\/v1\/card_tokens(?![\w/-])/i, "hosts": ["^api\\.mercadopago\\.com$"], "encoding": "json", "passthroughHeaders": [/^x-product-id$/i] }, { "psp": "payu", "match": /(secure\.payu\.com|(merch-prod|secure)\.snd\.payu\.com)\/api\/front\/tokens/i, "hosts": ["^secure\\.payu\\.com$", "^(merch-prod|secure)\\.snd\\.payu\\.com$"], "sandboxHosts": ["^(merch-prod|secure)\\.snd\\.payu\\.com$"], "encoding": "json", "passthroughHeaders": [/^authorization$/i] }, { "psp": "razorpay", "match": /api\.razorpay\.com\/v1\/(?:standard_checkout\/)?payments\/create\/(?:ajax|checkout|fees)/i, "hosts": ["^api\\.razorpay\\.com$"], "encoding": "form", "passthroughHeaders": [/^x-razorpay-sessionid$/i, /^x-customer-access-token$/i] }, { "psp": "mollie", "match": /api\.cc\.mollie\.com\/v1\/card-tokens/i, "hosts": ["^api\\.cc\\.mollie\\.com$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "paysafe", "match": /(?:api(\.test)?\.paysafe\.com\/(?:paymenthub\/v1\/singleusepaymenthandles|js\/api\/v1\/tokenize)|hosted(\.test)?\.paysafe\.com\/checkout\/api\/v1\/tokenize)(?![\w/-])/i, "hosts": ["^api\\.paysafe\\.com$", "^api\\.test\\.paysafe\\.com$", "^hosted\\.paysafe\\.com$", "^hosted\\.test\\.paysafe\\.com$"], "sandboxHosts": ["^api\\.test\\.paysafe\\.com$", "^hosted\\.test\\.paysafe\\.com$"], "encoding": "json", "passthroughHeaders": [/^authorization$/i, /^x-paysafe-credentials$/i, /^correlationid$/i] }, { "psp": "recurly", "match": /api(\.eu)?\.recurly\.com\/js\/v1\/token(?![\w-])/i, "hosts": ["^api\\.recurly\\.com$", "^api\\.eu\\.recurly\\.com$"], "encoding": "form", "passthroughHeaders": [/^recurly-credential-checkout-hostname$/i] }, { "psp": "moneris", "match": /(www3|esqa|gateway|gatewayqa|gatewayt|gatewaydev)\.moneris\.com\/HPPtoken\/request\.php/i, "hosts": ["^www3\\.moneris\\.com$", "^esqa\\.moneris\\.com$", "^gateway\\.moneris\\.com$", "^gatewayqa\\.moneris\\.com$", "^gatewayt\\.moneris\\.com$", "^gatewaydev\\.moneris\\.com$"], "sandboxHosts": ["^esqa\\.moneris\\.com$", "^gatewayqa\\.moneris\\.com$", "^gatewayt\\.moneris\\.com$", "^gatewaydev\\.moneris\\.com$"], "encoding": "form", "passthroughHeaders": [] }, { "psp": "bambora", "match": /(api\.na\.bambora\.com|api\.bam\.shift4api\.net)\/scripts\/tokenization\/tokens/i, "hosts": ["^api\\.na\\.bambora\\.com$", "^api\\.bam\\.shift4api\\.net$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "global_payments", "match": /(?:api\.heartlandportico\.com\/SecureSubmit\.v1\/api\/token|cert\.api2\.heartlandportico\.com\/Hps\.Exchange\.PosGateway\.Hpf\.v1\/api\/token|apis(?:\.sandbox)?(?:\.eu)?\.globalpay\.com\/ucp\/(?:merchants\/[^/]+\/)?payment-methods)/i, "hosts": ["^api\\.heartlandportico\\.com$", "^cert\\.api2\\.heartlandportico\\.com$", "^apis\\.globalpay\\.com$", "^apis\\.sandbox\\.globalpay\\.com$", "^apis\\.eu\\.globalpay\\.com$", "^apis\\.sandbox\\.eu\\.globalpay\\.com$"], "sandboxHosts": ["^cert\\.api2\\.heartlandportico\\.com$", "^apis\\.sandbox\\.globalpay\\.com$", "^apis\\.sandbox\\.eu\\.globalpay\\.com$"], "encoding": "json", "passthroughHeaders": [/^authorization$/i, /^x-gp-version$/i] }, { "psp": "gravy", "match": /api(\.sandbox)?\.[a-z0-9-]+\.gr4vy\.app\/checkout\/sessions\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\/fields/i, "hosts": ["^api\\.[a-z0-9-]+\\.gr4vy\\.app$", "^api\\.sandbox\\.[a-z0-9-]+\\.gr4vy\\.app$"], "sandboxHosts": ["^api\\.sandbox\\.[a-z0-9-]+\\.gr4vy\\.app$"], "encoding": "json", "passthroughHeaders": [] }];
1
+ export const BUILTIN_REGISTRY = [{ "psp": "spreedly", "match": /core\.spreedly\.com\/v1\/payment_methods\/restricted\.json/i, "hosts": ["^core\\.spreedly\\.com$"], "encoding": "json", "passthroughHeaders": [/^spreedly-environment-key$/i] }, { "psp": "shopify", "match": /(checkout\.pci\.shopifyinc\.com|deposit\.[a-z0-9-]+\.shopifycs\.com)\/sessions/i, "hosts": ["^checkout\\.pci\\.shopifyinc\\.com$", "^deposit\\.[a-z0-9-]+\\.shopifycs\\.com$"], "encoding": "json", "passthroughHeaders": [/^shopify-identification-signature$/i] }, { "psp": "stripe", "match": /api\.stripe\.com\/v1\/(payment_methods|tokens|sources|confirmation_tokens|setup_intents\/seti_\w+\/confirm|payment_intents\/pi_\w+\/confirm|payment_pages\/cs_(?:test|live)_\w+\/confirm)/i, "hosts": ["^api\\.stripe\\.com$"], "encoding": "form", "passthroughHeaders": [/^authorization$/i, /^stripe-version$/i, /^x-stripe-client-user-agent$/i], "cardFields": ["card[number]", "payment_method_data[card][number]"], "passWithoutCard": "api\\.stripe\\.com/v1/(sources|confirmation_tokens|payment_pages/cs_(?:test|live)_\\w+/confirm)" }, { "psp": "braintree", "match": /payments(\.sandbox)?\.braintree-api\.com\/graphql/i, "hosts": ["^payments\\.braintree-api\\.com$", "^payments\\.sandbox\\.braintree-api\\.com$"], "sandboxHosts": ["^payments\\.sandbox\\.braintree-api\\.com$"], "encoding": "json", "passthroughHeaders": [/^authorization$/i, /^braintree-version$/i] }, { "psp": "checkout_com", "match": /(api|card-acquisition-gateway)(\.sandbox)?\.checkout\.com\/tokens/i, "hosts": ["^api\\.checkout\\.com$", "^api\\.sandbox\\.checkout\\.com$", "^card-acquisition-gateway\\.checkout\\.com$", "^card-acquisition-gateway\\.sandbox\\.checkout\\.com$"], "sandboxHosts": ["^api\\.sandbox\\.checkout\\.com$", "^card-acquisition-gateway\\.sandbox\\.checkout\\.com$"], "encoding": "json", "passthroughHeaders": [/^authorization$/i] }, { "psp": "adyen", "match": /(checkoutshopper-(test|live(-[a-z]+)?)\.adyen\.com|([a-z0-9-]+\.)*adyenpayments\.com)\/checkoutshopper\/v1\/sessions\/[A-Za-z0-9_-]+\/payments/i, "hosts": ["^checkoutshopper-(test|live(-[a-z]+)?)\\.adyen\\.com$", "^([a-z0-9-]+\\.)*adyenpayments\\.com$"], "sandboxHosts": ["^checkoutshopper-test\\.adyen\\.com$"], "encoding": "json", "passthroughHeaders": [], "clientSideEncrypted": true, "mode": "cse" }, { "psp": "tranzila", "match": /(direct\.tranzila\.com\/process\/n\/|directng\.tranzila\.com\/process\/?)/i, "hosts": ["^direct\\.tranzila\\.com$", "^directng\\.tranzila\\.com$"], "encoding": "form", "passthroughHeaders": [], "mode": "hosted_form" }, { "psp": "square", "match": /pci-connect\.squareup(?:sandbox)?\.com\/v2\/card-nonce/i, "hosts": ["^pci-connect\\.squareup\\.com$", "^pci-connect\\.squareupsandbox\\.com$"], "sandboxHosts": ["^pci-connect\\.squareupsandbox\\.com$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "authorize_net", "match": /(api2|apitest)\.authorize\.net\/xml\/v1\/request\.api/i, "hosts": ["^api2\\.authorize\\.net$", "^apitest\\.authorize\\.net$"], "sandboxHosts": ["^apitest\\.authorize\\.net$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "worldpay", "match": /(try\.)?access\.worldpay\.com\/(sessions\/card|verifiedTokens\/sessions)/i, "hosts": ["^access\\.worldpay\\.com$", "^try\\.access\\.worldpay\\.com$"], "sandboxHosts": ["^try\\.access\\.worldpay\\.com$"], "encoding": "json", "passthroughHeaders": [/^accept$/i] }, { "psp": "nuvei", "match": /(secure|ppp-test)\.safecharge\.com\/ppp\/api\/v1\/(?:cardTokenization|clientPayment|websdk\/initPaymentWithCardTokenization)\.do/i, "hosts": ["^secure\\.safecharge\\.com$", "^ppp-test\\.safecharge\\.com$"], "sandboxHosts": ["^ppp-test\\.safecharge\\.com$"], "encoding": "json", "passthroughHeaders": [], "jsonCardFields": [["paymentOption", "card", "cardNumber"], ["cardData", "cardNumber"]], "passWithoutCard": "(?:secure|ppp-test)\\.safecharge\\.com/ppp/api/v1/(?:clientPayment|websdk/initPaymentWithCardTokenization)\\.do" }, { "psp": "airwallex", "match": /(checkout(\.sandbox)?\.airwallex\.com|pci-api(\.sandbox)?\.airwallex\.com)\/api\/v1\/pa\/(payment_intents\/[^/?#]+\/confirm|payment_consents\/[^/?#]+\/verify|payment_methods\/create)(\?|$)/i, "hosts": ["^checkout\\.airwallex\\.com$", "^checkout\\.sandbox\\.airwallex\\.com$", "^pci-api\\.airwallex\\.com$", "^pci-api\\.sandbox\\.airwallex\\.com$"], "sandboxHosts": ["^checkout\\.sandbox\\.airwallex\\.com$", "^pci-api\\.sandbox\\.airwallex\\.com$"], "encoding": "json", "passthroughHeaders": [/^client-secret$/i, /^authorization$/i, /^x-auth-token$/i, /^x-on-behalf-of$/i, /^x-api-version$/i] }, { "psp": "rapyd", "match": /(api|sandboxapi)\.rapyd\.net\/v1\/(?:hosted\/collect\/card\/[^/?#]+\/payment_method|checkout\/checkout_[A-Za-z0-9]+)(?:[?#]|$)/i, "hosts": ["^api\\.rapyd\\.net$", "^sandboxapi\\.rapyd\\.net$"], "sandboxHosts": ["^sandboxapi\\.rapyd\\.net$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "dlocal", "match": /ppmcc(-sandbox)?\.dlocal\.com\/cvault\/credit-card\/temporal/i, "hosts": ["^ppmcc\\.dlocal\\.com$", "^ppmcc-sandbox\\.dlocal\\.com$"], "sandboxHosts": ["^ppmcc-sandbox\\.dlocal\\.com$"], "encoding": "json", "passthroughHeaders": [/^x-fields-api-key$/i, /^x-uow$/i, /^x-dlocal-infrav2$/i] }, { "psp": "ebanx", "match": /(?:(?:customer-frontier|customer|api-local-latam|api|sandbox-local-latam|sandbox)\.ebanx\.com|(?:api-diamond|api|sandbox)\.ebanxpay\.com)\/ws\/token/i, "hosts": ["^customer\\.ebanx\\.com$", "^customer-frontier\\.ebanx\\.com$", "^api\\.ebanx\\.com$", "^sandbox\\.ebanx\\.com$", "^api-local-latam\\.ebanx\\.com$", "^sandbox-local-latam\\.ebanx\\.com$", "^api-diamond\\.ebanxpay\\.com$", "^api\\.ebanxpay\\.com$", "^sandbox\\.ebanxpay\\.com$"], "sandboxHosts": ["^sandbox\\.ebanx\\.com$", "^sandbox-local-latam\\.ebanx\\.com$", "^sandbox\\.ebanxpay\\.com$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "mercado_pago", "match": /api\.mercadopago\.com\/v1\/card_tokens(?![\w/-])/i, "hosts": ["^api\\.mercadopago\\.com$"], "encoding": "json", "passthroughHeaders": [/^x-product-id$/i] }, { "psp": "payu", "match": /(secure\.payu\.com|(merch-prod|secure)\.snd\.payu\.com)\/api\/front\/tokens/i, "hosts": ["^secure\\.payu\\.com$", "^(merch-prod|secure)\\.snd\\.payu\\.com$"], "sandboxHosts": ["^(merch-prod|secure)\\.snd\\.payu\\.com$"], "encoding": "json", "passthroughHeaders": [/^authorization$/i] }, { "psp": "razorpay", "match": /api\.razorpay\.com\/v1\/(?:standard_checkout\/)?payments\/create\/(?:ajax|checkout|fees)/i, "hosts": ["^api\\.razorpay\\.com$"], "encoding": "form", "passthroughHeaders": [/^x-razorpay-sessionid$/i, /^x-customer-access-token$/i] }, { "psp": "mollie", "match": /api\.cc\.mollie\.com\/v1\/card-tokens/i, "hosts": ["^api\\.cc\\.mollie\\.com$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "paysafe", "match": /(?:api(\.test)?\.paysafe\.com\/(?:paymenthub\/v1\/singleusepaymenthandles|js\/api\/v1\/tokenize)|hosted(\.test)?\.paysafe\.com\/checkout\/api\/v1\/tokenize)(?![\w/-])/i, "hosts": ["^api\\.paysafe\\.com$", "^api\\.test\\.paysafe\\.com$", "^hosted\\.paysafe\\.com$", "^hosted\\.test\\.paysafe\\.com$"], "sandboxHosts": ["^api\\.test\\.paysafe\\.com$", "^hosted\\.test\\.paysafe\\.com$"], "encoding": "json", "passthroughHeaders": [/^authorization$/i, /^x-paysafe-credentials$/i, /^correlationid$/i] }, { "psp": "recurly", "match": /api(\.eu)?\.recurly\.com\/js\/v1\/token(?![\w-])/i, "hosts": ["^api\\.recurly\\.com$", "^api\\.eu\\.recurly\\.com$"], "encoding": "form", "passthroughHeaders": [/^recurly-credential-checkout-hostname$/i] }, { "psp": "bambora", "match": /(api\.na\.bambora\.com|api\.bam\.shift4api\.net)\/scripts\/tokenization\/tokens/i, "hosts": ["^api\\.na\\.bambora\\.com$", "^api\\.bam\\.shift4api\\.net$"], "encoding": "json", "passthroughHeaders": [] }, { "psp": "global_payments", "match": /(?:api\.heartlandportico\.com\/SecureSubmit\.v1\/api\/token|cert\.api2\.heartlandportico\.com\/Hps\.Exchange\.PosGateway\.Hpf\.v1\/api\/token|apis(?:\.sandbox)?(?:\.eu)?\.globalpay\.com\/ucp\/(?:merchants\/[^/]+\/)?payment-methods)/i, "hosts": ["^api\\.heartlandportico\\.com$", "^cert\\.api2\\.heartlandportico\\.com$", "^apis\\.globalpay\\.com$", "^apis\\.sandbox\\.globalpay\\.com$", "^apis\\.eu\\.globalpay\\.com$", "^apis\\.sandbox\\.eu\\.globalpay\\.com$"], "sandboxHosts": ["^cert\\.api2\\.heartlandportico\\.com$", "^apis\\.sandbox\\.globalpay\\.com$", "^apis\\.sandbox\\.eu\\.globalpay\\.com$"], "encoding": "json", "passthroughHeaders": [/^authorization$/i, /^x-gp-version$/i] }];
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
2
  // Generated from @agent-cards/payment-core. Do not edit.
3
- // artifact-sha256: 5c2c8becc2301811aee1b42b47148039ab07c8854932a21e80687e18090f1a93
3
+ // artifact-sha256: 6a0cf6104aac41a93fb4788532c63075d6831419127b76b87228dd7839c2a106
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
@@ -29,7 +29,8 @@ function jsonAt(root, path) {
29
29
  // src/elavon-converge.js
30
30
  var CONVERGE_PROCESS_URLS = /* @__PURE__ */ Object.freeze([
31
31
  "https://api.convergepay.com/hosted-payments/service/payment/hpp/process",
32
- "https://api.demo.convergepay.com/hosted-payments/service/payment/hpp/process"
32
+ "https://api.demo.convergepay.com/hosted-payments/service/payment/hpp/process",
33
+ "https://www.convergepay.com/hosted-payments/service/payment/hpp/process"
33
34
  ]);
34
35
  var TOP_LEVEL_KEYS = /* @__PURE__ */ Object.freeze(["paymentType", "paymentData", "context", "captchaToken", "shippingSameAsBilling"]);
35
36
  var WALLET_FIELDS = /* @__PURE__ */ Object.freeze([
@@ -70,6 +71,7 @@ var RECURRING_FIELDS = /* @__PURE__ */ Object.freeze([
70
71
  "ssl_recurring_batch_count",
71
72
  "ssl_installment_id"
72
73
  ]);
74
+ var ONE_TIME_RECURRING_FLAG = "false";
73
75
  var CARD_SAVING_FLAGS = /* @__PURE__ */ Object.freeze(["ssl_get_token", "ssl_add_token"]);
74
76
  var CREDENTIAL_FIELDS = /* @__PURE__ */ Object.freeze(["ssl_account_id", "ssl_merchant_id", "ssl_user_id", "ssl_pin", "ssl_vendor_id"]);
75
77
  var AMOUNT_ADD_ON_FIELDS = /* @__PURE__ */ Object.freeze(["ssl_tip_amount", "ssl_cashback_amount"]);
@@ -79,6 +81,7 @@ var CVC = /^\d{3,4}$/;
79
81
  var AMOUNT = /^(\d{1,13})(?:\.(\d{1,2}))?$/;
80
82
  var isRecord = (value) => !!value && typeof value === "object" && !Array.isArray(value);
81
83
  var owns = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
84
+ var recurringRequested = (data) => RECURRING_FIELDS.some((key) => owns(data, key) && !(key === "recurring" && data[key] === ONE_TIME_RECURRING_FLAG));
82
85
  var refuse = (code) => Object.freeze({ verdict: "refuse", code });
83
86
  var CARD = /* @__PURE__ */ Object.freeze({ verdict: "card" });
84
87
  var CONTINUE = /* @__PURE__ */ Object.freeze({ verdict: "continue" });
@@ -140,7 +143,7 @@ function convergeBodyVerdict(body) {
140
143
  if (owns(data, "ssl_token") || CARD_SAVING_FLAGS.some((key) => owns(data, key) && !(typeof data[key] === "string" && /^n$/i.test(data[key])))) {
141
144
  return refuse("converge_card_saving_refused");
142
145
  }
143
- if (RECURRING_FIELDS.some((key) => owns(data, key)))
146
+ if (recurringRequested(data))
144
147
  return refuse("converge_recurring_refused");
145
148
  if (owns(data, "ssl_transaction_currency") && !(typeof data.ssl_transaction_currency === "string" && /^usd$/i.test(data.ssl_transaction_currency))) {
146
149
  return refuse("converge_currency_refused");
@@ -169,11 +172,155 @@ function isConvergeProcessUrl(url) {
169
172
  }
170
173
  return parsed.href === url && CONVERGE_PROCESS_URLS.includes(parsed.href);
171
174
  }
172
- // src/amadeus-body.js
173
- var AMADEUS_CARD_MOPID = /^creditcard[0-9]*$/;
175
+ // src/gravy.js
176
+ var GRAVY_PSP = "gravy";
177
+ var BODY_LIMIT = 4096;
178
+ var CARD_KEYS = /* @__PURE__ */ Object.freeze(["method", "number", "expiration_date", "security_code"]);
179
+ var ROOT_KEYS = /* @__PURE__ */ Object.freeze(["payment_method", "postal_code"]);
180
+ var CARD_NUMBER2 = /^[0-9]{12,19}$/;
181
+ var EXPIRY = /^(?:0[1-9]|1[0-2])\/[0-9]{2}$/;
182
+ var SECURITY_CODE = /^[0-9]{3,4}$/;
183
+ var POSTAL_CODE = /^[A-Za-z0-9 -]{0,16}$/;
184
+ var PAN_LIKE = /(?:[0-9][ _.:-]*){12,}/;
185
+ var EXPIRY_OR_CODE = /^(?:expiration_?date|expiry(?:_?date)?|exp_?date|card_?expiry|security_?code|cvc|cvc2|cvv|cvv2|cvd|card_?cvv|card_?cvc|verification_?value)$/i;
174
186
  var record = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
175
187
  var owns2 = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
176
- var holdsPan = (mopdata) => record(mopdata) && owns2(mopdata, "pan") && mopdata.pan !== null && mopdata.pan !== "";
188
+ function cardNamed(key) {
189
+ const name = key.slice(key.lastIndexOf(".") + 1);
190
+ return CARD_NUMBER_KEY.test(name) || /cardnumber$/i.test(name) || EXPIRY_OR_CODE.test(name);
191
+ }
192
+ function cardOutside(root) {
193
+ const pending = [];
194
+ for (const key of Object.keys(root)) {
195
+ const value = root[key];
196
+ if (key === "payment_method" && record(value)) {
197
+ for (const inner of Object.keys(value))
198
+ if (!CARD_KEYS.includes(inner))
199
+ pending.push([inner, value[inner]]);
200
+ }
201
+ else {
202
+ pending.push([key, value]);
203
+ }
204
+ }
205
+ while (pending.length > 0) {
206
+ const [key, value] = pending.pop();
207
+ if (key !== null && cardNamed(key))
208
+ return true;
209
+ if (typeof value === "string" || typeof value === "number") {
210
+ if (PAN_LIKE.test(String(value)))
211
+ return true;
212
+ }
213
+ else if (Array.isArray(value)) {
214
+ for (const item of value)
215
+ pending.push([null, item]);
216
+ }
217
+ else if (record(value)) {
218
+ for (const inner of Object.keys(value))
219
+ pending.push([inner, value[inner]]);
220
+ }
221
+ }
222
+ return false;
223
+ }
224
+ function readBody(body) {
225
+ if (typeof body !== "string" || body === "" || body.length > BODY_LIMIT)
226
+ return null;
227
+ let value;
228
+ try {
229
+ value = JSON.parse(body);
230
+ if (!record(value) || JSON.stringify(value) !== body)
231
+ return null;
232
+ }
233
+ catch {
234
+ return null;
235
+ }
236
+ return value;
237
+ }
238
+ var refuse2 = (code) => Object.freeze({ verdict: "refuse", code });
239
+ var CARD2 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
240
+ function gravyBodyVerdict(body) {
241
+ const value = readBody(body);
242
+ if (value === null)
243
+ return refuse2("gravy_body_unsupported");
244
+ if (cardOutside(value))
245
+ return refuse2("gravy_card_outside_payment_method");
246
+ const card = value.payment_method;
247
+ if (!record(card) || card.method !== "card" || !CARD_KEYS.every((key) => owns2(card, key)))
248
+ return refuse2("gravy_new_card_missing");
249
+ if (!Object.keys(value).every((key) => ROOT_KEYS.includes(key)) || !Object.keys(card).every((key) => CARD_KEYS.includes(key)) || typeof card.number !== "string" || !CARD_NUMBER2.test(card.number) || typeof card.expiration_date !== "string" || !EXPIRY.test(card.expiration_date) || typeof card.security_code !== "string" || !SECURITY_CODE.test(card.security_code) || owns2(value, "postal_code") && (typeof value.postal_code !== "string" || !POSTAL_CODE.test(value.postal_code))) {
250
+ return refuse2("gravy_body_unsupported");
251
+ }
252
+ return CARD2;
253
+ }
254
+ // src/moneris.js
255
+ var MONERIS_PSP = "moneris";
256
+ var CARD_KEYS2 = /* @__PURE__ */ Object.freeze(["input_data", "input_exp", "input_cvd", "hpt_id", "hpt_ticket", "doTokenize"]);
257
+ var PARTIAL_KEYS = /* @__PURE__ */ Object.freeze([
258
+ ["input_data", "hpt_id", "hpt_ticket", "doTokenize"],
259
+ ["input_data", "input_exp", "hpt_id", "hpt_ticket", "doTokenize"],
260
+ ["input_data", "input_cvd", "hpt_id", "hpt_ticket", "doTokenize"]
261
+ ]);
262
+ var CARD_NUMBER3 = /^\d{12,19}$/;
263
+ var GROUPED_DIGITS = /^\d+(?: \d+)*$/;
264
+ var EXPIRY_MMYY2 = /^(0[1-9]|1[0-2])\d{2}$/;
265
+ var CVD = /^\d{3,4}$/;
266
+ var PROFILE_ID = /^ht[A-Za-z0-9]{1,64}$/;
267
+ var TICKET = /^tt[A-Za-z0-9]{1,128}$/;
268
+ var refuse3 = (code) => Object.freeze({ verdict: "refuse", code });
269
+ var CARD3 = /* @__PURE__ */ Object.freeze({ verdict: "card" });
270
+ function readPairs(body) {
271
+ if (typeof body !== "string" || body === "" || body.length > 4096)
272
+ return null;
273
+ const pairs = [];
274
+ for (const chunk of body.split("&")) {
275
+ const eq = chunk.indexOf("=");
276
+ if (eq <= 0)
277
+ return null;
278
+ pairs.push([chunk.slice(0, eq), chunk.slice(eq + 1)]);
279
+ }
280
+ return pairs;
281
+ }
282
+ var hasKeys = (pairs, keys) => pairs.length === keys.length && pairs.every(([key], at) => key === keys[at]);
283
+ function monerisBodyVerdict(body) {
284
+ const pairs = readPairs(body);
285
+ if (pairs === null)
286
+ return refuse3("moneris_body_malformed");
287
+ if (PARTIAL_KEYS.some((keys) => hasKeys(pairs, keys)))
288
+ return refuse3("moneris_partial_card");
289
+ if (!hasKeys(pairs, CARD_KEYS2))
290
+ return refuse3("moneris_body_malformed");
291
+ const [[, number], [, expiry], [, cvd], [, profile], [, ticket], [, tokenize]] = pairs;
292
+ if (!GROUPED_DIGITS.test(number) || !CARD_NUMBER3.test(number.replace(/ /g, "")) || !EXPIRY_MMYY2.test(expiry) || !CVD.test(cvd) || !PROFILE_ID.test(profile) || !TICKET.test(ticket) || tokenize !== "true")
293
+ return refuse3("moneris_body_malformed");
294
+ return CARD3;
295
+ }
296
+ var MONERIS_TOKENIZE_HOSTS = /* @__PURE__ */ Object.freeze({
297
+ production: Object.freeze(["www3.moneris.com", "gateway.moneris.com"]),
298
+ sandbox: Object.freeze(["esqa.moneris.com"])
299
+ });
300
+ var MONERIS_TOKENIZE_PATH = "/HPPtoken/request.php";
301
+ function monerisTokenizeEnvironment(url) {
302
+ if (typeof url !== "string")
303
+ return null;
304
+ for (const environment of
305
+ /** @type {const} */
306
+ ["production", "sandbox"]) {
307
+ if (MONERIS_TOKENIZE_HOSTS[environment].some((host) => url === `https://${host}${MONERIS_TOKENIZE_PATH}`))
308
+ return environment;
309
+ }
310
+ return null;
311
+ }
312
+ function isMonerisTokenizeUrl(url) {
313
+ return monerisTokenizeEnvironment(url) !== null;
314
+ }
315
+ var pin = (fields) => Object.freeze({ ...fields, origins: Object.freeze([...fields.origins]), profileIds: Object.freeze([...fields.profileIds]) });
316
+ var MONERIS_MERCHANT_PINS = /* @__PURE__ */ Object.freeze([
317
+ pin({ id: "jack_org_raisin", merchant: "Jack.org", origins: ["https://jack.akaraisin.com"], profileIds: ["htL7TR9H7ICYN2B"] })
318
+ ]);
319
+ // src/amadeus-body.js
320
+ var AMADEUS_CARD_MOPID = /^creditcard[0-9]*$/;
321
+ var record2 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
322
+ var owns3 = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
323
+ var holdsPan = (mopdata) => record2(mopdata) && owns3(mopdata, "pan") && mopdata.pan !== null && mopdata.pan !== "";
177
324
  function amadeusBodyKind(body) {
178
325
  let value;
179
326
  try {
@@ -182,18 +329,25 @@ function amadeusBodyKind(body) {
182
329
  catch {
183
330
  return "card";
184
331
  }
185
- if (!record(value))
332
+ if (!record2(value))
186
333
  return "card";
187
334
  if (value.action === "add") {
188
335
  const entries = Array.isArray(value.data) ? value.data : [value.data];
189
- return entries.some((entry) => record(entry) && typeof entry.mopid === "string" && AMADEUS_CARD_MOPID.test(entry.mopid) && holdsPan(entry.mopdata)) ? "card" : "other";
336
+ return entries.some((entry) => record2(entry) && typeof entry.mopid === "string" && AMADEUS_CARD_MOPID.test(entry.mopid) && holdsPan(entry.mopdata)) ? "card" : "other";
190
337
  }
191
338
  if (value.action === "store")
192
- return record(value.data) && holdsPan(value.data.mopdata) ? "card" : "other";
339
+ return record2(value.data) && holdsPan(value.data.mopdata) ? "card" : "other";
193
340
  return "other";
194
341
  }
195
342
  // src/card-fields.js
196
343
  function processorGate(recognizer, url, body) {
344
+ if (recognizer && recognizer.psp === GRAVY_PSP)
345
+ return gravyBodyVerdict(body);
346
+ if (recognizer && recognizer.psp === MONERIS_PSP) {
347
+ if (url !== void 0 && !isMonerisTokenizeUrl(url))
348
+ return { verdict: "refuse", code: "moneris_url_refused" };
349
+ return monerisBodyVerdict(body);
350
+ }
197
351
  if (!recognizer || recognizer.psp !== "elavon_converge")
198
352
  return null;
199
353
  if (url !== void 0 && !isConvergeProcessUrl(url))