@asteby/storefront-react 0.18.0 → 0.19.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.
@@ -512,6 +512,8 @@ type MercadoPagoAdapterOptions = {
512
512
  getSdk?: () => MercadoPagoCtor | undefined;
513
513
  /** Reads the anti-fraud device id. Default: `window.MP_DEVICE_SESSION_ID`. */
514
514
  getDeviceSessionId?: () => string | undefined;
515
+ /** Wait before the single internal re-read of the form data (see `collect`). Default 400. */
516
+ collectRetryDelayMs?: number;
515
517
  };
516
518
  /**
517
519
  * The only fields that may leave the browser, and the only place that decides it. Anything else the SDK returns
@@ -520,7 +522,8 @@ type MercadoPagoAdapterOptions = {
520
522
  declare function sanitizeMercadoPagoFormData(data: Record<string, unknown> | null | undefined): Record<string, unknown>;
521
523
  /**
522
524
  * Card Payment Brick adapter. The payment button is hidden: the shop's own button calls `collect()` (MP's
523
- * `getFormData()`), which tokenises inside MP's iframes. Card data never touches this code.
525
+ * `getFormData()`), which tokenises inside MP's iframes. Card data never touches this code. `collect()` re-reads the
526
+ * form once if the first read fails, before anything is sent to the shop's server.
524
527
  */
525
528
  declare function mercadoPagoBricksAdapter(options?: MercadoPagoAdapterOptions): PaymentFormAdapter;
526
529
 
@@ -512,6 +512,8 @@ type MercadoPagoAdapterOptions = {
512
512
  getSdk?: () => MercadoPagoCtor | undefined;
513
513
  /** Reads the anti-fraud device id. Default: `window.MP_DEVICE_SESSION_ID`. */
514
514
  getDeviceSessionId?: () => string | undefined;
515
+ /** Wait before the single internal re-read of the form data (see `collect`). Default 400. */
516
+ collectRetryDelayMs?: number;
515
517
  };
516
518
  /**
517
519
  * The only fields that may leave the browser, and the only place that decides it. Anything else the SDK returns
@@ -520,7 +522,8 @@ type MercadoPagoAdapterOptions = {
520
522
  declare function sanitizeMercadoPagoFormData(data: Record<string, unknown> | null | undefined): Record<string, unknown>;
521
523
  /**
522
524
  * Card Payment Brick adapter. The payment button is hidden: the shop's own button calls `collect()` (MP's
523
- * `getFormData()`), which tokenises inside MP's iframes. Card data never touches this code.
525
+ * `getFormData()`), which tokenises inside MP's iframes. Card data never touches this code. `collect()` re-reads the
526
+ * form once if the first read fails, before anything is sent to the shop's server.
524
527
  */
525
528
  declare function mercadoPagoBricksAdapter(options?: MercadoPagoAdapterOptions): PaymentFormAdapter;
526
529
 
package/dist/payments.js CHANGED
@@ -84,6 +84,7 @@ function sanitizeMercadoPagoFormData(data) {
84
84
  function mercadoPagoBricksAdapter(options = {}) {
85
85
  const allowed = options.allowedSdkOrigins ?? ["https://sdk.mercadopago.com"];
86
86
  const getSdk = options.getSdk ?? (() => typeof window !== "undefined" ? window.MercadoPago : void 0);
87
+ const retryDelay = options.collectRetryDelayMs ?? 400;
87
88
  const getDevice = options.getDeviceSessionId ?? (() => typeof window !== "undefined" ? window.MP_DEVICE_SESSION_ID : void 0);
88
89
  return {
89
90
  kind: MERCADOPAGO_BRICKS_KIND,
@@ -125,9 +126,21 @@ function mercadoPagoBricksAdapter(options = {}) {
125
126
  return {
126
127
  async collect() {
127
128
  if (gone) throw new Error("payment form is unmounted");
128
- const raw = await controller.getFormData();
129
- const provider_data = sanitizeMercadoPagoFormData(raw);
130
- if (!provider_data.token) throw new Error("payment form incomplete");
129
+ const read = async () => {
130
+ const raw = await controller.getFormData();
131
+ const data = sanitizeMercadoPagoFormData(raw);
132
+ if (!data.token) throw new Error("payment form incomplete");
133
+ return data;
134
+ };
135
+ let provider_data;
136
+ try {
137
+ provider_data = await read();
138
+ } catch (first) {
139
+ if (gone) throw first;
140
+ await new Promise((r) => setTimeout(r, retryDelay));
141
+ if (gone) throw first;
142
+ provider_data = await read();
143
+ }
131
144
  const device = getDevice();
132
145
  return { provider_data, ...typeof device === "string" && device ? { device_session_id: device } : {} };
133
146
  },
@@ -783,15 +796,21 @@ function useEmbeddedPayment(options) {
783
796
  setError(null);
784
797
  setOutcome(null);
785
798
  emit({ type: "submit" });
799
+ const withdrawn = () => !alive.current || form.current !== m;
800
+ const settle = () => {
801
+ if (alive.current) setStatus((s) => s === "processing" ? "idle" : s);
802
+ };
786
803
  let data;
787
804
  try {
788
805
  data = await m.collect();
789
806
  } catch {
807
+ if (withdrawn()) return settle();
790
808
  emit({ type: "tokenize_error" });
791
809
  setError({ kind: "generic", message: live.current.msgs["error.card_data"], retrySameAttempt: false, canRetry: true });
792
810
  setStatus("ready");
793
811
  return;
794
812
  }
813
+ if (withdrawn()) return settle();
795
814
  const attempt = readAttempt();
796
815
  setAttemptId(attempt);
797
816
  await send(data, attempt, total);