@easypayment/medusa-payment-paypal 0.9.24 → 0.9.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (22) hide show
  1. package/.medusa/server/src/admin/index.js +187 -287
  2. package/.medusa/server/src/admin/index.mjs +187 -287
  3. package/.medusa/server/src/admin/routes/settings/paypal/connection/page.d.ts +0 -1
  4. package/.medusa/server/src/admin/routes/settings/paypal/connection/page.d.ts.map +1 -1
  5. package/.medusa/server/src/admin/routes/settings/paypal/connection/page.js +204 -332
  6. package/.medusa/server/src/admin/routes/settings/paypal/connection/page.js.map +1 -1
  7. package/.medusa/server/src/api/admin/paypal/onboard-complete/route.d.ts +7 -0
  8. package/.medusa/server/src/api/admin/paypal/onboard-complete/route.d.ts.map +1 -1
  9. package/.medusa/server/src/api/admin/paypal/onboard-complete/route.js +7 -0
  10. package/.medusa/server/src/api/admin/paypal/onboard-complete/route.js.map +1 -1
  11. package/.medusa/server/src/api/store/paypal/onboard-return/route.d.ts +25 -0
  12. package/.medusa/server/src/api/store/paypal/onboard-return/route.d.ts.map +1 -0
  13. package/.medusa/server/src/api/store/paypal/onboard-return/route.js +82 -0
  14. package/.medusa/server/src/api/store/paypal/onboard-return/route.js.map +1 -0
  15. package/.medusa/server/src/modules/paypal/service.d.ts.map +1 -1
  16. package/.medusa/server/src/modules/paypal/service.js +32 -2
  17. package/.medusa/server/src/modules/paypal/service.js.map +1 -1
  18. package/package.json +1 -1
  19. package/src/admin/routes/settings/paypal/connection/page.tsx +230 -354
  20. package/src/api/admin/paypal/onboard-complete/route.ts +7 -0
  21. package/src/api/store/paypal/onboard-return/route.ts +88 -0
  22. package/src/modules/paypal/service.ts +34 -3
@@ -223,9 +223,6 @@ function AdditionalSettingsTab() {
223
223
  )
224
224
  ] }) });
225
225
  }
226
- function PayPalApplePayPage() {
227
- return /* @__PURE__ */ jsx(Navigate, { to: "/settings/paypal/connection", replace: true });
228
- }
229
226
  const DEFAULT_FORM = {
230
227
  enabled: true,
231
228
  title: "Credit or Debit Card",
@@ -310,15 +307,17 @@ function AdvancedCardPaymentsTab() {
310
307
  )
311
308
  ] }) });
312
309
  }
310
+ function PayPalGooglePayPage() {
311
+ return /* @__PURE__ */ jsx(Navigate, { to: "/settings/paypal/connection", replace: true });
312
+ }
313
+ function PayPalApplePayPage() {
314
+ return /* @__PURE__ */ jsx(Navigate, { to: "/settings/paypal/connection", replace: true });
315
+ }
313
316
  const config = defineRouteConfig({
314
317
  label: "PayPal Connection"
315
318
  });
316
- const PARTNER_JS_URLS = {
317
- sandbox: "https://www.sandbox.paypal.com/webapps/merchantboarding/js/lib/lightbox/partner.js",
318
- live: "https://www.paypal.com/webapps/merchantboarding/js/lib/lightbox/partner.js"
319
- };
319
+ const PARTNER_JS_URL = "https://www.paypal.com/webapps/merchantboarding/js/lib/lightbox/partner.js";
320
320
  const SERVICE_URL = "/admin/paypal/onboarding-link";
321
- const POPUP_NAME = "PPFrame";
322
321
  const CACHE_PREFIX = "pp_onboard_cache";
323
322
  const CACHE_EXPIRY = 6 * 60 * 60 * 1e3;
324
323
  const ONBOARDING_COMPLETE_ENDPOINT = "/admin/paypal/onboard-complete";
