@agent-cards/sdk 0.23.28 → 0.24.0

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 (97) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/PREFLIGHT.md +7 -1
  3. package/README.md +137 -99
  4. package/dist/aci.d.ts +52 -22
  5. package/dist/aci.js +79 -15
  6. package/dist/adyen-merchant-hosted.generated.d.ts +1 -1
  7. package/dist/adyen-merchant-hosted.generated.js +459 -21
  8. package/dist/agent-amount.generated.js +1 -1
  9. package/dist/agentcard.d.ts +4 -5
  10. package/dist/agentcard.js +4 -5
  11. package/dist/amadeus.d.ts +9 -3
  12. package/dist/amadeus.js +33 -4
  13. package/dist/api-module.d.ts +1 -7
  14. package/dist/api-module.js +3 -5
  15. package/dist/{voice-retry.js → api-retry.js} +1 -1
  16. package/dist/api-types.d.ts +53 -0
  17. package/dist/{voice-types.js → api-types.js} +7 -2
  18. package/dist/approvals.d.ts +166 -0
  19. package/dist/approvals.js +213 -0
  20. package/dist/buy.d.ts +20 -101
  21. package/dist/buy.js +19 -74
  22. package/dist/capabilities.generated.js +1 -1
  23. package/dist/card-fields.generated.js +1398 -106
  24. package/dist/cdp.d.ts +3 -13
  25. package/dist/cdp.js +231 -175
  26. package/dist/client.d.ts +104 -22
  27. package/dist/client.js +215 -40
  28. package/dist/creditguard.generated.d.ts +4 -4
  29. package/dist/datatrans.generated.js +22 -1
  30. package/dist/elavon-converge.generated.js +5 -3
  31. package/dist/hold.d.ts +8 -0
  32. package/dist/hold.js +43 -2
  33. package/dist/hosted-entry.js +2 -0
  34. package/dist/index.d.ts +9 -15
  35. package/dist/index.js +6 -10
  36. package/dist/lifecycle.d.ts +9 -61
  37. package/dist/lifecycle.js +24 -10
  38. package/dist/merchant-card-endpoints.generated.d.ts +6 -1
  39. package/dist/merchant-card-endpoints.generated.js +344 -19
  40. package/dist/merchant-hosted.d.ts +8 -1
  41. package/dist/nike-order.d.ts +51 -0
  42. package/dist/nike-order.js +81 -0
  43. package/dist/oceanpayment.d.ts +38 -0
  44. package/dist/oceanpayment.js +70 -0
  45. package/dist/paddle-tokenex.generated.js +105 -10
  46. package/dist/payplug.d.ts +41 -0
  47. package/dist/payplug.js +71 -0
  48. package/dist/payrails.generated.js +27 -7
  49. package/dist/pre-claim.d.ts +9 -0
  50. package/dist/pre-claim.js +86 -7
  51. package/dist/preflight-capabilities.generated.d.ts +0 -4
  52. package/dist/preflight-capabilities.generated.js +0 -5
  53. package/dist/preflight-catalog.json +46 -5
  54. package/dist/preflight-playwright.d.ts +2 -2
  55. package/dist/preflight-playwright.js +63 -14
  56. package/dist/preflight-schemas.json +4 -0
  57. package/dist/preflight.generated.d.ts +0 -4
  58. package/dist/preflight.generated.js +24 -1
  59. package/dist/prepared-processor.d.ts +18 -5
  60. package/dist/prepared-processor.js +48 -8
  61. package/dist/primer.generated.js +1418 -120
  62. package/dist/processout.generated.d.ts +61 -0
  63. package/dist/processout.generated.js +577 -0
  64. package/dist/requests.js +1 -1
  65. package/dist/shiji-sts.generated.js +105 -10
  66. package/dist/stripe-checkout.generated.js +1405 -234
  67. package/dist/substitutions.generated.js +460 -26
  68. package/dist/tap-payments.generated.js +105 -10
  69. package/dist/twoc2p.generated.js +105 -10
  70. package/dist/url-masks/bluesnap.d.ts +2 -0
  71. package/dist/url-masks/bluesnap.js +15 -0
  72. package/dist/url-masks/oceanpayment.d.ts +2 -0
  73. package/dist/url-masks/oceanpayment.js +13 -0
  74. package/dist/url-masks/payplug.d.ts +2 -0
  75. package/dist/url-masks/payplug.js +13 -0
  76. package/dist/url-masks/vtex_payments.d.ts +2 -0
  77. package/dist/url-masks/vtex_payments.js +12 -0
  78. package/dist/url-masks.generated.d.ts +1 -1
  79. package/dist/url-masks.generated.js +6 -2
  80. package/dist/verifone.generated.js +42 -2
  81. package/dist/vtex-payments.generated.d.ts +127 -0
  82. package/dist/vtex-payments.generated.js +544 -0
  83. package/dist/webhooks.d.ts +2 -2
  84. package/dist/webhooks.js +2 -2
  85. package/examples/preflight/kernel-native/inventory.json +1 -1
  86. package/package.json +6 -8
  87. package/dist/languages.d.ts +0 -23
  88. package/dist/languages.js +0 -76
  89. package/dist/voice-pkce.d.ts +0 -49
  90. package/dist/voice-pkce.js +0 -147
  91. package/dist/voice-stream.generated.d.ts +0 -118
  92. package/dist/voice-stream.generated.js +0 -170
  93. package/dist/voice-types.d.ts +0 -735
  94. package/dist/voice.d.ts +0 -373
  95. package/dist/voice.js +0 -815
  96. package/readme.test.mjs +0 -53
  97. /package/dist/{voice-retry.d.ts → api-retry.d.ts} +0 -0
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Oceanpayment's hosted payment page (secure.oceanpayment.com, and test-secure.oceanpayment.com, its sandbox), as this SDK
3
+ * reads it.
4
+ *
5
+ * The page, where Oceanpayment's Shopify redirect app sends the buyer after Shopify's Pay now, submits its card form as one
6
+ * form post to /gateway/sendPay;jsessionid=<the payment's session>, the card in clear. That post is the one request this
7
+ * SDK pauses: the cardholder's device writes the real card into it and sends it through the checkout relay (payment-core
8
+ * processors/oceanpayment.js). The page's other posts to these hosts lead to or carry the card the agent typed: Cardinal's
9
+ * device-data call (/gateway/CreateJWTInterface) posts the whole number when the merchant's terminal turns it on, and a card
10
+ * post written another way would carry it to Oceanpayment as a payment. This SDK aborts every one of them in a page it
11
+ * watches, so the agent's placeholder never reaches Oceanpayment. A GET (the page, its scripts, its log) continues.
12
+ *
13
+ * OCEANPAYMENT_HOSTS is payment-core's OCEANPAYMENT_HOSTS, and isOceanpaymentSendPay takes the URLs payment-core's
14
+ * isOceanpaymentSendPayUrl takes; oceanpayment.test.mjs pins both to payment-core.
15
+ */
16
+ export declare const OCEANPAYMENT_PSP = "oceanpayment";
17
+ /** The dark-launch capability the API serves Oceanpayment's recognizer behind (payment-core processors/oceanpayment.js). */
18
+ export declare const OCEANPAYMENT_CAPABILITY = "oceanpayment_hosted_payment_page";
19
+ /** The live host and Oceanpayment's sandbox, which serves the same page for a test terminal. */
20
+ export declare const OCEANPAYMENT_HOSTS: readonly string[];
21
+ /** Whether this URL is on one of Oceanpayment's two hosts. */
22
+ export declare function isOceanpaymentHost(url: string): boolean;
23
+ /**
24
+ * The only request on Oceanpayment's hosts that is the page's card post: a POST to exactly
25
+ * https://<host>/gateway/sendPay;jsessionid=<session>, as the page's form action writes it, with no port, query, fragment
26
+ * or other spelling (payment-core isOceanpaymentSendPayUrl takes the same strings). The post the SDK pauses.
27
+ */
28
+ export declare function isOceanpaymentSendPay(url: string, method: string): boolean;
29
+ /**
30
+ * Whether an adapter must hand this request to the pre-claim gates: it is on an Oceanpayment host and this build's
31
+ * registry serves Oceanpayment's card post there. Cardinal's call and a card post of another spelling are not the card
32
+ * post, so the registry's card-request test does not name them; the CDP adapter still pauses them through the
33
+ * recognizer's host pattern, and attachToPlaywright's route predicate asks this, so both adapters show the gates every
34
+ * request to Oceanpayment once Oceanpayment is armed.
35
+ */
36
+ export declare function isArmedOceanpaymentUrl(vault: {
37
+ isCardRequest(url: string, method?: string): boolean;
38
+ }, url: string): boolean;
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Oceanpayment's hosted payment page (secure.oceanpayment.com, and test-secure.oceanpayment.com, its sandbox), as this SDK
3
+ * reads it.
4
+ *
5
+ * The page, where Oceanpayment's Shopify redirect app sends the buyer after Shopify's Pay now, submits its card form as one
6
+ * form post to /gateway/sendPay;jsessionid=<the payment's session>, the card in clear. That post is the one request this
7
+ * SDK pauses: the cardholder's device writes the real card into it and sends it through the checkout relay (payment-core
8
+ * processors/oceanpayment.js). The page's other posts to these hosts lead to or carry the card the agent typed: Cardinal's
9
+ * device-data call (/gateway/CreateJWTInterface) posts the whole number when the merchant's terminal turns it on, and a card
10
+ * post written another way would carry it to Oceanpayment as a payment. This SDK aborts every one of them in a page it
11
+ * watches, so the agent's placeholder never reaches Oceanpayment. A GET (the page, its scripts, its log) continues.
12
+ *
13
+ * OCEANPAYMENT_HOSTS is payment-core's OCEANPAYMENT_HOSTS, and isOceanpaymentSendPay takes the URLs payment-core's
14
+ * isOceanpaymentSendPayUrl takes; oceanpayment.test.mjs pins both to payment-core.
15
+ */
16
+ export const OCEANPAYMENT_PSP = 'oceanpayment';
17
+ /** The dark-launch capability the API serves Oceanpayment's recognizer behind (payment-core processors/oceanpayment.js). */
18
+ export const OCEANPAYMENT_CAPABILITY = 'oceanpayment_hosted_payment_page';
19
+ /** The live host and Oceanpayment's sandbox, which serves the same page for a test terminal. */
20
+ export const OCEANPAYMENT_HOSTS = Object.freeze(['secure.oceanpayment.com', 'test-secure.oceanpayment.com']);
21
+ const SEND_PAY = /^\/gateway\/sendPay;jsessionid=[A-Za-z0-9._!-]{16,128}$/;
22
+ // A session in the shape the recognizer takes, to ask whether this build's registry serves the card post on a host.
23
+ const PROBE_SESSION = 'ARMEDPROBESESSION0';
24
+ /** The Oceanpayment host a URL is on (https, no credentials, any port, any letter case, a trailing dot or not), or null. */
25
+ function oceanpaymentHost(raw) {
26
+ let url;
27
+ try {
28
+ url = new URL(raw);
29
+ }
30
+ catch {
31
+ return null;
32
+ }
33
+ if (url.protocol !== 'https:' || url.username || url.password)
34
+ return null;
35
+ const host = url.hostname.toLowerCase().replace(/\.$/, '');
36
+ return OCEANPAYMENT_HOSTS.includes(host) ? host : null;
37
+ }
38
+ /** Whether this URL is on one of Oceanpayment's two hosts. */
39
+ export function isOceanpaymentHost(url) {
40
+ return oceanpaymentHost(url) !== null;
41
+ }
42
+ /**
43
+ * The only request on Oceanpayment's hosts that is the page's card post: a POST to exactly
44
+ * https://<host>/gateway/sendPay;jsessionid=<session>, as the page's form action writes it, with no port, query, fragment
45
+ * or other spelling (payment-core isOceanpaymentSendPayUrl takes the same strings). The post the SDK pauses.
46
+ */
47
+ export function isOceanpaymentSendPay(url, method) {
48
+ if (String(method).toUpperCase() !== 'POST' || typeof url !== 'string' || url.includes('?') || url.includes('#'))
49
+ return false;
50
+ let parsed;
51
+ try {
52
+ parsed = new URL(url);
53
+ }
54
+ catch {
55
+ return false;
56
+ }
57
+ return parsed.href === url && parsed.protocol === 'https:' && !parsed.port && !parsed.username && !parsed.password
58
+ && OCEANPAYMENT_HOSTS.includes(parsed.hostname) && SEND_PAY.test(parsed.pathname);
59
+ }
60
+ /**
61
+ * Whether an adapter must hand this request to the pre-claim gates: it is on an Oceanpayment host and this build's
62
+ * registry serves Oceanpayment's card post there. Cardinal's call and a card post of another spelling are not the card
63
+ * post, so the registry's card-request test does not name them; the CDP adapter still pauses them through the
64
+ * recognizer's host pattern, and attachToPlaywright's route predicate asks this, so both adapters show the gates every
65
+ * request to Oceanpayment once Oceanpayment is armed.
66
+ */
67
+ export function isArmedOceanpaymentUrl(vault, url) {
68
+ const host = oceanpaymentHost(url);
69
+ return host !== null && vault.isCardRequest(`https://${host}/gateway/sendPay;jsessionid=${PROBE_SESSION}`, 'POST');
70
+ }
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
2
  // Generated from @agent-cards/payment-core. Do not edit.
