create-brainerce-store 1.12.1 → 1.12.3

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/dist/index.js CHANGED
@@ -31,7 +31,7 @@ var require_package = __commonJS({
31
31
  "package.json"(exports2, module2) {
32
32
  module2.exports = {
33
33
  name: "create-brainerce-store",
34
- version: "1.12.1",
34
+ version: "1.12.2",
35
35
  description: "Scaffold a production-ready e-commerce storefront connected to Brainerce",
36
36
  bin: {
37
37
  "create-brainerce-store": "dist/index.js"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-brainerce-store",
3
- "version": "1.12.1",
3
+ "version": "1.12.3",
4
4
  "description": "Scaffold a production-ready e-commerce storefront connected to Brainerce",
5
5
  "bin": {
6
6
  "create-brainerce-store": "dist/index.js"
@@ -82,6 +82,7 @@ export function PaymentStep({ checkoutId, className }: PaymentStepProps) {
82
82
  onError: (_r: unknown) => {},
83
83
  onTimeout: () => {},
84
84
  onWalletChange: (_s: string) => {},
85
+ retryRender: () => {},
85
86
  });
86
87
 
87
88
  const handleSuccess = useCallback(
@@ -115,8 +116,9 @@ export function PaymentStep({ checkoutId, className }: PaymentStepProps) {
115
116
  ];
116
117
  const msg = extractMessage(response);
117
118
  if (TRANSIENT.some((e) => msg.includes(e))) {
118
- console.info('Payment SDK: transient startup error (will retry):', msg);
119
- return; // Don't show error — renderWhenReady will retry
119
+ console.info('Payment SDK: transient error, retrying render in 1s:', msg);
120
+ setTimeout(() => cbRef.current.retryRender(), 1000);
121
+ return;
120
122
  }
121
123
  console.error('Payment SDK error:', response);
122
124
  setError(msg || t('paymentError'));
@@ -133,6 +135,7 @@ export function PaymentStep({ checkoutId, className }: PaymentStepProps) {
133
135
  }
134
136
  if (state === 'close') setSdkReady(false);
135
137
  },
138
+ retryRender: () => {},
136
139
  };
137
140
 
138
141
  // =========================================================================
@@ -191,6 +194,18 @@ export function PaymentStep({ checkoutId, className }: PaymentStepProps) {
191
194
  return;
192
195
  }
193
196
 
197
+ // Already loading (from a previous call)? Wait for it instead of duplicating
198
+ if (document.querySelector(`script[src="${sdk.scriptUrl}"]`)) {
199
+ const waitId = setInterval(() => {
200
+ if ((window as any)[sdk.globalName!]) {
201
+ clearInterval(waitId);
202
+ initSdk(sdk);
203
+ }
204
+ }, 100);
205
+ cleanups.push(() => clearInterval(waitId));
206
+ return;
207
+ }
208
+
194
209
  // Load main SDK — insertBefore first <script> as Grow docs show
195
210
  const s = document.createElement('script');
196
211
  s.type = 'text/javascript';
@@ -208,6 +223,8 @@ export function PaymentStep({ checkoutId, className }: PaymentStepProps) {
208
223
 
209
224
  // --- Init: called in s.onload (as Grow docs require) ---
210
225
  function initSdk(sdk: PaymentClientSdk) {
226
+ if (sdkInitDone) return; // Guard against double init
227
+
211
228
  const global = (window as any)[sdk.globalName!];
212
229
  if (!global) {
213
230
  setError(t('failedToLoadPaymentSdk'));
@@ -233,37 +250,47 @@ export function PaymentStep({ checkoutId, className }: PaymentStepProps) {
233
250
  sdkInitDone = true;
234
251
  }
235
252
 
236
- // --- Render: retry until wallet actually opens (onWalletChange) ---
237
- // No artificial timeout the SDK fires onTimeout when the session expires.
238
- function renderWhenReady(sdk: PaymentClientSdk, intent: PaymentIntent) {
253
+ // --- Render: call once, then safety-net retries if wallet doesn't open ---
254
+ // Grow SDK sometimes silently swallows renderPaymentOptions when its
255
+ // internal resources (mp.min.js etc.) aren't fully loaded yet.
256
+ // Strategy: render once, then retry up to 3 times with increasing delays
257
+ // (2s, 3s, 4s) if onWalletChange("open") hasn't fired.
258
+ let pendingRender: { sdk: PaymentClientSdk; intent: PaymentIntent } | null = null;
259
+ let renderAttempts = 0;
260
+ const MAX_RENDER_ATTEMPTS = 4;
261
+
262
+ function renderPayment(sdk: PaymentClientSdk, intent: PaymentIntent) {
239
263
  const global = (window as any)[sdk.globalName!];
240
- if (!global) return;
264
+ if (!global || walletOpenRef.current) return;
241
265
 
242
266
  const renderMethod = sdk.renderMethod || 'renderPaymentOptions';
243
267
  const renderArg = sdk.renderArg || intent.clientSecret;
244
- let renderCalled = false;
245
-
246
- function attempt() {
247
- if (walletOpenRef.current) return;
248
- try {
249
- global[renderMethod](renderArg);
250
- renderCalled = true;
251
- console.info('Payment SDK: render call accepted');
252
- } catch (err) {
253
- console.info('Payment SDK: render not ready yet, retrying...');
254
- }
268
+ renderAttempts++;
269
+
270
+ try {
271
+ global[renderMethod](renderArg);
272
+ console.info(`Payment SDK: renderPaymentOptions called (attempt ${renderAttempts})`);
273
+ } catch (err) {
274
+ console.info('Payment SDK: render threw, will retry in 1s');
255
275
  }
256
276
 
257
- // Try immediately, then keep retrying until onWalletChange('open') fires
258
- attempt();
259
- const id = setInterval(() => {
260
- if (walletOpenRef.current) {
261
- clearInterval(id);
262
- return;
263
- }
264
- if (!renderCalled) attempt();
265
- }, 500);
266
- cleanups.push(() => clearInterval(id));
277
+ // Safety net: if wallet doesn't open within a delay, retry
278
+ if (renderAttempts < MAX_RENDER_ATTEMPTS) {
279
+ const delay = 1000 + renderAttempts * 1000; // 2s, 3s, 4s
280
+ const retryId = setTimeout(() => {
281
+ if (!walletOpenRef.current) {
282
+ console.info(`Payment SDK: wallet not open after ${delay}ms, retrying render...`);
283
+ renderPayment(sdk, intent);
284
+ }
285
+ }, delay);
286
+ cleanups.push(() => clearTimeout(retryId));
287
+ }
288
+ }
289
+
290
+ function retryRender() {
291
+ if (pendingRender && !walletOpenRef.current) {
292
+ renderPayment(pendingRender.sdk, pendingRender.intent);
293
+ }
267
294
  }
268
295
 
269
296
  // =============================================
@@ -314,14 +341,18 @@ export function PaymentStep({ checkoutId, className }: PaymentStepProps) {
314
341
  }
315
342
  if (sdk.renderType !== 'sdk-widget' || !sdk.globalName) return;
316
343
 
344
+ // Store for retryRender from onError callback
345
+ pendingRender = { sdk, intent };
346
+ cbRef.current.retryRender = retryRender;
347
+
317
348
  // If SDK wasn't loaded from providers, load + init now
318
349
  if (!sdkInitDone) {
319
350
  loadScript(sdk);
320
- // Wait for init to complete, then render
351
+ // Wait for init to complete, then render once
321
352
  const id = setInterval(() => {
322
353
  if (sdkInitDone) {
323
354
  clearInterval(id);
324
- renderWhenReady(sdk, intent);
355
+ renderPayment(sdk, intent);
325
356
  }
326
357
  }, 100);
327
358
  cleanups.push(() => clearInterval(id));
@@ -346,8 +377,8 @@ export function PaymentStep({ checkoutId, className }: PaymentStepProps) {
346
377
  }
347
378
  }
348
379
 
349
- // SDK ready — render
350
- renderWhenReady(sdk, intent);
380
+ // SDK ready — render once
381
+ renderPayment(sdk, intent);
351
382
  });
352
383
 
353
384
  return () => cleanups.forEach((fn) => fn());