@@ -343,9 +342,7 @@ function readCachedUrl(env) {
343
342
  function writeCachedUrl(env, url) {
344
343
  try {
345
344
  localStorage.setItem(cacheKeyFor(env), JSON.stringify({ url, ts: Date.now() }));
346
- return readCachedUrl(env) === url;
347
345
  } catch {
348
- return false;
349
346
  }
350
347
  }
351
348
  function clearCachedUrl(env) {
@@ -359,62 +356,11 @@ function clearCachedUrl(env) {
359
356
  } catch {
360
357
  }
361
358
  }
362
- function isPayPalOrigin(origin) {
363
- try {
364
- const host = new URL(origin).hostname.toLowerCase();
365
- return host === "www.paypal.com" || host === "www.sandbox.paypal.com" || host.endsWith(".paypal.com") || host.endsWith(".paypalobjects.com");
366
- } catch {
367
- return false;
368
- }
369
- }
370
- function extractAuth(data) {
371
- if (!data) return {};
372
- if (typeof data === "object") {
373
- const obj = data;
374
- const authCode = obj.authCode ?? obj.auth_code ?? obj.authcode ?? obj.code;
375
- const sharedId = obj.sharedId ?? obj.shared_id ?? obj.sharedid;
376
- if (authCode && sharedId) {
377
- return { authCode: String(authCode), sharedId: String(sharedId) };
378
- }
379
- for (const key of ["data", "payload", "message", "detail", "body", "params"]) {
380
- if (obj[key] && typeof obj[key] === "object") {
381
- const inner = extractAuth(obj[key]);
382
- if (inner.authCode && inner.sharedId) return inner;
383
- }
384
- if (typeof obj[key] === "string") {
385
- const inner = extractAuth(obj[key]);
386
- if (inner.authCode && inner.sharedId) return inner;
387
- }
388
- }
389
- return {};
390
- }
391
- if (typeof data === "string") {
392
- const s = data.trim();
393
- if (!s) return {};
394
- if (s.startsWith("{") || s.startsWith("[")) {
395
- try {
396
- return extractAuth(JSON.parse(s));
397
- } catch {
398
- }
399
- }
400
- if (/auth_?code/i.test(s) && /shared_?id/i.test(s)) {
401
- try {
402
- const sp = new URLSearchParams(s.replace(/^[?#]/, ""));
403
- const authCode = sp.get("authCode") || sp.get("auth_code") || void 0;
404
- const sharedId = sp.get("sharedId") || sp.get("shared_id") || void 0;
405
- if (authCode && sharedId) return { authCode, sharedId };
406
- } catch {
407
- }
408
- }
409
- }
410
- return {};
411
- }
412
359
  function PayPalConnectionPage() {
413
360
  const [env, setEnv] = useState("live");
414
361
  const [envReady, setEnvReady] = useState(false);
415
362
  const [connState, setConnState] = useState("loading");
416
363
  const [error, setError] = useState(null);
417
- const [popupBlocked, setPopupBlocked] = useState(false);
418
364
  const [finalUrl, setFinalUrl] = useState("");
419
365
  const [showManual, setShowManual] = useState(false);
420
366
  const [clientId, setClientId] = useState("");
@@ -426,17 +372,11 @@ function PayPalConnectionPage() {
426
372
  const errorLogRef = useRef(null);
427
373
  const runIdRef = useRef(0);
428
374
  const currentRunId = useRef(0);
375
+ const completedRef = useRef(false);
429
376
  const envRef = useRef(env);
430
377
  envRef.current = env;
431
- const finalUrlRef = useRef(finalUrl);
432
- finalUrlRef.current = finalUrl;
433
- const connStateRef = useRef(connState);
434
- connStateRef.current = connState;
435
- const inProgressRef = useRef(onboardingInProgress);
436
- inProgressRef.current = onboardingInProgress;
437
- const popupRef = useRef(null);
438
- const pollRef = useRef(null);
439
- const completedRef = useRef(false);
378
+ const pollTimerRef = useRef(null);
379
+ const pollAttemptsRef = useRef(0);
440
380
  const ppBtnMeasureRef = useRef(null);
441
381
  const [ppBtnWidth, setPpBtnWidth] = useState(null);
442
382
  const canSaveManual = useMemo(() => {
@@ -446,44 +386,72 @@ function PayPalConnectionPage() {
446
386
  setConnState("error");
447
387
  setError(msg);
448
388
  }, []);
449
- const stopPoll = useCallback(() => {
450
- if (pollRef.current) {
451
- clearInterval(pollRef.current);
452
- pollRef.current = null;
389
+ const closeMiniBrowser = useCallback(() => {
390
+ var _a, _b, _c, _d, _e, _f, _g, _h;
391
+ try {
392
+ const close1 = (_d = (_c = (_b = (_a = window.PAYPAL) == null ? void 0 : _a.apps) == null ? void 0 : _b.Signup) == null ? void 0 : _c.MiniBrowser) == null ? void 0 : _d.closeFlow;
393
+ if (typeof close1 === "function") close1();
394
+ } catch {
453
395
  }
454
- }, []);
455
- const openOnboardingPopup = useCallback((url) => {
456
- const w = 450;
457
- const h = 600;
458
- const baseLeft = typeof window.screenX === "number" ? window.screenX : window.screenLeft || 0;
459
- const baseTop = typeof window.screenY === "number" ? window.screenY : window.screenTop || 0;
460
- const outerW = window.outerWidth || document.documentElement.clientWidth || 1024;
461
- const outerH = window.outerHeight || document.documentElement.clientHeight || 768;
462
- const left = Math.round(baseLeft + Math.max(0, (outerW - w) / 2));
463
- const top = Math.round(baseTop + Math.max(0, (outerH - h) / 2));
464
- const features = `popup=yes,width=${w},height=${h},left=${left},top=${top},scrollbars=yes,resizable=yes`;
465
- let popup = null;
466
396
  try {
467
- popup = window.open(url, POPUP_NAME, features);
397
+ const close2 = (_h = (_g = (_f = (_e = window.PAYPAL) == null ? void 0 : _e.apps) == null ? void 0 : _f.Signup) == null ? void 0 : _g.miniBrowser) == null ? void 0 : _h.closeFlow;
398
+ if (typeof close2 === "function") close2();
468
399
  } catch {
469
- popup = null;
470
400
  }
471
- if (popup) {
472
- popupRef.current = popup;
401
+ }, []);
402
+ const stopStatusPolling = useCallback(() => {
403
+ if (pollTimerRef.current) {
404
+ clearTimeout(pollTimerRef.current);
405
+ pollTimerRef.current = null;
406
+ }
407
+ pollAttemptsRef.current = 0;
408
+ }, []);
409
+ const refreshStatusAndMaybeConnect = useCallback(
410
+ async (activeEnv) => {
473
411
  try {
474
- popup.focus();
412
+ const res = await fetch(`${STATUS_ENDPOINT}?environment=${activeEnv}`, {
413
+ method: "GET",
414
+ credentials: "include"
415
+ });
416
+ const st = await res.json().catch(() => ({}));
417
+ const connected = (st == null ? void 0 : st.status) === "connected" && (st == null ? void 0 : st.seller_client_id_present) === true;
418
+ if (connected) {
419
+ completedRef.current = true;
420
+ setStatusInfo(st);
421
+ setConnState("connected");
422
+ setShowManual(false);
423
+ setOnboardingInProgress(false);
424
+ clearCachedUrl(activeEnv);
425
+ closeMiniBrowser();
426
+ stopStatusPolling();
427
+ }
428
+ return connected;
475
429
  } catch {
430
+ return false;
476
431
  }
477
- }
478
- return popup;
479
- }, []);
432
+ },
433
+ [closeMiniBrowser, stopStatusPolling]
434
+ );
435
+ const startStatusPolling = useCallback(() => {
436
+ stopStatusPolling();
437
+ const MAX_ATTEMPTS = 100;
438
+ const tick = async () => {
439
+ pollAttemptsRef.current += 1;
440
+ const connected = await refreshStatusAndMaybeConnect(envRef.current);
441
+ if (connected || completedRef.current) return;
442
+ if (pollAttemptsRef.current >= MAX_ATTEMPTS) {
443
+ stopStatusPolling();
444
+ return;
445
+ }
446
+ pollTimerRef.current = setTimeout(tick, 3e3);
447
+ };
448
+ pollTimerRef.current = setTimeout(tick, 3e3);
449
+ }, [refreshStatusAndMaybeConnect, stopStatusPolling]);
480
450
  const completeOnboarding = useCallback(
481
451
  async (authCode, sharedId) => {
482
- var _a, _b, _c, _d, _e, _f, _g, _h;
483
452
  if (!authCode || !sharedId) return;
484
453
  if (completedRef.current) return;
485
454
  completedRef.current = true;
486
- stopPoll();
487
455
  try {
488
456
  window.onbeforeunload = null;
489
457
  } catch {
@@ -492,7 +460,6 @@ function PayPalConnectionPage() {
492
460
  setOnboardingInProgress(true);
493
461
  setConnState("loading");
494
462
  setError(null);
495
- setPopupBlocked(false);
496
463
  try {
497
464
  const res = await fetch(ONBOARDING_COMPLETE_ENDPOINT, {
498
465
  method: "POST",
@@ -504,32 +471,20 @@ function PayPalConnectionPage() {
504
471
  const txt = await res.text().catch(() => "");
505
472
  throw new Error(txt || `Onboarding exchange failed (${res.status})`);
506
473
  }
507
- try {
508
- (_a = popupRef.current) == null ? void 0 : _a.close();
509
- } catch {
510
- }
511
- try {
512
- const close1 = (_e = (_d = (_c = (_b = window.PAYPAL) == null ? void 0 : _b.apps) == null ? void 0 : _c.Signup) == null ? void 0 : _d.MiniBrowser) == null ? void 0 : _e.closeFlow;
513
- if (typeof close1 === "function") close1();
514
- } catch {
515
- }
516
- try {
517
- const close2 = ((_h = (_g = (_f = window.PAYPAL) == null ? void 0 : _f.apps) == null ? void 0 : _g.Signup) == null ? void 0 : _h.miniBrowser) && window.PAYPAL.apps.Signup.miniBrowser.closeFlow;
518
- if (typeof close2 === "function") close2();
519
- } catch {
520
- }
474
+ closeMiniBrowser();
521
475
  clearCachedUrl(activeEnv);
522
476
  try {
523
- const statusRes = await fetch(`${STATUS_ENDPOINT}?environment=${activeEnv}`, {
524
- method: "GET",
525
- credentials: "include"
526
- });
477
+ const statusRes = await fetch(
478
+ `${STATUS_ENDPOINT}?environment=${activeEnv}`,
479
+ { method: "GET", credentials: "include" }
480
+ );
527
481
  const refreshedStatus = await statusRes.json().catch(() => ({}));
528
482
  setStatusInfo(refreshedStatus || null);
529
483
  } catch {
530
484
  }
531
485
  setConnState("connected");
532
486
  setShowManual(false);
487
+ stopStatusPolling();
533
488
  } catch (e) {
534
489
  completedRef.current = false;
535
490
  console.error(e);
@@ -539,42 +494,72 @@ function PayPalConnectionPage() {
539
494
  setOnboardingInProgress(false);
540
495
  }
541
496
  },
542
- [stopPoll]
497
+ [closeMiniBrowser, stopStatusPolling]
543
498
  );
544
- const startStatusPoll = useCallback(() => {
545
- stopPoll();
546
- let ticks = 0;
547
- pollRef.current = setInterval(async () => {
548
- var _a;
549
- ticks += 1;
550
- if (completedRef.current || ticks > 150) {
551
- stopPoll();
552
- return;
553
- }
499
+ const initPartner = useCallback(() => {
500
+ var _a, _b;
501
+ const signup = (_b = (_a = window.PAYPAL) == null ? void 0 : _a.apps) == null ? void 0 : _b.Signup;
502
+ const init = (signup == null ? void 0 : signup.miniBrowser) && signup.miniBrowser.init || (signup == null ? void 0 : signup.MiniBrowser) && signup.MiniBrowser.init;
503
+ if (typeof init === "function") {
554
504
  try {
555
- const r = await fetch(`${STATUS_ENDPOINT}?environment=${envRef.current}`, {
556
- method: "GET",
557
- credentials: "include"
558
- });
559
- const st = await r.json().catch(() => ({}));
560
- if ((st == null ? void 0 : st.status) === "connected" && (st == null ? void 0 : st.seller_client_id_present) === true) {
561
- completedRef.current = true;
562
- stopPoll();
563
- try {
564
- (_a = popupRef.current) == null ? void 0 : _a.close();
565
- } catch {
566
- }
567
- clearCachedUrl(envRef.current);
568
- setStatusInfo(st);
569
- setConnState("connected");
570
- setShowManual(false);
571
- setOnboardingInProgress(false);
572
- }
573
- } catch {
505
+ init();
506
+ } catch (e) {
507
+ console.error("[paypal] partner.js init failed:", e);
508
+ }
509
+ }
510
+ }, []);
511
+ useEffect(() => {
512
+ const existingScript = document.getElementById("paypal-partner-js");
513
+ if (existingScript) return;
514
+ const preloadHref = PARTNER_JS_URL;
515
+ let preloadLink = null;
516
+ if (!document.head.querySelector(`link[rel="preload"][href="${preloadHref}"]`)) {
517
+ preloadLink = document.createElement("link");
518
+ preloadLink.rel = "preload";
519
+ preloadLink.href = preloadHref;
520
+ preloadLink.as = "script";
521
+ document.head.appendChild(preloadLink);
522
+ }
523
+ const ppScript = document.createElement("script");
524
+ ppScript.id = "paypal-partner-js";
525
+ ppScript.src = preloadHref;
526
+ ppScript.async = true;
527
+ document.head.appendChild(ppScript);
528
+ return () => {
529
+ if (preloadLink == null ? void 0 : preloadLink.parentNode) preloadLink.parentNode.removeChild(preloadLink);
530
+ if (ppScript.parentNode) ppScript.parentNode.removeChild(ppScript);
531
+ };
532
+ }, []);
533
+ const activatePayPal = useCallback(
534
+ (url, runId) => {
535
+ if (paypalButtonRef.current) {
536
+ paypalButtonRef.current.href = url;
574
537
  }
575
- }, 2e3);
576
- }, [stopPoll]);
577
- const generateLinkAndReload = useCallback(
538
+ setFinalUrl(url);
539
+ let attempts = 0;
540
+ const MAX_ATTEMPTS = 200;
541
+ const tryInit = () => {
542
+ var _a, _b;
543
+ if (runId !== currentRunId.current) return;
544
+ if ((_b = (_a = window.PAYPAL) == null ? void 0 : _a.apps) == null ? void 0 : _b.Signup) {
545
+ initPartner();
546
+ setConnState("ready");
547
+ return;
548
+ }
549
+ attempts++;
550
+ if (attempts >= MAX_ATTEMPTS) {
551
+ showError(
552
+ "PayPal partner script failed to load. Please refresh and try again."
553
+ );
554
+ return;
555
+ }
556
+ setTimeout(tryInit, 50);
557
+ };
558
+ tryInit();
559
+ },
560
+ [initPartner, showError]
561
+ );
562
+ const fetchFreshLink = useCallback(
578
563
  async (targetEnv, runId) => {
579
564
  if (initLoaderRef.current) {
580
565
  const loaderText = initLoaderRef.current.querySelector("#loader-text");
@@ -596,19 +581,14 @@ function PayPalConnectionPage() {
596
581
  return;
597
582
  }
598
583
  const url = href + (href.includes("?") ? "&" : "?") + "displayMode=minibrowser";
599
- const persisted = writeCachedUrl(targetEnv, url);
600
- if (persisted) {
601
- window.location.reload();
602
- return;
603
- }
604
- setFinalUrl(url);
605
- setConnState("ready");
584
+ writeCachedUrl(targetEnv, url);
585
+ activatePayPal(url, runId);
606
586
  } catch {
607
587
  if (runId !== currentRunId.current) return;
608
588
  showError("Unable to connect to service.");
609
589
  }
610
590
  },
611
- [showError]
591
+ [activatePayPal, showError]
612
592
  );
613
593
  useEffect(() => {
614
594
  let alive = true;
@@ -632,7 +612,6 @@ function PayPalConnectionPage() {
632
612
  const run = async () => {
633
613
  setConnState("loading");
634
614
  setError(null);
635
- setPopupBlocked(false);
636
615
  setFinalUrl("");
637
616
  try {
638
617
  const r = await fetch(`${STATUS_ENDPOINT}?environment=${env}`, {
@@ -654,135 +633,43 @@ function PayPalConnectionPage() {
654
633
  if (cancelled || runId !== currentRunId.current) return;
655
634
  const cached = readCachedUrl(env);
656
635
  if (cached) {
657
- setFinalUrl(cached);
658
- setConnState("ready");
636
+ activatePayPal(cached, runId);
659
637
  return;
660
638
  }
661
- await generateLinkAndReload(env, runId);
639
+ await fetchFreshLink(env, runId);
662
640
  };
663
641
  run();
664
642
  return () => {
665
643
  cancelled = true;
666
644
  };
667
- }, [env, envReady, generateLinkAndReload]);
668
- useEffect(() => {
669
- var _a, _b, _c;
670
- if (connState !== "ready" || !finalUrl) return;
671
- const scriptUrl = PARTNER_JS_URLS[env];
672
- let cancelled = false;
673
- let pollTimer;
674
- const initPartner = (attempt = 0) => {
675
- var _a2, _b2;
676
- if (cancelled) return;
677
- const signup = (_b2 = (_a2 = window.PAYPAL) == null ? void 0 : _a2.apps) == null ? void 0 : _b2.Signup;
678
- const target = (signup == null ? void 0 : signup.miniBrowser) && typeof signup.miniBrowser.init === "function" ? signup.miniBrowser : (signup == null ? void 0 : signup.MiniBrowser) && typeof signup.MiniBrowser.init === "function" ? signup.MiniBrowser : null;
679
- if (target == null ? void 0 : target.init) {
680
- try {
681
- target.init();
682
- } catch (e) {
683
- console.error("[paypal] partner.js init failed:", e);
684
- }
685
- return;
686
- }
687
- if (typeof (signup == null ? void 0 : signup.render) === "function") {
688
- try {
689
- signup.render();
690
- } catch (e) {
691
- console.error("[paypal] partner.js render failed:", e);
692
- }
693
- return;
694
- }
695
- if (attempt < 40) {
696
- pollTimer = setTimeout(() => initPartner(attempt + 1), 50);
697
- return;
698
- }
699
- try {
700
- document.dispatchEvent(new Event("DOMContentLoaded"));
701
- } catch {
702
- }
703
- };
704
- const existingScript = document.getElementById("paypal-partner-js");
705
- if (existingScript) {
706
- (_a = existingScript.parentNode) == null ? void 0 : _a.removeChild(existingScript);
707
- }
708
- if ((_c = (_b = window.PAYPAL) == null ? void 0 : _b.apps) == null ? void 0 : _c.Signup) {
709
- try {
710
- delete window.PAYPAL.apps.Signup;
711
- } catch {
712
- }
713
- }
714
- const ppScript = document.createElement("script");
715
- ppScript.id = "paypal-partner-js";
716
- ppScript.src = scriptUrl;
717
- ppScript.async = true;
718
- ppScript.onload = () => initPartner();
719
- document.body.appendChild(ppScript);
720
- return () => {
721
- cancelled = true;
722
- if (pollTimer) clearTimeout(pollTimer);
723
- if (ppScript.parentNode) ppScript.parentNode.removeChild(ppScript);
724
- };
725
- }, [connState, finalUrl, env]);
726
- useEffect(() => {
727
- const onMessage = (ev) => {
728
- let serialized = "";
729
- try {
730
- serialized = typeof ev.data === "string" ? ev.data : JSON.stringify(ev.data);
731
- } catch {
732
- serialized = String(ev.data);
733
- }
734
- const looksRelevant = isPayPalOrigin(ev.origin) || /auth_?code|shared_?id|onboard|merchantId/i.test(serialized || "");
735
- if (looksRelevant) {
736
- console.info(
737
- "[PayPal onboarding] message from",
738
- ev.origin,
739
- "·",
740
- (serialized || "").slice(0, 500)
741
- );
742
- }
743
- if (!isPayPalOrigin(ev.origin)) return;
744
- const { authCode, sharedId } = extractAuth(ev.data);
745
- if (authCode && sharedId) {
746
- completeOnboarding(authCode, sharedId);
747
- }
748
- };
749
- window.addEventListener("message", onMessage);
750
- return () => window.removeEventListener("message", onMessage);
751
- }, [completeOnboarding]);
645
+ }, [env, envReady, fetchFreshLink, activatePayPal]);
752
646
  useLayoutEffect(() => {
753
647
  window.onboardingCallback = (authCode, sharedId) => {
754
- completeOnboarding(authCode, sharedId);
648
+ void completeOnboarding(authCode, sharedId);
755
649
  };
756
650
  return () => {
757
651
  window.onboardingCallback = void 0;
758
652
  };
759
653
  }, [completeOnboarding]);
760
654
  useEffect(() => {
761
- const onCaptureClick = (e) => {
762
- const btn = paypalButtonRef.current;
763
- if (!btn) return;
764
- const target = e.target;
765
- if (!target || !btn.contains(target)) return;
766
- e.preventDefault();
767
- e.stopImmediatePropagation();
768
- if (connStateRef.current !== "ready" || !finalUrlRef.current || inProgressRef.current) {
769
- return;
770
- }
771
- completedRef.current = false;
772
- const popup = openOnboardingPopup(finalUrlRef.current);
773
- if (!popup) {
774
- setPopupBlocked(true);
775
- return;
776
- }
777
- setPopupBlocked(false);
778
- startStatusPoll();
655
+ const onMessage = (event) => {
656
+ const data = event == null ? void 0 : event.data;
657
+ if (!data || data.source !== "paypal-onboarding-return") return;
658
+ const params = data.params || {};
659
+ const authCode = params.authCode || params.auth_code;
660
+ const sharedId = params.sharedId || params.shared_id;
661
+ const activeEnv = envRef.current;
662
+ void (async () => {
663
+ const connected = await refreshStatusAndMaybeConnect(activeEnv);
664
+ if (!connected && authCode && sharedId) {
665
+ await completeOnboarding(authCode, sharedId);
666
+ }
667
+ })();
779
668
  };
780
- document.addEventListener("click", onCaptureClick, true);
781
- return () => document.removeEventListener("click", onCaptureClick, true);
782
- }, [openOnboardingPopup, startStatusPoll]);
783
- useEffect(() => {
784
- return () => stopPoll();
785
- }, [stopPoll]);
669
+ window.addEventListener("message", onMessage);
670
+ return () => window.removeEventListener("message", onMessage);
671
+ }, [completeOnboarding, refreshStatusAndMaybeConnect]);
672
+ useEffect(() => stopStatusPolling, [stopStatusPolling]);
786
673
  useLayoutEffect(() => {
787
674
  const el = ppBtnMeasureRef.current;
788
675
  if (!el) return;
@@ -804,7 +691,12 @@ function PayPalConnectionPage() {
804
691
  };
805
692
  }, [connState, env, finalUrl]);
806
693
  const handleConnectClick = (e) => {
807
- e.preventDefault();
694
+ if (connState !== "ready" || !finalUrl || onboardingInProgress) {
695
+ e.preventDefault();
696
+ return;
697
+ }
698
+ completedRef.current = false;
699
+ startStatusPolling();
808
700
  };
809
701
  const handleSaveManual = async () => {
810
702
  if (!canSaveManual || onboardingInProgress) return;
@@ -846,6 +738,7 @@ function PayPalConnectionPage() {
846
738
  const handleDisconnect = async () => {
847
739
  if (onboardingInProgress) return;
848
740
  if (!window.confirm("Disconnect PayPal for this environment?")) return;
741
+ stopStatusPolling();
849
742
  setOnboardingInProgress(true);
850
743
  setConnState("loading");
851
744
  setError(null);
@@ -866,7 +759,7 @@ function PayPalConnectionPage() {
866
759
  clearCachedUrl(env);
867
760
  completedRef.current = false;
868
761
  currentRunId.current = ++runIdRef.current;
869
- await generateLinkAndReload(env, currentRunId.current);
762
+ await fetchFreshLink(env, currentRunId.current);
870
763
  } catch (e) {
871
764
  console.error(e);
872
765
  setConnState("error");
@@ -878,9 +771,9 @@ function PayPalConnectionPage() {
878
771
  const handleEnvChange = async (e) => {
879
772
  const next = e.target.value;
880
773
  if (next === env || onboardingInProgress) return;
774
+ stopStatusPolling();
881
775
  completedRef.current = false;
882
776
  clearCachedUrl();
883
- setPopupBlocked(false);
884
777
  setConnState("loading");
885
778
  try {
886
779
  await fetch(ENVIRONMENT_ENDPOINT, {
@@ -914,7 +807,19 @@ function PayPalConnectionPage() {
914
807
  ) }),
915
808
  /* @__PURE__ */ jsx("div", { className: "text-sm font-medium pt-2", children: env === "sandbox" ? "Connect to PayPal (Sandbox)" : "Connect to PayPal" }),
916
809
  /* @__PURE__ */ jsx("div", { className: "max-w-xl", children: connState === "connected" ? /* @__PURE__ */ jsxs("div", { children: [
917
- /* @__PURE__ */ jsx("div", { className: "text-sm text-green-600 bg-green-50 p-3 rounded border border-green-200", children: "✅ Successfully connected to PayPal!" }),
810
+ /* @__PURE__ */ jsxs("div", { className: "text-sm text-green-600 bg-green-50 p-3 rounded border border-green-200", children: [
811
+ "✅ Successfully connected to PayPal!",
812
+ /* @__PURE__ */ jsx(
813
+ "a",
814
+ {
815
+ "data-paypal-button": "true",
816
+ "data-paypal-onboard-complete": "onboardingCallback",
817
+ href: "#",
818
+ style: { display: "none" },
819
+ children: "PayPal"
820
+ }
821
+ )
822
+ ] }),
918
823
  /* @__PURE__ */ jsxs("div", { className: "mt-3 rounded-md border border-ui-border-base bg-ui-bg-subtle p-3 text-xs text-ui-fg-subtle", children: [
919
824
  /* @__PURE__ */ jsx("div", { className: "font-medium text-ui-fg-base", children: "Connected PayPal account" }),
920
825
  /* @__PURE__ */ jsxs("div", { className: "mt-1", children: [
@@ -955,7 +860,6 @@ function PayPalConnectionPage() {
955
860
  ppBtnMeasureRef.current = node;
956
861
  },
957
862
  id: "paypal-button",
958
- target: POPUP_NAME,
959
863
  "data-paypal-button": "true",
960
864
  href: finalUrl || "#",
961
865
  "data-paypal-onboard-complete": "onboardingCallback",
@@ -969,7 +873,6 @@ function PayPalConnectionPage() {
969
873
  children: "Connect to PayPal"
970
874
  }
971
875
  ),
972
- popupBlocked && /* @__PURE__ */ jsx("div", { className: "mt-3 text-left text-xs bg-amber-50 text-amber-700 p-3 border border-amber-200 rounded", children: "Your browser blocked the PayPal popup. Please allow popups for this site, then click “Connect to PayPal” again." }),
973
876
  /* @__PURE__ */ jsx(
974
877
  "div",
975
878
  {
@@ -1125,9 +1028,6 @@ function PayPalConnectionPage() {
1125
1028
  ` })
1126
1029
  ] });
1127
1030
  }
1128
- function PayPalGooglePayPage() {
1129
- return /* @__PURE__ */ jsx(Navigate, { to: "/settings/paypal/connection", replace: true });
1130
- }
1131
1031
  function PayPalPayLaterMessagingPage() {
1132
1032
  return /* @__PURE__ */ jsx(Navigate, { to: "/settings/paypal/connection", replace: true });
1133
1033
  }
@@ -1349,22 +1249,22 @@ const routeModule = {
1349
1249
  Component: AdditionalSettingsTab,
1350
1250
  path: "/settings/paypal/additional-settings"
1351
1251
  },
1352
- {
1353
- Component: PayPalApplePayPage,
1354
- path: "/settings/paypal/apple-pay"
1355
- },
1356
1252
  {
1357
1253
  Component: AdvancedCardPaymentsTab,
1358
1254
  path: "/settings/paypal/advanced-card-payments"
1359
1255
  },
1360
- {
1361
- Component: PayPalConnectionPage,
1362
- path: "/settings/paypal/connection"
1363
- },
1364
1256
  {
1365
1257
  Component: PayPalGooglePayPage,
1366
1258
  path: "/settings/paypal/google-pay"
1367
1259
  },
1260
+ {
1261
+ Component: PayPalApplePayPage,
1262
+ path: "/settings/paypal/apple-pay"
1263
+ },
1264
+ {
1265
+ Component: PayPalConnectionPage,
1266
+ path: "/settings/paypal/connection"
1267
+ },
1368
1268
  {
1369
1269
  Component: PayPalPayLaterMessagingPage,
1370
1270
  path: "/settings/paypal/pay-later-messaging"
@@ -12,7 +12,6 @@ declare global {
12
12
  init?: () => void;
13
13
  closeFlow?: () => void;
14
14
  };
15
- render?: () => void;
16
15
  };
17
16
  };
18
17
  };