@agent-cards/sdk 0.24.0 → 0.24.2

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 (44) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +61 -4
  3. package/dist/adyen-merchant-hosted.generated.d.ts +1 -1
  4. package/dist/adyen-merchant-hosted.generated.js +128 -35
  5. package/dist/agent-amount.generated.js +1 -1
  6. package/dist/aurus.d.ts +33 -0
  7. package/dist/aurus.js +75 -0
  8. package/dist/builtin-registry.generated.js +1 -1
  9. package/dist/capabilities.generated.js +1 -1
  10. package/dist/card-fields.generated.js +1854 -440
  11. package/dist/cardlink-vpos.d.ts +43 -0
  12. package/dist/cardlink-vpos.js +90 -0
  13. package/dist/cdp.js +22 -0
  14. package/dist/checkout-com.generated.js +5 -1
  15. package/dist/client.d.ts +75 -0
  16. package/dist/client.js +75 -0
  17. package/dist/cybersource-flex.generated.d.ts +39 -1
  18. package/dist/cybersource-flex.generated.js +100 -11
  19. package/dist/eghl.d.ts +40 -0
  20. package/dist/eghl.js +72 -0
  21. package/dist/gmo.generated.js +7 -2
  22. package/dist/hosted-entry.js +2 -0
  23. package/dist/lifecycle.d.ts +10 -0
  24. package/dist/lifecycle.js +25 -0
  25. package/dist/paddle-tokenex.generated.js +7 -2
  26. package/dist/payrails.generated.js +7 -2
  27. package/dist/pre-claim.d.ts +5 -0
  28. package/dist/pre-claim.js +90 -2
  29. package/dist/preflight-catalog.json +179 -1
  30. package/dist/preflight-schemas.json +16 -0
  31. package/dist/preflight.generated.d.ts +5 -0
  32. package/dist/preflight.generated.js +49 -3
  33. package/dist/preparation.d.ts +7 -0
  34. package/dist/preparation.js +21 -0
  35. package/dist/primer.generated.js +1856 -442
  36. package/dist/shiji-sts.generated.js +7 -2
  37. package/dist/stripe-checkout.generated.js +1837 -475
  38. package/dist/substitutions.generated.js +94 -1
  39. package/dist/tap-payments.generated.js +7 -2
  40. package/dist/token-repeats.d.ts +32 -0
  41. package/dist/token-repeats.js +64 -0
  42. package/dist/twoc2p.generated.js +7 -2
  43. package/examples/preflight/kernel-native/inventory.json +1 -1
  44. package/package.json +2 -2
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
2
  // Generated from @agent-cards/payment-core. Do not edit.
3
- // artifact-sha256: c6a711b5dc964dbeb45863780001d99b79090f919b282fed9ae6fc06b4839681
3
+ // artifact-sha256: a9a624dbdd5a025d710f99e5ce83a985e4561b4db6d3e60dc427b5e406e4b653
4
4
  // src/cybersource-flex-rules.js
5
5
  var CYBERSOURCE_FLEX_RULES_SOURCE = Object.freeze({ version: "2.12.1", sha256: "8429ebae83e9745cd53ad8ff0d9ba69bee0087c1435ed0695a25444bed418327" });
