@asteby/storefront-react 0.16.1 → 0.18.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.
- package/README.md +58 -1
- package/dist/checkout.cjs +108 -20
- package/dist/checkout.cjs.map +1 -1
- package/dist/checkout.d.cts +15 -1
- package/dist/checkout.d.ts +15 -1
- package/dist/checkout.js +107 -21
- package/dist/checkout.js.map +1 -1
- package/dist/{chunk-ISEOCKIR.js → chunk-MNLROALF.js} +96 -8
- package/dist/chunk-MNLROALF.js.map +1 -0
- package/dist/{choices-DEPE9KRq.d.cts → csp-DZPuExzu.d.cts} +93 -55
- package/dist/{choices-DEPE9KRq.d.ts → csp-DZPuExzu.d.ts} +93 -55
- package/dist/payments-server.cjs +159 -12
- package/dist/payments-server.cjs.map +1 -1
- package/dist/payments-server.d.cts +23 -3
- package/dist/payments-server.d.ts +23 -3
- package/dist/payments-server.js +70 -13
- package/dist/payments-server.js.map +1 -1
- package/dist/payments.cjs +784 -160
- package/dist/payments.cjs.map +1 -1
- package/dist/payments.css +84 -0
- package/dist/payments.d.cts +227 -8
- package/dist/payments.d.ts +227 -8
- package/dist/payments.js +628 -102
- package/dist/payments.js.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-ISEOCKIR.js.map +0 -1
package/dist/payments-server.cjs
CHANGED
|
@@ -4,6 +4,74 @@ var storefront = require('@asteby/storefront');
|
|
|
4
4
|
|
|
5
5
|
// src/payments/server.ts
|
|
6
6
|
|
|
7
|
+
// src/payments/recovery-messages.ts
|
|
8
|
+
var ES = {
|
|
9
|
+
"error.transient": "Estamos verificando tu pago. Si el cargo se hizo, lo veremos aqu\xED; no te cobraremos dos veces.",
|
|
10
|
+
"error.in_progress": "Ya hay un pago en proceso para este pedido. Estamos verific\xE1ndolo; no vuelvas a pagar.",
|
|
11
|
+
"error.rate_limited": "Hiciste varios intentos seguidos. Espera unos minutos e int\xE9ntalo de nuevo.",
|
|
12
|
+
"error.merchant_config": "Por ahora no podemos procesar pagos con tarjeta. No es un problema con tu tarjeta: puedes pagar de otra forma.",
|
|
13
|
+
"error.provider_declined": "No pudimos procesar tu pago con esa tarjeta. Revisa los datos o prueba con otro m\xE9todo; no se hizo ning\xFAn cobro.",
|
|
14
|
+
"error.stale_checkout": "Este pedido ya qued\xF3 registrado y no se pudo reabrir el pago. Actualiza para ver c\xF3mo va tu pedido.",
|
|
15
|
+
"error.expired": "Tu carrito venci\xF3. Vuelve a armarlo para pagar.",
|
|
16
|
+
"error.price_mismatch": "El total cambi\xF3. Revisa el nuevo total y vuelve a pagar.",
|
|
17
|
+
"error.store_closed": "Esta tienda a\xFAn no est\xE1 abierta para compras. Vuelve pronto.",
|
|
18
|
+
"error.validation": "Completa los campos marcados.",
|
|
19
|
+
"error.other": "No pudimos procesar tu pago. Intenta de nuevo.",
|
|
20
|
+
"notice.confirming.title": "Estamos confirmando tu pago\u2026",
|
|
21
|
+
"notice.confirming.body": "No cierres esta p\xE1gina ni vuelvas a pagar. Si el cargo ya se hizo, lo ver\xE1s reflejado aqu\xED.",
|
|
22
|
+
"notice.form_failed.title": "No pudimos cargar el formulario de tarjeta",
|
|
23
|
+
"notice.form_failed.body": "Suele resolverse al intentar de nuevo. Tambi\xE9n puedes pagar de otra forma.",
|
|
24
|
+
"notice.rejected.title": "El cargo no se complet\xF3",
|
|
25
|
+
"notice.rejected.body": "No se hizo ning\xFAn cobro. Puedes intentar con otra tarjeta o elegir otra forma de pago.",
|
|
26
|
+
"notice.provider_declined.title": "No pudimos procesar tu pago con esa tarjeta",
|
|
27
|
+
"notice.provider_declined.body": "No se hizo ning\xFAn cobro. Revisa los datos o prueba con otra tarjeta u otro m\xE9todo de pago.",
|
|
28
|
+
"notice.merchant_config.title": "Por ahora no podemos cobrar con tarjeta",
|
|
29
|
+
"notice.merchant_config.body": "No es un problema con tu tarjeta: es un tema de nuestro lado. Puedes pagar de otra forma.",
|
|
30
|
+
"notice.stale_checkout.title": "Tu pedido ya qued\xF3 registrado",
|
|
31
|
+
"notice.stale_checkout.body": "No pudimos reabrir el pago de este pedido. Actualiza para ver c\xF3mo va tu pedido; no se cobr\xF3 de nuevo.",
|
|
32
|
+
"notice.other.title": "No pudimos procesar tu pago",
|
|
33
|
+
"notice.other.body": "Intenta de nuevo; si sigue igual, puedes pagar de otra forma.",
|
|
34
|
+
"action.retry": "Reintentar pago",
|
|
35
|
+
"action.retry_form": "Reintentar",
|
|
36
|
+
"action.refresh": "Actualizar mi pedido",
|
|
37
|
+
"action.alternative": "Pagar con {label}"
|
|
38
|
+
};
|
|
39
|
+
var EN = {
|
|
40
|
+
"error.transient": "We're verifying your payment. If the charge went through we'll show it here; you won't be charged twice.",
|
|
41
|
+
"error.in_progress": "A payment is already in progress for this order. We're verifying it; don't pay again.",
|
|
42
|
+
"error.rate_limited": "Too many attempts in a row. Wait a few minutes and try again.",
|
|
43
|
+
"error.merchant_config": "We can't take card payments right now. It isn't a problem with your card: you can pay another way.",
|
|
44
|
+
"error.provider_declined": "We couldn't process your payment with that card. Check the details or try another method; you were not charged.",
|
|
45
|
+
"error.stale_checkout": "This order is already registered and the payment couldn't be reopened. Refresh to see how it's going.",
|
|
46
|
+
"error.expired": "Your cart expired. Rebuild it to pay.",
|
|
47
|
+
"error.price_mismatch": "The total changed. Check the new total and pay again.",
|
|
48
|
+
"error.store_closed": "This store isn't open for purchases yet. Come back soon.",
|
|
49
|
+
"error.validation": "Complete the marked fields.",
|
|
50
|
+
"error.other": "We couldn't process your payment. Try again.",
|
|
51
|
+
"notice.confirming.title": "We're confirming your payment\u2026",
|
|
52
|
+
"notice.confirming.body": "Don't close this page or pay again. If the charge already went through you'll see it here.",
|
|
53
|
+
"notice.form_failed.title": "We couldn't load the card form",
|
|
54
|
+
"notice.form_failed.body": "Trying again usually fixes it. You can also pay another way.",
|
|
55
|
+
"notice.rejected.title": "The charge didn't go through",
|
|
56
|
+
"notice.rejected.body": "You were not charged. Try another card or choose another way to pay.",
|
|
57
|
+
"notice.provider_declined.title": "We couldn't process your payment with that card",
|
|
58
|
+
"notice.provider_declined.body": "You were not charged. Check the details or try another card or method.",
|
|
59
|
+
"notice.merchant_config.title": "We can't charge cards right now",
|
|
60
|
+
"notice.merchant_config.body": "It isn't a problem with your card: it's on our side. You can pay another way.",
|
|
61
|
+
"notice.stale_checkout.title": "Your order is already registered",
|
|
62
|
+
"notice.stale_checkout.body": "We couldn't reopen the payment for this order. Refresh to see how it's going; you were not charged again.",
|
|
63
|
+
"notice.other.title": "We couldn't process your payment",
|
|
64
|
+
"notice.other.body": "Try again; if it keeps failing you can pay another way.",
|
|
65
|
+
"action.retry": "Retry payment",
|
|
66
|
+
"action.retry_form": "Retry",
|
|
67
|
+
"action.refresh": "Refresh my order",
|
|
68
|
+
"action.alternative": "Pay with {label}"
|
|
69
|
+
};
|
|
70
|
+
function paymentRecoveryMessages(locale, overrides) {
|
|
71
|
+
const base = (locale ?? "es-MX").toLowerCase().startsWith("en") ? EN : ES;
|
|
72
|
+
return overrides ? { ...base, ...overrides } : base;
|
|
73
|
+
}
|
|
74
|
+
|
|
7
75
|
// src/payments/choices.ts
|
|
8
76
|
var SEP = "|";
|
|
9
77
|
function choiceValue(methodKey, option) {
|
|
@@ -78,13 +146,33 @@ function checkoutToAttempt(result) {
|
|
|
78
146
|
if (action?.type === "challenge") return { ...base, payment: { provider: payment.provider, status: "requires_action", outcome: "challenge", action } };
|
|
79
147
|
return { ...base, payment: { provider: payment.provider, status: "pending", outcome: "pending", action: action ?? { type: "none" } } };
|
|
80
148
|
}
|
|
81
|
-
function
|
|
149
|
+
function safeHttpStatus(status) {
|
|
150
|
+
return status === 502 || status === 503 || status === 504 ? 500 : status;
|
|
151
|
+
}
|
|
152
|
+
function payErrorResponse(err, options = {}) {
|
|
82
153
|
const status = typeof err.status === "number" && err.status >= 400 ? err.status : 503;
|
|
83
|
-
|
|
154
|
+
const { kind: classified, retryable } = storefront.classifyPaymentError({ ...err, status, checkoutId: err.checkoutId ?? null });
|
|
155
|
+
const kind = options.kind ?? classified;
|
|
156
|
+
let code = err.code ?? (kind === "transient" ? "unavailable" : "server_error");
|
|
84
157
|
if (status === 409 && err.field === "payment_in_progress") code = "payment_in_progress";
|
|
85
158
|
if (status === 429) code = "too_many_attempts";
|
|
86
159
|
if (status === 422 && err.field === "expected_total") code = "price_mismatch";
|
|
87
|
-
|
|
160
|
+
const own = (options.ownMessage || kind === "validation" || kind === "expired" || kind === "price_mismatch" || kind === "other" && status < 500) && err.message;
|
|
161
|
+
const message = own || paymentRecoveryMessages(options.locale, options.messages)[`error.${kind}`];
|
|
162
|
+
return {
|
|
163
|
+
status: safeHttpStatus(status),
|
|
164
|
+
body: {
|
|
165
|
+
error: {
|
|
166
|
+
code,
|
|
167
|
+
message,
|
|
168
|
+
retryable: options.kind ? options.kind === "transient" || options.kind === "in_progress" || options.kind === "rate_limited" : retryable,
|
|
169
|
+
kind,
|
|
170
|
+
...err.field ? { field: err.field } : {},
|
|
171
|
+
...err.retryAfter ? { retry_after: err.retryAfter } : {},
|
|
172
|
+
...err.details !== void 0 ? { details: err.details } : {}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
};
|
|
88
176
|
}
|
|
89
177
|
function voucherRows(voucher, labels, locale) {
|
|
90
178
|
if (!voucher) return [];
|
|
@@ -202,6 +290,53 @@ function deviceSessionId(v) {
|
|
|
202
290
|
const id = v.trim();
|
|
203
291
|
return id.length > 0 && id.length <= DEVICE_SESSION_ID_MAX && /^[\w.:-]+$/.test(id) ? id : void 0;
|
|
204
292
|
}
|
|
293
|
+
var JSON_HEADERS = { "Content-Type": "application/json" };
|
|
294
|
+
function copyHeaders(from) {
|
|
295
|
+
const out = new Headers();
|
|
296
|
+
from.forEach((value, key) => {
|
|
297
|
+
const k = key.toLowerCase();
|
|
298
|
+
if (k === "content-length" || k === "content-type" || k === "set-cookie" || k === "refresh") return;
|
|
299
|
+
out.set(key, value);
|
|
300
|
+
});
|
|
301
|
+
for (const cookie of from.getSetCookie?.() ?? []) out.append("Set-Cookie", cookie);
|
|
302
|
+
return out;
|
|
303
|
+
}
|
|
304
|
+
async function jsonPayRoute(run, where, options = {}) {
|
|
305
|
+
const opts = typeof options === "string" ? { cacheControl: options } : options;
|
|
306
|
+
const cache = opts.cacheControl ?? "private, no-store";
|
|
307
|
+
const errorOptions = { ...opts.locale ? { locale: opts.locale } : {}, ...opts.messages ? { messages: opts.messages } : {} };
|
|
308
|
+
let res;
|
|
309
|
+
try {
|
|
310
|
+
res = await run();
|
|
311
|
+
} catch (err) {
|
|
312
|
+
const entry = { level: "warn", msg: "excepci\xF3n en la ruta de pago", where, error: String(err?.message ?? err).slice(0, 300) };
|
|
313
|
+
if (opts.log) opts.log(entry);
|
|
314
|
+
else console.warn(JSON.stringify(entry));
|
|
315
|
+
const { status: status2, body: body2 } = payErrorResponse({ status: 500, code: "server_error" }, errorOptions);
|
|
316
|
+
return new Response(JSON.stringify(body2), { status: status2, headers: { ...JSON_HEADERS, "Cache-Control": cache } });
|
|
317
|
+
}
|
|
318
|
+
const type = res.headers.get("content-type") ?? "";
|
|
319
|
+
if (res.ok && type.includes("json")) return res;
|
|
320
|
+
let parsed = null;
|
|
321
|
+
if (type.includes("json")) parsed = await res.clone().json().catch(() => null);
|
|
322
|
+
const e = parsed?.error;
|
|
323
|
+
if (!res.ok && e && typeof e.kind === "string" && safeHttpStatus(res.status) === res.status) return res;
|
|
324
|
+
const { status, body } = payErrorResponse(
|
|
325
|
+
{
|
|
326
|
+
status: res.ok ? 500 : res.status,
|
|
327
|
+
...e?.code ? { code: e.code } : {},
|
|
328
|
+
...e?.message ? { message: e.message } : {},
|
|
329
|
+
...e?.field ? { field: e.field } : {},
|
|
330
|
+
...e?.details !== void 0 ? { details: e.details } : {},
|
|
331
|
+
...typeof e?.retryable === "boolean" ? { retryable: e.retryable } : {}
|
|
332
|
+
},
|
|
333
|
+
errorOptions
|
|
334
|
+
);
|
|
335
|
+
const headers = copyHeaders(res.headers);
|
|
336
|
+
headers.set("Content-Type", "application/json");
|
|
337
|
+
headers.set("Cache-Control", cache);
|
|
338
|
+
return new Response(JSON.stringify(body), { status, headers });
|
|
339
|
+
}
|
|
205
340
|
var ATTEMPT = /^[A-Za-z0-9_-]{8,100}$/;
|
|
206
341
|
var asMoney = (v) => {
|
|
207
342
|
const m = v;
|
|
@@ -234,10 +369,14 @@ function createEmbeddedPayHandlers(config) {
|
|
|
234
369
|
headers.set("Content-Type", "application/json");
|
|
235
370
|
return new Response(JSON.stringify(body), { status: init.status ?? 200, headers });
|
|
236
371
|
};
|
|
237
|
-
const
|
|
372
|
+
const errorOptions = { locale, ...config.errorMessages ? { messages: config.errorMessages } : {} };
|
|
373
|
+
const fail = (status2, code, message, extra = {}, more = {}) => {
|
|
374
|
+
const r = payErrorResponse({ status: status2, code, message, ...more.field ? { field: more.field } : {} }, { ...errorOptions, ownMessage: true, ...more.kind ? { kind: more.kind } : {} });
|
|
375
|
+
return json(r.body, { status: r.status, headers: extra });
|
|
376
|
+
};
|
|
238
377
|
async function pay(request) {
|
|
239
378
|
const site = config.site(request);
|
|
240
|
-
if (!sameOrigin(request, site)) return fail(403, "forbidden", "origin");
|
|
379
|
+
if (!sameOrigin(request, site)) return fail(403, "forbidden", "origin", {}, { kind: "other" });
|
|
241
380
|
if (limiter) {
|
|
242
381
|
const gate = limiter.hit(clientKey(request, config.trustProxy));
|
|
243
382
|
if (!gate.allowed) return fail(429, "too_many_attempts", msg.tooManyRequests, { "Retry-After": String(gate.retryAfterSec) });
|
|
@@ -267,7 +406,7 @@ function createEmbeddedPayHandlers(config) {
|
|
|
267
406
|
try {
|
|
268
407
|
const methods = await sf.carts.paymentMethods(cartId);
|
|
269
408
|
const card = buildPayChoices(methods.methods, config.hide ? { hide: config.hide } : {}).choices.find((c) => c.mode === "card" && c.value === fields.payment_choice);
|
|
270
|
-
if (!choice || !card) return fail(422, "invalid_state", msg.methodUnavailable);
|
|
409
|
+
if (!choice || !card) return fail(422, "invalid_state", msg.methodUnavailable, {}, { field: storefront.PAYMENT_CHOICE_REFUSED_FIELD });
|
|
271
410
|
const previous = await config.readSession(request);
|
|
272
411
|
const reusedId = previous && previous.cart_id === cartId ? previous.draft.checkout_id : void 0;
|
|
273
412
|
let checkoutId;
|
|
@@ -297,7 +436,7 @@ function createEmbeddedPayHandlers(config) {
|
|
|
297
436
|
return json(result, { headers });
|
|
298
437
|
} catch (err) {
|
|
299
438
|
if (storefront.isStorefrontError(err)) {
|
|
300
|
-
const { status: status2, body: errBody } = payErrorResponse(err);
|
|
439
|
+
const { status: status2, body: errBody } = payErrorResponse(err, errorOptions);
|
|
301
440
|
log({ level: "warn", msg: "cobro rechazado por OPS", status: err.status, code: err.code ?? null, field: err.field ?? null, message: String(err.message).slice(0, 300) });
|
|
302
441
|
const headers = new Headers();
|
|
303
442
|
if (session) headers.append("Set-Cookie", await config.serializeSession(session));
|
|
@@ -307,21 +446,22 @@ function createEmbeddedPayHandlers(config) {
|
|
|
307
446
|
}
|
|
308
447
|
}
|
|
309
448
|
async function status(request) {
|
|
310
|
-
if (!sameOrigin(request, config.site(request))) return fail(403, "forbidden", "origin");
|
|
449
|
+
if (!sameOrigin(request, config.site(request))) return fail(403, "forbidden", "origin", {}, { kind: "other" });
|
|
311
450
|
const session = await config.readSession(request);
|
|
312
451
|
const id = session?.draft.checkout_id;
|
|
313
|
-
|
|
452
|
+
const none = async () => json({ payment: { provider: "", status: "none" }, recoverable: Boolean(await config.readCartId(request)) });
|
|
453
|
+
if (!session || !id) return none();
|
|
314
454
|
try {
|
|
315
455
|
const sf = await config.client(request);
|
|
316
456
|
const found = await sf.checkouts.get(id);
|
|
317
|
-
if (!found) return
|
|
457
|
+
if (!found) return none();
|
|
318
458
|
const attempt = checkoutToAttempt(found);
|
|
319
459
|
const headers = new Headers();
|
|
320
460
|
await config.settle({ draft: session.draft, result: attempt, headers });
|
|
321
461
|
return json(attempt, { headers });
|
|
322
462
|
} catch (err) {
|
|
323
463
|
if (storefront.isStorefrontError(err)) {
|
|
324
|
-
const { status: code, body } = payErrorResponse(err);
|
|
464
|
+
const { status: code, body } = payErrorResponse(err, errorOptions);
|
|
325
465
|
return json(body, { status: code });
|
|
326
466
|
}
|
|
327
467
|
throw err;
|
|
@@ -343,7 +483,12 @@ function createEmbeddedPayHandlers(config) {
|
|
|
343
483
|
const outcome = storefront.paymentOutcome(result, locale);
|
|
344
484
|
return { kind: "error", status: storefront.safeHttpsUrl(outcome.redirect_url) ? 409 : 422, message: outcome.message, fields: [] };
|
|
345
485
|
}
|
|
346
|
-
|
|
486
|
+
const routeOptions = { cacheControl: cache, ...errorOptions };
|
|
487
|
+
return {
|
|
488
|
+
pay: (request) => jsonPayRoute(() => pay(request), "pay", routeOptions),
|
|
489
|
+
status: (request) => jsonPayRoute(() => status(request), "status", routeOptions),
|
|
490
|
+
cash
|
|
491
|
+
};
|
|
347
492
|
}
|
|
348
493
|
|
|
349
494
|
exports.DEVICE_SESSION_ID_MAX = DEVICE_SESSION_ID_MAX;
|
|
@@ -355,6 +500,7 @@ exports.clientKey = clientKey;
|
|
|
355
500
|
exports.createEmbeddedPayHandlers = createEmbeddedPayHandlers;
|
|
356
501
|
exports.createRateLimiter = createRateLimiter;
|
|
357
502
|
exports.deviceSessionId = deviceSessionId;
|
|
503
|
+
exports.jsonPayRoute = jsonPayRoute;
|
|
358
504
|
exports.parseChoice = parseChoice;
|
|
359
505
|
exports.payErrorResponse = payErrorResponse;
|
|
360
506
|
exports.paymentCsp = paymentCsp;
|
|
@@ -363,6 +509,7 @@ exports.paymentCspHeaders = paymentCspHeaders;
|
|
|
363
509
|
exports.paymentCspMode = paymentCspMode;
|
|
364
510
|
exports.paymentNonce = paymentNonce;
|
|
365
511
|
exports.paymentNonceFromHeaders = paymentNonceFromHeaders;
|
|
512
|
+
exports.safeHttpStatus = safeHttpStatus;
|
|
366
513
|
exports.sameOrigin = sameOrigin;
|
|
367
514
|
exports.voucherRows = voucherRows;
|
|
368
515
|
//# sourceMappingURL=payments-server.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/payments/choices.ts","../src/payments/csp.ts","../src/payments/server.ts"],"names":["status","paymentIdempotencyKey","isStorefrontError","paymentOutcome","safeHttpsUrl"],"mappings":";;;;;;;AAgDA,IAAM,GAAA,GAAM,GAAA;AAEL,SAAS,WAAA,CAAY,WAAmB,MAAA,EAAyC;AACtF,EAAA,OAAO,SAAS,CAAA,EAAG,SAAS,GAAG,GAAG,CAAA,EAAG,MAAM,CAAA,CAAA,GAAK,SAAA;AAClD;AAGO,SAAS,YAAY,KAAA,EAAiG;AAC3H,EAAA,MAAM,GAAA,GAAA,CAAO,KAAA,IAAS,EAAA,EAAI,IAAA,EAAK;AAC/B,EAAA,IAAI,CAAC,KAAK,OAAO,IAAA;AACjB,EAAA,MAAM,CAAA,GAAI,GAAA,CAAI,WAAA,CAAY,GAAG,CAAA;AAC7B,EAAA,IAAI,MAAM,EAAA,EAAI,OAAO,EAAE,SAAA,EAAW,GAAA,EAAK,QAAQ,IAAA,EAAK;AACpD,EAAA,MAAM,MAAA,GAAS,GAAA,CAAI,KAAA,CAAM,CAAA,GAAI,CAAC,CAAA;AAC9B,EAAA,IAAI,MAAA,KAAW,UAAU,MAAA,KAAW,MAAA,IAAU,WAAW,QAAA,IAAY,MAAA,KAAW,WAAW,OAAO,IAAA;AAClG,EAAA,OAAO,EAAE,SAAA,EAAW,GAAA,CAAI,MAAM,CAAA,EAAG,CAAC,GAAG,MAAA,EAAO;AAC9C;AAEA,SAAS,OAAO,MAAA,EAA0C;AACxD,EAAA,IAAI,MAAA,CAAO,YAAY,MAAA,CAAO,GAAA,KAAQ,YAAY,MAAA,CAAO,GAAA,KAAQ,WAAW,OAAO,UAAA;AACnF,EAAA,OAAO,MAAA,CAAO,GAAA,KAAQ,MAAA,GAAS,MAAA,GAAS,MAAA;AAC1C;AAMO,SAAS,eAAA,CAAgB,OAAA,EAAmC,OAAA,GAAkC,EAAC,EAAe;AACnH,EAAA,MAAM,SAAS,IAAI,GAAA,CAAI,OAAA,CAAQ,IAAA,IAAQ,EAAE,CAAA;AACzC,EAAA,MAAM,UAAuB,EAAC;AAC9B,EAAA,IAAI,UAAA,GAAmC,IAAA;AACvC,EAAA,IAAI,YAAA,GAA8B,IAAA;AAClC,EAAA,KAAA,MAAW,UAAU,OAAA,EAAS;AAC5B,IAAA,IAAI,MAAA,CAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,EAAG;AAC5B,IAAA,MAAM,IAAA,GAAO,MAAA,CAAO,OAAA,IAAW,EAAC;AAChC,IAAA,IAAI,IAAA,CAAK,WAAW,CAAA,EAAG;AACrB,MAAA,MAAM,KAAA,GAAQ,WAAA,CAAY,MAAA,CAAO,GAAA,EAAK,IAAI,CAAA;AAC1C,MAAA,OAAA,CAAQ,KAAK,EAAE,KAAA,EAAO,SAAA,EAAW,MAAA,CAAO,KAAK,MAAA,EAAQ,IAAA,EAAM,IAAA,EAAM,OAAA,EAAS,OAAO,IAAA,EAAM,MAAA,EAAQ,EAAC,EAAG,eAAA,EAAiB,MAAM,CAAA;AAC1H,MAAA,IAAI,MAAA,CAAO,OAAA,IAAW,CAAC,YAAA,EAAc,YAAA,GAAe,KAAA;AACpD,MAAA;AAAA,IACF;AACA,IAAA,IAAA,CAAK,OAAA,CAAQ,CAAC,MAAA,EAAQ,CAAA,KAAM;AAC1B,MAAA,MAAM,IAAA,GAAO,OAAO,MAAM,CAAA;AAC1B,MAAA,MAAM,KAAA,GAAQ,WAAA,CAAY,MAAA,CAAO,GAAA,EAAK,OAAO,GAAG,CAAA;AAChD,MAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,QACX,KAAA;AAAA,QACA,WAAW,MAAA,CAAO,GAAA;AAAA,QAClB,QAAQ,MAAA,CAAO,GAAA;AAAA,QACf,IAAA;AAAA,QACA,KAAA,EAAO,MAAA,CAAO,KAAA,EAAO,IAAA,EAAK,IAAK,IAAA;AAAA,QAC/B,MAAA,EAAQ,OAAO,GAAA,KAAQ,MAAA,GAAU,OAAO,MAAA,IAAU,KAAM,EAAC;AAAA,QACzD,eAAA,EAAiB,OAAO,gBAAA,IAAoB;AAAA,OAC7C,CAAA;AACD,MAAA,IAAI,SAAS,MAAA,IAAU,MAAA,CAAO,UAAU,CAAC,UAAA,eAAyB,MAAA,CAAO,MAAA;AACzE,MAAA,IAAI,OAAO,OAAA,IAAW,CAAA,KAAM,CAAA,IAAK,CAAC,cAAc,YAAA,GAAe,KAAA;AAAA,IACjE,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,MAAM,SAAS,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,KAAO,EAAE,IAAA,KAAS,MAAA,IAAU,CAAC,UAAA,GAAa,EAAE,GAAG,CAAA,EAAG,IAAA,EAAM,UAAA,KAAwB,CAAE,CAAA;AAC9G,EAAA,OAAO,EAAE,OAAA,EAAS,MAAA,EAAQ,UAAA,EAAY,YAAA,EAAc,gBAAgB,MAAA,CAAO,CAAC,CAAA,EAAG,KAAA,IAAS,IAAA,EAAK;AAC/F;AAGO,SAAS,gBAAA,CAAiB,QAAiC,OAAA,EAAmE;AACnI,EAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,EAAA,KAAO,OAAO,CAAA,KAAM,OAAA,GAAU,IAAA,GAAO,MAAA,CAAO,CAAC,CAAA,CAAA;AAChF,EAAA,IAAI,CAAC,OAAO,OAAO,IAAA;AACnB,EAAA,OAAO;AAAA,IACL,mBAAmB,KAAA,CAAM,iBAAA;AAAA,IACzB,GAAI,MAAM,aAAA,GAAgB,EAAE,eAAe,KAAA,CAAM,aAAA,KAAkB;AAAC,GACtE;AACF;AAMO,SAAS,kBAAkB,MAAA,EAA8C;AAC9E,EAAA,MAAM,EAAE,QAAA,EAAU,OAAA,EAAS,KAAA,EAAM,GAAI,MAAA;AACrC,EAAA,MAAM,MAAA,GAAS,QAAQ,MAAA,IAAU,IAAA;AACjC,EAAA,MAAM,IAAA,GAAO,EAAE,QAAA,EAAU,GAAI,QAAQ,EAAE,KAAA,EAAM,GAAI,EAAC,EAAG;AACrD,EAAA,MAAM,MAAA,GAAA,CAAU,QAAA,CAAS,MAAA,IAAU,EAAA,EAAI,WAAA,EAAY;AACnD,EAAA,IAAI,WAAW,MAAA,IAAU,MAAA,KAAW,WAAA,EAAa,OAAO,EAAE,GAAG,IAAA,EAAM,OAAA,EAAS,EAAE,UAAU,OAAA,CAAQ,QAAA,EAAU,QAAQ,MAAA,EAAQ,OAAA,EAAS,YAAW,EAAE;AAChJ,EAAA,IAAI,MAAA,KAAW,WAAA,IAAe,MAAA,KAAW,UAAA,SAAmB,EAAE,GAAG,IAAA,EAAM,OAAA,EAAS,EAAE,QAAA,EAAU,OAAA,CAAQ,QAAA,EAAU,MAAA,EAAQ,aAAY,EAAE;AACpI,EAAA,IAAI,MAAA,KAAW,SAAA,EAAW,OAAO,EAAE,GAAG,IAAA,EAAM,OAAA,EAAS,EAAE,QAAA,EAAU,OAAA,CAAQ,QAAA,EAAU,MAAA,EAAQ,WAAU,EAAE;AACvG,EAAA,IAAI,WAAW,QAAA,EAAU;AACvB,IAAA,MAAM,OAAA,GAAW,QAA+E,YAAA,IAAgB,UAAA;AAChH,IAAA,OAAO,EAAE,GAAG,IAAA,EAAM,OAAA,EAAS,EAAE,UAAU,OAAA,CAAQ,QAAA,EAAU,MAAA,EAAQ,QAAA,EAAU,SAAS,UAAA,EAAY,YAAA,EAAc,OAAA,EAAS,SAAA,EAAW,MAAK,EAAE;AAAA,EAC3I;AAEA,EAAA,IAAI,QAAQ,IAAA,KAAS,WAAA,EAAa,OAAO,EAAE,GAAG,IAAA,EAAM,OAAA,EAAS,EAAE,QAAA,EAAU,QAAQ,QAAA,EAAU,MAAA,EAAQ,mBAAmB,OAAA,EAAS,WAAA,EAAa,QAAO,EAAE;AACrJ,EAAA,OAAO,EAAE,GAAG,IAAA,EAAM,SAAS,EAAE,QAAA,EAAU,QAAQ,QAAA,EAAU,MAAA,EAAQ,SAAA,EAAW,OAAA,EAAS,WAAW,MAAA,EAAQ,MAAA,IAAU,EAAE,IAAA,EAAM,MAAA,IAAS,EAAE;AACvI;AAWO,SAAS,iBAAiB,GAAA,EAAwD;AACvF,EAAA,MAAM,MAAA,GAAS,OAAO,GAAA,CAAI,MAAA,KAAW,YAAY,GAAA,CAAI,MAAA,IAAU,GAAA,GAAM,GAAA,CAAI,MAAA,GAAS,GAAA;AAClF,EAAA,IAAI,IAAA,GAAO,IAAI,IAAA,IAAQ,cAAA;AACvB,EAAA,IAAI,MAAA,KAAW,GAAA,IAAO,GAAA,CAAI,KAAA,KAAU,uBAAuB,IAAA,GAAO,qBAAA;AAClE,EAAA,IAAI,MAAA,KAAW,KAAK,IAAA,GAAO,mBAAA;AAC3B,EAAA,IAAI,MAAA,KAAW,GAAA,IAAO,GAAA,CAAI,KAAA,KAAU,kBAAkB,IAAA,GAAO,gBAAA;AAC7D,EAAA,OAAO,EAAE,QAAQ,IAAA,EAAM,EAAE,OAAO,EAAE,IAAA,EAAM,OAAA,EAAS,GAAA,CAAI,OAAA,IAAW,EAAA,EAAI,GAAI,GAAA,CAAI,OAAA,KAAY,MAAA,GAAY,EAAE,OAAA,EAAS,GAAA,CAAI,SAAQ,GAAI,EAAC,EAAG,EAAE,EAAE;AACzI;AAKO,SAAS,WAAA,CACd,OAAA,EACA,MAAA,EACA,MAAA,EACkC;AAClC,EAAA,IAAI,CAAC,OAAA,EAAS,OAAO,EAAC;AACtB,EAAA,MAAM,OAA2B,EAAC;AAClC,EAAA,IAAI,OAAA,CAAQ,aAAA,EAAe,IAAA,CAAK,IAAA,CAAK,CAAC,MAAA,CAAO,KAAA,EAAO,MAAA,CAAO,OAAA,CAAQ,aAAa,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,EAAE,CAAC,CAAC,CAAA;AAC/F,EAAA,IAAI,OAAA,CAAQ,SAAA,EAAW,IAAA,CAAK,IAAA,CAAK,CAAC,MAAA,CAAO,SAAA,EAAW,MAAA,CAAO,OAAA,CAAQ,SAAS,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,EAAE,CAAC,CAAC,CAAA;AAC3F,EAAA,IAAI,OAAA,CAAQ,KAAA,EAAO,IAAA,CAAK,IAAA,CAAK,CAAC,MAAA,CAAO,KAAA,EAAO,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,EAAE,CAAC,CAAC,CAAA;AAC/E,EAAA,IAAI,OAAA,CAAQ,OAAA,EAAS,IAAA,CAAK,IAAA,CAAK,CAAC,MAAA,CAAO,OAAA,EAAS,MAAA,CAAO,OAAA,CAAQ,OAAO,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,EAAE,CAAC,CAAC,CAAA;AACrF,EAAA,IAAI,QAAQ,UAAA,EAAY;AACtB,IAAA,MAAM,CAAA,GAAI,IAAI,IAAA,CAAK,OAAA,CAAQ,UAAU,CAAA;AACrC,IAAA,IAAI,CAAC,MAAA,CAAO,KAAA,CAAM,CAAA,CAAE,OAAA,EAAS,CAAA,EAAG;AAC9B,MAAA,IAAA,CAAK,IAAA,CAAK,CAAC,MAAA,CAAO,OAAA,EAAS,IAAI,IAAA,CAAK,cAAA,CAAe,QAAQ,EAAE,SAAA,EAAW,QAAQ,SAAA,EAAW,OAAA,EAAS,UAAU,KAAA,EAAO,EAAE,MAAA,CAAO,CAAC,CAAA,GAAI,MAAM,CAAC,CAAA;AAAA,IAC5I;AAAA,EACF;AACA,EAAA,OAAO,IAAA;AACT;;;ACnKA,IAAM,MAAA,GAAS,gGAAA;AAEf,SAAS,WAAW,KAAA,EAAoD;AACtE,EAAA,MAAM,GAAA,uBAAU,GAAA,EAAY;AAC5B,EAAA,KAAA,MAAW,IAAA,IAAQ,KAAA,EAAO,KAAA,MAAW,CAAA,IAAK,QAAQ,EAAC,EAAG,IAAI,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA,EAAG,GAAA,CAAI,IAAI,CAAC,CAAA;AACnF,EAAA,OAAO,CAAC,GAAG,GAAG,CAAA;AAChB;AASO,SAAS,UAAA,CAAW,OAAA,EAAwD,OAAA,GAA6B,EAAC,EAAW;AAC1H,EAAA,MAAM,OAAO,OAAA,CAAQ,MAAA,CAAO,CAAC,CAAA,KAA0B,CAAC,CAAC,CAAC,CAAA;AAC1D,EAAA,MAAM,IAAA,GAAO,CAAC,CAAA,KAA+C,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,GAAA,GAAM,CAAC,CAAC,CAAA;AACvF,EAAA,MAAM,KAAA,GAAQ,QAAQ,KAAA,IAAS,qBAAA,CAAsB,KAAK,OAAA,CAAQ,KAAK,CAAA,GAAI,OAAA,CAAQ,KAAA,GAAQ,MAAA;AAC3F,EAAA,MAAM,UAAA,GAAa,IAAA,CAAK,OAAA,CAAQ,CAAC,CAAA,KAAM;AACrC,IAAA,IAAI;AACF,MAAA,MAAM,CAAA,GAAI,IAAI,GAAA,CAAI,CAAA,CAAE,OAAO,CAAA;AAC3B,MAAA,OAAO,EAAE,QAAA,KAAa,QAAA,GAAW,CAAC,CAAA,CAAE,MAAM,IAAI,EAAC;AAAA,IACjD,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,EAAC;AAAA,IACV;AAAA,EACF,CAAC,CAAA;AACD,EAAA,MAAM,GAAA,GAAM,CAAC,IAAA,EAAc,MAAA,KAAqB,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,MAAA,CAAO,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA;AAC3E,EAAA,MAAM,KAAA,GAAQ;AAAA,IACZ,oBAAA;AAAA,IACA,IAAI,YAAA,EAAc,CAAC,QAAA,EAAU,GAAA,CAAI,QAAQ,YAAA,IAAgB,EAAC,EAAG,MAAA,CAAO,CAAC,CAAA,KAAM,sCAAA,CAAuC,IAAA,CAAK,CAAC,CAAC,CAAA,EAAG,GAAI,KAAA,GAAQ,CAAC,UAAU,KAAK,CAAA,CAAA,CAAG,CAAA,GAAI,IAAK,GAAG,OAAA,CAAQ,UAAA,EAAY,GAAG,KAAK,QAAQ,CAAA,EAAG,QAAQ,KAAA,EAAO,MAAM,CAAC,CAAC,CAAA;AAAA,IACrO,GAAA,CAAI,aAAa,OAAA,CAAQ,GAAG,KAAK,OAAO,CAAA,EAAG,OAAA,CAAQ,KAAA,EAAO,KAAK,CAAA,CAAE,SAAS,OAAA,CAAQ,GAAG,IAAA,CAAK,OAAO,CAAA,EAAG,OAAA,CAAQ,OAAO,KAAK,CAAA,GAAI,CAAC,QAAQ,CAAC,CAAA;AAAA,IACtI,GAAA,CAAI,aAAA,EAAe,CAAC,QAAA,EAAU,GAAG,OAAA,CAAQ,GAAG,IAAA,CAAK,SAAS,CAAA,EAAG,OAAA,CAAQ,KAAA,EAAO,OAAO,CAAC,CAAC,CAAA;AAAA,IACrF,GAAA,CAAI,WAAW,CAAC,QAAA,EAAU,SAAS,GAAI,OAAA,CAAQ,QAAA,GAAW,CAAC,QAAQ,CAAA,GAAI,EAAC,EAAI,GAAG,OAAA,CAAQ,GAAG,IAAA,CAAK,KAAK,GAAG,OAAA,CAAQ,KAAA,EAAO,GAAG,CAAC,CAAC,CAAA;AAAA,IAC3H,kCAAA;AAAA,IACA,GAAA,CAAI,aAAA,EAAe,CAAC,QAAA,EAAU,GAAG,OAAA,CAAQ,GAAG,IAAA,CAAK,MAAM,CAAA,EAAG,OAAA,CAAQ,KAAA,EAAO,IAAI,CAAC,CAAC,CAAA;AAAA,IAC/E,wBAAA;AAAA,IACA,iBAAA;AAAA,IACA;AAAA,GACF;AACA,EAAA,IAAI,OAAA,CAAQ,SAAA,IAAa,2BAAA,CAA4B,IAAA,CAAK,OAAA,CAAQ,SAAS,CAAA,EAAG,KAAA,CAAM,IAAA,CAAK,CAAA,WAAA,EAAc,OAAA,CAAQ,SAAS,CAAA,CAAE,CAAA;AAC1H,EAAA,OAAO,KAAA,CAAM,KAAK,IAAI,CAAA;AACxB;AAGO,SAAS,qBAAqB,UAAA,EAA6B;AAChE,EAAA,OAAO,aAAa,qCAAA,GAAwC,yBAAA;AAC9D;AAKO,SAAS,cAAA,CAAe,OAAkC,UAAA,EAAqC;AACpG,EAAA,MAAM,GAAA,GAAA,CAAO,KAAA,IAAS,EAAA,EAAI,IAAA,GAAO,WAAA,EAAY;AAC7C,EAAA,IAAI,QAAQ,KAAA,IAAS,GAAA,KAAQ,aAAA,IAAiB,GAAA,KAAQ,WAAW,OAAO,GAAA;AACxE,EAAA,OAAO,aAAa,aAAA,GAAgB,KAAA;AACtC;AAGO,SAAS,YAAA,GAAuB;AACrC,EAAA,MAAM,KAAA,GAAQ,IAAI,UAAA,CAAW,EAAE,CAAA;AAC/B,EAAA,MAAA,CAAO,gBAAgB,KAAK,CAAA;AAC5B,EAAA,IAAI,GAAA,GAAM,EAAA;AACV,EAAA,KAAA,MAAW,CAAA,IAAK,KAAA,EAAO,GAAA,IAAO,MAAA,CAAO,aAAa,CAAC,CAAA;AACnD,EAAA,OAAO,KAAK,GAAG,CAAA;AACjB;AAGO,SAAS,iBAAA,CACd,SACA,OAAA,EACwB;AACxB,EAAA,IAAI,OAAA,CAAQ,IAAA,KAAS,KAAA,EAAO,OAAO,EAAC;AACpC,EAAA,OAAO,EAAE,CAAC,oBAAA,CAAqB,OAAA,CAAQ,IAAA,KAAS,aAAa,CAAC,GAAG,UAAA,CAAW,OAAA,EAAS,OAAO,CAAA,EAAE;AAChG;AAGO,SAAS,wBAAwB,OAAA,EAAsC;AAC5E,EAAA,MAAM,GAAA,GAAM,QAAQ,GAAA,CAAI,yBAAyB,KAAK,OAAA,CAAQ,GAAA,CAAI,qCAAqC,CAAA,IAAK,EAAA;AAC5G,EAAA,OAAO,6BAAA,CAA8B,IAAA,CAAK,GAAG,CAAA,GAAI,CAAC,CAAA;AACpD;;;AC/DO,SAAS,iBAAA,CAAkB,EAAE,KAAA,EAAO,QAAA,EAAS,EAAqD;AACvG,EAAA,MAAM,IAAA,uBAAW,GAAA,EAAsB;AACvC,EAAA,OAAO;AAAA,IACL,GAAA,CAAI,GAAA,EAAK,GAAA,GAAM,IAAA,CAAK,KAAI,EAAG;AACzB,MAAA,MAAM,MAAA,GAAA,CAAU,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA,IAAK,EAAC,EAAG,MAAA,CAAO,CAAC,CAAA,KAAM,GAAA,GAAM,CAAA,GAAI,QAAQ,CAAA;AACrE,MAAA,IAAI,MAAA,CAAO,UAAU,KAAA,EAAO;AAC1B,QAAA,IAAA,CAAK,GAAA,CAAI,KAAK,MAAM,CAAA;AACpB,QAAA,OAAO,EAAE,OAAA,EAAS,KAAA,EAAO,aAAA,EAAe,IAAA,CAAK,IAAI,CAAA,EAAG,IAAA,CAAK,IAAA,CAAA,CAAM,MAAA,CAAO,CAAC,CAAA,GAAK,QAAA,GAAW,GAAA,IAAO,GAAI,CAAC,CAAA,EAAE;AAAA,MACvG;AACA,MAAA,MAAA,CAAO,KAAK,GAAG,CAAA;AACf,MAAA,IAAA,CAAK,GAAA,CAAI,KAAK,MAAM,CAAA;AACpB,MAAA,IAAI,KAAK,IAAA,GAAO,GAAA,EAAA;AAAM,QAAA,KAAA,MAAW,CAAC,CAAA,EAAG,CAAC,CAAA,IAAK,IAAA,MAAU,CAAA,CAAE,KAAA,CAAM,CAAC,CAAA,KAAM,MAAM,CAAA,IAAK,QAAQ,CAAA,EAAG,IAAA,CAAK,OAAO,CAAC,CAAA;AAAA,MAAA;AACvG,MAAA,OAAO,EAAE,OAAA,EAAS,IAAA,EAAM,aAAA,EAAe,CAAA,EAAE;AAAA,IAC3C;AAAA,GACF;AACF;AAGO,SAAS,SAAA,CAAU,OAAA,EAAkB,UAAA,GAAa,KAAA,EAAe;AACtE,EAAA,IAAI,CAAC,YAAY,OAAO,QAAA;AACxB,EAAA,MAAM,EAAA,GAAK,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,kBAAkB,CAAA;AACjD,EAAA,IAAI,EAAA,EAAI,OAAO,EAAA,CAAG,IAAA,EAAK;AACvB,EAAA,OAAO,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,iBAAiB,CAAA,EAAG,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,CAAA,EAAG,IAAA,EAAK,IAAK,QAAA;AAC1E;AAMO,SAAS,UAAA,CAAW,SAAkB,IAAA,EAAuB;AAClE,EAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,QAAQ,CAAA;AAC3C,EAAA,IAAI,CAAC,QAAQ,OAAO,IAAA;AACpB,EAAA,IAAI;AACF,IAAA,MAAM,IAAA,GAAO,IAAI,GAAA,CAAI,MAAM,CAAA,CAAE,QAAA;AAC7B,IAAA,OAAO,IAAA,KAAS,IAAI,GAAA,CAAI,IAAI,CAAA,CAAE,QAAA,IAAY,IAAA,KAAS,IAAI,GAAA,CAAI,OAAA,CAAQ,GAAG,CAAA,CAAE,QAAA;AAAA,EAC1E,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACF;AAGO,IAAM,qBAAA,GAAwB;AAC9B,SAAS,gBAAgB,CAAA,EAAgC;AAC9D,EAAA,IAAI,OAAO,CAAA,KAAM,QAAA,EAAU,OAAO,MAAA;AAClC,EAAA,MAAM,EAAA,GAAK,EAAE,IAAA,EAAK;AAClB,EAAA,OAAO,EAAA,CAAG,MAAA,GAAS,CAAA,IAAK,EAAA,CAAG,MAAA,IAAU,yBAAyB,YAAA,CAAa,IAAA,CAAK,EAAE,CAAA,GAAI,EAAA,GAAK,MAAA;AAC7F;AAEA,IAAM,OAAA,GAAU,wBAAA;AAEhB,IAAM,OAAA,GAAU,CAAC,CAAA,KAA6B;AAC5C,EAAA,MAAM,CAAA,GAAI,CAAA;AACV,EAAA,OAAO,CAAA,IAAK,OAAO,CAAA,CAAE,MAAA,KAAW,QAAA,IAAY,gBAAgB,IAAA,CAAK,CAAA,CAAE,MAAM,CAAA,IAAK,OAAO,CAAA,CAAE,kBAAkB,QAAA,IAAY,CAAA,CAAE,aAAA,CAAc,MAAA,KAAW,CAAA,GAC5I,EAAE,MAAA,EAAQ,CAAA,CAAE,MAAA,EAAQ,aAAA,EAAe,CAAA,CAAE,aAAA,EAAc,GACnD,IAAA;AACN,CAAA;AAgBA,IAAM,gBAAA,GAAwC;AAAA,EAC5C,UAAA,EAAY,+BAAA;AAAA,EACZ,WAAA,EAAa,oDAAA;AAAA,EACb,iBAAA,EAAmB,qDAAA;AAAA,EACnB,eAAA,EAAiB,mEAAA;AAAA,EACjB,eAAA,EAAiB;AACnB,CAAA;AAkDO,SAAS,0BAAmE,MAAA,EAAwD;AACzI,EAAA,MAAM,MAAM,EAAE,GAAG,gBAAA,EAAkB,GAAG,OAAO,QAAA,EAAS;AACtD,EAAA,MAAM,MAAA,GAAS,OAAO,MAAA,IAAU,OAAA;AAChC,EAAA,MAAM,KAAA,GAAQ,OAAO,YAAA,IAAgB,mBAAA;AACrC,EAAA,MAAM,cAAc,MAA0B;AAC5C,IAAA,MAAM,IAAI,MAAA,CAAO,SAAA;AACjB,IAAA,IAAI,CAAA,KAAM,OAAO,OAAO,IAAA;AACxB,IAAA,IAAI,CAAA,IAAK,KAAA,IAAS,CAAA,EAAG,OAAO,CAAA;AAC5B,IAAA,OAAO,iBAAA,CAAkB,EAAE,KAAA,EAAO,IAAA,CAAK,IAAI,CAAA,EAAG,CAAA,EAAG,KAAA,IAAS,EAAE,GAAG,QAAA,EAAU,CAAA,EAAG,QAAA,IAAY,EAAA,GAAK,KAAQ,CAAA;AAAA,EACvG,CAAA;AACA,EAAA,MAAM,UAAU,WAAA,EAAY;AAC5B,EAAA,MAAM,GAAA,GACJ,MAAA,CAAO,GAAA,KACN,CAAC,KAAA,KAAU;AACV,IAAA,OAAA,CAAQ,IAAA,CAAK,IAAA,CAAK,SAAA,CAAU,KAAK,CAAC,CAAA;AAAA,EACpC,CAAA,CAAA;AAEF,EAAA,MAAM,IAAA,GAAO,CAAC,IAAA,EAAe,IAAA,GAAwE,EAAC,KAAM;AAC1G,IAAA,MAAM,OAAA,GAAU,IAAI,OAAA,CAAQ,IAAA,CAAK,OAAO,CAAA;AACxC,IAAA,OAAA,CAAQ,GAAA,CAAI,iBAAiB,KAAK,CAAA;AAClC,IAAA,OAAA,CAAQ,GAAA,CAAI,gBAAgB,kBAAkB,CAAA;AAC9C,IAAA,OAAO,IAAI,QAAA,CAAS,IAAA,CAAK,SAAA,CAAU,IAAI,CAAA,EAAG,EAAE,MAAA,EAAQ,IAAA,CAAK,MAAA,IAAU,GAAA,EAAK,OAAA,EAAS,CAAA;AAAA,EACnF,CAAA;AACA,EAAA,MAAM,IAAA,GAAO,CAACA,OAAAA,EAAgB,IAAA,EAAc,SAAiB,KAAA,GAA0C,OAAO,IAAA,CAAK,EAAE,OAAO,EAAE,IAAA,EAAM,SAAQ,EAAE,EAAG,EAAE,MAAA,EAAAA,OAAAA,EAAQ,OAAA,EAAS,KAAA,EAAO,CAAA;AAE3K,EAAA,eAAe,IAAI,OAAA,EAAqC;AACtD,IAAA,MAAM,IAAA,GAAO,MAAA,CAAO,IAAA,CAAK,OAAO,CAAA;AAChC,IAAA,IAAI,CAAC,WAAW,OAAA,EAAS,IAAI,GAAG,OAAO,IAAA,CAAK,GAAA,EAAK,WAAA,EAAa,QAAQ,CAAA;AACtE,IAAA,IAAI,OAAA,EAAS;AACX,MAAA,MAAM,OAAO,OAAA,CAAQ,GAAA,CAAI,UAAU,OAAA,EAAS,MAAA,CAAO,UAAU,CAAC,CAAA;AAC9D,MAAA,IAAI,CAAC,IAAA,CAAK,OAAA,EAAS,OAAO,KAAK,GAAA,EAAK,mBAAA,EAAqB,GAAA,CAAI,eAAA,EAAiB,EAAE,aAAA,EAAe,MAAA,CAAO,IAAA,CAAK,aAAa,GAAG,CAAA;AAAA,IAC7H;AACA,IAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,UAAA,CAAW,OAAO,CAAA;AAC9C,IAAA,IAAI,CAAC,MAAA,EAAQ,OAAO,KAAK,GAAA,EAAK,SAAA,EAAW,IAAI,WAAW,CAAA;AAExD,IAAA,IAAI,IAAA;AACJ,IAAA,IAAI;AACF,MAAA,IAAA,GAAQ,MAAM,QAAQ,IAAA,EAAK;AAAA,IAC7B,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,IAAA,CAAK,GAAA,EAAK,YAAA,EAAc,GAAA,CAAI,UAAU,CAAA;AAAA,IAC/C;AACA,IAAA,MAAM,OAAA,GAAU,OAAO,IAAA,CAAK,OAAA,KAAY,QAAA,IAAY,OAAA,CAAQ,IAAA,CAAK,IAAA,CAAK,OAAO,CAAA,GAAI,IAAA,CAAK,OAAA,GAAU,IAAA;AAChG,IAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,IAAA,CAAK,cAAc,CAAA;AAC5C,IAAA,MAAM,OAAO,IAAA,CAAK,aAAA;AAClB,IAAA,IAAI,IAAA,CAAK,MAAA,KAAW,MAAA,IAAU,CAAC,WAAW,CAAC,QAAA,IAAY,CAAC,IAAA,IAAQ,OAAO,IAAA,KAAS,QAAA,IAAY,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA,EAAG;AAC/G,MAAA,OAAO,IAAA,CAAK,GAAA,EAAK,YAAA,EAAc,GAAA,CAAI,UAAU,CAAA;AAAA,IAC/C;AAEA,IAAA,MAAM,EAAE,kBAAA,EAAoB,QAAA,EAAU,GAAG,cAAa,GAAI,IAAA;AAC1D,IAAA,MAAM,SAAiC,EAAC;AACxC,IAAA,KAAA,MAAW,CAAC,CAAA,EAAG,CAAC,KAAK,MAAA,CAAO,OAAA,CAAS,KAAK,MAAA,IAAU,EAA8B,CAAA,EAAG,IAAI,OAAO,CAAA,KAAM,QAAA,SAAiB,CAAC,CAAA,GAAI,EAAE,IAAA,EAAK;AACnI,IAAA,MAAM,OAAA,GAAU,MAAA,CAAO,cAAA,CAAe,MAAM,CAAA;AAC5C,IAAA,IAAI,OAAA,EAAS,OAAO,IAAA,CAAK,GAAA,EAAK,cAAc,OAAO,CAAA;AAEnD,IAAA,MAAM,EAAA,GAAK,MAAM,MAAA,CAAO,MAAA,CAAO,OAAO,CAAA;AACtC,IAAA,MAAM,MAAA,GAAS,WAAA,CAAY,MAAA,CAAO,cAAc,CAAA;AAChD,IAAA,IAAI,OAAA;AACJ,IAAA,IAAI;AAEF,MAAA,MAAM,OAAA,GAAU,MAAM,EAAA,CAAG,KAAA,CAAM,eAAe,MAAM,CAAA;AACpD,MAAA,MAAM,IAAA,GAAO,eAAA,CAAgB,OAAA,CAAQ,OAAA,EAAS,MAAA,CAAO,OAAO,EAAE,IAAA,EAAM,MAAA,CAAO,IAAA,EAAK,GAAI,EAAE,CAAA,CAAE,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,SAAS,MAAA,IAAU,CAAA,CAAE,KAAA,KAAU,MAAA,CAAO,cAAc,CAAA;AAClK,MAAA,IAAI,CAAC,UAAU,CAAC,IAAA,SAAa,IAAA,CAAK,GAAA,EAAK,eAAA,EAAiB,GAAA,CAAI,iBAAiB,CAAA;AAI7E,MAAA,MAAM,QAAA,GAAW,MAAM,MAAA,CAAO,WAAA,CAAY,OAAO,CAAA;AACjD,MAAA,MAAM,WAAW,QAAA,IAAY,QAAA,CAAS,YAAY,MAAA,GAAS,QAAA,CAAS,MAAM,WAAA,GAAc,KAAA,CAAA;AACxF,MAAA,IAAI,UAAA;AACJ,MAAA,IAAI,YAAY,QAAA,EAAU;AACxB,QAAA,OAAA,GAAU,QAAA;AACV,QAAA,UAAA,GAAa,QAAA;AAAA,MACf,CAAA,MAAO;AACL,QAAA,MAAM,OAAO,WAAA,CAAY,EAAE,EAAA,EAAI,MAAA,EAAQ,QAAQ,CAAA;AAC/C,QAAA,MAAM,MAAA,GAAS,MAAM,EAAA,CAAG,KAAA,CAAM,IAAI,MAAM,CAAA,CAAE,KAAA,CAAM,MAAM,IAAI,CAAA;AAC1D,QAAA,MAAM,OAAA,GAAU,MAAM,EAAA,CAAG,KAAA,CAAM,QAAA;AAAA,UAC7B,MAAA;AAAA,UACA,EAAE,cAAA,EAAgB,IAAA,CAAK,SAAA,EAAW,YAAA,EAAc,YAAY,cAAA,EAAgB,MAAA,EAAQ,cAAA,EAAgB,QAAA,EAAU,YAAY,CAAA,EAAG,IAAI,CAAA,EAAG,MAAA,CAAO,UAAU,CAAA,CAAA,EAAG;AAAA,UACxJ,EAAE,cAAA,EAAgB,CAAA,IAAA,EAAO,MAAM,CAAA,CAAA;AAAG,SACpC;AACA,QAAA,UAAA,GAAa,QAAQ,QAAA,CAAS,EAAA;AAC9B,QAAA,OAAA,GAAU,EAAE,OAAA,EAAS,MAAA,EAAQ,KAAA,EAAO,MAAA,CAAO,WAAA,CAAY,EAAE,OAAA,EAAS,MAAA,EAAQ,MAAA,EAAQ,CAAA,EAAE;AAAA,MACtF;AAEA,MAAA,MAAM,MAAA,GAAS,eAAA,CAAgB,IAAA,CAAK,iBAAiB,CAAA;AACrD,MAAA,MAAM,MAAA,GAAS,MAAM,EAAA,CAAG,SAAA,CAAU,GAAA;AAAA,QAChC,UAAA;AAAA,QACA,EAAE,MAAA,EAAQ,MAAA,EAAQ,aAAA,EAAe,cAAc,GAAI,MAAA,GAAS,EAAE,iBAAA,EAAmB,MAAA,EAAO,GAAI,EAAC,EAAI,gBAAgB,QAAA,EAAS;AAAA,QAC1H,EAAE,cAAA,EAAgBC,gCAAA,CAAsB,UAAA,EAAY,OAAO,CAAA;AAAE,OAC/D;AAEA,MAAA,MAAM,OAAA,GAAU,IAAI,OAAA,EAAQ;AAC5B,MAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,MAAA,CAAO,EAAE,OAAO,OAAA,CAAQ,KAAA,EAAO,MAAA,EAAQ,OAAA,EAAS,CAAA;AAC5E,MAAA,IAAI,CAAC,QAAQ,OAAA,CAAQ,MAAA,CAAO,cAAc,MAAM,MAAA,CAAO,gBAAA,CAAiB,OAAO,CAAC,CAAA;AAChF,MAAA,OAAO,IAAA,CAAK,MAAA,EAAQ,EAAE,OAAA,EAAS,CAAA;AAAA,IACjC,SAAS,GAAA,EAAK;AACZ,MAAA,IAAIC,4BAAA,CAAkB,GAAG,CAAA,EAAG;AAC1B,QAAA,MAAM,EAAE,MAAA,EAAAF,OAAAA,EAAQ,MAAM,OAAA,EAAQ,GAAI,iBAAiB,GAAG,CAAA;AACtD,QAAA,GAAA,CAAI,EAAE,KAAA,EAAO,MAAA,EAAQ,GAAA,EAAK,yBAAA,EAA2B,QAAQ,GAAA,CAAI,MAAA,EAAQ,IAAA,EAAM,GAAA,CAAI,IAAA,IAAQ,IAAA,EAAM,OAAO,GAAA,CAAI,KAAA,IAAS,IAAA,EAAM,OAAA,EAAS,MAAA,CAAO,GAAA,CAAI,OAAO,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,GAAG,CAAA,EAAG,CAAA;AAGvK,QAAA,MAAM,OAAA,GAAU,IAAI,OAAA,EAAQ;AAC5B,QAAA,IAAI,OAAA,UAAiB,MAAA,CAAO,YAAA,EAAc,MAAM,MAAA,CAAO,gBAAA,CAAiB,OAAO,CAAC,CAAA;AAChF,QAAA,OAAO,KAAK,OAAA,EAAS,EAAE,MAAA,EAAAA,OAAAA,EAAQ,SAAS,CAAA;AAAA,MAC1C;AACA,MAAA,MAAM,GAAA;AAAA,IACR;AAAA,EACF;AAEA,EAAA,eAAe,OAAO,OAAA,EAAqC;AACzD,IAAA,IAAI,CAAC,UAAA,CAAW,OAAA,EAAS,MAAA,CAAO,IAAA,CAAK,OAAO,CAAC,CAAA,EAAG,OAAO,IAAA,CAAK,GAAA,EAAK,WAAA,EAAa,QAAQ,CAAA;AACtF,IAAA,MAAM,OAAA,GAAU,MAAM,MAAA,CAAO,WAAA,CAAY,OAAO,CAAA;AAChD,IAAA,MAAM,EAAA,GAAK,SAAS,KAAA,CAAM,WAAA;AAC1B,IAAA,IAAI,CAAC,WAAW,CAAC,EAAA,SAAW,IAAA,CAAK,GAAA,EAAK,WAAA,EAAa,GAAA,CAAI,WAAW,CAAA;AAClE,IAAA,IAAI;AACF,MAAA,MAAM,EAAA,GAAK,MAAM,MAAA,CAAO,MAAA,CAAO,OAAO,CAAA;AACtC,MAAA,MAAM,KAAA,GAAQ,MAAM,EAAA,CAAG,SAAA,CAAU,IAAI,EAAE,CAAA;AACvC,MAAA,IAAI,CAAC,KAAA,EAAO,OAAO,KAAK,GAAA,EAAK,WAAA,EAAa,IAAI,WAAW,CAAA;AACzD,MAAA,MAAM,OAAA,GAAU,kBAAkB,KAAK,CAAA;AACvC,MAAA,MAAM,OAAA,GAAU,IAAI,OAAA,EAAQ;AAC5B,MAAA,MAAM,MAAA,CAAO,OAAO,EAAE,KAAA,EAAO,QAAQ,KAAA,EAAO,MAAA,EAAQ,OAAA,EAAS,OAAA,EAAS,CAAA;AACtE,MAAA,OAAO,IAAA,CAAK,OAAA,EAAS,EAAE,OAAA,EAAS,CAAA;AAAA,IAClC,SAAS,GAAA,EAAK;AACZ,MAAA,IAAIE,4BAAA,CAAkB,GAAG,CAAA,EAAG;AAC1B,QAAA,MAAM,EAAE,MAAA,EAAQ,IAAA,EAAM,IAAA,EAAK,GAAI,iBAAiB,GAAG,CAAA;AACnD,QAAA,OAAO,IAAA,CAAK,IAAA,EAAM,EAAE,MAAA,EAAQ,MAAM,CAAA;AAAA,MACpC;AACA,MAAA,MAAM,GAAA;AAAA,IACR;AAAA,EACF;AAEA,EAAA,eAAe,KAAK,IAAA,EAAwE;AAC1F,IAAA,MAAM,EAAE,EAAA,EAAI,OAAA,EAAS,QAAQ,MAAA,EAAQ,MAAA,EAAQ,QAAO,GAAI,IAAA;AACxD,IAAA,MAAM,YAAA,GAAe,gBAAA,CAAiB,MAAA,CAAO,MAAA,EAAQ,OAAO,UAAU,CAAA;AACtE,IAAA,IAAI,CAAC,YAAA,EAAc,OAAO,EAAE,MAAM,OAAA,EAAS,MAAA,EAAQ,GAAA,EAAK,OAAA,EAAS,GAAA,CAAI,eAAA,EAAiB,MAAA,EAAQ,CAAC,YAAY,CAAA,EAAE;AAC7G,IAAA,MAAM,OAAA,GAAU,MAAM,EAAA,CAAG,KAAA,CAAM,QAAA;AAAA,MAC7B,MAAA;AAAA,MACA,EAAE,cAAA,EAAgB,MAAA,CAAO,SAAA,EAAW,YAAA,EAAc,YAAY,cAAA,EAAgB,MAAA,EAAQ,UAAA,EAAY,CAAA,EAAG,OAAO,IAAA,CAAK,OAAO,CAAC,CAAA,EAAG,MAAA,CAAO,UAAU,CAAA,CAAA,EAAG;AAAA,MAChJ,EAAE,cAAA,EAAgB,CAAA,IAAA,EAAO,MAAM,CAAA,KAAA,CAAA;AAAQ,KACzC;AACA,IAAA,MAAM,QAAQ,MAAA,CAAO,WAAA,CAAY,EAAE,OAAA,EAAS,MAAA,EAAQ,QAAQ,CAAA;AAE5D,IAAA,MAAM,MAAA,GAAS,MAAM,EAAA,CAAG,SAAA,CAAU,IAAI,OAAA,CAAQ,QAAA,CAAS,EAAA,EAAI,EAAE,MAAA,EAAQ,MAAA,EAAQ,eAAe,YAAA,EAAa,EAAG,EAAE,cAAA,EAAgBD,gCAAA,CAAsB,QAAQ,QAAA,CAAS,EAAA,EAAI,MAAM,CAAA,EAAG,CAAA;AAClL,IAAA,MAAM,OAAA,GAAU,IAAI,OAAA,EAAQ;AAC5B,IAAA,IAAI,MAAM,MAAA,CAAO,MAAA,CAAO,EAAE,KAAA,EAAO,MAAA,EAAQ,OAAA,EAAS,CAAA,EAAG,OAAO,EAAE,IAAA,EAAM,QAAQ,OAAA,EAAQ;AACpF,IAAA,MAAM,OAAA,GAAUE,yBAAA,CAAe,MAAA,EAAQ,MAAM,CAAA;AAC7C,IAAA,OAAO,EAAE,IAAA,EAAM,OAAA,EAAS,MAAA,EAAQC,wBAAa,OAAA,CAAQ,YAAY,CAAA,GAAI,GAAA,GAAM,KAAK,OAAA,EAAS,OAAA,CAAQ,OAAA,EAAS,MAAA,EAAQ,EAAC,EAAE;AAAA,EACvH;AAEA,EAAA,OAAO,EAAE,GAAA,EAAK,MAAA,EAAQ,IAAA,EAAK;AAC7B","file":"payments-server.cjs","sourcesContent":["/**\n * \"Payment method\" rows for a hybrid checkout: pure functions, no DOM and no server, so the loader, the action and the\n * browser share them.\n *\n * Rules (embedded-payment contract 1.2):\n * - Rows come ONLY from what the server publishes (`payment-methods[].options` and `.client`). No provider names and no\n * amounts live here.\n * - Card and cash are paid in the page; `wallet` and `credits` redirect to the provider.\n * - Without `client`, or with the card flagged `redirect: true`, the server does not offer `embedded`: the shop falls\n * back to the usual redirect flow.\n */\nimport type {\n CheckoutResult,\n PaymentAttemptResult,\n PaymentClient,\n PaymentMethod,\n PaymentOption,\n PaymentOptionKey,\n PaymentPoint,\n} from '@asteby/storefront'\n\n/** One row of \"Payment method\". `value` is what travels in the form (`payment_choice`). */\nexport type PayChoice = {\n value: string\n /** Server method key (`payment_method` of the checkout). */\n methodKey: string\n /** Provider option; `null` for a method without options (the plain flow). */\n option: PaymentOptionKey | null\n /** `card` (form in the page), `cash` (voucher), `redirect` (leaves to the gateway) or `plain`. */\n mode: 'card' | 'cash' | 'redirect' | 'plain'\n /** The provider's own text (`option.label`); the shop supplies its own when missing. */\n label: string | null\n points: PaymentPoint[]\n maxInstallments: number | null\n}\n\nexport type PayChoices = {\n choices: PayChoice[]\n /** Public data to mount the card form; `null` when the server does not offer `embedded`. */\n cardClient: PaymentClient | null\n defaultValue: string | null\n}\n\nexport type BuildPayChoicesOptions = {\n /** Method keys this shop never offers even when the server publishes them (e.g. a manual transfer). */\n hide?: Iterable<string>\n}\n\nconst SEP = '|'\n\nexport function choiceValue(methodKey: string, option: PaymentOptionKey | null): string {\n return option ? `${methodKey}${SEP}${option}` : methodKey\n}\n\n/** `\"mercadopago|card\"` becomes method and option. A value without `|` is a method without options. */\nexport function parseChoice(value: string | null | undefined): { methodKey: string; option: PaymentOptionKey | null } | null {\n const raw = (value ?? '').trim()\n if (!raw) return null\n const i = raw.lastIndexOf(SEP)\n if (i === -1) return { methodKey: raw, option: null }\n const option = raw.slice(i + 1)\n if (option !== 'card' && option !== 'cash' && option !== 'wallet' && option !== 'credits') return null\n return { methodKey: raw.slice(0, i), option }\n}\n\nfunction modeOf(option: PaymentOption): PayChoice['mode'] {\n if (option.redirect || option.key === 'wallet' || option.key === 'credits') return 'redirect'\n return option.key === 'cash' ? 'cash' : 'card'\n}\n\n/**\n * Rows from `GET payment-methods`. A method with `options` unfolds into one row per option (server order); one without\n * is a single plain row. `cardClient` only exists when the card is paid in the page.\n */\nexport function buildPayChoices(methods: readonly PaymentMethod[], options: BuildPayChoicesOptions = {}): PayChoices {\n const hidden = new Set(options.hide ?? [])\n const choices: PayChoice[] = []\n let cardClient: PaymentClient | null = null\n let defaultValue: string | null = null\n for (const method of methods) {\n if (hidden.has(method.key)) continue\n const opts = method.options ?? []\n if (opts.length === 0) {\n const value = choiceValue(method.key, null)\n choices.push({ value, methodKey: method.key, option: null, mode: 'plain', label: null, points: [], maxInstallments: null })\n if (method.default && !defaultValue) defaultValue = value\n continue\n }\n opts.forEach((option, i) => {\n const mode = modeOf(option)\n const value = choiceValue(method.key, option.key)\n choices.push({\n value,\n methodKey: method.key,\n option: option.key,\n mode,\n label: option.label?.trim() || null,\n points: option.key === 'cash' ? (option.points ?? []) : [],\n maxInstallments: option.max_installments ?? null,\n })\n if (mode === 'card' && method.client && !cardClient) cardClient = method.client\n if (method.default && i === 0 && !defaultValue) defaultValue = value\n })\n }\n // A card meant for the page but without `client` cannot be mounted: it is paid by redirect.\n const usable = choices.map((c) => (c.mode === 'card' && !cardClient ? { ...c, mode: 'redirect' as const } : c))\n return { choices: usable, cardClient, defaultValue: defaultValue ?? usable[0]?.value ?? null }\n}\n\n/** Chosen cash point becomes the cash `provider_data`, built on the server from the provider's list. */\nexport function cashProviderData(points: readonly PaymentPoint[], pointId: string | null | undefined): Record<string, string> | null {\n const point = points.find((p) => p.id === pointId) ?? (pointId ? null : points[0])\n if (!point) return null\n return {\n payment_method_id: point.payment_method_id,\n ...(point.payment_point ? { payment_point: point.payment_point } : {}),\n }\n}\n\n/**\n * A checkout (`GET checkouts/:id`) as an attempt result, for polling a 3DS challenge or a payment under review.\n * It only translates server states: it never decides a payment.\n */\nexport function checkoutToAttempt(result: CheckoutResult): PaymentAttemptResult {\n const { checkout, payment, order } = result\n const action = payment.action ?? null\n const base = { checkout, ...(order ? { order } : {}) }\n const status = (checkout.status ?? '').toLowerCase()\n if (status === 'paid' || status === 'converted') return { ...base, payment: { provider: payment.provider, status: 'paid', outcome: 'approved' } }\n if (status === 'cancelled' || status === 'canceled') return { ...base, payment: { provider: payment.provider, status: 'cancelled' } }\n if (status === 'expired') return { ...base, payment: { provider: payment.provider, status: 'expired' } }\n if (status === 'failed') {\n const decline = (payment as { decline_code?: PaymentAttemptResult['payment']['decline_code'] }).decline_code ?? 'declined'\n return { ...base, payment: { provider: payment.provider, status: 'failed', outcome: 'rejected', decline_code: decline, retryable: true } }\n }\n // Still pending: same as the last attempt left it (challenge or review), so the screen does not change.\n if (action?.type === 'challenge') return { ...base, payment: { provider: payment.provider, status: 'requires_action', outcome: 'challenge', action } }\n return { ...base, payment: { provider: payment.provider, status: 'pending', outcome: 'pending', action: action ?? { type: 'none' } } }\n}\n\n/** Body `{ error: { code, message, details } }` that `createFetchTransport` understands. */\nexport type PayErrorBody = { error: { code: string; message: string; details?: unknown } }\n\ntype ErrorLike = { status?: number; code?: string; field?: string; message?: string; details?: unknown }\n\n/**\n * Server error becomes a JSON response for the browser. Keeps the codes the SDK knows how to read (`price_mismatch`,\n * `payment_in_progress`, `expired`, `too_many_attempts`); the mock sends \"in progress\" in `field`, so that is checked too.\n */\nexport function payErrorResponse(err: ErrorLike): { status: number; body: PayErrorBody } {\n const status = typeof err.status === 'number' && err.status >= 400 ? err.status : 503\n let code = err.code ?? 'server_error'\n if (status === 409 && err.field === 'payment_in_progress') code = 'payment_in_progress'\n if (status === 429) code = 'too_many_attempts'\n if (status === 422 && err.field === 'expected_total') code = 'price_mismatch'\n return { status, body: { error: { code, message: err.message ?? '', ...(err.details !== undefined ? { details: err.details } : {}) } } }\n}\n\nexport type VoucherRowLabels = { point: string; reference: string; clabe: string; barcode: string; expires: string }\n\n/** Cookie receipt rows for a payment under review or with a voucher (shown on the thank-you page). */\nexport function voucherRows(\n voucher: NonNullable<NonNullable<PaymentAttemptResult['payment']['action']>['voucher']> | null | undefined,\n labels: VoucherRowLabels,\n locale: string,\n): [label: string, value: string][] {\n if (!voucher) return []\n const rows: [string, string][] = []\n if (voucher.payment_point) rows.push([labels.point, String(voucher.payment_point).slice(0, 60)])\n if (voucher.reference) rows.push([labels.reference, String(voucher.reference).slice(0, 80)])\n if (voucher.clabe) rows.push([labels.clabe, String(voucher.clabe).slice(0, 40)])\n if (voucher.barcode) rows.push([labels.barcode, String(voucher.barcode).slice(0, 80)])\n if (voucher.expires_at) {\n const d = new Date(voucher.expires_at)\n if (!Number.isNaN(d.getTime())) {\n rows.push([labels.expires, new Intl.DateTimeFormat(locale, { dateStyle: 'long', timeStyle: 'short', timeZone: 'UTC' }).format(d) + ' UTC'])\n }\n }\n return rows\n}\n","import type { PaymentClient } from '@asteby/storefront'\n\nexport type PaymentCspOptions = {\n /** Per-request nonce; also set it on the inserted `<script>` and on `<Scripts nonce>`. */\n nonce?: string\n /** Extra origins by directive (e.g. your image CDN). */\n extra?: { script?: string[]; frame?: string[]; connect?: string[]; img?: string[]; form?: string[] }\n /** `report-uri` / `report-to` target for the report-only rollout. */\n reportUri?: string\n /** Inline scripts allowed by hash (`'sha256-…'`), e.g. a theme bootstrap that runs before paint. */\n scriptHashes?: string[]\n /** Allow any https image source (product photos from a CDN). */\n imgHttps?: boolean\n}\n\n/** One origin source: `https://host`, `https://*.host`, optional port. Anything else (`;`, spaces, `'unsafe-eval'`) is dropped. */\nconst ORIGIN = /^https:\\/\\/(\\*\\.)?[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*(:\\d{1,5})?$/i\n\nfunction origins(...lists: (readonly string[] | undefined)[]): string[] {\n const out = new Set<string>()\n for (const list of lists) for (const o of list ?? []) if (ORIGIN.test(o)) out.add(o)\n return [...out]\n}\n\n/**\n * Builds the Content-Security-Policy for the payment routes from what each provider declares\n * (`PaymentClient.csp`), so the shop never hard-codes provider hosts. Meant for `/pagar` only,\n * never for the whole site. Roll out as `Content-Security-Policy-Report-Only` first.\n *\n * No SRI on purpose: provider SDK URLs are unversioned and a hash would break payments on any update.\n */\nexport function paymentCsp(clients: readonly (PaymentClient | null | undefined)[], options: PaymentCspOptions = {}): string {\n const list = clients.filter((c): c is PaymentClient => !!c)\n const pick = (k: keyof NonNullable<PaymentClient['csp']>) => list.map((c) => c.csp?.[k])\n const nonce = options.nonce && /^[A-Za-z0-9+/=_-]+$/.test(options.nonce) ? options.nonce : undefined\n const sdkOrigins = list.flatMap((c) => {\n try {\n const u = new URL(c.sdk_url)\n return u.protocol === 'https:' ? [u.origin] : []\n } catch {\n return []\n }\n })\n const dir = (name: string, values: string[]) => `${name} ${values.join(' ')}`\n const parts = [\n \"default-src 'self'\",\n dir('script-src', [\"'self'\", ...(options.scriptHashes ?? []).filter((h) => /^'sha(256|384|512)-[A-Za-z0-9+/=]+'$/.test(h)), ...(nonce ? [`'nonce-${nonce}'`] : []), ...origins(sdkOrigins, ...pick('script'), options.extra?.script)]),\n dir('frame-src', origins(...pick('frame'), options.extra?.frame).length ? origins(...pick('frame'), options.extra?.frame) : [\"'none'\"]),\n dir('connect-src', [\"'self'\", ...origins(...pick('connect'), options.extra?.connect)]),\n dir('img-src', [\"'self'\", 'data:', ...(options.imgHttps ? ['https:'] : []), ...origins(...pick('img'), options.extra?.img)]),\n \"style-src 'self' 'unsafe-inline'\",\n dir('form-action', [\"'self'\", ...origins(...pick('form'), options.extra?.form)]),\n \"frame-ancestors 'none'\",\n \"base-uri 'self'\",\n \"object-src 'none'\",\n ]\n if (options.reportUri && /^(https:\\/\\/|\\/)[^\\s;,]+$/.test(options.reportUri)) parts.push(`report-uri ${options.reportUri}`)\n return parts.join('; ')\n}\n\n/** `Content-Security-Policy` or, during the rollout week, `Content-Security-Policy-Report-Only`. */\nexport function paymentCspHeaderName(reportOnly: boolean): string {\n return reportOnly ? 'Content-Security-Policy-Report-Only' : 'Content-Security-Policy'\n}\n\nexport type PaymentCspMode = 'off' | 'report-only' | 'enforce'\n\n/** `PAYMENT_CSP`-style value: `off`, `report-only` or `enforce`. Unset: report-only in production, off elsewhere (dev servers inject scripts). */\nexport function paymentCspMode(value: string | null | undefined, production: boolean): PaymentCspMode {\n const raw = (value ?? '').trim().toLowerCase()\n if (raw === 'off' || raw === 'report-only' || raw === 'enforce') return raw\n return production ? 'report-only' : 'off'\n}\n\n/** Fresh per-request nonce (128 bits, base64). Works in Node, edge and browsers. */\nexport function paymentNonce(): string {\n const bytes = new Uint8Array(16)\n crypto.getRandomValues(bytes)\n let bin = ''\n for (const b of bytes) bin += String.fromCharCode(b)\n return btoa(bin)\n}\n\n/** Header ready for the response (`{}` when `off`): policy from the providers' `client.csp`, never the whole site. */\nexport function paymentCspHeaders(\n clients: readonly (PaymentClient | null | undefined)[],\n options: PaymentCspOptions & { mode: PaymentCspMode },\n): Record<string, string> {\n if (options.mode === 'off') return {}\n return { [paymentCspHeaderName(options.mode === 'report-only')]: paymentCsp(clients, options) }\n}\n\n/** The nonce the route left in the CSP header, to hand to `ServerRouter` / `<Scripts>`. */\nexport function paymentNonceFromHeaders(headers: Headers): string | undefined {\n const csp = headers.get('Content-Security-Policy') ?? headers.get('Content-Security-Policy-Report-Only') ?? ''\n return /'nonce-([A-Za-z0-9+/=_-]+)'/.exec(csp)?.[1]\n}\n","/**\n * Server side of the embedded payment (`@asteby/storefront-react/payments/server`): the two JSON resource routes the\n * browser talks to (charge the card, re-read the payment) and the cash voucher of the page form. No React, no router:\n * Web `Request`/`Response` only, so any framework mounts it.\n *\n * The browser NEVER calls OPS. These handlers translate to `carts.checkout` + `checkouts.pay` with the shop's `sk_` token.\n *\n * Money: no amount is computed here. `expected_total` is the total the server showed the buyer (echoed back by the SDK);\n * OPS compares it with the order and answers `422 price_mismatch` when it changed.\n *\n * Everything shop-specific (cookies, receipt shape, which fields the form requires, how contact/delivery are saved)\n * arrives through `EmbeddedPayConfig` callbacks.\n */\nimport {\n isStorefrontError,\n paymentIdempotencyKey,\n paymentOutcome,\n safeHttpsUrl,\n type Cart,\n type CheckoutResult,\n type Money,\n type PaymentAttemptResult,\n type StorefrontClient,\n} from '@asteby/storefront'\nimport { buildPayChoices, cashProviderData, checkoutToAttempt, parseChoice, payErrorResponse, type PayChoice } from './choices.js'\n\nexport * from './choices.js'\nexport { paymentCsp, paymentCspHeaderName, paymentCspHeaders, paymentCspMode, paymentNonce, paymentNonceFromHeaders } from './csp.js'\nexport type { PaymentCspMode, PaymentCspOptions } from './csp.js'\n\nexport type RateLimiter = { hit(key: string, now?: number): { allowed: boolean; retryAfterSec: number } }\n\n/** In-memory sliding window per key. Protects this process; OPS puts its own cap per checkout on top. */\nexport function createRateLimiter({ limit, windowMs }: { limit: number; windowMs: number }): RateLimiter {\n const hits = new Map<string, number[]>()\n return {\n hit(key, now = Date.now()) {\n const recent = (hits.get(key) ?? []).filter((t) => now - t < windowMs)\n if (recent.length >= limit) {\n hits.set(key, recent)\n return { allowed: false, retryAfterSec: Math.max(1, Math.ceil((recent[0]! + windowMs - now) / 1000)) }\n }\n recent.push(now)\n hits.set(key, recent)\n if (hits.size > 5000) for (const [k, v] of hits) if (v.every((t) => now - t >= windowMs)) hits.delete(k)\n return { allowed: true, retryAfterSec: 0 }\n },\n }\n}\n\n/** Buyer IP as forwarded by a trusted proxy/CDN; without `trustProxy` a single shared key. */\nexport function clientKey(request: Request, trustProxy = false): string {\n if (!trustProxy) return 'direct'\n const cf = request.headers.get('cf-connecting-ip')\n if (cf) return cf.trim()\n return request.headers.get('x-forwarded-for')?.split(',')[0]?.trim() || 'direct'\n}\n\n/**\n * A request from another site cannot pay with the buyer's cookie. Only the HOST is compared (no scheme or port): behind\n * the proxy the request scheme can be http while the browser sent https.\n */\nexport function sameOrigin(request: Request, site: string): boolean {\n const origin = request.headers.get('origin')\n if (!origin) return true\n try {\n const host = new URL(origin).hostname\n return host === new URL(site).hostname || host === new URL(request.url).hostname\n } catch {\n return false\n }\n}\n\n/** Device fingerprint (anti-fraud): OPTIONAL, so it never breaks a payment. Anything over 200 chars or odd is dropped. */\nexport const DEVICE_SESSION_ID_MAX = 200\nexport function deviceSessionId(v: unknown): string | undefined {\n if (typeof v !== 'string') return undefined\n const id = v.trim()\n return id.length > 0 && id.length <= DEVICE_SESSION_ID_MAX && /^[\\w.:-]+$/.test(id) ? id : undefined\n}\n\nconst ATTEMPT = /^[A-Za-z0-9_-]{8,100}$/\n\nconst asMoney = (v: unknown): Money | null => {\n const m = v as Partial<Money> | null\n return m && typeof m.amount === 'string' && /^\\d+(\\.\\d+)?$/.test(m.amount) && typeof m.currency_code === 'string' && m.currency_code.length === 3\n ? { amount: m.amount, currency_code: m.currency_code }\n : null\n}\n\n/** What the shop keeps between the checkout creation and the end of the payment (usually in a cookie). */\nexport type PaySession<TDraft extends { checkout_id?: string }> = { cart_id: string; draft: TDraft }\n\nexport type EmbeddedPayMessages = {\n /** Required form fields missing. */\n fillFields: string\n /** The cart cookie is gone or the checkout expired. */\n expiredCart: string\n /** The chosen row is not payable in the page (the server decides, not the browser). */\n methodUnavailable: string\n tooManyRequests: string\n cashChoosePoint: string\n}\n\nconst DEFAULT_MESSAGES: EmbeddedPayMessages = {\n fillFields: 'Completa los campos marcados.',\n expiredCart: 'Tu carrito venció. Vuelve a armarlo para pagar.',\n methodUnavailable: 'Esta forma de pago no está disponible por ahora.',\n tooManyRequests: 'Demasiados intentos. Espera unos minutos e inténtalo de nuevo.',\n cashChoosePoint: 'Elige dónde pagar en efectivo.',\n}\n\nexport type EmbeddedPayConfig<TDraft extends { checkout_id?: string }> = {\n /** The store client with the `sk_` token for this request. */\n client: (request: Request) => Promise<StorefrontClient>\n /** Public origin of the shop (`https://tienda.com`). Used for `return_url` and the origin check. */\n site: (request: Request) => string\n /** Path of the thank-you page, appended to `site`. */\n returnPath: string\n /** Locale for the outcome texts and voucher dates. Default `es-MX`. */\n locale?: string\n readCartId: (request: Request) => Promise<string | null>\n readSession: (request: Request) => Promise<PaySession<TDraft> | null>\n /** `Set-Cookie` value that keeps the session so a retry reuses the already created checkout. */\n serializeSession: (session: PaySession<TDraft>) => Promise<string>\n /** `null` when the form is complete; otherwise the message to show (HTTP 400). The shop knows its required fields. */\n validateFields: (fields: Record<string, string>) => string | null\n /** Saves contact, address and delivery on the server cart (the cart becomes an order at checkout, so do it before). */\n prepareCart: (args: { sf: StorefrontClient; cartId: string; fields: Record<string, string> }) => Promise<void>\n /** First draft of the receipt from the created checkout and the cart as it was before. */\n createDraft: (args: { created: CheckoutResult; before: Cart | null; fields: Record<string, string> }) => TDraft\n /**\n * Called after every attempt. When the order is closed (approved, under review, voucher) append the receipt cookie and\n * clear the cart/session cookies to `headers` and return `true`; otherwise return `false` (the session is kept).\n */\n settle: (args: { draft: TDraft; result: PaymentAttemptResult; headers: Headers }) => Promise<boolean>\n /** Method keys the shop never offers (the server also checks them: a forged `payment_choice` is refused). */\n hide?: Iterable<string>\n messages?: Partial<EmbeddedPayMessages>\n /** Per-IP limit on charges. Default 10 per 10 minutes; `false` disables (OPS still caps attempts per checkout). */\n rateLimit?: RateLimiter | { limit?: number; windowMs?: number } | false\n /** Trust `cf-connecting-ip` / `x-forwarded-for` for the limiter key. */\n trustProxy?: boolean\n /** Cache header of every response. Default `private, no-store`. */\n cacheControl?: string\n /** Diagnostic log of an OPS rejection (no bodies, no buyer data). Default: one JSON line with `console.warn`. */\n log?: (entry: { level: 'warn'; msg: string; status: number; code: string | null; field: string | null; message: string }) => void\n}\n\nexport type CashOutcome = { kind: 'done'; headers: Headers } | { kind: 'error'; status: number; message: string; fields: string[] }\n\nexport type EmbeddedPayHandlers = {\n /** POST JSON from the card form: creates the checkout (idempotent per cart) and charges the attempt. */\n pay: (request: Request) => Promise<Response>\n /** POST: re-reads the checkout (3DS challenge, \"under review\") in the shape of an attempt. */\n status: (request: Request) => Promise<Response>\n /** Cash from the page form (with or without JavaScript): creates the `embedded/cash` checkout and asks for the voucher. */\n cash: (args: { sf: StorefrontClient; request: Request; cartId: string; fields: Record<string, string>; choice: PayChoice; before: Cart | null }) => Promise<CashOutcome>\n}\n\nexport function createEmbeddedPayHandlers<TDraft extends { checkout_id?: string }>(config: EmbeddedPayConfig<TDraft>): EmbeddedPayHandlers {\n const msg = { ...DEFAULT_MESSAGES, ...config.messages }\n const locale = config.locale ?? 'es-MX'\n const cache = config.cacheControl ?? 'private, no-store'\n const makeLimiter = (): RateLimiter | null => {\n const r = config.rateLimit\n if (r === false) return null\n if (r && 'hit' in r) return r\n return createRateLimiter({ limit: Math.max(1, r?.limit ?? 10), windowMs: r?.windowMs ?? 10 * 60_000 })\n }\n const limiter = makeLimiter()\n const log =\n config.log ??\n ((entry) => {\n console.warn(JSON.stringify(entry))\n })\n\n const json = (body: unknown, init: { status?: number; headers?: Headers | Record<string, string> } = {}) => {\n const headers = new Headers(init.headers)\n headers.set('Cache-Control', cache)\n headers.set('Content-Type', 'application/json')\n return new Response(JSON.stringify(body), { status: init.status ?? 200, headers })\n }\n const fail = (status: number, code: string, message: string, extra: Headers | Record<string, string> = {}) => json({ error: { code, message } }, { status, headers: extra })\n\n async function pay(request: Request): Promise<Response> {\n const site = config.site(request)\n if (!sameOrigin(request, site)) return fail(403, 'forbidden', 'origin')\n if (limiter) {\n const gate = limiter.hit(clientKey(request, config.trustProxy))\n if (!gate.allowed) return fail(429, 'too_many_attempts', msg.tooManyRequests, { 'Retry-After': String(gate.retryAfterSec) })\n }\n const cartId = await config.readCartId(request)\n if (!cartId) return fail(409, 'expired', msg.expiredCart)\n\n let body: { option?: unknown; attempt?: unknown; provider_data?: unknown; device_session_id?: unknown; expected_total?: unknown; fields?: unknown }\n try {\n body = (await request.json()) as typeof body\n } catch {\n return fail(400, 'validation', msg.fillFields)\n }\n const attempt = typeof body.attempt === 'string' && ATTEMPT.test(body.attempt) ? body.attempt : null\n const expected = asMoney(body.expected_total)\n const data = body.provider_data\n if (body.option !== 'card' || !attempt || !expected || !data || typeof data !== 'object' || Array.isArray(data)) {\n return fail(400, 'validation', msg.fillFields)\n }\n // The amount does not travel in `provider_data`: OPS sets it. Even if the browser (or a stray script) sends one, it is not forwarded.\n const { transaction_amount: _ignored, ...providerData } = data as Record<string, unknown>\n const fields: Record<string, string> = {}\n for (const [k, v] of Object.entries((body.fields ?? {}) as Record<string, unknown>)) if (typeof v === 'string') fields[k] = v.trim()\n const invalid = config.validateFields(fields)\n if (invalid) return fail(400, 'validation', invalid)\n\n const sf = await config.client(request)\n const choice = parseChoice(fields.payment_choice)\n let session: PaySession<TDraft> | undefined\n try {\n // The server decides what can be paid in the page: the browser only picks among what OPS published.\n const methods = await sf.carts.paymentMethods(cartId)\n const card = buildPayChoices(methods.methods, config.hide ? { hide: config.hide } : {}).choices.find((c) => c.mode === 'card' && c.value === fields.payment_choice)\n if (!choice || !card) return fail(422, 'invalid_state', msg.methodUnavailable)\n\n // A retry (the first charge failed or the network dropped) reuses the checkout already created: the cart is an\n // order by now and cannot be edited again. Only the attempt (the payment key) changes.\n const previous = await config.readSession(request)\n const reusedId = previous && previous.cart_id === cartId ? previous.draft.checkout_id : undefined\n let checkoutId: string\n if (previous && reusedId) {\n session = previous\n checkoutId = reusedId\n } else {\n await config.prepareCart({ sf, cartId, fields })\n const before = await sf.carts.get(cartId).catch(() => null)\n const created = await sf.carts.checkout(\n cartId,\n { payment_method: card.methodKey, payment_flow: 'embedded', payment_option: 'card', expected_total: expected, return_url: `${site}${config.returnPath}` },\n { idempotencyKey: `chk-${cartId}` },\n )\n checkoutId = created.checkout.id\n session = { cart_id: cartId, draft: config.createDraft({ created, before, fields }) }\n }\n\n const device = deviceSessionId(body.device_session_id)\n const result = await sf.checkouts.pay(\n checkoutId,\n { method: 'card', provider_data: providerData, ...(device ? { device_session_id: device } : {}), expected_total: expected },\n { idempotencyKey: paymentIdempotencyKey(checkoutId, attempt) },\n )\n\n const headers = new Headers()\n const closed = await config.settle({ draft: session.draft, result, headers })\n if (!closed) headers.append('Set-Cookie', await config.serializeSession(session))\n return json(result, { headers })\n } catch (err) {\n if (isStorefrontError(err)) {\n const { status, body: errBody } = payErrorResponse(err)\n log({ level: 'warn', msg: 'cobro rechazado por OPS', status: err.status, code: err.code ?? null, field: err.field ?? null, message: String(err.message).slice(0, 300) })\n // 5xx, network or timeout: the charge may have happened; the browser retries with the SAME key.\n // The checkout exists even when the charge fails: kept so the retry reuses it.\n const headers = new Headers()\n if (session) headers.append('Set-Cookie', await config.serializeSession(session))\n return json(errBody, { status, headers })\n }\n throw err\n }\n }\n\n async function status(request: Request): Promise<Response> {\n if (!sameOrigin(request, config.site(request))) return fail(403, 'forbidden', 'origin')\n const session = await config.readSession(request)\n const id = session?.draft.checkout_id\n if (!session || !id) return fail(404, 'not_found', msg.expiredCart)\n try {\n const sf = await config.client(request)\n const found = await sf.checkouts.get(id)\n if (!found) return fail(404, 'not_found', msg.expiredCart)\n const attempt = checkoutToAttempt(found)\n const headers = new Headers()\n await config.settle({ draft: session.draft, result: attempt, headers })\n return json(attempt, { headers })\n } catch (err) {\n if (isStorefrontError(err)) {\n const { status: code, body } = payErrorResponse(err)\n return json(body, { status: code })\n }\n throw err\n }\n }\n\n async function cash(args: Parameters<EmbeddedPayHandlers['cash']>[0]): Promise<CashOutcome> {\n const { sf, request, cartId, fields, choice, before } = args\n const providerData = cashProviderData(choice.points, fields.cash_point)\n if (!providerData) return { kind: 'error', status: 422, message: msg.cashChoosePoint, fields: ['cash_point'] }\n const created = await sf.carts.checkout(\n cartId,\n { payment_method: choice.methodKey, payment_flow: 'embedded', payment_option: 'cash', return_url: `${config.site(request)}${config.returnPath}` },\n { idempotencyKey: `chk-${cartId}-cash` },\n )\n const draft = config.createDraft({ created, before, fields })\n // One fixed key per checkout: a double submit returns the SAME voucher.\n const result = await sf.checkouts.pay(created.checkout.id, { method: 'cash', provider_data: providerData }, { idempotencyKey: paymentIdempotencyKey(created.checkout.id, 'cash') })\n const headers = new Headers()\n if (await config.settle({ draft, result, headers })) return { kind: 'done', headers }\n const outcome = paymentOutcome(result, locale)\n return { kind: 'error', status: safeHttpsUrl(outcome.redirect_url) ? 409 : 422, message: outcome.message, fields: [] }\n }\n\n return { pay, status, cash }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/payments/recovery-messages.ts","../src/payments/choices.ts","../src/payments/csp.ts","../src/payments/server.ts"],"names":["classifyPaymentError","status","body","PAYMENT_CHOICE_REFUSED_FIELD","paymentIdempotencyKey","isStorefrontError","paymentOutcome","safeHttpsUrl"],"mappings":"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","file":"payments-server.cjs","sourcesContent":["import type { PaymentErrorClassKind } from '@asteby/storefront'\n\n/** The notices `<PaymentRecovery>` can show. */\nexport type PaymentNoticeKind =\n /** Confirming the payment (automatic retry or status check). */\n | 'confirming'\n /** The secure card form did not load after the automatic retries. */\n | 'form_failed'\n /** The bank or provider rejected the charge (definitive): another card can be tried. */\n | 'rejected'\n /** The provider refused the charge at API level (definitive, nothing charged). */\n | 'provider_declined'\n /** Credentials or configuration of the merchant with the provider. */\n | 'merchant_config'\n /** The cart already became an order and the payment could not be reopened. */\n | 'stale_checkout'\n /** Another definitive error. */\n | 'other'\n\nexport type PaymentRecoveryMessageKey =\n | `error.${PaymentErrorClassKind}`\n | `notice.${PaymentNoticeKind}.title`\n | `notice.${PaymentNoticeKind}.body`\n | 'action.retry'\n | 'action.retry_form'\n | 'action.refresh'\n /** `{label}` is the name of the alternative payment choice. */\n | 'action.alternative'\n\nexport type PaymentRecoveryMessages = Record<PaymentRecoveryMessageKey, string>\n\nconst ES: PaymentRecoveryMessages = {\n 'error.transient': 'Estamos verificando tu pago. Si el cargo se hizo, lo veremos aquí; no te cobraremos dos veces.',\n 'error.in_progress': 'Ya hay un pago en proceso para este pedido. Estamos verificándolo; no vuelvas a pagar.',\n 'error.rate_limited': 'Hiciste varios intentos seguidos. Espera unos minutos e inténtalo de nuevo.',\n 'error.merchant_config': 'Por ahora no podemos procesar pagos con tarjeta. No es un problema con tu tarjeta: puedes pagar de otra forma.',\n 'error.provider_declined': 'No pudimos procesar tu pago con esa tarjeta. Revisa los datos o prueba con otro método; no se hizo ningún cobro.',\n 'error.stale_checkout': 'Este pedido ya quedó registrado y no se pudo reabrir el pago. Actualiza para ver cómo va tu pedido.',\n 'error.expired': 'Tu carrito venció. Vuelve a armarlo para pagar.',\n 'error.price_mismatch': 'El total cambió. Revisa el nuevo total y vuelve a pagar.',\n 'error.store_closed': 'Esta tienda aún no está abierta para compras. Vuelve pronto.',\n 'error.validation': 'Completa los campos marcados.',\n 'error.other': 'No pudimos procesar tu pago. Intenta de nuevo.',\n 'notice.confirming.title': 'Estamos confirmando tu pago…',\n 'notice.confirming.body': 'No cierres esta página ni vuelvas a pagar. Si el cargo ya se hizo, lo verás reflejado aquí.',\n 'notice.form_failed.title': 'No pudimos cargar el formulario de tarjeta',\n 'notice.form_failed.body': 'Suele resolverse al intentar de nuevo. También puedes pagar de otra forma.',\n 'notice.rejected.title': 'El cargo no se completó',\n 'notice.rejected.body': 'No se hizo ningún cobro. Puedes intentar con otra tarjeta o elegir otra forma de pago.',\n 'notice.provider_declined.title': 'No pudimos procesar tu pago con esa tarjeta',\n 'notice.provider_declined.body': 'No se hizo ningún cobro. Revisa los datos o prueba con otra tarjeta u otro método de pago.',\n 'notice.merchant_config.title': 'Por ahora no podemos cobrar con tarjeta',\n 'notice.merchant_config.body': 'No es un problema con tu tarjeta: es un tema de nuestro lado. Puedes pagar de otra forma.',\n 'notice.stale_checkout.title': 'Tu pedido ya quedó registrado',\n 'notice.stale_checkout.body': 'No pudimos reabrir el pago de este pedido. Actualiza para ver cómo va tu pedido; no se cobró de nuevo.',\n 'notice.other.title': 'No pudimos procesar tu pago',\n 'notice.other.body': 'Intenta de nuevo; si sigue igual, puedes pagar de otra forma.',\n 'action.retry': 'Reintentar pago',\n 'action.retry_form': 'Reintentar',\n 'action.refresh': 'Actualizar mi pedido',\n 'action.alternative': 'Pagar con {label}',\n}\n\nconst EN: PaymentRecoveryMessages = {\n 'error.transient': \"We're verifying your payment. If the charge went through we'll show it here; you won't be charged twice.\",\n 'error.in_progress': \"A payment is already in progress for this order. We're verifying it; don't pay again.\",\n 'error.rate_limited': 'Too many attempts in a row. Wait a few minutes and try again.',\n 'error.merchant_config': \"We can't take card payments right now. It isn't a problem with your card: you can pay another way.\",\n 'error.provider_declined': \"We couldn't process your payment with that card. Check the details or try another method; you were not charged.\",\n 'error.stale_checkout': \"This order is already registered and the payment couldn't be reopened. Refresh to see how it's going.\",\n 'error.expired': 'Your cart expired. Rebuild it to pay.',\n 'error.price_mismatch': 'The total changed. Check the new total and pay again.',\n 'error.store_closed': \"This store isn't open for purchases yet. Come back soon.\",\n 'error.validation': 'Complete the marked fields.',\n 'error.other': \"We couldn't process your payment. Try again.\",\n 'notice.confirming.title': \"We're confirming your payment…\",\n 'notice.confirming.body': \"Don't close this page or pay again. If the charge already went through you'll see it here.\",\n 'notice.form_failed.title': \"We couldn't load the card form\",\n 'notice.form_failed.body': 'Trying again usually fixes it. You can also pay another way.',\n 'notice.rejected.title': \"The charge didn't go through\",\n 'notice.rejected.body': 'You were not charged. Try another card or choose another way to pay.',\n 'notice.provider_declined.title': \"We couldn't process your payment with that card\",\n 'notice.provider_declined.body': 'You were not charged. Check the details or try another card or method.',\n 'notice.merchant_config.title': \"We can't charge cards right now\",\n 'notice.merchant_config.body': \"It isn't a problem with your card: it's on our side. You can pay another way.\",\n 'notice.stale_checkout.title': 'Your order is already registered',\n 'notice.stale_checkout.body': \"We couldn't reopen the payment for this order. Refresh to see how it's going; you were not charged again.\",\n 'notice.other.title': \"We couldn't process your payment\",\n 'notice.other.body': 'Try again; if it keeps failing you can pay another way.',\n 'action.retry': 'Retry payment',\n 'action.retry_form': 'Retry',\n 'action.refresh': 'Refresh my order',\n 'action.alternative': 'Pay with {label}',\n}\n\n/** Texts for a locale (`es*` default, `en*`), with optional overrides. Nothing here names a provider or a brand. */\nexport function paymentRecoveryMessages(locale?: string | null, overrides?: Partial<PaymentRecoveryMessages> | null): PaymentRecoveryMessages {\n const base = (locale ?? 'es-MX').toLowerCase().startsWith('en') ? EN : ES\n return overrides ? { ...base, ...overrides } : base\n}\n","/**\n * \"Payment method\" rows for a hybrid checkout: pure functions, no DOM and no server, so the loader, the action and the\n * browser share them.\n *\n * Rules (embedded-payment contract 1.2):\n * - Rows come ONLY from what the server publishes (`payment-methods[].options` and `.client`). No provider names and no\n * amounts live here.\n * - Card and cash are paid in the page; `wallet` and `credits` redirect to the provider.\n * - Without `client`, or with the card flagged `redirect: true`, the server does not offer `embedded`: the shop falls\n * back to the usual redirect flow.\n */\nimport { classifyPaymentError } from '@asteby/storefront'\nimport type {\n CheckoutResult,\n PaymentAttemptResult,\n PaymentClient,\n PaymentErrorClassKind,\n PaymentMethod,\n PaymentOption,\n PaymentOptionKey,\n PaymentPoint,\n} from '@asteby/storefront'\nimport { paymentRecoveryMessages, type PaymentRecoveryMessages } from './recovery-messages.js'\n\n/** One row of \"Payment method\". `value` is what travels in the form (`payment_choice`). */\nexport type PayChoice = {\n value: string\n /** Server method key (`payment_method` of the checkout). */\n methodKey: string\n /** Provider option; `null` for a method without options (the plain flow). */\n option: PaymentOptionKey | null\n /** `card` (form in the page), `cash` (voucher), `redirect` (leaves to the gateway) or `plain`. */\n mode: 'card' | 'cash' | 'redirect' | 'plain'\n /** The provider's own text (`option.label`); the shop supplies its own when missing. */\n label: string | null\n points: PaymentPoint[]\n maxInstallments: number | null\n}\n\nexport type PayChoices = {\n choices: PayChoice[]\n /** Public data to mount the card form; `null` when the server does not offer `embedded`. */\n cardClient: PaymentClient | null\n defaultValue: string | null\n}\n\nexport type BuildPayChoicesOptions = {\n /** Method keys this shop never offers even when the server publishes them (e.g. a manual transfer). */\n hide?: Iterable<string>\n}\n\nconst SEP = '|'\n\nexport function choiceValue(methodKey: string, option: PaymentOptionKey | null): string {\n return option ? `${methodKey}${SEP}${option}` : methodKey\n}\n\n/** `\"mercadopago|card\"` becomes method and option. A value without `|` is a method without options. */\nexport function parseChoice(value: string | null | undefined): { methodKey: string; option: PaymentOptionKey | null } | null {\n const raw = (value ?? '').trim()\n if (!raw) return null\n const i = raw.lastIndexOf(SEP)\n if (i === -1) return { methodKey: raw, option: null }\n const option = raw.slice(i + 1)\n if (option !== 'card' && option !== 'cash' && option !== 'wallet' && option !== 'credits') return null\n return { methodKey: raw.slice(0, i), option }\n}\n\nfunction modeOf(option: PaymentOption): PayChoice['mode'] {\n if (option.redirect || option.key === 'wallet' || option.key === 'credits') return 'redirect'\n return option.key === 'cash' ? 'cash' : 'card'\n}\n\n/**\n * Rows from `GET payment-methods`. A method with `options` unfolds into one row per option (server order); one without\n * is a single plain row. `cardClient` only exists when the card is paid in the page.\n */\nexport function buildPayChoices(methods: readonly PaymentMethod[], options: BuildPayChoicesOptions = {}): PayChoices {\n const hidden = new Set(options.hide ?? [])\n const choices: PayChoice[] = []\n let cardClient: PaymentClient | null = null\n let defaultValue: string | null = null\n for (const method of methods) {\n if (hidden.has(method.key)) continue\n const opts = method.options ?? []\n if (opts.length === 0) {\n const value = choiceValue(method.key, null)\n choices.push({ value, methodKey: method.key, option: null, mode: 'plain', label: null, points: [], maxInstallments: null })\n if (method.default && !defaultValue) defaultValue = value\n continue\n }\n opts.forEach((option, i) => {\n const mode = modeOf(option)\n const value = choiceValue(method.key, option.key)\n choices.push({\n value,\n methodKey: method.key,\n option: option.key,\n mode,\n label: option.label?.trim() || null,\n points: option.key === 'cash' ? (option.points ?? []) : [],\n maxInstallments: option.max_installments ?? null,\n })\n if (mode === 'card' && method.client && !cardClient) cardClient = method.client\n if (method.default && i === 0 && !defaultValue) defaultValue = value\n })\n }\n // A card meant for the page but without `client` cannot be mounted: it is paid by redirect.\n const usable = choices.map((c) => (c.mode === 'card' && !cardClient ? { ...c, mode: 'redirect' as const } : c))\n return { choices: usable, cardClient, defaultValue: defaultValue ?? usable[0]?.value ?? null }\n}\n\n/** Chosen cash point becomes the cash `provider_data`, built on the server from the provider's list. */\nexport function cashProviderData(points: readonly PaymentPoint[], pointId: string | null | undefined): Record<string, string> | null {\n const point = points.find((p) => p.id === pointId) ?? (pointId ? null : points[0])\n if (!point) return null\n return {\n payment_method_id: point.payment_method_id,\n ...(point.payment_point ? { payment_point: point.payment_point } : {}),\n }\n}\n\n/**\n * A checkout (`GET checkouts/:id`) as an attempt result, for polling a 3DS challenge or a payment under review.\n * It only translates server states: it never decides a payment.\n */\nexport function checkoutToAttempt(result: CheckoutResult): PaymentAttemptResult {\n const { checkout, payment, order } = result\n const action = payment.action ?? null\n const base = { checkout, ...(order ? { order } : {}) }\n const status = (checkout.status ?? '').toLowerCase()\n if (status === 'paid' || status === 'converted') return { ...base, payment: { provider: payment.provider, status: 'paid', outcome: 'approved' } }\n if (status === 'cancelled' || status === 'canceled') return { ...base, payment: { provider: payment.provider, status: 'cancelled' } }\n if (status === 'expired') return { ...base, payment: { provider: payment.provider, status: 'expired' } }\n if (status === 'failed') {\n const decline = (payment as { decline_code?: PaymentAttemptResult['payment']['decline_code'] }).decline_code ?? 'declined'\n return { ...base, payment: { provider: payment.provider, status: 'failed', outcome: 'rejected', decline_code: decline, retryable: true } }\n }\n // Still pending: same as the last attempt left it (challenge or review), so the screen does not change.\n if (action?.type === 'challenge') return { ...base, payment: { provider: payment.provider, status: 'requires_action', outcome: 'challenge', action } }\n return { ...base, payment: { provider: payment.provider, status: 'pending', outcome: 'pending', action: action ?? { type: 'none' } } }\n}\n\n/**\n * Body `{ error: { code, message, retryable, kind, ... } }` that `createFetchTransport` and `createResilientTransport`\n * understand. `retryable` and `kind` come from `classifyPaymentError`: the browser never guesses them from the status.\n */\nexport type PayErrorBody = {\n error: { code: string; message: string; retryable: boolean; kind: PaymentErrorClassKind; field?: string; retry_after?: number; details?: unknown }\n}\n\ntype ErrorLike = {\n status?: number\n code?: string\n field?: string\n message?: string\n details?: unknown\n /** `StorefrontError.retryable`: what OPS declared. */\n retryable?: boolean | undefined\n checkoutId?: string | undefined\n retryAfter?: number | undefined\n}\n\nexport type PayErrorOptions = {\n locale?: string\n /** Replaces the default texts (`error.<kind>`). */\n messages?: Partial<PaymentRecoveryMessages>\n /** Forces the classification (for refusals the shop itself makes). */\n kind?: PaymentErrorClassKind\n /** `err.message` was written by the shop itself (a refusal it makes, such as `tooManyRequests`): always kept. */\n ownMessage?: boolean\n}\n\n/**\n * 502-504 never leave the shop's pay routes: the proxy (Traefik's `errors` middleware, a CDN) replaces them with an HTML\n * page, and the browser loses the JSON and the `Set-Cookie` of the payment session. They are answered as 500; the\n * body (`retryable`, `kind`) is what decides.\n */\nexport function safeHttpStatus(status: number): number {\n return status === 502 || status === 503 || status === 504 ? 500 : status\n}\n\n/**\n * Server error becomes a JSON response for the browser. Keeps the codes the SDK knows how to read (`price_mismatch`,\n * `payment_in_progress`, `expired`, `too_many_attempts`); the mock sends \"in progress\" in `field`, so that is checked too.\n * Always JSON, never 502-504 (see `safeHttpStatus`), always with `retryable` and `kind`.\n */\nexport function payErrorResponse(err: ErrorLike, options: PayErrorOptions = {}): { status: number; body: PayErrorBody } {\n const status = typeof err.status === 'number' && err.status >= 400 ? err.status : 503\n const { kind: classified, retryable } = classifyPaymentError({ ...err, status, checkoutId: err.checkoutId ?? null })\n const kind = options.kind ?? classified\n let code = err.code ?? (kind === 'transient' ? 'unavailable' : 'server_error')\n if (status === 409 && err.field === 'payment_in_progress') code = 'payment_in_progress'\n if (status === 429) code = 'too_many_attempts'\n if (status === 422 && err.field === 'expected_total') code = 'price_mismatch'\n // Texts the shop wrote itself (missing fields, expired cart, a row it does not offer) are kept; OPS' own message,\n // often technical or in English, is replaced by the catalog text for the kind.\n const own = (options.ownMessage || kind === 'validation' || kind === 'expired' || kind === 'price_mismatch' || (kind === 'other' && status < 500)) && err.message\n const message = own || paymentRecoveryMessages(options.locale, options.messages)[`error.${kind}`]\n return {\n status: safeHttpStatus(status),\n body: {\n error: {\n code,\n message,\n retryable: options.kind ? options.kind === 'transient' || options.kind === 'in_progress' || options.kind === 'rate_limited' : retryable,\n kind,\n ...(err.field ? { field: err.field } : {}),\n ...(err.retryAfter ? { retry_after: err.retryAfter } : {}),\n ...(err.details !== undefined ? { details: err.details } : {}),\n },\n },\n }\n}\n\nexport type VoucherRowLabels = { point: string; reference: string; clabe: string; barcode: string; expires: string }\n\n/** Cookie receipt rows for a payment under review or with a voucher (shown on the thank-you page). */\nexport function voucherRows(\n voucher: NonNullable<NonNullable<PaymentAttemptResult['payment']['action']>['voucher']> | null | undefined,\n labels: VoucherRowLabels,\n locale: string,\n): [label: string, value: string][] {\n if (!voucher) return []\n const rows: [string, string][] = []\n if (voucher.payment_point) rows.push([labels.point, String(voucher.payment_point).slice(0, 60)])\n if (voucher.reference) rows.push([labels.reference, String(voucher.reference).slice(0, 80)])\n if (voucher.clabe) rows.push([labels.clabe, String(voucher.clabe).slice(0, 40)])\n if (voucher.barcode) rows.push([labels.barcode, String(voucher.barcode).slice(0, 80)])\n if (voucher.expires_at) {\n const d = new Date(voucher.expires_at)\n if (!Number.isNaN(d.getTime())) {\n rows.push([labels.expires, new Intl.DateTimeFormat(locale, { dateStyle: 'long', timeStyle: 'short', timeZone: 'UTC' }).format(d) + ' UTC'])\n }\n }\n return rows\n}\n","import type { PaymentClient } from '@asteby/storefront'\n\nexport type PaymentCspOptions = {\n /** Per-request nonce; also set it on the inserted `<script>` and on `<Scripts nonce>`. */\n nonce?: string\n /** Extra origins by directive (e.g. your image CDN). */\n extra?: { script?: string[]; frame?: string[]; connect?: string[]; img?: string[]; form?: string[] }\n /** `report-uri` / `report-to` target for the report-only rollout. */\n reportUri?: string\n /** Inline scripts allowed by hash (`'sha256-…'`), e.g. a theme bootstrap that runs before paint. */\n scriptHashes?: string[]\n /** Allow any https image source (product photos from a CDN). */\n imgHttps?: boolean\n}\n\n/** One origin source: `https://host`, `https://*.host`, optional port. Anything else (`;`, spaces, `'unsafe-eval'`) is dropped. */\nconst ORIGIN = /^https:\\/\\/(\\*\\.)?[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*(:\\d{1,5})?$/i\n\nfunction origins(...lists: (readonly string[] | undefined)[]): string[] {\n const out = new Set<string>()\n for (const list of lists) for (const o of list ?? []) if (ORIGIN.test(o)) out.add(o)\n return [...out]\n}\n\n/**\n * Builds the Content-Security-Policy for the payment routes from what each provider declares\n * (`PaymentClient.csp`), so the shop never hard-codes provider hosts. Meant for `/pagar` only,\n * never for the whole site. Roll out as `Content-Security-Policy-Report-Only` first.\n *\n * No SRI on purpose: provider SDK URLs are unversioned and a hash would break payments on any update.\n */\nexport function paymentCsp(clients: readonly (PaymentClient | null | undefined)[], options: PaymentCspOptions = {}): string {\n const list = clients.filter((c): c is PaymentClient => !!c)\n const pick = (k: keyof NonNullable<PaymentClient['csp']>) => list.map((c) => c.csp?.[k])\n const nonce = options.nonce && /^[A-Za-z0-9+/=_-]+$/.test(options.nonce) ? options.nonce : undefined\n const sdkOrigins = list.flatMap((c) => {\n try {\n const u = new URL(c.sdk_url)\n return u.protocol === 'https:' ? [u.origin] : []\n } catch {\n return []\n }\n })\n const dir = (name: string, values: string[]) => `${name} ${values.join(' ')}`\n const parts = [\n \"default-src 'self'\",\n dir('script-src', [\"'self'\", ...(options.scriptHashes ?? []).filter((h) => /^'sha(256|384|512)-[A-Za-z0-9+/=]+'$/.test(h)), ...(nonce ? [`'nonce-${nonce}'`] : []), ...origins(sdkOrigins, ...pick('script'), options.extra?.script)]),\n dir('frame-src', origins(...pick('frame'), options.extra?.frame).length ? origins(...pick('frame'), options.extra?.frame) : [\"'none'\"]),\n dir('connect-src', [\"'self'\", ...origins(...pick('connect'), options.extra?.connect)]),\n dir('img-src', [\"'self'\", 'data:', ...(options.imgHttps ? ['https:'] : []), ...origins(...pick('img'), options.extra?.img)]),\n \"style-src 'self' 'unsafe-inline'\",\n dir('form-action', [\"'self'\", ...origins(...pick('form'), options.extra?.form)]),\n \"frame-ancestors 'none'\",\n \"base-uri 'self'\",\n \"object-src 'none'\",\n ]\n if (options.reportUri && /^(https:\\/\\/|\\/)[^\\s;,]+$/.test(options.reportUri)) parts.push(`report-uri ${options.reportUri}`)\n return parts.join('; ')\n}\n\n/** `Content-Security-Policy` or, during the rollout week, `Content-Security-Policy-Report-Only`. */\nexport function paymentCspHeaderName(reportOnly: boolean): string {\n return reportOnly ? 'Content-Security-Policy-Report-Only' : 'Content-Security-Policy'\n}\n\nexport type PaymentCspMode = 'off' | 'report-only' | 'enforce'\n\n/** `PAYMENT_CSP`-style value: `off`, `report-only` or `enforce`. Unset: report-only in production, off elsewhere (dev servers inject scripts). */\nexport function paymentCspMode(value: string | null | undefined, production: boolean): PaymentCspMode {\n const raw = (value ?? '').trim().toLowerCase()\n if (raw === 'off' || raw === 'report-only' || raw === 'enforce') return raw\n return production ? 'report-only' : 'off'\n}\n\n/** Fresh per-request nonce (128 bits, base64). Works in Node, edge and browsers. */\nexport function paymentNonce(): string {\n const bytes = new Uint8Array(16)\n crypto.getRandomValues(bytes)\n let bin = ''\n for (const b of bytes) bin += String.fromCharCode(b)\n return btoa(bin)\n}\n\n/** Header ready for the response (`{}` when `off`): policy from the providers' `client.csp`, never the whole site. */\nexport function paymentCspHeaders(\n clients: readonly (PaymentClient | null | undefined)[],\n options: PaymentCspOptions & { mode: PaymentCspMode },\n): Record<string, string> {\n if (options.mode === 'off') return {}\n return { [paymentCspHeaderName(options.mode === 'report-only')]: paymentCsp(clients, options) }\n}\n\n/** The nonce the route left in the CSP header, to hand to `ServerRouter` / `<Scripts>`. */\nexport function paymentNonceFromHeaders(headers: Headers): string | undefined {\n const csp = headers.get('Content-Security-Policy') ?? headers.get('Content-Security-Policy-Report-Only') ?? ''\n return /'nonce-([A-Za-z0-9+/=_-]+)'/.exec(csp)?.[1]\n}\n","/**\n * Server side of the embedded payment (`@asteby/storefront-react/payments/server`): the two JSON resource routes the\n * browser talks to (charge the card, re-read the payment) and the cash voucher of the page form. No React, no router:\n * Web `Request`/`Response` only, so any framework mounts it.\n *\n * The browser NEVER calls OPS. These handlers translate to `carts.checkout` + `checkouts.pay` with the shop's `sk_` token.\n *\n * Money: no amount is computed here. `expected_total` is the total the server showed the buyer (echoed back by the SDK);\n * OPS compares it with the order and answers `422 price_mismatch` when it changed.\n *\n * Everything shop-specific (cookies, receipt shape, which fields the form requires, how contact/delivery are saved)\n * arrives through `EmbeddedPayConfig` callbacks.\n */\nimport {\n PAYMENT_CHOICE_REFUSED_FIELD,\n isStorefrontError,\n paymentIdempotencyKey,\n paymentOutcome,\n safeHttpsUrl,\n type Cart,\n type CheckoutResult,\n type Money,\n type PaymentAttemptResult,\n type PaymentErrorClassKind,\n type StorefrontClient,\n} from '@asteby/storefront'\nimport { buildPayChoices, cashProviderData, checkoutToAttempt, parseChoice, payErrorResponse, safeHttpStatus, type PayChoice, type PayErrorOptions } from './choices.js'\nimport type { PaymentRecoveryMessages } from './recovery-messages.js'\n\nexport * from './choices.js'\nexport { paymentCsp, paymentCspHeaderName, paymentCspHeaders, paymentCspMode, paymentNonce, paymentNonceFromHeaders } from './csp.js'\nexport type { PaymentCspMode, PaymentCspOptions } from './csp.js'\n\nexport type RateLimiter = { hit(key: string, now?: number): { allowed: boolean; retryAfterSec: number } }\n\n/** In-memory sliding window per key. Protects this process; OPS puts its own cap per checkout on top. */\nexport function createRateLimiter({ limit, windowMs }: { limit: number; windowMs: number }): RateLimiter {\n const hits = new Map<string, number[]>()\n return {\n hit(key, now = Date.now()) {\n const recent = (hits.get(key) ?? []).filter((t) => now - t < windowMs)\n if (recent.length >= limit) {\n hits.set(key, recent)\n return { allowed: false, retryAfterSec: Math.max(1, Math.ceil((recent[0]! + windowMs - now) / 1000)) }\n }\n recent.push(now)\n hits.set(key, recent)\n if (hits.size > 5000) for (const [k, v] of hits) if (v.every((t) => now - t >= windowMs)) hits.delete(k)\n return { allowed: true, retryAfterSec: 0 }\n },\n }\n}\n\n/** Buyer IP as forwarded by a trusted proxy/CDN; without `trustProxy` a single shared key. */\nexport function clientKey(request: Request, trustProxy = false): string {\n if (!trustProxy) return 'direct'\n const cf = request.headers.get('cf-connecting-ip')\n if (cf) return cf.trim()\n return request.headers.get('x-forwarded-for')?.split(',')[0]?.trim() || 'direct'\n}\n\n/**\n * A request from another site cannot pay with the buyer's cookie. Only the HOST is compared (no scheme or port): behind\n * the proxy the request scheme can be http while the browser sent https.\n */\nexport function sameOrigin(request: Request, site: string): boolean {\n const origin = request.headers.get('origin')\n if (!origin) return true\n try {\n const host = new URL(origin).hostname\n return host === new URL(site).hostname || host === new URL(request.url).hostname\n } catch {\n return false\n }\n}\n\n/** Device fingerprint (anti-fraud): OPTIONAL, so it never breaks a payment. Anything over 200 chars or odd is dropped. */\nexport const DEVICE_SESSION_ID_MAX = 200\nexport function deviceSessionId(v: unknown): string | undefined {\n if (typeof v !== 'string') return undefined\n const id = v.trim()\n return id.length > 0 && id.length <= DEVICE_SESSION_ID_MAX && /^[\\w.:-]+$/.test(id) ? id : undefined\n}\n\nconst JSON_HEADERS = { 'Content-Type': 'application/json' }\n\nexport type JsonPayRouteOptions = PayErrorOptions & {\n /** Cache header of the response. Default `private, no-store`. */\n cacheControl?: string\n /** Diagnostic line for an exception inside the route. Default: one JSON line with `console.warn`. */\n log?: (entry: { level: 'warn'; msg: string; where: string; error: string }) => void\n}\n\nfunction copyHeaders(from: Headers): Headers {\n const out = new Headers()\n from.forEach((value, key) => {\n const k = key.toLowerCase()\n if (k === 'content-length' || k === 'content-type' || k === 'set-cookie' || k === 'refresh') return\n out.set(key, value)\n })\n for (const cookie of from.getSetCookie?.() ?? []) out.append('Set-Cookie', cookie)\n return out\n}\n\n/**\n * Runs a payment route and guarantees a JSON answer: `{ error: { code, message, retryable, kind } }` with a status the\n * proxy leaves alone (never 502-504, which Traefik/CDNs replace with an HTML page, dropping the JSON and the\n * `Set-Cookie` of the payment session). An exception becomes a transient, retryable error (same idempotency key).\n * `createEmbeddedPayHandlers` already applies it; use it for routes of your own.\n */\nexport async function jsonPayRoute(run: () => Promise<Response>, where: string, options: JsonPayRouteOptions | string = {}): Promise<Response> {\n const opts: JsonPayRouteOptions = typeof options === 'string' ? { cacheControl: options } : options\n const cache = opts.cacheControl ?? 'private, no-store'\n const errorOptions: PayErrorOptions = { ...(opts.locale ? { locale: opts.locale } : {}), ...(opts.messages ? { messages: opts.messages } : {}) }\n let res: Response\n try {\n res = await run()\n } catch (err) {\n const entry = { level: 'warn' as const, msg: 'excepción en la ruta de pago', where, error: String((err as Error)?.message ?? err).slice(0, 300) }\n if (opts.log) opts.log(entry)\n else console.warn(JSON.stringify(entry))\n const { status, body } = payErrorResponse({ status: 500, code: 'server_error' }, errorOptions)\n return new Response(JSON.stringify(body), { status, headers: { ...JSON_HEADERS, 'Cache-Control': cache } })\n }\n const type = res.headers.get('content-type') ?? ''\n if (res.ok && type.includes('json')) return res\n\n let parsed: { error?: { code?: string; message?: string; retryable?: boolean; kind?: string; field?: string; details?: unknown } } | null = null\n if (type.includes('json')) parsed = await res.clone().json().catch(() => null)\n const e = parsed?.error\n // Already normalised by the shop (has `kind`) and with a status the proxy keeps: leave it as it is.\n if (!res.ok && e && typeof e.kind === 'string' && safeHttpStatus(res.status) === res.status) return res\n const { status, body } = payErrorResponse(\n {\n status: res.ok ? 500 : res.status,\n ...(e?.code ? { code: e.code } : {}),\n ...(e?.message ? { message: e.message } : {}),\n ...(e?.field ? { field: e.field } : {}),\n ...(e?.details !== undefined ? { details: e.details } : {}),\n ...(typeof e?.retryable === 'boolean' ? { retryable: e.retryable } : {}),\n },\n errorOptions,\n )\n const headers = copyHeaders(res.headers)\n headers.set('Content-Type', 'application/json')\n headers.set('Cache-Control', cache)\n return new Response(JSON.stringify(body), { status, headers })\n}\n\nconst ATTEMPT = /^[A-Za-z0-9_-]{8,100}$/\n\nconst asMoney = (v: unknown): Money | null => {\n const m = v as Partial<Money> | null\n return m && typeof m.amount === 'string' && /^\\d+(\\.\\d+)?$/.test(m.amount) && typeof m.currency_code === 'string' && m.currency_code.length === 3\n ? { amount: m.amount, currency_code: m.currency_code }\n : null\n}\n\n/** What the shop keeps between the checkout creation and the end of the payment (usually in a cookie). */\nexport type PaySession<TDraft extends { checkout_id?: string }> = { cart_id: string; draft: TDraft }\n\nexport type EmbeddedPayMessages = {\n /** Required form fields missing. */\n fillFields: string\n /** The cart cookie is gone or the checkout expired. */\n expiredCart: string\n /** The chosen row is not payable in the page (the server decides, not the browser). */\n methodUnavailable: string\n tooManyRequests: string\n cashChoosePoint: string\n}\n\nconst DEFAULT_MESSAGES: EmbeddedPayMessages = {\n fillFields: 'Completa los campos marcados.',\n expiredCart: 'Tu carrito venció. Vuelve a armarlo para pagar.',\n methodUnavailable: 'Esta forma de pago no está disponible por ahora.',\n tooManyRequests: 'Demasiados intentos. Espera unos minutos e inténtalo de nuevo.',\n cashChoosePoint: 'Elige dónde pagar en efectivo.',\n}\n\nexport type EmbeddedPayConfig<TDraft extends { checkout_id?: string }> = {\n /** The store client with the `sk_` token for this request. */\n client: (request: Request) => Promise<StorefrontClient>\n /** Public origin of the shop (`https://tienda.com`). Used for `return_url` and the origin check. */\n site: (request: Request) => string\n /** Path of the thank-you page, appended to `site`. */\n returnPath: string\n /** Locale for the outcome texts and voucher dates. Default `es-MX`. */\n locale?: string\n readCartId: (request: Request) => Promise<string | null>\n readSession: (request: Request) => Promise<PaySession<TDraft> | null>\n /** `Set-Cookie` value that keeps the session so a retry reuses the already created checkout. */\n serializeSession: (session: PaySession<TDraft>) => Promise<string>\n /** `null` when the form is complete; otherwise the message to show (HTTP 400). The shop knows its required fields. */\n validateFields: (fields: Record<string, string>) => string | null\n /** Saves contact, address and delivery on the server cart (the cart becomes an order at checkout, so do it before). */\n prepareCart: (args: { sf: StorefrontClient; cartId: string; fields: Record<string, string> }) => Promise<void>\n /** First draft of the receipt from the created checkout and the cart as it was before. */\n createDraft: (args: { created: CheckoutResult; before: Cart | null; fields: Record<string, string> }) => TDraft\n /**\n * Called after every attempt. When the order is closed (approved, under review, voucher) append the receipt cookie and\n * clear the cart/session cookies to `headers` and return `true`; otherwise return `false` (the session is kept).\n */\n settle: (args: { draft: TDraft; result: PaymentAttemptResult; headers: Headers }) => Promise<boolean>\n /** Method keys the shop never offers (the server also checks them: a forged `payment_choice` is refused). */\n hide?: Iterable<string>\n messages?: Partial<EmbeddedPayMessages>\n /** Replaces the default texts of the error bodies (`error.<kind>`), e.g. to speak in the shop's voice. */\n errorMessages?: Partial<PaymentRecoveryMessages>\n /** Per-IP limit on charges. Default 10 per 10 minutes; `false` disables (OPS still caps attempts per checkout). */\n rateLimit?: RateLimiter | { limit?: number; windowMs?: number } | false\n /** Trust `cf-connecting-ip` / `x-forwarded-for` for the limiter key. */\n trustProxy?: boolean\n /** Cache header of every response. Default `private, no-store`. */\n cacheControl?: string\n /** Diagnostic log of an OPS rejection (no bodies, no buyer data). Default: one JSON line with `console.warn`. */\n log?: (entry: { level: 'warn'; msg: string; status: number; code: string | null; field: string | null; message: string }) => void\n}\n\nexport type CashOutcome = { kind: 'done'; headers: Headers } | { kind: 'error'; status: number; message: string; fields: string[] }\n\nexport type EmbeddedPayHandlers = {\n /** POST JSON from the card form: creates the checkout (idempotent per cart) and charges the attempt. */\n pay: (request: Request) => Promise<Response>\n /** POST: re-reads the checkout (3DS challenge, \"under review\") in the shape of an attempt. */\n status: (request: Request) => Promise<Response>\n /** Cash from the page form (with or without JavaScript): creates the `embedded/cash` checkout and asks for the voucher. */\n cash: (args: { sf: StorefrontClient; request: Request; cartId: string; fields: Record<string, string>; choice: PayChoice; before: Cart | null }) => Promise<CashOutcome>\n}\n\nexport function createEmbeddedPayHandlers<TDraft extends { checkout_id?: string }>(config: EmbeddedPayConfig<TDraft>): EmbeddedPayHandlers {\n const msg = { ...DEFAULT_MESSAGES, ...config.messages }\n const locale = config.locale ?? 'es-MX'\n const cache = config.cacheControl ?? 'private, no-store'\n const makeLimiter = (): RateLimiter | null => {\n const r = config.rateLimit\n if (r === false) return null\n if (r && 'hit' in r) return r\n return createRateLimiter({ limit: Math.max(1, r?.limit ?? 10), windowMs: r?.windowMs ?? 10 * 60_000 })\n }\n const limiter = makeLimiter()\n const log =\n config.log ??\n ((entry) => {\n console.warn(JSON.stringify(entry))\n })\n\n const json = (body: unknown, init: { status?: number; headers?: Headers | Record<string, string> } = {}) => {\n const headers = new Headers(init.headers)\n headers.set('Cache-Control', cache)\n headers.set('Content-Type', 'application/json')\n return new Response(JSON.stringify(body), { status: init.status ?? 200, headers })\n }\n const errorOptions: PayErrorOptions = { locale, ...(config.errorMessages ? { messages: config.errorMessages } : {}) }\n /** The shop's own refusal, in the same body shape (`retryable`, `kind`) as an OPS failure. */\n const fail = (status: number, code: string, message: string, extra: Headers | Record<string, string> = {}, more: { field?: string; kind?: PaymentErrorClassKind } = {}) => {\n const r = payErrorResponse({ status, code, message, ...(more.field ? { field: more.field } : {}) }, { ...errorOptions, ownMessage: true, ...(more.kind ? { kind: more.kind } : {}) })\n return json(r.body, { status: r.status, headers: extra })\n }\n\n async function pay(request: Request): Promise<Response> {\n const site = config.site(request)\n if (!sameOrigin(request, site)) return fail(403, 'forbidden', 'origin', {}, { kind: 'other' })\n if (limiter) {\n const gate = limiter.hit(clientKey(request, config.trustProxy))\n if (!gate.allowed) return fail(429, 'too_many_attempts', msg.tooManyRequests, { 'Retry-After': String(gate.retryAfterSec) })\n }\n const cartId = await config.readCartId(request)\n if (!cartId) return fail(409, 'expired', msg.expiredCart)\n\n let body: { option?: unknown; attempt?: unknown; provider_data?: unknown; device_session_id?: unknown; expected_total?: unknown; fields?: unknown }\n try {\n body = (await request.json()) as typeof body\n } catch {\n return fail(400, 'validation', msg.fillFields)\n }\n const attempt = typeof body.attempt === 'string' && ATTEMPT.test(body.attempt) ? body.attempt : null\n const expected = asMoney(body.expected_total)\n const data = body.provider_data\n if (body.option !== 'card' || !attempt || !expected || !data || typeof data !== 'object' || Array.isArray(data)) {\n return fail(400, 'validation', msg.fillFields)\n }\n // The amount does not travel in `provider_data`: OPS sets it. Even if the browser (or a stray script) sends one, it is not forwarded.\n const { transaction_amount: _ignored, ...providerData } = data as Record<string, unknown>\n const fields: Record<string, string> = {}\n for (const [k, v] of Object.entries((body.fields ?? {}) as Record<string, unknown>)) if (typeof v === 'string') fields[k] = v.trim()\n const invalid = config.validateFields(fields)\n if (invalid) return fail(400, 'validation', invalid)\n\n const sf = await config.client(request)\n const choice = parseChoice(fields.payment_choice)\n let session: PaySession<TDraft> | undefined\n try {\n // The server decides what can be paid in the page: the browser only picks among what OPS published.\n const methods = await sf.carts.paymentMethods(cartId)\n const card = buildPayChoices(methods.methods, config.hide ? { hide: config.hide } : {}).choices.find((c) => c.mode === 'card' && c.value === fields.payment_choice)\n if (!choice || !card) return fail(422, 'invalid_state', msg.methodUnavailable, {}, { field: PAYMENT_CHOICE_REFUSED_FIELD })\n\n // A retry (the first charge failed or the network dropped) reuses the checkout already created: the cart is an\n // order by now and cannot be edited again. Only the attempt (the payment key) changes.\n const previous = await config.readSession(request)\n const reusedId = previous && previous.cart_id === cartId ? previous.draft.checkout_id : undefined\n let checkoutId: string\n if (previous && reusedId) {\n session = previous\n checkoutId = reusedId\n } else {\n await config.prepareCart({ sf, cartId, fields })\n const before = await sf.carts.get(cartId).catch(() => null)\n const created = await sf.carts.checkout(\n cartId,\n { payment_method: card.methodKey, payment_flow: 'embedded', payment_option: 'card', expected_total: expected, return_url: `${site}${config.returnPath}` },\n { idempotencyKey: `chk-${cartId}` },\n )\n checkoutId = created.checkout.id\n session = { cart_id: cartId, draft: config.createDraft({ created, before, fields }) }\n }\n\n const device = deviceSessionId(body.device_session_id)\n const result = await sf.checkouts.pay(\n checkoutId,\n { method: 'card', provider_data: providerData, ...(device ? { device_session_id: device } : {}), expected_total: expected },\n { idempotencyKey: paymentIdempotencyKey(checkoutId, attempt) },\n )\n\n const headers = new Headers()\n const closed = await config.settle({ draft: session.draft, result, headers })\n if (!closed) headers.append('Set-Cookie', await config.serializeSession(session))\n return json(result, { headers })\n } catch (err) {\n if (isStorefrontError(err)) {\n const { status, body: errBody } = payErrorResponse(err, errorOptions)\n log({ level: 'warn', msg: 'cobro rechazado por OPS', status: err.status, code: err.code ?? null, field: err.field ?? null, message: String(err.message).slice(0, 300) })\n // 5xx, network or timeout: the charge may have happened; the browser retries with the SAME key.\n // The checkout exists even when the charge fails: kept so the retry reuses it.\n const headers = new Headers()\n if (session) headers.append('Set-Cookie', await config.serializeSession(session))\n return json(errBody, { status, headers })\n }\n throw err\n }\n }\n\n async function status(request: Request): Promise<Response> {\n if (!sameOrigin(request, config.site(request))) return fail(403, 'forbidden', 'origin', {}, { kind: 'other' })\n const session = await config.readSession(request)\n const id = session?.draft.checkout_id\n // No payment session in this browser (cookie lost or never set). It is NOT an error and NOT a result: `none` tells the\n // transport there is nothing to read, so an unknown outcome stays unknown and is repeated with the SAME key.\n // `recoverable`: the shop still has the buyer's cart, so that same-key retry can proceed.\n const none = async (): Promise<Response> => json({ payment: { provider: '', status: 'none' }, recoverable: Boolean(await config.readCartId(request)) })\n if (!session || !id) return none()\n try {\n const sf = await config.client(request)\n const found = await sf.checkouts.get(id)\n if (!found) return none()\n const attempt = checkoutToAttempt(found)\n const headers = new Headers()\n await config.settle({ draft: session.draft, result: attempt, headers })\n return json(attempt, { headers })\n } catch (err) {\n if (isStorefrontError(err)) {\n const { status: code, body } = payErrorResponse(err, errorOptions)\n return json(body, { status: code })\n }\n throw err\n }\n }\n\n async function cash(args: Parameters<EmbeddedPayHandlers['cash']>[0]): Promise<CashOutcome> {\n const { sf, request, cartId, fields, choice, before } = args\n const providerData = cashProviderData(choice.points, fields.cash_point)\n if (!providerData) return { kind: 'error', status: 422, message: msg.cashChoosePoint, fields: ['cash_point'] }\n const created = await sf.carts.checkout(\n cartId,\n { payment_method: choice.methodKey, payment_flow: 'embedded', payment_option: 'cash', return_url: `${config.site(request)}${config.returnPath}` },\n { idempotencyKey: `chk-${cartId}-cash` },\n )\n const draft = config.createDraft({ created, before, fields })\n // One fixed key per checkout: a double submit returns the SAME voucher.\n const result = await sf.checkouts.pay(created.checkout.id, { method: 'cash', provider_data: providerData }, { idempotencyKey: paymentIdempotencyKey(created.checkout.id, 'cash') })\n const headers = new Headers()\n if (await config.settle({ draft, result, headers })) return { kind: 'done', headers }\n const outcome = paymentOutcome(result, locale)\n return { kind: 'error', status: safeHttpsUrl(outcome.redirect_url) ? 409 : 422, message: outcome.message, fields: [] }\n }\n\n const routeOptions: JsonPayRouteOptions = { cacheControl: cache, ...errorOptions }\n return {\n pay: (request) => jsonPayRoute(() => pay(request), 'pay', routeOptions),\n status: (request) => jsonPayRoute(() => status(request), 'status', routeOptions),\n cash,\n }\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { StorefrontClient, CheckoutResult, Cart, PaymentAttemptResult } from '@asteby/storefront';
|
|
2
|
-
import { P as PayChoice } from './
|
|
3
|
-
export { B as BuildPayChoicesOptions, a as PayChoices, b as PayErrorBody,
|
|
2
|
+
import { h as PaymentRecoveryMessages, P as PayChoice, c as PayErrorOptions } from './csp-DZPuExzu.cjs';
|
|
3
|
+
export { B as BuildPayChoicesOptions, a as PayChoices, b as PayErrorBody, d as PaymentCspMode, e as PaymentCspOptions, V as VoucherRowLabels, i as buildPayChoices, j as cashProviderData, k as checkoutToAttempt, l as choiceValue, p as parseChoice, m as payErrorResponse, n as paymentCsp, o as paymentCspHeaderName, q as paymentCspHeaders, r as paymentCspMode, s as paymentNonce, t as paymentNonceFromHeaders, v as safeHttpStatus, w as voucherRows } from './csp-DZPuExzu.cjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Server side of the embedded payment (`@asteby/storefront-react/payments/server`): the two JSON resource routes the
|
|
@@ -37,6 +37,24 @@ declare function sameOrigin(request: Request, site: string): boolean;
|
|
|
37
37
|
/** Device fingerprint (anti-fraud): OPTIONAL, so it never breaks a payment. Anything over 200 chars or odd is dropped. */
|
|
38
38
|
declare const DEVICE_SESSION_ID_MAX = 200;
|
|
39
39
|
declare function deviceSessionId(v: unknown): string | undefined;
|
|
40
|
+
type JsonPayRouteOptions = PayErrorOptions & {
|
|
41
|
+
/** Cache header of the response. Default `private, no-store`. */
|
|
42
|
+
cacheControl?: string;
|
|
43
|
+
/** Diagnostic line for an exception inside the route. Default: one JSON line with `console.warn`. */
|
|
44
|
+
log?: (entry: {
|
|
45
|
+
level: 'warn';
|
|
46
|
+
msg: string;
|
|
47
|
+
where: string;
|
|
48
|
+
error: string;
|
|
49
|
+
}) => void;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Runs a payment route and guarantees a JSON answer: `{ error: { code, message, retryable, kind } }` with a status the
|
|
53
|
+
* proxy leaves alone (never 502-504, which Traefik/CDNs replace with an HTML page, dropping the JSON and the
|
|
54
|
+
* `Set-Cookie` of the payment session). An exception becomes a transient, retryable error (same idempotency key).
|
|
55
|
+
* `createEmbeddedPayHandlers` already applies it; use it for routes of your own.
|
|
56
|
+
*/
|
|
57
|
+
declare function jsonPayRoute(run: () => Promise<Response>, where: string, options?: JsonPayRouteOptions | string): Promise<Response>;
|
|
40
58
|
/** What the shop keeps between the checkout creation and the end of the payment (usually in a cookie). */
|
|
41
59
|
type PaySession<TDraft extends {
|
|
42
60
|
checkout_id?: string;
|
|
@@ -95,6 +113,8 @@ type EmbeddedPayConfig<TDraft extends {
|
|
|
95
113
|
/** Method keys the shop never offers (the server also checks them: a forged `payment_choice` is refused). */
|
|
96
114
|
hide?: Iterable<string>;
|
|
97
115
|
messages?: Partial<EmbeddedPayMessages>;
|
|
116
|
+
/** Replaces the default texts of the error bodies (`error.<kind>`), e.g. to speak in the shop's voice. */
|
|
117
|
+
errorMessages?: Partial<PaymentRecoveryMessages>;
|
|
98
118
|
/** Per-IP limit on charges. Default 10 per 10 minutes; `false` disables (OPS still caps attempts per checkout). */
|
|
99
119
|
rateLimit?: RateLimiter | {
|
|
100
120
|
limit?: number;
|
|
@@ -142,4 +162,4 @@ declare function createEmbeddedPayHandlers<TDraft extends {
|
|
|
142
162
|
checkout_id?: string;
|
|
143
163
|
}>(config: EmbeddedPayConfig<TDraft>): EmbeddedPayHandlers;
|
|
144
164
|
|
|
145
|
-
export { type CashOutcome, DEVICE_SESSION_ID_MAX, type EmbeddedPayConfig, type EmbeddedPayHandlers, type EmbeddedPayMessages, PayChoice, type PaySession, type RateLimiter, clientKey, createEmbeddedPayHandlers, createRateLimiter, deviceSessionId, sameOrigin };
|
|
165
|
+
export { type CashOutcome, DEVICE_SESSION_ID_MAX, type EmbeddedPayConfig, type EmbeddedPayHandlers, type EmbeddedPayMessages, type JsonPayRouteOptions, PayChoice, PayErrorOptions, type PaySession, type RateLimiter, clientKey, createEmbeddedPayHandlers, createRateLimiter, deviceSessionId, jsonPayRoute, sameOrigin };
|