@agent-cards/checkout 0.19.0 → 0.22.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 (106) hide show
  1. package/README.md +6 -753
  2. package/cdp.d.ts +1 -0
  3. package/cdp.js +2 -0
  4. package/index.d.ts +1 -0
  5. package/index.js +2 -0
  6. package/package.json +33 -33
  7. package/playwright.d.ts +1 -0
  8. package/playwright.js +2 -0
  9. package/preflight.d.ts +1 -0
  10. package/preflight.js +2 -0
  11. package/CHANGELOG.md +0 -132
  12. package/PREFLIGHT.md +0 -312
  13. package/dist/adyen-merchant-hosted.generated.d.ts +0 -277
  14. package/dist/adyen-merchant-hosted.generated.js +0 -1902
  15. package/dist/adyen.generated.d.ts +0 -24
  16. package/dist/adyen.generated.js +0 -64
  17. package/dist/attachment.d.ts +0 -11
  18. package/dist/attachment.js +0 -50
  19. package/dist/braintree.d.ts +0 -2
  20. package/dist/braintree.generated.d.ts +0 -10
  21. package/dist/braintree.generated.js +0 -302
  22. package/dist/braintree.js +0 -2
  23. package/dist/builtin-registry.generated.d.ts +0 -2
  24. package/dist/builtin-registry.generated.js +0 -1
  25. package/dist/card-fields.generated.d.ts +0 -3
  26. package/dist/card-fields.generated.js +0 -46
  27. package/dist/cdp.d.ts +0 -192
  28. package/dist/cdp.js +0 -2393
  29. package/dist/checkout-com.generated.d.ts +0 -4
  30. package/dist/checkout-com.generated.js +0 -183
  31. package/dist/client.d.ts +0 -849
  32. package/dist/client.js +0 -1754
  33. package/dist/cse-body.d.ts +0 -25
  34. package/dist/cse-body.js +0 -41
  35. package/dist/fiserv.d.ts +0 -65
  36. package/dist/fiserv.generated.d.ts +0 -73
  37. package/dist/fiserv.generated.js +0 -830
  38. package/dist/fiserv.js +0 -104
  39. package/dist/hosted-form.d.ts +0 -44
  40. package/dist/hosted-form.js +0 -78
  41. package/dist/index.d.ts +0 -18
  42. package/dist/index.js +0 -10
  43. package/dist/lifecycle.d.ts +0 -179
  44. package/dist/lifecycle.js +0 -395
  45. package/dist/mercado-checkout.d.ts +0 -20
  46. package/dist/mercado-checkout.generated.d.ts +0 -52
  47. package/dist/mercado-checkout.generated.js +0 -198
  48. package/dist/mercado-checkout.js +0 -108
  49. package/dist/merchant-handoff.d.ts +0 -54
  50. package/dist/merchant-handoff.js +0 -100
  51. package/dist/merchant-hosted.d.ts +0 -140
  52. package/dist/merchant-hosted.js +0 -170
  53. package/dist/merchant-total-watch.d.ts +0 -115
  54. package/dist/merchant-total-watch.js +0 -268
  55. package/dist/merchant-total.d.ts +0 -257
  56. package/dist/merchant-total.js +0 -383
  57. package/dist/owned-shop.generated.d.ts +0 -24
  58. package/dist/owned-shop.generated.js +0 -108
  59. package/dist/paysafe.generated.d.ts +0 -12
  60. package/dist/paysafe.generated.js +0 -87
  61. package/dist/playwright.d.ts +0 -3
  62. package/dist/playwright.js +0 -3
  63. package/dist/pre-claim.d.ts +0 -123
  64. package/dist/pre-claim.js +0 -386
  65. package/dist/preflight-capabilities.generated.d.ts +0 -1253
  66. package/dist/preflight-capabilities.generated.js +0 -1929
  67. package/dist/preflight-catalog.json +0 -4727
  68. package/dist/preflight-playwright.d.ts +0 -34
  69. package/dist/preflight-playwright.js +0 -355
  70. package/dist/preflight-schemas.json +0 -1122
  71. package/dist/preflight.d.ts +0 -1
  72. package/dist/preflight.generated.d.ts +0 -1965
  73. package/dist/preflight.generated.js +0 -570
  74. package/dist/preflight.js +0 -2
  75. package/dist/preparation.d.ts +0 -38
  76. package/dist/preparation.js +0 -191
  77. package/dist/prepared-processor.d.ts +0 -43
  78. package/dist/prepared-processor.js +0 -172
  79. package/dist/recurly.generated.d.ts +0 -1
  80. package/dist/recurly.generated.js +0 -87
  81. package/dist/registry.d.ts +0 -121
  82. package/dist/registry.js +0 -310
  83. package/dist/spreedly.generated.d.ts +0 -10
  84. package/dist/spreedly.generated.js +0 -332
  85. package/dist/stripe-checkout.d.ts +0 -81
  86. package/dist/stripe-checkout.generated.d.ts +0 -82
  87. package/dist/stripe-checkout.generated.js +0 -1093
  88. package/dist/stripe-checkout.js +0 -140
  89. package/dist/substitute.d.ts +0 -38
  90. package/dist/substitute.js +0 -23
  91. package/dist/substitutions.generated.d.ts +0 -11
  92. package/dist/substitutions.generated.js +0 -818
  93. package/examples/existing-browser.mjs +0 -63
  94. package/examples/preflight/classify-direct.mjs +0 -21
  95. package/examples/preflight/classify-kernel.mjs +0 -30
  96. package/examples/preflight/inspect-browser.mjs +0 -44
  97. package/examples/preflight/kernel-native/README.md +0 -112
  98. package/examples/preflight/kernel-native/documented-adapters.json +0 -113
  99. package/examples/preflight/kernel-native/inventory.json +0 -233
  100. package/examples/preflight/kernel-native/qualification.mjs +0 -182
  101. package/examples/preflight/kernel-profile.empty.json +0 -11
  102. package/examples/preflight/mollie-hosted.observations.json +0 -23
  103. package/examples/preflight/mollie-hosted.result.json +0 -103
  104. package/examples/preflight/stripe-script.direct.result.json +0 -92
  105. package/examples/preflight/stripe-script.observations.json +0 -16
  106. package/examples/preflight/stripe-script.result.json +0 -87