6
6
  var CYBERSOURCE_FLEX_RULES = [
@@ -201,6 +201,7 @@ async function sealCompactJwe(jwk, plaintext, { crypto }) {
201
201
  }
202
202
  // src/cybersource-flex-context.js
203
203
  var FLEX_TOKENS_PATH = "/flex/v2/tokens";
204
+ var UNIFIED_CHECKOUT_TOKENS_PATH = "/flex/v2/tokens/uc";
204
205
  var FLEX_HOSTS = Object.freeze({ production: "flex.cybersource.com", sandbox: "testflex.cybersource.com" });
205
206
  var CAPTURE_CONTEXT_MAX_LENGTH = 16384;
206
207
  var CLOCK_SKEW_MS = 6e4;
@@ -233,7 +234,8 @@ function origins(value) {
233
234
  return Object.freeze([]);
234
235
  return Object.freeze(value.filter((origin) => typeof origin === "string" && origin.length <= 2048).slice(0, 16));
235
236
  }
236
- async function verifyContextWithKeys(jwt, keys, { crypto, now } = {}) {
237
+ async function verifyContextWithKeys(jwt, keys, { crypto, now, kind = "microform" } = {}) {
238
+ const unified = kind === "unified_checkout";
237
239
  const [encodedHeader] = compactParts(jwt, 3, CAPTURE_CONTEXT_MAX_LENGTH, "format");
238
240
  const peek = jsonFromBytes(base64UrlToBytes(encodedHeader), "format");
239
241
  const kid = peek.kid;
@@ -254,8 +256,9 @@ async function verifyContextWithKeys(jwt, keys, { crypto, now } = {}) {
254
256
  if (!record(flx))
255
257
  refuse("format", "the capture context has no Flex section.");
256
258
  const origin = `https://${host}`;
257
- const url = `${origin}${FLEX_TOKENS_PATH}`;
258
- if (flx.origin !== origin || flx.path !== FLEX_TOKENS_PATH || own(flx, "tokensUrl") && flx.tokensUrl !== url) {
259
+ const path = unified ? UNIFIED_CHECKOUT_TOKENS_PATH : FLEX_TOKENS_PATH;
260
+ const url = `${origin}${path}`;
261
+ if (unified ? flx.origin !== origin || flx.tokensUrl !== url || own(flx, "path") : flx.origin !== origin || flx.path !== FLEX_TOKENS_PATH || own(flx, "tokensUrl") && flx.tokensUrl !== url) {
259
262
  refuse("url_mismatch", `the capture context does not send the card to ${url}.`);
260
263
  }
261
264
  const jwk = flx.jwk;
@@ -271,21 +274,22 @@ async function verifyContextWithKeys(jwt, keys, { crypto, now } = {}) {
271
274
  refuse("expired", "the capture context has expired.");
272
275
  }
273
276
  const ctx = Array.isArray(payload.ctx) ? payload.ctx : [];
274
- const index = ctx.findIndex((entry) => record(entry) && typeof entry.type === "string" && /^mf-/.test(entry.type));
277
+ const index = ctx.findIndex((entry) => record(entry) && typeof entry.type === "string" && (unified ? /^uc-/ : /^mf-/).test(entry.type));
275
278
  if (index < 0)
276
- refuse("microform", "the capture context is not a Microform context.");
279
+ refuse("microform", unified ? "the capture context is not a Unified Checkout context." : "the capture context is not a Microform context.");
277
280
  const data = record(ctx[index].data) ? ctx[index].data : {};
278
281
  const context = Object.freeze({
279
282
  raw: jwt,
280
283
  signingKid: kid,
281
284
  environment,
282
285
  origin,
283
- path: FLEX_TOKENS_PATH,
286
+ path,
284
287
  url,
285
288
  jwk: Object.freeze({ kty: "RSA", n: jwk.n, e: jwk.e, kid: jwk.kid }),
286
289
  modulusBytes: Math.ceil(bits / 8),
287
290
  index,
288
291
  contextType: ctx[index].type,
292
+ clientVersion: unified && typeof data.clientVersion === "string" && data.clientVersion.length <= 32 ? data.clientVersion : null,
289
293
  allowedCardNetworks: networks(data.allowedCardNetworks),
290
294
  targetOrigins: origins(data.targetOrigins),
291
295
  iat: Number.isFinite(payload.iat) ? payload.iat : null,
@@ -294,6 +298,51 @@ async function verifyContextWithKeys(jwt, keys, { crypto, now } = {}) {
294
298
  VERIFIED.add(context);
295
299
  return context;
296
300
  }
301
+ // src/cybersource-unified-checkout.js
302
+ var UNIFIED_CHECKOUT_HOSTS = Object.freeze({ production: "up.cybersource.com", sandbox: "testup.cybersource.com" });
303
+ var UNIFIED_CHECKOUT_REVIEWED_CLIENT_VERSIONS = Object.freeze(["1.8.2"]);
304
+ var UNIFIED_CHECKOUT_FRAMES = Object.freeze(["mce", "orc", "ga"]);
305
+ var FRAME_PATH = /^\/uc\/v1\/assets\/([A-Za-z0-9_-]{16,1024})\/(mce|orc|ga)\/(mce|orc|ga)\.html$/;
306
+ var FRAGMENT_MAX_LENGTH = CAPTURE_CONTEXT_MAX_LENGTH + 4096;
307
+ function unifiedCheckoutHostEnvironment(hostname) {
308
+ const host = String(hostname ?? "").toLowerCase();
309
+ if (host === UNIFIED_CHECKOUT_HOSTS.production)
310
+ return "production";
311
+ if (host === UNIFIED_CHECKOUT_HOSTS.sandbox)
312
+ return "sandbox";
313
+ return null;
314
+ }
315
+ function parseUnifiedCheckoutFrame(rawUrl) {
316
+ if (typeof rawUrl !== "string" || rawUrl.length > FRAGMENT_MAX_LENGTH + 2048)
317
+ return null;
318
+ let url;
319
+ try {
320
+ url = new URL(rawUrl);
321
+ }
322
+ catch {
323
+ return null;
324
+ }
325
+ const environment = unifiedCheckoutHostEnvironment(url.hostname);
326
+ const path = FRAME_PATH.exec(url.pathname);
327
+ if (url.protocol !== "https:" || url.port || url.username || url.password || !environment || !path || path[2] !== path[3])
328
+ return null;
329
+ const fragment = url.hash.slice(1);
330
+ if (!fragment || fragment.length > FRAGMENT_MAX_LENGTH)
331
+ return null;
332
+ let value;
333
+ try {
334
+ value = JSON.parse(decodeURIComponent(fragment));
335
+ }
336
+ catch {
337
+ return null;
338
+ }
339
+ if (!value || typeof value !== "object" || Array.isArray(value))
340
+ return null;
341
+ const ctx = value.ctx;
342
+ if (typeof ctx !== "string" || ctx.length < 1 || ctx.length > CAPTURE_CONTEXT_MAX_LENGTH)
343
+ return null;
344
+ return Object.freeze({ environment, frame: path[2], asset: path[1], captureContext: ctx });
345
+ }
297
346
  // src/cybersource-flex.js
298
347
  var CYBERSOURCE_FLEX_PSP = "cybersource_flex";
299
348
  var CYBERSOURCE_FLEX_CONTENT_TYPE = "application/jwt; charset=utf-8";
@@ -343,11 +392,11 @@ function cybersourceFlexEnvironment(url) {
343
392
  return "sandbox";
344
393
  return void 0;
345
394
  }
346
- var FRAGMENT_MAX_LENGTH = 16384;
395
+ var FRAGMENT_MAX_LENGTH2 = 16384;
347
396
  var IFRAME_PATH = /^\/microform\/bundle\/v(\d+\.\d+\.\d+)\/iframe\.html$/;
348
397
  var FIELD_TYPES = Object.freeze(["number", "securityCode"]);
349
398
  function parseMicroformFragment(rawUrl) {
350
- if (typeof rawUrl !== "string" || rawUrl.length > FRAGMENT_MAX_LENGTH + 2048)
399
+ if (typeof rawUrl !== "string" || rawUrl.length > FRAGMENT_MAX_LENGTH2 + 2048)
351
400
  return null;
352
401
  let url;
353
402
  try {
@@ -361,7 +410,7 @@ function parseMicroformFragment(rawUrl) {
361
410
  if (url.protocol !== "https:" || url.port || url.username || url.password || !environment || !path)
362
411
  return null;
363
412
  const fragment = url.hash.slice(1);
364
- if (!fragment || fragment.length > FRAGMENT_MAX_LENGTH)
413
+ if (!fragment || fragment.length > FRAGMENT_MAX_LENGTH2)
365
414
  return null;
366
415
  let value;
367
416
  try {
@@ -556,6 +605,46 @@ async function sealForContext(verified, plaintext, { crypto } = {}) {
556
605
  refuse("context", "the capture context was not verified on this device.");
557
606
  return sealCompactJwe(verified.jwk, plaintext, { crypto });
558
607
  }
608
+ function verifyUnifiedCheckoutContext(jwt, { crypto, now } = {}) {
609
+ return verifyContextWithKeys(jwt, CYBERSOURCE_FLEX_SIGNING_KEYS, { crypto, now, kind: "unified_checkout" });
610
+ }
611
+ var BILL_TO_NAME = /^[^\u0000-\u001f\u007f<>]{1,60}$/;
612
+ var BILL_TO_EMAIL = /^[^\s@<>]{1,64}@[^\s@<>]{1,190}$/;
613
+ function buildUnifiedCheckoutPlaintext(verified, card, { billTo, now } = {}) {
614
+ if (!isVerifiedCaptureContext(verified) || !/^uc-/.test(verified.contextType))
615
+ refuse("context", "the capture context was not verified as a Unified Checkout context on this device.");
616
+ if (!UNIFIED_CHECKOUT_REVIEWED_CLIENT_VERSIONS.includes(verified.clientVersion))
617
+ refuse("microform_version", "this Unified Checkout client version was not reviewed.");
618
+ const first = billTo?.firstName;
619
+ const last = billTo?.lastName;
620
+ const email = billTo?.email;
621
+ if (typeof first !== "string" || !BILL_TO_NAME.test(first) || typeof last !== "string" || !BILL_TO_NAME.test(last) || email !== void 0 && (typeof email !== "string" || !BILL_TO_EMAIL.test(email)))
622
+ refuse("fields", "the billing name or email is not one the card entry takes.");
623
+ const normalized = flexCard(card, typeof now === "function" ? now() : Date.now());
624
+ const detected = detectCardTypes(normalized.number, verified.allowedCardNetworks ?? void 0);
625
+ if (detected.codes.length === 0)
626
+ refuse("card_network", "this merchant's CyberSource form does not accept this card network.");
627
+ if (!detected.valid)
628
+ refuse("card_invalid", "the card number fails its network's length or check digit.");
629
+ if (detected.securityCode.required && !new RegExp(`^[0-9]{${detected.securityCode.length}}$`).test(normalized.cvc)) {
630
+ refuse("card_security_code", "the security code has the wrong length for this card.");
631
+ }
632
+ const data = {
633
+ PANENTRY: {
634
+ orderInformation: { billTo: { firstName: first, lastName: last, ...email !== void 0 ? { email } : {} } },
635
+ paymentInformation: { card: {
636
+ number: normalized.number,
637
+ expirationMonth: normalized.expirationMonth,
638
+ expirationYear: normalized.expirationYear,
639
+ securityCode: normalized.cvc,
640
+ type: detected.codes[0]
641
+ } }
642
+ }
643
+ };
644
+ const plaintext = JSON.stringify({ data, context: verified.raw, index: 0 }).replace(/[\u0080-\uffff]/g, (c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, "0")}`);
645
+ asciiBytes(plaintext, "card_ascii");
646
+ return plaintext;
647
+ }
559
648
  var TOKEN_MAX_LENGTH = 8192;
560
649
  var CYBERSOURCE_FLEX_REFUSAL_REASONS = Object.freeze([
561
650
  "VALIDATION_ERROR",
@@ -728,4 +817,4 @@ function sameCybersourceFlexPreparation(prepared, request) {
728
817
  const theirs = new Set(two.fields);
729
818
  return mine.size === one.fields.length && theirs.size === two.fields.length && mine.size === theirs.size && [...mine].every((field) => theirs.has(field));
730
819
  }
731
- export { CYBERSOURCE_FLEX_CAPTURE_CONTEXT_MAX_LENGTH, CYBERSOURCE_FLEX_CONTENT_TYPE, CYBERSOURCE_FLEX_PRESEAL_TRIGGER, CYBERSOURCE_FLEX_PSP, CYBERSOURCE_FLEX_REFUSAL_REASONS, CYBERSOURCE_FLEX_REVIEWED_IFRAME_VERSIONS, CYBERSOURCE_FLEX_RULES_SOURCE, CYBERSOURCE_FLEX_SIGNING_KEYS, CYBERSOURCE_FLEX_TEST_PANS, CYBERSOURCE_FLEX_TOKENS_URLS, CybersourceFlexError, admitCybersourceFlexPreparation, assertCybersourceFlexTemplate, buildCardPlaintext, cybersourceFlexEnvironment, flexHostEnvironment as cybersourceFlexHostEnvironment, cybersourceFlexPreparationUrl, cybersourceFlexRefusalCode, cybersourceFlexTemplateKid, detectCardTypes, isCybersourceFlexMediaType, isCybersourceFlexRequest, isCybersourceFlexTemplateBody, isCybersourceFlexTokenShape, isPreparedCybersourceFlexRequest, isVerifiedCaptureContext, parseMicroformFragment, sameCybersourceFlexPreparation, sealForContext, transientTokenFacts, transientTokenSigned, verifyCaptureContext };
820
+ export { CYBERSOURCE_FLEX_CAPTURE_CONTEXT_MAX_LENGTH, CYBERSOURCE_FLEX_CONTENT_TYPE, CYBERSOURCE_FLEX_PRESEAL_TRIGGER, CYBERSOURCE_FLEX_PSP, CYBERSOURCE_FLEX_REFUSAL_REASONS, CYBERSOURCE_FLEX_REVIEWED_IFRAME_VERSIONS, CYBERSOURCE_FLEX_RULES_SOURCE, CYBERSOURCE_FLEX_SIGNING_KEYS, CYBERSOURCE_FLEX_TEST_PANS, CYBERSOURCE_FLEX_TOKENS_URLS, CybersourceFlexError, UNIFIED_CHECKOUT_FRAMES, UNIFIED_CHECKOUT_HOSTS, UNIFIED_CHECKOUT_REVIEWED_CLIENT_VERSIONS, admitCybersourceFlexPreparation, assertCybersourceFlexTemplate, buildCardPlaintext, buildUnifiedCheckoutPlaintext, cybersourceFlexEnvironment, flexHostEnvironment as cybersourceFlexHostEnvironment, cybersourceFlexPreparationUrl, cybersourceFlexRefusalCode, cybersourceFlexTemplateKid, detectCardTypes, isCybersourceFlexMediaType, isCybersourceFlexRequest, isCybersourceFlexTemplateBody, isCybersourceFlexTokenShape, isPreparedCybersourceFlexRequest, isVerifiedCaptureContext, parseMicroformFragment, parseUnifiedCheckoutFrame, sameCybersourceFlexPreparation, sealForContext, transientTokenFacts, transientTokenSigned, unifiedCheckoutHostEnvironment, verifyCaptureContext, verifyUnifiedCheckoutContext };
package/dist/eghl.d.ts ADDED
@@ -0,0 +1,40 @@
1
+ /**
2
+ * eGHL's hosted payment page (securepay.e-ghl.com, the Malaysian gateway now sold as ADAPTIS, behind its own Shopify app
3
+ * among others), as this SDK reads it.
4
+ *
5
+ * The merchant's checkout sends the buyer's browser to https://securepay.e-ghl.com/IPG/payment.aspx with the payment in
6
+ * the query: a GET that carries no card, and the one request a build that declares eGHL's capability pauses
7
+ * (hosted-entry.ts). The cardholder's device repeats it over the end-to-end TLS relay and pays on the card page eGHL
8
+ * returns to it (payment-core processors/eghl.js). Every step toward paying on that page is a POST to eGHL's hosts, the
9
+ * card page's card post to the entry's own address among them, so this SDK aborts every POST there once the lane is
10
+ * served, and no placeholder card reaches eGHL.
11
+ *
12
+ * EGHL_HOST is payment-core's EGHL_HOST, and isEghlEntryUrl is payment-core's isEghlEntryUrl; eghl.test.mjs pins both
13
+ * to payment-core.
14
+ */
15
+ export declare const EGHL_PSP = "eghl";
16
+ /** The dark-launch capability the API serves eGHL's recognizer behind (payment-core processors/eghl.js). */
17
+ export declare const EGHL_CAPABILITY = "eghl_hosted_payment_page";
18
+ /** eGHL's live host, and its test platform's. */
19
+ export declare const EGHL_HOST = "securepay.e-ghl.com";
20
+ export declare const EGHL_SANDBOX_HOST = "test2pay.ghl.com";
21
+ /**
22
+ * Whether a URL is an entry as a browser sends it: https, eGHL's live host with its entry path or its test host with its
23
+ * test path, the path in any letter case as IIS reads it, the default port, no credentials, no fragment, and a query
24
+ * that names the payment. Any other request to eGHL's hosts is not the entry.
25
+ */
26
+ export declare function isEghlEntryUrl(raw: unknown): boolean;
27
+ /**
28
+ * Whether a request on eGHL's hosts is a step toward paying there: any POST, the card page's card post and its Click to
29
+ * Pay post among them. The entry, the page's scripts and its images are GETs and are not one.
30
+ */
31
+ export declare function isEghlPayStep(url: string, method: string): boolean;
32
+ /**
33
+ * Whether an adapter must hand this request to the pre-claim gates: it is on eGHL's hosts and this build's registry
34
+ * serves eGHL's entry. The page's posts are not the entry, so the registry's card-request test does not name them; the
35
+ * CDP adapter still pauses them through the recognizer's host patterns, and attachToPlaywright's route predicate asks
36
+ * this, so both adapters show the gates every request to eGHL's hosts once the lane is armed.
37
+ */
38
+ export declare function isArmedEghlUrl(vault: {
39
+ isCardRequest(url: string, method?: string): boolean;
40
+ } | undefined, url: string): boolean;
package/dist/eghl.js ADDED
@@ -0,0 +1,72 @@
1
+ /**
2
+ * eGHL's hosted payment page (securepay.e-ghl.com, the Malaysian gateway now sold as ADAPTIS, behind its own Shopify app
3
+ * among others), as this SDK reads it.
4
+ *
5
+ * The merchant's checkout sends the buyer's browser to https://securepay.e-ghl.com/IPG/payment.aspx with the payment in
6
+ * the query: a GET that carries no card, and the one request a build that declares eGHL's capability pauses
7
+ * (hosted-entry.ts). The cardholder's device repeats it over the end-to-end TLS relay and pays on the card page eGHL
8
+ * returns to it (payment-core processors/eghl.js). Every step toward paying on that page is a POST to eGHL's hosts, the
9
+ * card page's card post to the entry's own address among them, so this SDK aborts every POST there once the lane is
10
+ * served, and no placeholder card reaches eGHL.
11
+ *
12
+ * EGHL_HOST is payment-core's EGHL_HOST, and isEghlEntryUrl is payment-core's isEghlEntryUrl; eghl.test.mjs pins both
13
+ * to payment-core.
14
+ */
15
+ export const EGHL_PSP = 'eghl';
16
+ /** The dark-launch capability the API serves eGHL's recognizer behind (payment-core processors/eghl.js). */
17
+ export const EGHL_CAPABILITY = 'eghl_hosted_payment_page';
18
+ /** eGHL's live host, and its test platform's. */
19
+ export const EGHL_HOST = 'securepay.e-ghl.com';
20
+ export const EGHL_SANDBOX_HOST = 'test2pay.ghl.com';
21
+ const LIVE_PATH = '/ipg/payment.aspx';
22
+ const SANDBOX_PATH = '/ipgsg/payment.aspx';
23
+ // An entry of that shape, for asking whether this build's registry serves the entry.
24
+ const PROBE = 'https://securepay.e-ghl.com/IPG/payment.aspx?TransactionType=SALE';
25
+ /**
26
+ * Whether a URL is an entry as a browser sends it: https, eGHL's live host with its entry path or its test host with its
27
+ * test path, the path in any letter case as IIS reads it, the default port, no credentials, no fragment, and a query
28
+ * that names the payment. Any other request to eGHL's hosts is not the entry.
29
+ */
30
+ export function isEghlEntryUrl(raw) {
31
+ if (typeof raw !== 'string' || raw.length > 8192 || raw.includes('#'))
32
+ return false;
33
+ let url;
34
+ try {
35
+ url = new URL(raw);
36
+ }
37
+ catch {
38
+ return false;
39
+ }
40
+ if (url.href !== raw || url.protocol !== 'https:' || url.port || url.username || url.password || url.search.length < 2)
41
+ return false;
42
+ const path = url.pathname.toLowerCase();
43
+ return (url.hostname === EGHL_HOST && path === LIVE_PATH) || (url.hostname === EGHL_SANDBOX_HOST && path === SANDBOX_PATH);
44
+ }
45
+ /** Whether a URL is on one of eGHL's hosts, live or test: https, no credentials, any port, any case, a trailing dot or not. */
46
+ function onEghlHost(raw) {
47
+ let url;
48
+ try {
49
+ url = new URL(raw);
50
+ }
51
+ catch {
52
+ return false;
53
+ }
54
+ const host = url.hostname.toLowerCase().replace(/\.$/, '');
55
+ return url.protocol === 'https:' && !url.username && !url.password && (host === EGHL_HOST || host === EGHL_SANDBOX_HOST);
56
+ }
57
+ /**
58
+ * Whether a request on eGHL's hosts is a step toward paying there: any POST, the card page's card post and its Click to
59
+ * Pay post among them. The entry, the page's scripts and its images are GETs and are not one.
60
+ */
61
+ export function isEghlPayStep(url, method) {
62
+ return onEghlHost(url) && String(method).toUpperCase() === 'POST';
63
+ }
64
+ /**
65
+ * Whether an adapter must hand this request to the pre-claim gates: it is on eGHL's hosts and this build's registry
66
+ * serves eGHL's entry. The page's posts are not the entry, so the registry's card-request test does not name them; the
67
+ * CDP adapter still pauses them through the recognizer's host patterns, and attachToPlaywright's route predicate asks
68
+ * this, so both adapters show the gates every request to eGHL's hosts once the lane is armed.
69
+ */
70
+ export function isArmedEghlUrl(vault, url) {
71
+ return onEghlHost(url) && typeof vault?.isCardRequest === 'function' && vault.isCardRequest(PROBE, 'GET');
72
+ }
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
2
  // Generated from @agent-cards/payment-core. Do not edit.
3
- // artifact-sha256: a65199bcbf0b67546130fb4f2c12ba72c8f51a2ff5b4e3054e2bfcc29b06f95d
3
+ // artifact-sha256: 192df19d53f4c68d74db3d692397b94f4a1b45ce8bee44a2326e01b56a329adf
4
4
  // src/sha256.js
5
5
  var K = /* @__PURE__ */ new Uint32Array([
6
6
  1116352408,
@@ -146,6 +146,7 @@ var BASE64 = /^[A-Za-z0-9+/]+={0,2}$/;
146
146
  var SHA256_HEX = /^[0-9a-f]{64}$/;
147
147
  var RSA_ALGORITHM = [48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0];
148
148
  var MODULUS_BYTES = [128, 256, 384, 512];
149
+ var SMALL_MODULUS_BYTES = 64;
149
150
  var MIN_PADDING = 8;
150
151
  var MAX_DRAWS = 16;
151
152
  var TYPED_ARRAY = Object.getPrototypeOf(Uint8Array.prototype);
@@ -156,6 +157,9 @@ function parseRsaPublicKey(key) {
156
157
  const named = key && typeof key === "object" && Object.prototype.hasOwnProperty.call(key, "exponent") ? key.exponent : void 0;
157
158
  if (named !== void 0 && named !== 17)
158
159
  throw refuse("key");
160
+ const sized = key && typeof key === "object" && Object.prototype.hasOwnProperty.call(key, "bits") ? key.bits : void 0;
161
+ if (sized !== void 0 && sized !== 512)
162
+ throw refuse("key");
159
163
  if (typeof spki !== "string" || spki.length > 1024 || spki.length % 4 !== 0 || !BASE64.test(spki))
160
164
  throw refuse("key");
161
165
  if (typeof pin !== "string" || !SHA256_HEX.test(pin))
@@ -188,7 +192,8 @@ function parseRsaPublicKey(key) {
188
192
  if (exponent.end !== rsa.end)
189
193
  throw refuse("key");
190
194
  const n = modulus.bytes;
191
- if (!MODULUS_BYTES.includes(n.length) || !(n[0] & 128) || !(n[n.length - 1] & 1))
195
+ const sizes = sized === 512 ? [SMALL_MODULUS_BYTES] : MODULUS_BYTES;
196
+ if (!sizes.includes(n.length) || !(n[0] & 128) || !(n[n.length - 1] & 1))
192
197
  throw refuse("key");
193
198
  const e = exponent.bytes;
194
199
  const expected = named === 17 ? [17] : [1, 0, 1];
@@ -19,12 +19,14 @@ import { COMGATE_PSP, isComgateEntryUrl } from './comgate.js';
19
19
  import { TRANSBANK_PSP, isTransbankEntryUrl } from './transbank.js';
20
20
  import { BARION_PSP, isBarionEntryUrl } from './barion.js';
21
21
  import { PAYPLUG_PSP, isPayplugEntryUrl } from './payplug.js';
22
+ import { EGHL_PSP, isEghlEntryUrl } from './eghl.js';
22
23
  const HOSTED_GET_ENTRIES = new Map([
23
24
  [PRZELEWY24_PSP, isPrzelewy24EntryUrl],
24
25
  [COMGATE_PSP, isComgateEntryUrl],
25
26
  [TRANSBANK_PSP, isTransbankEntryUrl],
26
27
  [BARION_PSP, isBarionEntryUrl],
27
28
  [PAYPLUG_PSP, isPayplugEntryUrl],
29
+ [EGHL_PSP, isEghlEntryUrl],
28
30
  ]);
29
31
  /** Whether this processor's hosted page is entered with a GET this build reads exactly. */
30
32
  export function hasHostedGetEntry(psp) {
@@ -109,6 +109,7 @@ export declare class CheckoutLifecycle implements CheckoutController {
109
109
  private orderRefusal;
110
110
  private readonly handoffs;
111
111
  private reconciliation;
112
+ private pendingHold;
112
113
  /**
113
114
  * EBANX sends this attachment claimed that are still out (pre-claim.ts ebanxFollowUp): the cardholder's device may be
114
115
  * sending a confirm that pays, outside `active`, so reconcile() and retryAfterMerchantFailure() wait for them too.
@@ -150,6 +151,15 @@ export declare class CheckoutLifecycle implements CheckoutController {
150
151
  isCancelled(): boolean;
151
152
  /** Whether the application gave a merchant resolver, so reconcile() reads the merchant's own record. */
152
153
  hasMerchantResolver(): boolean;
154
+ /**
155
+ * Whether the page's byte-identical re-send of the card request this approval answered may get the same answer
156
+ * (token-repeats.ts, pre-claim.ts tokenRepeatPreClaim): the checkout awaits the merchant on a plain token handoff
157
+ * that held nothing, and the only hold since is the merchant resolver reading the order as pending. A hold from
158
+ * anything else stands: an amount the processor charged that differs from the approval's, an unbound Stripe token,
159
+ * a hosted form or card endpoint, an integrator's requireMerchantResult, a follow-up send still out, an unsupported
160
+ * request, a cancel or an aborted request. The gate still asks the resolver before it answers.
161
+ */
162
+ repeatAnswerable(): boolean;
153
163
  /**
154
164
  * For a Datatrans re-submit once the approved answer reached the page (pre-claim.ts): whether the
155
165
  * application's merchant resolver still reports this approval's order pending. A read only: no
package/dist/lifecycle.js CHANGED
@@ -70,6 +70,8 @@ export class CheckoutLifecycle {
70
70
  // Every request this attachment handed the card to: see cardHandoffs().
71
71
  handoffs = [];
72
72
  reconciliation = null;
73
+ // The hold is only the merchant resolver's `pending` on a handoff nothing else held (resolve): see repeatAnswerable.
74
+ pendingHold = false;
73
75
  /**
74
76
  * EBANX sends this attachment claimed that are still out (pre-claim.ts ebanxFollowUp): the cardholder's device may be
75
77
  * sending a confirm that pays, outside `active`, so reconcile() and retryAfterMerchantFailure() wait for them too.
@@ -140,6 +142,18 @@ export class CheckoutLifecycle {
140
142
  isCancelled() { return this.cancelled; }
141
143
  /** Whether the application gave a merchant resolver, so reconcile() reads the merchant's own record. */
142
144
  hasMerchantResolver() { return typeof this.options.resolveMerchantResult === 'function'; }
145
+ /**
146
+ * Whether the page's byte-identical re-send of the card request this approval answered may get the same answer
147
+ * (token-repeats.ts, pre-claim.ts tokenRepeatPreClaim): the checkout awaits the merchant on a plain token handoff
148
+ * that held nothing, and the only hold since is the merchant resolver reading the order as pending. A hold from
149
+ * anything else stands: an amount the processor charged that differs from the approval's, an unbound Stripe token,
150
+ * a hosted form or card endpoint, an integrator's requireMerchantResult, a follow-up send still out, an unsupported
151
+ * request, a cancel or an aborted request. The gate still asks the resolver before it answers.
152
+ */
153
+ repeatAnswerable() {
154
+ return this.state.status === 'awaiting_merchant' && !!this.state.authorizationId && !this.active && !this.cancelled
155
+ && !this.merchantAborted && this.followUpsOut === 0 && (!this.held || this.pendingHold);
156
+ }
143
157
  /**
144
158
  * For a Datatrans re-submit once the approved answer reached the page (pre-claim.ts): whether the
145
159
  * application's merchant resolver still reports this approval's order pending. A read only: no
@@ -169,6 +183,10 @@ export class CheckoutLifecycle {
169
183
  }
170
184
  end() { this.active = false; }
171
185
  set(state) {
186
+ // Any state but awaiting the merchant (a challenge, a failure, a completion) ends the pending read's exception for
187
+ // good: a later pending read that brings awaiting_merchant back holds every card request again (repeatAnswerable).
188
+ if (state.status !== 'awaiting_merchant')
189
+ this.pendingHold = false;
172
190
  this.state = state;
173
191
  // Application telemetry must never interrupt a paused payment after it reaches the processor.
174
192
  try {
@@ -287,6 +305,7 @@ export class CheckoutLifecycle {
287
305
  */
288
306
  unsupported(reason = 'unrecognized_payment_endpoint') {
289
307
  this.held = true;
308
+ this.pendingHold = false;
290
309
  if (this.state.authorizationId)
291
310
  return; // do not hide an outstanding/completed payment behind a later unsupported request
292
311
  this.set({ ...this.state, status: 'unsupported', reason });
@@ -416,6 +435,7 @@ export class CheckoutLifecycle {
416
435
  if (this.merchantAborted)
417
436
  return;
418
437
  this.settled = true;
438
+ this.pendingHold = false;
419
439
  if (this.orderRefusal) {
420
440
  // Nike's order was refused while this approval was on its way: the answer lands, and the checkout stays failed.
421
441
  this.held = true;
@@ -591,6 +611,10 @@ export class CheckoutLifecycle {
591
611
  await this.requestUserAction(result.reason);
592
612
  }
593
613
  else {
614
+ // A pending order on a handoff nothing held still lets the page's identical re-send of the same card request have
615
+ // its answer again (repeatAnswerable); every other card request stays refused.
616
+ if (!this.held && result.status === 'pending' && this.state.status === 'awaiting_merchant')
617
+ this.pendingHold = true;
594
618
  this.held = true;
595
619
  this.set({ ...this.state, status: result.status === 'pending' ? 'awaiting_merchant' : 'outcome_unknown', reason: 'merchant_not_confirmed' });
596
620
  }
@@ -612,6 +636,7 @@ export class CheckoutLifecycle {
612
636
  if (this.unboundStripeToken)
613
637
  throw new Error('This attachment delivered an unbound Stripe token; reconcile the merchant order and use a separately validated checkout flow.');
614
638
  this.held = false;
639
+ this.pendingHold = false;
615
640
  this.merchantAborted = false;
616
641
  this.orderRefusal = null;
617
642
  this.set({ status: 'idle', authorizationId: null });
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
2
  // Generated from @agent-cards/payment-core. Do not edit.
3
- // artifact-sha256: 4b24c682dbd8cd7bbaa0157f2932021d71f7c6802ce3814c6f3047173df29911
3
+ // artifact-sha256: 0bd60e76821ed0f63235a99cc37dece9f0db8afef89492a0a7930fb49f80eb18
4
4
  // src/sha256.js
5
5
  var K = /* @__PURE__ */ new Uint32Array([
6
6
  1116352408,
@@ -146,6 +146,7 @@ var BASE64 = /^[A-Za-z0-9+/]+={0,2}$/;
146
146
  var SHA256_HEX = /^[0-9a-f]{64}$/;
147
147
  var RSA_ALGORITHM = [48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0];
148
148
  var MODULUS_BYTES = [128, 256, 384, 512];
149
+ var SMALL_MODULUS_BYTES = 64;
149
150
  var MIN_PADDING = 8;
150
151
  var MAX_DRAWS = 16;
151
152
  var TYPED_ARRAY = Object.getPrototypeOf(Uint8Array.prototype);
@@ -156,6 +157,9 @@ function parseRsaPublicKey(key) {
156
157
  const named = key && typeof key === "object" && Object.prototype.hasOwnProperty.call(key, "exponent") ? key.exponent : void 0;
157
158
  if (named !== void 0 && named !== 17)
158
159
  throw refuse("key");
160
+ const sized = key && typeof key === "object" && Object.prototype.hasOwnProperty.call(key, "bits") ? key.bits : void 0;
161
+ if (sized !== void 0 && sized !== 512)
162
+ throw refuse("key");
159
163
  if (typeof spki !== "string" || spki.length > 1024 || spki.length % 4 !== 0 || !BASE64.test(spki))
160
164
  throw refuse("key");
161
165
  if (typeof pin2 !== "string" || !SHA256_HEX.test(pin2))
@@ -188,7 +192,8 @@ function parseRsaPublicKey(key) {
188
192
  if (exponent.end !== rsa.end)
189
193
  throw refuse("key");
190
194
  const n = modulus.bytes;
191
- if (!MODULUS_BYTES.includes(n.length) || !(n[0] & 128) || !(n[n.length - 1] & 1))
195
+ const sizes = sized === 512 ? [SMALL_MODULUS_BYTES] : MODULUS_BYTES;
196
+ if (!sizes.includes(n.length) || !(n[0] & 128) || !(n[n.length - 1] & 1))
192
197
  throw refuse("key");
193
198
  const e = exponent.bytes;
194
199
  const expected = named === 17 ? [17] : [1, 0, 1];
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
2
  // Generated from @agent-cards/payment-core. Do not edit.
3
- // artifact-sha256: 139d0001a168e053ebe3283721905ae95d7c159a25848469965f037b844a44cf
3
+ // artifact-sha256: d6d50b6577a932c3586fcade6b8cbd03c562bd3394e8addcb954d797ea9999b4
4
4
  // src/json-path.js
5
5
  function roundTrips(parsed, body) {
6
6
  try {
@@ -174,6 +174,7 @@ var BASE64 = /^[A-Za-z0-9+/]+={0,2}$/;
174
174
  var SHA256_HEX = /^[0-9a-f]{64}$/;
175
175
  var RSA_ALGORITHM = [48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0];
176
176
  var MODULUS_BYTES = [128, 256, 384, 512];
177
+ var SMALL_MODULUS_BYTES = 64;
177
178
  var TYPED_ARRAY = Object.getPrototypeOf(Uint8Array.prototype);
178
179
  var typedArrayName = Object.getOwnPropertyDescriptor(TYPED_ARRAY, Symbol.toStringTag).get;
179
180
  function parseRsaPublicKey(key) {
@@ -182,6 +183,9 @@ function parseRsaPublicKey(key) {
182
183
  const named = key && typeof key === "object" && Object.prototype.hasOwnProperty.call(key, "exponent") ? key.exponent : void 0;
183
184
  if (named !== void 0 && named !== 17)
184
185
  throw refuse("key");
186
+ const sized = key && typeof key === "object" && Object.prototype.hasOwnProperty.call(key, "bits") ? key.bits : void 0;
187
+ if (sized !== void 0 && sized !== 512)
188
+ throw refuse("key");
185
189
  if (typeof spki !== "string" || spki.length > 1024 || spki.length % 4 !== 0 || !BASE64.test(spki))
186
190
  throw refuse("key");
187
191
  if (typeof pin !== "string" || !SHA256_HEX.test(pin))
@@ -214,7 +218,8 @@ function parseRsaPublicKey(key) {
214
218
  if (exponent.end !== rsa.end)
215
219
  throw refuse("key");
216
220
  const n = modulus.bytes;
217
- if (!MODULUS_BYTES.includes(n.length) || !(n[0] & 128) || !(n[n.length - 1] & 1))
221
+ const sizes = sized === 512 ? [SMALL_MODULUS_BYTES] : MODULUS_BYTES;
222
+ if (!sizes.includes(n.length) || !(n[0] & 128) || !(n[n.length - 1] & 1))
218
223
  throw refuse("key");
219
224
  const e = exponent.bytes;
220
225
  const expected = named === 17 ? [17] : [1, 0, 1];
@@ -15,6 +15,7 @@ import { type CardEndpointProfile } from './card-endpoint.js';
15
15
  import { type NikeOrders } from './nike-order.js';
16
16
  import { type PayrailsSessionCapture, type PayrailsSidecar } from './payrails.js';
17
17
  import { type VerifoneProfile } from './verifone.js';
18
+ import type { TokenRepeats } from './token-repeats.js';
18
19
  import { type WorldlineMyCheckoutProducts } from './worldline-mycheckout.js';
19
20
  import { type PaddleVgsPayGate } from './paddle-vgs-pay.js';
20
21
  import { type EbanxFollowUps } from './ebanx.js';
@@ -210,6 +211,8 @@ export interface PreClaimContext {
210
211
  datatrans?: DatatransRepeats;
211
212
  /** The attachment's approved TokenEx iframe answers (the repeat rule, tokenex-iframe.ts). Absent: none are kept. */
212
213
  tokenexIframe?: TokenexIframeRepeats;
214
+ /** The attachment's last approved plain token answer, for the page's identical re-send (token-repeats.ts). Absent: none is kept. */
215
+ tokenRepeats?: TokenRepeats;
213
216
  /** The adapter's identity for the request's frame (CDP frameId, Playwright Frame); undefined when unknown. */
214
217
  frame?: unknown;
215
218
  /**
@@ -288,6 +291,8 @@ export declare function isArmedCreditguardCall(vault: {
288
291
  export declare const przelewy24PreClaim: PreClaimGate;
289
292
  export declare const barionPreClaim: PreClaimGate;
290
293
  export declare const payplugPreClaim: PreClaimGate;
294
+ export declare const eghlPreClaim: PreClaimGate;
295
+ export declare const cardlinkVposPreClaim: PreClaimGate;
291
296
  export declare const ekashuPreClaim: PreClaimGate;
292
297
  export declare const transbankPreClaim: PreClaimGate;
293
298
  export declare const paytrailPreClaim: PreClaimGate;