3
- // artifact-sha256: cb62940ac92ca9f2a61b5168f362003d67998f12d045b18d8bd07ae352e0cb3e
3
+ // artifact-sha256: 4b24c682dbd8cd7bbaa0157f2932021d71f7c6802ce3814c6f3047173df29911
4
4
  // src/sha256.js
5
5
  var K = /* @__PURE__ */ new Uint32Array([
6
6
  1116352408,
@@ -429,9 +429,64 @@ function isPlainObject(v) {
429
429
  return !!v && typeof v === "object" && !Array.isArray(v);
430
430
  }
431
431
  var MAX_PATH_STEPS = 16;
432
+ var MAX_TEXT_STEPS = 2;
433
+ function isTextStep(step) {
434
+ return isPlainObject(step) && Object.keys(step).length === 1 && step.text === "json";
435
+ }
436
+ function sameStep(a, b) {
437
+ return a === b || isTextStep(a) && isTextStep(b);
438
+ }
439
+ function spellJson(parsed, form) {
440
+ const text = JSON.stringify(parsed);
441
+ if (form !== "php")
442
+ return text;
443
+ return text.replace(/\//g, "\\/").replace(/[\u0080-\uffff]/g, (unit) => `\\u${unit.charCodeAt(0).toString(16).padStart(4, "0")}`);
444
+ }
445
+ function jsonTextForm(value) {
446
+ if (typeof value !== "string" || !/^[[{]/.test(value))
447
+ return void 0;
448
+ let parsed;
449
+ try {
450
+ parsed = JSON.parse(value);
451
+ }
452
+ catch {
453
+ return void 0;
454
+ }
455
+ if (parsed === null || typeof parsed !== "object")
456
+ return void 0;
457
+ for (const form of ["js", "php"]) {
458
+ try {
459
+ if (spellJson(parsed, form) === value)
460
+ return { parsed, form };
461
+ }
462
+ catch {
463
+ return void 0;
464
+ }
465
+ }
466
+ return void 0;
467
+ }
468
+ function jsonText(value) {
469
+ return jsonTextForm(value)?.parsed;
470
+ }
432
471
  function isJsonPath(path) {
433
472
  return Array.isArray(path) && path.length <= MAX_PATH_STEPS && path.every((step) => typeof step === "string" ? step.length > 0 && !FORBIDDEN_KEYS.has(step) : Number.isSafeInteger(step) && step >= 0);
434
473
  }
474
+ function isProfilePath(path) {
475
+ if (!Array.isArray(path) || path.length > MAX_PATH_STEPS)
476
+ return false;
477
+ let texts = 0;
478
+ for (const [i, step] of path.entries()) {
479
+ if (isTextStep(step)) {
480
+ texts += 1;
481
+ if (i === 0 || i === path.length - 1 || isTextStep(path[i - 1]) || texts > MAX_TEXT_STEPS)
482
+ return false;
483
+ }
484
+ else if (!isJsonPath([step])) {
485
+ return false;
486
+ }
487
+ }
488
+ return true;
489
+ }
435
490
  function jsonAt(root, path) {
436
491
  let node = root;
437
492
  for (const step of path) {
@@ -446,6 +501,42 @@ function jsonAt(root, path) {
446
501
  }
447
502
  return { found: true, value: node };
448
503
  }
504
+ function profileAt(root, path) {
505
+ if (!isProfilePath(path))
506
+ return { found: false };
507
+ let node = root;
508
+ for (const step of path) {
509
+ if (isTextStep(step)) {
510
+ const inner = jsonText(node);
511
+ if (inner === void 0)
512
+ return { found: false };
513
+ node = inner;
514
+ continue;
515
+ }
516
+ const at = jsonAt(node, [step]);
517
+ if (!at.found)
518
+ return { found: false };
519
+ node = at.value;
520
+ }
521
+ return { found: true, value: node };
522
+ }
523
+ function editAtProfilePath(root, path, edit) {
524
+ const at = profileAt(root, path);
525
+ if (!at.found || !isPlainObject(at.value))
526
+ return false;
527
+ const k = path.findIndex(isTextStep);
528
+ if (k === -1) {
529
+ edit(at.value);
530
+ return true;
531
+ }
532
+ const holder = jsonAt(root, path.slice(0, k - 1)).value;
533
+ const key = path[k - 1];
534
+ const text = jsonTextForm(holder[key]);
535
+ if (!text || !editAtProfilePath(text.parsed, path.slice(k + 1), edit))
536
+ return false;
537
+ holder[key] = spellJson(text.parsed, text.form);
538
+ return true;
539
+ }
449
540
  function roundTrips(parsed, body) {
450
541
  try {
451
542
  return JSON.stringify(parsed) === body;
@@ -455,17 +546,17 @@ function roundTrips(parsed, body) {
455
546
  }
456
547
  }
457
548
  function sameSteps(a, b) {
458
- return Array.isArray(a) && Array.isArray(b) && a.length === b.length && a.every((step, i) => step === b[i]);
549
+ return Array.isArray(a) && Array.isArray(b) && a.length === b.length && a.every((step, i) => sameStep(step, b[i]));
459
550
  }
460
551
  function pathsOverlap(a, b) {
461
552
  const n = Math.min(a.length, b.length);
462
553
  for (let i = 0; i < n; i += 1)
463
- if (a[i] !== b[i])
554
+ if (!sameStep(a[i], b[i]))
464
555
  return false;
465
556
  return true;
466
557
  }
467
558
  function describePath(path) {
468
- return path.length ? path.map((step) => typeof step === "number" ? `[${step}]` : `.${step}`).join("").replace(/^\./, "") : "(root)";
559
+ return path.length ? path.map((step) => typeof step === "number" ? `[${step}]` : isTextStep(step) ? "<json>" : `.${step}`).join("").replace(/^\./, "") : "(root)";
469
560
  }
470
561
  // src/substitution-primitives.js
471
562
  var SubstitutionError = class extends Error {
@@ -514,7 +605,7 @@ function swapMerchantHostedFields(body, spec, ciphertext = ADYEN_JWE) {
514
605
  const path = Array.isArray(spec.path) ? [...spec.path] : spec.path;
515
606
  const fields = isPlainObject(spec.fields) ? Object.fromEntries(Object.entries(spec.fields)) : null;
516
607
  const remove = Array.isArray(spec.remove) ? [...spec.remove] : spec.remove ?? [];
517
- if (!isJsonPath(path))
608
+ if (!isProfilePath(path))
518
609
  throw new SubstitutionError("refusing substitution path");
519
610
  if (!fields || Object.keys(fields).length === 0)
520
611
  throw new SubstitutionError("substitutions carry no fields");
@@ -548,7 +639,7 @@ function swapMerchantHostedFields(body, spec, ciphertext = ADYEN_JWE) {
548
639
  }
549
640
  if (!isPlainObject(parsed))
550
641
  throw new SubstitutionError("the paused body is not a JSON object");
551
- const holder = jsonAt(parsed, path);
642
+ const holder = profileAt(parsed, path);
552
643
  if (!holder.found || !isPlainObject(holder.value))
553
644
  throw new SubstitutionError(`the paused body has no object at ${describePath(path)}`);
554
645
  const swaps = /* @__PURE__ */ new Map();
@@ -600,15 +691,19 @@ function swapMerchantHostedFields(body, spec, ciphertext = ADYEN_JWE) {
600
691
  catch {
601
692
  throw new SubstitutionError("the substituted body is not JSON");
602
693
  }
603
- const written = jsonAt(out, path);
694
+ const written = profileAt(out, path);
604
695
  if (!written.found || !isPlainObject(written.value) || names.some((name) => written.value[name] !== fields[name]) || dummies.some((dummy) => swapped.includes(dummy))) {
605
696
  throw new SubstitutionError(`the substitution did not land at ${describePath(path)}`);
606
697
  }
607
698
  if (remove.length === 0 && set.length === 0)
608
699
  return swapped;
609
- for (const key of remove)
610
- if (Object.prototype.hasOwnProperty.call(written.value, key))
611
- delete written.value[key];
700
+ if (remove.length > 0 && !editAtProfilePath(out, path, (object) => {
701
+ for (const key of remove)
702
+ if (Object.prototype.hasOwnProperty.call(object, key))
703
+ delete object[key];
704
+ })) {
705
+ throw new SubstitutionError(`the substitution did not land at ${describePath(path)}`);
706
+ }
612
707
  for (const entry of set) {
613
708
  const parent = jsonAt(out, entry.path.slice(0, -1));
614
709
  if (!parent.found || !isPlainObject(parent.value))
@@ -0,0 +1,41 @@
1
+ /**
2
+ * PayPlug's hosted payment page (secure.payplug.com, where French merchants send a buyer who pays by card), as this SDK
3
+ * reads it.
4
+ *
5
+ * The merchant's server creates the payment with PayPlug and sends the buyer's browser to the page's URL PayPlug answered
6
+ * with, https://secure.payplug.com/pay/<payment id>, or /pay/test/<payment id> for a test payment, by a redirect or by
7
+ * setting the page's location. PayPlug's Shopify app does the same from Shopify's checkout. That GET carries no card, no
8
+ * amount and no merchant, and it is the one request a build that declares PayPlug's capability pauses (hosted-entry.ts):
9
+ * the cardholder's device repeats it over the end-to-end TLS relay and pays on the page PayPlug returns to it (payment-core
10
+ * processors/payplug.js). Every step toward paying on that page is a POST to PayPlug's host, the page's card post among
11
+ * them, with the card encrypted under the page's own key.
12
+ *
13
+ * PAYPLUG_HOST is payment-core's PAYPLUG_HOST, and isPayplugEntryUrl is payment-core's isPayplugEntryUrl; payplug.test.mjs
14
+ * pins both to payment-core on every case payment-core's own tests list.
15
+ */
16
+ export declare const PAYPLUG_PSP = "payplug";
17
+ /** The dark-launch capability the API serves PayPlug's recognizer behind (payment-core processors/payplug.js). */
18
+ export declare const PAYPLUG_CAPABILITY = "payplug_hosted_payment_page";
19
+ /** PayPlug's page host, which its test and live payments share; the entry's path says which one a payment is. */
20
+ export declare const PAYPLUG_HOST = "secure.payplug.com";
21
+ /**
22
+ * Whether a URL is the payment page's URL exactly as PayPlug writes payment_url: https, secure.payplug.com in lower case,
23
+ * the default port, no credentials, no query and no fragment, not even an empty one, and the path /pay/<id> or
24
+ * /pay/test/<id> with the payment's 22-character id. The lightbox's ?lightbox=1, or any other query, asks PayPlug's page
25
+ * for something else, so it is not the entry, and neither is any other request to PayPlug's host.
26
+ */
27
+ export declare function isPayplugEntryUrl(raw: unknown): boolean;
28
+ /**
29
+ * Whether a request on PayPlug's page host is a step toward paying there: any POST, the page's card post and its
30
+ * 3-D Secure posts among them. The page itself, its scripts, its images and its frames are GETs of no card and are not one.
31
+ */
32
+ export declare function isPayplugPayStep(url: string, method: string): boolean;
33
+ /**
34
+ * Whether an adapter must hand this request to the pre-claim gates: it is on PayPlug's page host and this build's
35
+ * registry serves PayPlug's entry. The page's posts are not the entry, so the registry's card-request test does not name
36
+ * them; the CDP adapter still pauses them through the recognizer's host pattern, and attachToPlaywright's route predicate
37
+ * asks this, so both adapters show the gates every request to the page's host once PayPlug is armed.
38
+ */
39
+ export declare function isArmedPayplugUrl(vault: {
40
+ isCardRequest(url: string, method?: string): boolean;
41
+ } | undefined, url: string): boolean;
@@ -0,0 +1,71 @@
1
+ /**
2
+ * PayPlug's hosted payment page (secure.payplug.com, where French merchants send a buyer who pays by card), as this SDK
3
+ * reads it.
4
+ *
5
+ * The merchant's server creates the payment with PayPlug and sends the buyer's browser to the page's URL PayPlug answered
6
+ * with, https://secure.payplug.com/pay/<payment id>, or /pay/test/<payment id> for a test payment, by a redirect or by
7
+ * setting the page's location. PayPlug's Shopify app does the same from Shopify's checkout. That GET carries no card, no
8
+ * amount and no merchant, and it is the one request a build that declares PayPlug's capability pauses (hosted-entry.ts):
9
+ * the cardholder's device repeats it over the end-to-end TLS relay and pays on the page PayPlug returns to it (payment-core
10
+ * processors/payplug.js). Every step toward paying on that page is a POST to PayPlug's host, the page's card post among
11
+ * them, with the card encrypted under the page's own key.
12
+ *
13
+ * PAYPLUG_HOST is payment-core's PAYPLUG_HOST, and isPayplugEntryUrl is payment-core's isPayplugEntryUrl; payplug.test.mjs
14
+ * pins both to payment-core on every case payment-core's own tests list.
15
+ */
16
+ export const PAYPLUG_PSP = 'payplug';
17
+ /** The dark-launch capability the API serves PayPlug's recognizer behind (payment-core processors/payplug.js). */
18
+ export const PAYPLUG_CAPABILITY = 'payplug_hosted_payment_page';
19
+ /** PayPlug's page host, which its test and live payments share; the entry's path says which one a payment is. */
20
+ export const PAYPLUG_HOST = 'secure.payplug.com';
21
+ // The entry's path: /pay/<id> for a live payment, /pay/test/<id> for a test one, the id as PayPlug writes it.
22
+ const ENTRY_PATH = /^\/pay\/(?:test\/)?[A-Za-z0-9]{22}$/;
23
+ // An id of that shape, for asking whether this build's registry serves the entry.
24
+ const PROBE = 'https://secure.payplug.com/pay/0000000000000000000000';
25
+ /**
26
+ * Whether a URL is the payment page's URL exactly as PayPlug writes payment_url: https, secure.payplug.com in lower case,
27
+ * the default port, no credentials, no query and no fragment, not even an empty one, and the path /pay/<id> or
28
+ * /pay/test/<id> with the payment's 22-character id. The lightbox's ?lightbox=1, or any other query, asks PayPlug's page
29
+ * for something else, so it is not the entry, and neither is any other request to PayPlug's host.
30
+ */
31
+ export function isPayplugEntryUrl(raw) {
32
+ if (typeof raw !== 'string' || raw.length > 256 || raw.includes('?') || raw.includes('#'))
33
+ return false;
34
+ let url;
35
+ try {
36
+ url = new URL(raw);
37
+ }
38
+ catch {
39
+ return false;
40
+ }
41
+ if (url.href !== raw || url.protocol !== 'https:' || url.hostname !== PAYPLUG_HOST || url.port || url.username || url.password)
42
+ return false;
43
+ return ENTRY_PATH.test(url.pathname);
44
+ }
45
+ /** Whether a URL is on PayPlug's page host: https, no credentials, any port, any letter case, a trailing dot or not. */
46
+ function onPayplugHost(raw) {
47
+ let url;
48
+ try {
49
+ url = new URL(raw);
50
+ }
51
+ catch {
52
+ return false;
53
+ }
54
+ return url.protocol === 'https:' && !url.username && !url.password && url.hostname.toLowerCase().replace(/\.$/, '') === PAYPLUG_HOST;
55
+ }
56
+ /**
57
+ * Whether a request on PayPlug's page host is a step toward paying there: any POST, the page's card post and its
58
+ * 3-D Secure posts among them. The page itself, its scripts, its images and its frames are GETs of no card and are not one.
59
+ */
60
+ export function isPayplugPayStep(url, method) {
61
+ return onPayplugHost(url) && String(method).toUpperCase() === 'POST';
62
+ }
63
+ /**
64
+ * Whether an adapter must hand this request to the pre-claim gates: it is on PayPlug's page host and this build's
65
+ * registry serves PayPlug's entry. The page's posts are not the entry, so the registry's card-request test does not name
66
+ * them; the CDP adapter still pauses them through the recognizer's host pattern, and attachToPlaywright's route predicate
67
+ * asks this, so both adapters show the gates every request to the page's host once PayPlug is armed.
68
+ */
69
+ export function isArmedPayplugUrl(vault, url) {
70
+ return onPayplugHost(url) && typeof vault?.isCardRequest === 'function' && vault.isCardRequest(PROBE, 'GET');
71
+ }
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
2
  // Generated from @agent-cards/payment-core. Do not edit.
3
- // artifact-sha256: 056fa54de953be9af775505906b2fba30def2787a217a12fe2ca2a50b8614649
3
+ // artifact-sha256: 139d0001a168e053ebe3283721905ae95d7c159a25848469965f037b844a44cf
4
4
  // src/json-path.js
5
5
  function roundTrips(parsed, body) {
6
6
  try {
@@ -10,6 +10,25 @@ function roundTrips(parsed, body) {
10
10
  return false;
11
11
  }
12
12
  }
13
+ // src/answer-card-leak.js
14
+ var DECIMAL = /\p{Nd}/u;
15
+ function digitValue(char) {
16
+ const point = char.codePointAt(0);
17
+ let first = point;
18
+ while (DECIMAL.test(String.fromCodePoint(first - 1)))
19
+ first -= 1;
20
+ return String((point - first) % 10);
21
+ }
22
+ var ENCLOSED = /* @__PURE__ */ Object.freeze([[9451, 10, 11], [9461, 10, 1], [9471, 1, 0], [10102, 30, 1], [127243, 2, 0]]);
23
+ var ENCLOSED_CHAR = /[\u24eb-\u24ff\u2776-\u2793\u{1f10b}\u{1f10c}]/gu;
24
+ function enclosedValue(char) {
25
+ const point = char.codePointAt(0);
26
+ const [first, , start] = ENCLOSED.find(([from, size]) => point >= from && point < from + size);
27
+ return String(first === 127243 ? 0 : first === 10102 ? (point - first) % 10 + 1 : start + point - first);
28
+ }
29
+ var asciiDigits = (text) => (typeof text.normalize === "function" ? text.normalize("NFKC") : text).replace(ENCLOSED_CHAR, enclosedValue).replace(/\p{Nd}/gu, (char) => char >= "0" && char <= "9" ? char : digitValue(char));
30
+ var digitCount = (text) => (asciiDigits(String(text)).match(/\p{N}/gu) ?? []).length;
31
+ var NAME_DIGITS = 3;
13
32
  // src/sha256.js
14
33
  var K = /* @__PURE__ */ new Uint32Array([
15
34
  1116352408,
@@ -139,7 +158,7 @@ function sha256Hex(input) {
139
158
  H[6] += g;
140
159
  H[7] += h;
141
160
  }
142
- return Array.from(H, (word) => word.toString(16).padStart(8, "0")).join("");
161
+ return Array.from(H, (word2) => word2.toString(16).padStart(8, "0")).join("");
143
162
  }
144
163
  // src/rsa-pkcs1v15.js
145
164
  var RsaPkcs1v15Error = class extends Error {
@@ -652,6 +671,7 @@ var PAYRAILS_SERVED_CARD_FACTS = Object.freeze(["bin", "binLookup", "holderName"
652
671
  var exact = (pattern, value) => typeof value === "string" && pattern.exec(value)?.[0] === value;
653
672
  var bin6 = (value) => exact(/^[0-9]{6,8}$/, value) ? value.slice(0, 6) : void 0;
654
673
  var label = (value, max) => plainText(value, max) ? value : void 0;
674
+ var word = (value, max, digits = 0) => plainText(value, max) && digitCount(value) <= digits ? value : void 0;
655
675
  var pick = (value, pattern) => exact(pattern, value) ? value : void 0;
656
676
  var compact = (object) => Object.fromEntries(Object.entries(object).filter(([, value]) => value !== void 0));
657
677
  var nonEmpty = (object) => Object.keys(object).length ? object : void 0;
@@ -691,13 +711,13 @@ function sanitizePayrailsResponse(text) {
691
711
  bin: served.has("bin") ? bin6(data.bin) : void 0,
692
712
  binLookup: lookup ? nonEmpty(compact({
693
713
  bin: bin6(lookup.bin),
694
- network: label(lookup.network, 32),
695
- issuer: label(lookup.issuer, 128),
696
- issuerCountry: country ? nonEmpty(compact({ code: pick(country.code, /^[A-Z]{2}$/), name: label(country.name, 64), iso3: pick(country.iso3, /^[A-Z]{3}$/) })) : void 0,
697
- type: label(lookup.type, 32)
714
+ network: word(lookup.network, 32),
715
+ issuer: word(lookup.issuer, 128, NAME_DIGITS),
716
+ issuerCountry: country ? nonEmpty(compact({ code: pick(country.code, /^[A-Z]{2}$/), name: word(country.name, 64), iso3: pick(country.iso3, /^[A-Z]{3}$/) })) : void 0,
717
+ type: word(lookup.type, 32)
698
718
  })) : void 0,
699
719
  holderName: served.has("holderName") ? label(data.holderName, 200) : void 0,
700
- network: served.has("network") ? label(data.network, 32) : void 0,
720
+ network: served.has("network") ? word(data.network, 32) : void 0,
701
721
  suffix: data.suffix,
702
722
  expiryMonth: served.has("expiryMonth") ? pick(data.expiryMonth, /^(?:0[1-9]|1[0-2])$/) : void 0,
703
723
  expiryYear: served.has("expiryYear") ? pick(data.expiryYear, /^(?:[0-9]{2}|[0-9]{4})$/) : void 0
@@ -12,6 +12,7 @@ import { type MerchantProfile } from './merchant-hosted.js';
12
12
  import type { MerchantHandoffWatch } from './merchant-handoff.js';
13
13
  import { type CybersourceFlexDecision, type CybersourceFlexPause, type FlexRequest } from './cybersource-flex.js';
14
14
  import { type CardEndpointProfile } from './card-endpoint.js';
15
+ import { type NikeOrders } from './nike-order.js';
15
16
  import { type PayrailsSessionCapture, type PayrailsSidecar } from './payrails.js';
16
17
  import { type VerifoneProfile } from './verifone.js';
17
18
  import { type WorldlineMyCheckoutProducts } from './worldline-mycheckout.js';
@@ -250,6 +251,8 @@ export interface PreClaimContext {
250
251
  * card frame is refused.
251
252
  */
252
253
  payrexx?: PayrexxFollowUps;
254
+ /** The approval Nike's order is held to once a card went through Nike's profile (nike-order.ts). Absent: Nike's order is left alone. */
255
+ nikeOrders?: NikeOrders;
253
256
  }
254
257
  /**
255
258
  * The URL an event may name for a request. For an armed merchant profile's
@@ -265,6 +268,10 @@ export declare function eventUrl(vault: {
265
268
  /** A gate returns a decision when it handles the request, undefined to defer to
266
269
  * the next gate, or a promise of either when it must do I/O first. */
267
270
  export type PreClaimGate = (ctx: PreClaimContext) => PreClaimDecision | undefined | Promise<PreClaimDecision | undefined>;
271
+ /** What the Nike order gate reads of a paused request and its attachment. */
272
+ export type NikeOrderGateContext = Pick<PreClaimContext, 'request' | 'nikeOrders' | 'lifecycle' | 'effects' | 'onEvent' | 'lifecycleAborted' | 'terminal'>;
273
+ /** The Nike order gate's decision, already performed, or undefined when the request is not its to judge. */
274
+ export declare function nikeOrderGate(ctx: NikeOrderGateContext): Promise<PreClaimDecision> | undefined;
268
275
  export declare const MERCHANT_BODY_UNREADABLE = "the paused request carries no body the SDK could read, so Agentcard cannot tell whether it carries a card";
269
276
  export declare const verifonePreClaim: PreClaimGate;
270
277
  export declare const fiservPreClaim: PreClaimGate;
@@ -280,6 +287,7 @@ export declare function isArmedCreditguardCall(vault: {
280
287
  } | undefined, url: string): boolean;
281
288
  export declare const przelewy24PreClaim: PreClaimGate;
282
289
  export declare const barionPreClaim: PreClaimGate;
290
+ export declare const payplugPreClaim: PreClaimGate;
283
291
  export declare const ekashuPreClaim: PreClaimGate;
284
292
  export declare const transbankPreClaim: PreClaimGate;
285
293
  export declare const paytrailPreClaim: PreClaimGate;
@@ -287,6 +295,7 @@ export declare const redsysPreClaim: PreClaimGate;
287
295
  export declare const quickpayPreClaim: PreClaimGate;
288
296
  export declare const comgatePreClaim: PreClaimGate;
289
297
  export declare const eximbayPreClaim: PreClaimGate;
298
+ export declare const oceanpaymentPreClaim: PreClaimGate;
290
299
  export declare const paypalHostedFieldsPreClaim: PreClaimGate;
291
300
  export declare const paypalCardFormsPreClaim: PreClaimGate;
292
301
  export declare const cybersourceSecureAcceptancePreClaim: PreClaimGate;