@@ -1,198 +0,0 @@
1
- // @ts-nocheck
2
- // Generated from @agent-cards/payment-core. Do not edit.
3
- // artifact-sha256: 0ea817a75d86052699eeaa7546950e6c046bb0d7a96e4a18dfcd3a0fdd2afc99
4
- // src/mercado-checkout.js
5
- var MERCADO_CHECKOUT_ORIGIN = "https://www.mercadopago.com.mx";
6
- var MERCADO_CONFIGURATION_URL = MERCADO_CHECKOUT_ORIGIN + "/checkout/v1/payment/api/bricks/card-form/tokenization";
7
- var MERCADO_CHECKOUT_PATTERN = MERCADO_CHECKOUT_ORIGIN + "/checkout/v1/payment/api/*";
8
- var reject = () => {
9
- throw new Error("mercado_checkout_context_invalid");
10
- };
11
- var object = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
12
- var only = (v, keys) => object(v) && Object.keys(v).every((k) => keys.includes(k));
13
- var exact = (v, keys) => only(v, keys) && keys.every((k) => Object.hasOwn(v, k));
14
- var text = (v, max = 200) => typeof v === "string" && v.length > 0 && v.length <= max && !/[\u0000-\u001f\u007f]/.test(v);
15
- var id = (v) => typeof v === "string" && /^[A-Za-z0-9_-]{1,128}$/.test(v);
16
- var numberId = (v) => typeof v === "string" && /^\d{1,20}$/.test(v);
17
- var label = (v) => text(v, 120) && /\p{L}/u.test(v) && !/[<>]|\d(?:[ -]*\d){5}|https?:|javascript:|data:/i.test(v);
18
- var digest = (v) => typeof v === "string" && /^[a-f0-9]{64}$/.test(v);
19
- var METHODS = ["visa", "master", "amex"];
20
- var TYPES = ["credit_card", "debit_card", "prepaid_card"];
21
- function checkedUrl(raw) {
22
- let url;
23
- try {
24
- url = new URL(raw);
25
- }
26
- catch {
27
- reject();
28
- }
29
- if (!text(raw, 4096) || url.href !== raw || url.origin !== MERCADO_CHECKOUT_ORIGIN || url.username || url.password || url.hash)
30
- reject();
31
- return url;
32
- }
33
- function mercadoCheckoutDocument(raw) {
34
- const url = checkedUrl(raw);
35
- const match = /^\/checkout\/v1\/payment\/redirect\/([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})\/card-form\/$/.exec(url.pathname);
36
- const keys = [...url.searchParams.keys()];
37
- if (!match || keys.length !== 3 || new Set(keys).size !== 3 || keys.some((k) => !["preference-id", "router-request-id", "p"].includes(k)) || !id(url.searchParams.get("preference-id")) || !id(url.searchParams.get("router-request-id")) || !text(url.searchParams.get("p"), 2048))
38
- reject();
39
- return { flowId: match[1], preferenceId: url.searchParams.get("preference-id"), query: url.search.slice(1) };
40
- }
41
- function initialization(value) {
42
- const keys = [
43
- "callerId",
44
- "collectorId",
45
- "allowThirdPartyCard",
46
- "clientId",
47
- "flowId",
48
- "checkoutId",
49
- "scope",
50
- "excludedPaymentTypesAndIds",
51
- "locale",
52
- "siteId",
53
- "serviceRoutePrefix",
54
- "productId",
55
- "marketplace",
56
- "platform",
57
- "cardDetails"
58
- ];
59
- if (!exact(value, keys) || !numberId(value.callerId) || !numberId(value.collectorId) || !numberId(value.clientId) || value.allowThirdPartyCard !== true || value.flowId !== "checkout-pro-payment" || value.checkoutId !== "cow" || value.scope !== "prod" || value.locale !== "es-MX" || value.siteId !== "MLM" || value.serviceRoutePrefix !== "/checkout/v1/payment/api" || !id(value.productId) || value.marketplace !== "NONE" || value.platform !== "MP" || !Array.isArray(value.excludedPaymentTypesAndIds) || value.excludedPaymentTypesAndIds.length !== 0 || !exact(value.cardDetails, ["fieldsSetting", "identificationTypes", "additionalSteps"]) || !Array.isArray(value.cardDetails.identificationTypes) || value.cardDetails.identificationTypes.length !== 0 || JSON.stringify(value.cardDetails.additionalSteps) !== '["name"]')
60
- reject();
61
- const fields = value.cardDetails.fieldsSetting;
62
- if (!Array.isArray(fields) || fields.length !== 5 || new Set(fields.map((f) => f?.name)).size !== 5)
63
- reject();
64
- for (const field of fields) {
65
- if (!only(field, ["name", "type", "title", "placeholder", "length", "validationMessages", "mask", "hintMessage", "validationPattern", "autocomplete", "tooltipMessage"]) || !["card_number", "name", "expiration", "security_code", "identification_types"].includes(field.name) || field.type !== (field.name === "name" ? "text" : "number") || !text(field.title) || field.placeholder !== void 0 && !text(field.placeholder) || ["hintMessage", "validationPattern", "tooltipMessage"].some((k) => field[k] !== void 0 && !text(field[k], 1024)) || field.autocomplete !== void 0 && typeof field.autocomplete !== "boolean" || field.length !== void 0 && (!Number.isInteger(field.length) || field.length < 1 || field.length > 40) || field.mask !== void 0 && (!text(field.mask, 30) || !/^[ $/]+$/.test(field.mask)) || !only(field.validationMessages, ["emptyField", "incompleteField", "invalidField"]) || Object.values(field.validationMessages).some((v) => !text(v)))
66
- reject();
67
- }
68
- if (JSON.stringify(value).length > 12e3)
69
- reject();
70
- return value;
71
- }
72
- function parseMercadoCheckoutContext(value) {
73
- if (!exact(value, ["version", "documentUrl", "initializationData"]) || value.version !== 1)
74
- reject();
75
- mercadoCheckoutDocument(value.documentUrl);
76
- initialization(value.initializationData);
77
- return JSON.parse(JSON.stringify(value));
78
- }
79
- function captureMercadoCheckoutContext(url, method, body, documentUrl) {
80
- if (url !== MERCADO_CONFIGURATION_URL || method !== "POST" || typeof body !== "string" || body.length > 16e3)
81
- reject();
82
- let parsed;
83
- try {
84
- parsed = JSON.parse(body);
85
- }
86
- catch {
87
- reject();
88
- }
89
- if (!exact(parsed, ["cardBin", "initializationData"]) || typeof parsed.cardBin !== "string" || !/^\d{8}$/.test(parsed.cardBin))
90
- reject();
91
- return parseMercadoCheckoutContext({ version: 1, documentUrl, initializationData: parsed.initializationData });
92
- }
93
- function isMercadoTokenRequest(url, method) {
94
- try {
95
- const value = new URL(url), names = [...value.searchParams.keys()];
96
- return method === "POST" && value.href === url && value.origin === "https://api.mercadopago.com" && value.pathname === "/v1/card_tokens" && !value.username && !value.password && !value.hash && new Set(names).size === names.length && names.every((n) => ["public_key", "locale", "js_version", "referer"].includes(n)) && id(value.searchParams.get("public_key"));
97
- }
98
- catch {
99
- return false;
100
- }
101
- }
102
- async function mercadoDigest(value) {
103
- const bytes = new TextEncoder().encode(value);
104
- return Array.from(new Uint8Array(await globalThis.crypto.subtle.digest("SHA-256", bytes)), (byte) => byte.toString(16).padStart(2, "0")).join("");
105
- }
106
- function canonical(value) {
107
- return Array.isArray(value) ? value.map(canonical) : object(value) ? Object.fromEntries(Object.keys(value).sort().map((key) => [key, canonical(value[key])])) : value;
108
- }
109
- async function mercadoContextDigest(context, tokenUrl) {
110
- if (!isMercadoTokenRequest(tokenUrl, "POST"))
111
- reject();
112
- return mercadoDigest(JSON.stringify(canonical({ context: parseMercadoCheckoutContext(context), tokenUrl })));
113
- }
114
- function prepareMercadoConfiguration(context, card) {
115
- const parsed = parseMercadoCheckoutContext(context);
116
- const number = card?.number;
117
- if (typeof number !== "string" || !/^\d{12,19}$/.test(number))
118
- reject();
119
- return { url: MERCADO_CONFIGURATION_URL, body: JSON.stringify({ cardBin: number.slice(0, 8), initializationData: parsed.initializationData }) };
120
- }
121
- function parseMercadoConfiguration(value) {
122
- const method = value?.paymentMethod, issuers = value?.issuersSettings;
123
- if (!object(value) || !exact(method, ["paymentMethodId", "paymentTypeId", "name"]) || !METHODS.includes(method.paymentMethodId) || !TYPES.includes(method.paymentTypeId) || !label(method.name) || !Array.isArray(issuers) || issuers.length !== 1 || !object(issuers[0]) || !label(issuers[0].name))
124
- reject();
125
- const issuerId = String(issuers[0].id);
126
- if (!/^\d{1,11}$/.test(issuerId) || typeof issuers[0].id !== "string" && !Number.isSafeInteger(issuers[0].id))
127
- reject();
128
- const cvc = Array.isArray(value.fieldsSetting) ? value.fieldsSetting.filter((f) => f?.name === "security_code") : [];
129
- const amex = method.paymentMethodId === "amex";
130
- if (cvc.length !== 1 || cvc[0].type !== "number" || cvc[0].length !== (amex ? 4 : 3) || value.securityCodeSettings?.mode !== "mandatory" || value.securityCodeSettings?.location !== (amex ? "front" : "back"))
131
- reject();
132
- return {
133
- paymentMethodId: method.paymentMethodId,
134
- paymentTypeId: method.paymentTypeId,
135
- paymentMethodName: method.name,
136
- issuerId,
137
- issuerName: issuers[0].name
138
- };
139
- }
140
- function tokenIdentity(body) {
141
- let value;
142
- try {
143
- value = JSON.parse(body);
144
- }
145
- catch {
146
- reject();
147
- }
148
- if (!object(value) || value.live_mode === false || typeof value.id !== "string" || !/^[A-Za-z0-9_-]{8,256}$/.test(value.id))
149
- reject();
150
- return value.id;
151
- }
152
- async function createMercadoProcessorContext(configuration, context, tokenUrl, tokenBody) {
153
- return {
154
- version: 1,
155
- psp: "mercado_pago",
156
- source: "checkout_pro_bin8",
157
- contextDigest: await mercadoContextDigest(context, tokenUrl),
158
- tokenDigest: await mercadoDigest(tokenIdentity(tokenBody)),
159
- ...parseMercadoConfiguration(configuration)
160
- };
161
- }
162
- async function validateMercadoProcessorContext(value, context, tokenUrl, tokenBody) {
163
- if (!exact(value, ["version", "psp", "source", "contextDigest", "tokenDigest", "paymentMethodId", "paymentTypeId", "paymentMethodName", "issuerId", "issuerName"]) || value.version !== 1 || value.psp !== "mercado_pago" || value.source !== "checkout_pro_bin8" || !digest(value.contextDigest) || !digest(value.tokenDigest) || !METHODS.includes(value.paymentMethodId) || !TYPES.includes(value.paymentTypeId) || !label(value.paymentMethodName) || !numberId(value.issuerId) || value.issuerId.length > 11 || !label(value.issuerName) || value.contextDigest !== await mercadoContextDigest(context, tokenUrl) || value.tokenDigest !== await mercadoDigest(tokenIdentity(tokenBody)))
164
- reject();
165
- return { ...value };
166
- }
167
- async function createMercadoAssociationGate({ context, tokenUrl, tokenBody, processorContext }) {
168
- const checked = parseMercadoCheckoutContext(context), metadata = await validateMercadoProcessorContext(processorContext, checked, tokenUrl, tokenBody);
169
- const document = mercadoCheckoutDocument(checked.documentUrl), token = tokenIdentity(tokenBody);
170
- let claimed = false;
171
- return { take({ url, method, body, documentUrl }) {
172
- if (claimed)
173
- reject();
174
- const target = checkedUrl(url);
175
- if (method !== "PUT" || documentUrl !== checked.documentUrl || target.pathname !== "/checkout/v1/payment/api/flow/" + document.flowId || target.search || typeof body !== "string" || body.length > 64e3)
176
- reject();
177
- let parsed;
178
- try {
179
- parsed = JSON.parse(body);
180
- }
181
- catch {
182
- reject();
183
- }
184
- if (!only(parsed, ["id", "values", "type", "featureFlags", "version", "prev_step", "urlParams"]) || parsed.id !== "next_step" || parsed.type !== "redirect" || parsed.version !== "checkout" || parsed.prev_step !== "card_form" || parsed.urlParams !== document.query || !only(parsed.values, ["payment_method", "card_token", "card_ui_settings", "captchaToken"]) || parsed.values.card_token !== token || !object(parsed.values.card_ui_settings) || !only(parsed.values.payment_method, ["id", "type", "name", "issuer"]) || parsed.values.payment_method.id !== metadata.paymentMethodId || parsed.values.payment_method.type !== metadata.paymentTypeId)
185
- reject();
186
- claimed = true;
187
- parsed.values.payment_method = {
188
- id: metadata.paymentMethodId,
189
- type: metadata.paymentTypeId,
190
- name: metadata.paymentMethodName,
191
- issuer: { id: Number(metadata.issuerId), name: metadata.issuerName }
192
- };
193
- return JSON.stringify(parsed);
194
- }, get claimed() {
195
- return claimed;
196
- } };
197
- }
198
- export { MERCADO_CHECKOUT_ORIGIN, MERCADO_CHECKOUT_PATTERN, MERCADO_CONFIGURATION_URL, captureMercadoCheckoutContext, createMercadoAssociationGate, createMercadoProcessorContext, isMercadoTokenRequest, mercadoCheckoutDocument, mercadoContextDigest, mercadoDigest, parseMercadoCheckoutContext, parseMercadoConfiguration, prepareMercadoConfiguration, validateMercadoProcessorContext };
@@ -1,108 +0,0 @@
1
- import { captureMercadoCheckoutContext, createMercadoAssociationGate, isMercadoTokenRequest, MERCADO_CONFIGURATION_URL, MERCADO_CHECKOUT_ORIGIN, parseMercadoCheckoutContext } from './mercado-checkout.generated.js';
2
- /** Capture only the native Checkout Pro configuration. A late configuration,
3
- * navigation or repeated token cannot replace the context of an issued token.
4
- * Final payment requests retain the attachment's existing payment guards.
5
- */
6
- export class MercadoCheckoutGate {
7
- context = null;
8
- started = false;
9
- stopped = false;
10
- sequence = 0;
11
- associatedFlow = null;
12
- association = null;
13
- matches(url) {
14
- try {
15
- const parsed = new URL(url);
16
- return parsed.origin === MERCADO_CHECKOUT_ORIGIN
17
- && (parsed.pathname === new URL(MERCADO_CONFIGURATION_URL).pathname || parsed.pathname.startsWith('/checkout/v1/payment/api/flow/'));
18
- }
19
- catch {
20
- return false;
21
- }
22
- }
23
- requiresDocument(url, method) {
24
- try {
25
- const parsed = new URL(url);
26
- return method.toUpperCase() === 'POST'
27
- && parsed.origin === 'https://api.mercadopago.com' && /^\/v1\/card_tokens$/i.test(parsed.pathname);
28
- }
29
- catch {
30
- return false;
31
- }
32
- }
33
- invalidate() {
34
- if (!this.context && !this.started && this.sequence === 0)
35
- return;
36
- this.stopped = true;
37
- this.context = null;
38
- this.association = null;
39
- this.sequence++;
40
- }
41
- async configuration(url, method, body, readDocument) {
42
- if (url !== MERCADO_CONFIGURATION_URL || method !== 'POST')
43
- return false;
44
- if (this.started || this.stopped)
45
- throw new Error('mercado_checkout_configuration_changed');
46
- const sequence = ++this.sequence;
47
- this.context = null;
48
- const documentUrl = await readDocument();
49
- // A newer native BIN lookup owns the context; the older harmless lookup
50
- // still continues, but cannot erase or invalidate that newer capture.
51
- if (sequence !== this.sequence && !this.stopped)
52
- return true;
53
- const context = captureMercadoCheckoutContext(url, method, body, documentUrl);
54
- if (sequence !== this.sequence || this.started || this.stopped)
55
- throw new Error('mercado_checkout_configuration_changed');
56
- this.context = context;
57
- return true;
58
- }
59
- claimToken(url, method, documentUrl) {
60
- if (!this.requiresDocument(url, method))
61
- return undefined;
62
- // Other Mercado products remain on their existing tokenization path.
63
- if (!documentUrl.startsWith(MERCADO_CHECKOUT_ORIGIN + '/checkout/'))
64
- return undefined;
65
- if (!isMercadoTokenRequest(url, method) || this.started || this.stopped || !this.context || this.context.documentUrl !== documentUrl)
66
- throw new Error('mercado_checkout_configuration_unavailable');
67
- this.started = true;
68
- return parseMercadoCheckoutContext(this.context);
69
- }
70
- async arm(replay, tokenUrl) {
71
- if (!this.started)
72
- return;
73
- if (this.stopped || !this.context || replay.mode !== 'token' || replay.status !== 201 || !replay.processorContext)
74
- throw new Error('mercado_checkout_metadata_unavailable');
75
- const context = this.context;
76
- const association = await createMercadoAssociationGate({ context, tokenUrl, tokenBody: replay.body, processorContext: replay.processorContext });
77
- if (this.stopped || this.context !== context)
78
- throw new Error('mercado_checkout_context_changed');
79
- this.association = association;
80
- }
81
- associationBody(url, method, body, documentUrl) {
82
- if (['GET', 'HEAD', 'OPTIONS'].includes(method) || !this.matches(url) || url === MERCADO_CONFIGURATION_URL)
83
- return undefined;
84
- let parsed;
85
- try {
86
- parsed = JSON.parse(body);
87
- }
88
- catch {
89
- if (this.started)
90
- throw new Error('mercado_checkout_association_invalid');
91
- return undefined;
92
- }
93
- // The observed Pay request keeps the existing payment guards, including
94
- // after the native document navigates to review. Every card association
95
- // must use the checked shape; changing prev_step cannot bypass correction.
96
- const cardAssociation = parsed?.id === 'next_step' || parsed?.prev_step === 'card_form'
97
- || (parsed?.values && ('card_token' in parsed.values || 'payment_method' in parsed.values));
98
- if (!cardAssociation && parsed?.id === 'pay' && parsed?.prev_step === 'review' && this.associatedFlow === url)
99
- return undefined;
100
- if (!cardAssociation && !this.started)
101
- return undefined;
102
- if (!this.started || this.stopped || !this.association)
103
- throw new Error('mercado_checkout_association_unavailable');
104
- const corrected = this.association.take({ url, method, body, documentUrl });
105
- this.associatedFlow = url;
106
- return corrected;
107
- }
108
- }
@@ -1,54 +0,0 @@
1
- import type { CheckoutLifecycle } from './lifecycle.js';
2
- /** onEvent is ordinary integrator telemetry; the shape matches AttachOptions.onEvent. */
3
- type HandoffEvent = {
4
- type: string;
5
- detail?: unknown;
6
- };
7
- /**
8
- * A merchant-hosted card request after hand-off, shared by the CDP and
9
- * Playwright adapters so both read it the same way.
10
- *
11
- * The browser continued the merchant's own request with the Vault's ciphertext in
12
- * it; the merchant's server now charges the card through Adyen and answers its own
13
- * page. Nothing Agentcard holds says whether it did. Two things after hand-off are
14
- * therefore an unknown outcome, never a failure to retry:
15
- * - the continued request answers 5xx or fails in the network: the merchant may
16
- * have charged the card, and its page may never learn that it did;
17
- * - the page sends the card request again before an answer arrived (Dick's
18
- * retries on a network error or a 500, ATG on anything not OK): its retry
19
- * carries the agent's dummy card, and the approval is spent.
20
- * Either reports `payment_outcome_unknown` once and holds the checkout until the
21
- * application reconciles the merchant order. Every card request to the same
22
- * profile after hand-off is aborted, answered or not: a prepared approval is
23
- * single use.
24
- *
25
- * Which of the two it reports follows the order the page saw them in. A page that
26
- * retries because the merchant answered 5xx read that answer first, but an
27
- * adapter can read the retry first (Chrome pauses a request in the browser
28
- * process, ahead of the renderer's report of the answer), so retried() judges
29
- * a retry once the adapter has read what the page reported before sending it.
30
- */
31
- export declare class MerchantHandoffWatch {
32
- private readonly lifecycle;
33
- private readonly onEvent?;
34
- private handoff;
35
- private answered;
36
- private reported;
37
- constructor(lifecycle: CheckoutLifecycle, onEvent?: ((event: HandoffEvent) => void) | undefined);
38
- /** Record a hand-off before its continue is sent, so an answer that races the command is still read. */
39
- begin(profile: string, authorizationId: string, url: string): void;
40
- /** The continued request's response arrived with this status. */
41
- responded(status: number): void;
42
- /** The continued request failed before any response arrived. */
43
- failed(): void;
44
- /**
45
- * The page sent a card request to a profile. True when it is the profile a
46
- * hand-off already went to: the caller aborts it at once. A retry sent before
47
- * any answer reached the page also reports the unknown outcome. When the
48
- * adapter must first read more of what the page reported before it sent this
49
- * retry, `inPageOrder` keeps `judge`, calls it once it has, and returns true.
50
- */
51
- retried(profile: string, inPageOrder?: (judge: () => void) => boolean): boolean;
52
- private unknown;
53
- }
54
- export {};
@@ -1,100 +0,0 @@
1
- import { PaymentOutcomeUnknownError } from './client.js';
2
- /**
3
- * A merchant-hosted card request after hand-off, shared by the CDP and
4
- * Playwright adapters so both read it the same way.
5
- *
6
- * The browser continued the merchant's own request with the Vault's ciphertext in
7
- * it; the merchant's server now charges the card through Adyen and answers its own
8
- * page. Nothing Agentcard holds says whether it did. Two things after hand-off are
9
- * therefore an unknown outcome, never a failure to retry:
10
- * - the continued request answers 5xx or fails in the network: the merchant may
11
- * have charged the card, and its page may never learn that it did;
12
- * - the page sends the card request again before an answer arrived (Dick's
13
- * retries on a network error or a 500, ATG on anything not OK): its retry
14
- * carries the agent's dummy card, and the approval is spent.
15
- * Either reports `payment_outcome_unknown` once and holds the checkout until the
16
- * application reconciles the merchant order. Every card request to the same
17
- * profile after hand-off is aborted, answered or not: a prepared approval is
18
- * single use.
19
- *
20
- * Which of the two it reports follows the order the page saw them in. A page that
21
- * retries because the merchant answered 5xx read that answer first, but an
22
- * adapter can read the retry first (Chrome pauses a request in the browser
23
- * process, ahead of the renderer's report of the answer), so retried() judges
24
- * a retry once the adapter has read what the page reported before sending it.
25
- */
26
- export class MerchantHandoffWatch {
27
- lifecycle;
28
- onEvent;
29
- handoff = null;
30
- answered = false;
31
- reported = false;
32
- constructor(lifecycle, onEvent) {
33
- this.lifecycle = lifecycle;
34
- this.onEvent = onEvent;
35
- }
36
- /** Record a hand-off before its continue is sent, so an answer that races the command is still read. */
37
- begin(profile, authorizationId, url) {
38
- this.handoff = { profile, authorizationId, url };
39
- this.answered = false;
40
- this.reported = false;
41
- }
42
- /** The continued request's response arrived with this status. */
43
- responded(status) {
44
- if (!this.handoff || this.answered)
45
- return;
46
- this.answered = true;
47
- if (Number.isInteger(status) && status >= 500)
48
- this.unknown('merchant_server_error', { status });
49
- }
50
- /** The continued request failed before any response arrived. */
51
- failed() {
52
- if (!this.handoff || this.answered)
53
- return;
54
- this.answered = true;
55
- this.unknown('merchant_request_failed');
56
- }
57
- /**
58
- * The page sent a card request to a profile. True when it is the profile a
59
- * hand-off already went to: the caller aborts it at once. A retry sent before
60
- * any answer reached the page also reports the unknown outcome. When the
61
- * adapter must first read more of what the page reported before it sent this
62
- * retry, `inPageOrder` keeps `judge`, calls it once it has, and returns true.
63
- */
64
- retried(profile, inPageOrder) {
65
- const handoff = this.handoff;
66
- if (!handoff || handoff.profile !== profile)
67
- return false;
68
- let judged = false;
69
- const judge = () => {
70
- if (judged)
71
- return;
72
- judged = true;
73
- if (this.handoff === handoff && !this.answered)
74
- this.unknown('merchant_retried_after_handoff');
75
- this.onEvent?.({ type: 'blocked', detail: 'merchant_retried_after_handoff' });
76
- };
77
- let waiting = false;
78
- // An order the adapter cannot establish is judged on what it has read.
79
- try {
80
- waiting = !this.answered && inPageOrder?.(judge) === true;
81
- }
82
- catch {
83
- waiting = false;
84
- }
85
- if (!waiting)
86
- judge();
87
- return true;
88
- }
89
- unknown(reason, extra = {}) {
90
- if (!this.handoff || this.reported)
91
- return;
92
- // A result the application already confirmed with the merchant stands.
93
- if (this.lifecycle.getState().status === 'completed')
94
- return;
95
- this.reported = true;
96
- const { authorizationId, profile, url } = this.handoff;
97
- this.lifecycle.failed(new PaymentOutcomeUnknownError(authorizationId, reason), true);
98
- this.onEvent?.({ type: 'payment_outcome_unknown', detail: { authorizationId, reason, profile, url, ...extra } });
99
- }
100
- }
@@ -1,140 +0,0 @@
1
- /** 'observe': paused, reported and aborted, never paid. 'enabled': a prepared checkout may pay it. */
2
- export type MerchantProfileStatus = 'observe' | 'enabled';
3
- /**
4
- * A test-mode checkout against your own Adyen TEST account: your own server's
5
- * card endpoint (an exact HTTPS URL), taking a card request shaped like a reviewed
6
- * profile's, encrypted under your own Adyen TEST client key (test_...). The API
7
- * accepts one only from a test-mode client of an org Agentcard turned declarations
8
- * on for, reads the key's public key from Adyen's TEST platform itself, and the
9
- * Vault encrypts only Adyen's documented test cards under it.
10
- */
11
- export interface SandboxMerchantDeclaration {
12
- /** The reviewed profile whose card request your endpoint takes (its body rules, holder and fields). */
13
- profile: string;
14
- /** Your endpoint: HTTPS, written exactly as the browser sends it, no port, credentials or fragment. */
15
- endpoint: string;
16
- /** Your Adyen TEST client key (test_ followed by 32 letters and digits). */
17
- clientKey: string;
18
- }
19
- /** A reviewed merchant profile this client arms: its id, the merchant it names, and its effective status. */
20
- export interface MerchantProfile {
21
- readonly id: string;
22
- readonly merchant: string;
23
- readonly status: MerchantProfileStatus;
24
- /** Present when this client armed the profile's shape at its own declared test endpoint (declareSandboxMerchant). */
25
- readonly sandboxDeclaration?: Readonly<Pick<SandboxMerchantDeclaration, 'endpoint' | 'clientKey'>>;
26
- }
27
- /** A profile's verdict on a paused request; see classifyMerchantRequest. */
28
- export type MerchantRequestVerdict = {
29
- verdict: 'pause';
30
- } | {
31
- verdict: 'abort';
32
- reason: string;
33
- } | {
34
- verdict: 'pass';
35
- };
36
- /** One step of a JSON path: an object key, or an index into an array. */
37
- export type JsonPathStep = string | number;
38
- /** A card fact the API asks to write beside the ciphertext (reserved: no profile declares one yet). */
39
- export interface MerchantHostedFact {
40
- path: JsonPathStep[];
41
- value: string;
42
- }
43
- /**
44
- * Where a merchant-hosted approval's ciphertext goes: the profile's holder path
45
- * (`[]` is the body root), the merchant's names for Adyen's four fields, and the
46
- * keys at the holder to drop with the swap (adyen-web's `brand`, derived from the
47
- * agent's dummy digits). payment-core's substituteMerchantHosted refuses anything
48
- * but exactly the profile's own values.
49
- */
50
- export interface MerchantHostedSubstitutions {
51
- encoding: 'json';
52
- kind: 'merchant_hosted';
53
- profile: string;
54
- path: JsonPathStep[];
55
- fields: Record<string, string>;
56
- remove: string[];
57
- /** Card facts to write after the swap. No profile declares any yet, and the substitution refuses them. */
58
- set?: MerchantHostedFact[];
59
- }
60
- /**
61
- * The profile's verdict on a paused request: pause (its reviewed card request),
62
- * abort (encrypted card data it cannot finish, with the reason) or pass (no
63
- * encrypted card data, or not its endpoint or a sibling of it). Reads only;
64
- * throws for a profile id this build did not review.
65
- */
66
- export declare const classifyMerchantRequest: (profileId: string, url: string, method: string, body: string | null | undefined) => MerchantRequestVerdict;
67
- /** The endpoint origin, the path TEMPLATE and the profile's own query: what an event may name. */
68
- export declare const merchantProfileTemplatedUrl: (profileId: string, url: string) => string;
69
- /** SHA-256 of a JSON body's sorted key paths, no value in it; null for a body that is not JSON. */
70
- export declare const merchantBodyKeyPathSha256: (body: string) => string | null;
71
- /** 'sandbox' for a profile on Adyen's TEST platform, 'production' for every live environment. */
72
- export declare const merchantProfileEnvironment: (profileId: string) => 'production' | 'sandbox';
73
- /** classifyMerchantRequest for a sandbox declaration: the profile's body rules at the declared endpoint instead of the profile's. */
74
- export declare const classifyDeclaredMerchantRequest: (profileId: string, endpoint: string, url: string, method: string, body: string | null | undefined) => MerchantRequestVerdict;
75
- /**
76
- * The profiles this client arms: every profile this build reviewed, once each, in
77
- * this build's order. A served entry is `{ merchant_profile: <the profile's wire
78
- * projection> }`, and the first one that names a profile with exactly this build's
79
- * rules (endpoint, body rules, holder, fields, key: everything but `status`) and a
80
- * status this build knows decides it: 'enabled' only when both that entry and this
81
- * build say so. Every other profile stays in 'observe': one the API did not serve (no
82
- * sync yet, a failed sync, an API that predates profiles) and one the API reviewed
83
- * again after this build was cut, which this build cannot pay. In 'observe' its card
84
- * request is still paused and aborted, so the agent's dummy card never reaches a
85
- * reviewed merchant, whatever the API answered.
86
- */
87
- export declare function armServedProfiles(entries?: readonly unknown[]): MerchantProfile[];
88
- /**
89
- * Arms a sandbox declaration: the reviewed profile's card request at your own
90
- * endpoint, under your own Adyen TEST key. Throws a TypeError for a profile this
91
- * build did not review, an endpoint the API would refuse, or a key that is not a
92
- * test_ key. The endpoint rule is the API's own (payment-core sandboxDeclarationRefusal):
93
- * an HTTPS URL in the exact form the browser writes it (no port, credentials or
94
- * fragment), on a public domain name outside Adyen's domains, Agentcard's and every
95
- * reviewed merchant's domain (declaredEndpointRefusal), and on no host this build's
96
- * processor registry names. The armed entry names its host as the merchant, and is
97
- * 'enabled' whatever the reviewed profile's status: it never pays the reviewed
98
- * merchant, the API refuses it from a live client and from an org it has not turned
99
- * declarations on for, and the Vault encrypts only Adyen's documented test cards
100
- * under a test_ key.
101
- */
102
- export declare function declareSandboxMerchant(input: SandboxMerchantDeclaration): MerchantProfile;
103
- /** The armed profile whose endpoint, or a sibling of it (same origin and path shape), a URL is; null for any other URL. */
104
- export declare function merchantProfileFor(profiles: readonly MerchantProfile[], url: string): MerchantProfile | null;
105
- /** The Fetch.enable globs that pause every armed profile's endpoint and its siblings, a declared endpoint included. */
106
- export declare function merchantProfileUrlPatterns(profiles: readonly MerchantProfile[]): string[];
107
- /** classifyMerchantRequest for an armed profile: at its declared endpoint when it has one. */
108
- export declare function classifyProfileRequest(profile: MerchantProfile, url: string, method: string, body: string | null | undefined): MerchantRequestVerdict;
109
- /** merchantProfileTemplatedUrl for an armed profile: a declared endpoint's origin and path, never its query. */
110
- export declare function profileTemplatedUrl(profile: MerchantProfile, url: string): string;
111
- /**
112
- * The Fetch.enable globs for every profile this build reviewed. Every one of them is
113
- * armed from the start (armServedProfiles), so attachToCdp arms all of them at attach
114
- * and a syncRegistry() before or after it changes only a profile's status: its card
115
- * request is paused and judged under CDP exactly as attachToPlaywright's per-request
116
- * route judges it.
117
- */
118
- export declare function reviewedMerchantProfileUrlPatterns(): string[];
119
- /**
120
- * The continuation of a merchant-hosted approval: the live paused body with the
121
- * Vault's ciphertext in place of the dummy fields. The API never sees the body the
122
- * browser continues, so the live body must first hash to the one the API checked
123
- * when the authorization was created (`bodySha256`); a page that rewrote its body
124
- * while the cardholder decided is refused rather than paid. payment-core's
125
- * substituteMerchantHosted then reads the profile's body rules again on the live
126
- * body, writes only the profile's four fields, and refuses a profile that is not
127
- * enabled, unless this client armed the endpoint from its own sandbox declaration
128
- * (the replay carries `sandboxDeclaration`), where every body rule still applies.
129
- * Throws SubstitutionError; nothing leaves the browser when it does.
130
- */
131
- export declare function substituteMerchantHostedBody(body: string, replay: {
132
- substitutions: MerchantHostedSubstitutions;
133
- bodySha256: string;
134
- sandboxDeclaration?: MerchantProfile['sandboxDeclaration'];
135
- }): string;
136
- /** The URL an event names for a merchant-hosted replay's request: its declared endpoint's origin and path, or the profile's template. */
137
- export declare function replayTemplatedUrl(replay: {
138
- profile: string;
139
- sandboxDeclaration?: MerchantProfile['sandboxDeclaration'];
140
- }, url: string): string;